You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ya...@apache.org on 2026/06/11 01:43:26 UTC
(airavata-portals) branch main updated: Thin proto-direct Django portal: Keycloak-only auth, no DRF/Thrift/DB account layer (#211)
This is an automated email from the ASF dual-hosted git repository.
yasithdev pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airavata-portals.git
The following commit(s) were added to refs/heads/main by this push:
new fa5e322a2 Thin proto-direct Django portal: Keycloak-only auth, no DRF/Thrift/DB account layer (#211)
fa5e322a2 is described below
commit fa5e322a24d380fd0106fba241586231fd6edf98
Author: Yasith Jayawardana <ya...@gatech.edu>
AuthorDate: Wed Jun 10 21:43:20 2026 -0400
Thin proto-direct Django portal: Keycloak-only auth, no DRF/Thrift/DB account layer (#211)
Reduces the Airavata Django portal to a thin client over the proto-direct airavata-python-sdk (its sole Airavata dependency). Removes Django REST Framework entirely in favor of a small in-repo request/response/router/auth layer that renders protobuf messages to snake_case JSON, drops the retired Thrift SDKs, and feeds the frontend lean snake_case proto shapes. Makes auth Keycloak-only — the portal keeps only login-initiation and a post-logout landing while registration, password reset [...]
---
.../compose/dbinit/01-init-db.sql | 8 -
airavata-django-portal/compose/docker-compose.yaml | 52 -
airavata-django-portal/django_airavata/__init__.py | 10 -
.../BatchQueueResourcePolicy.vue | 44 +-
.../ComputePreference.vue | 92 +-
.../ComputeResourcePolicyEditor.vue | 42 +-
.../ComputeResourcePolicySummary.vue | 16 +-
.../ComputeResourceReservationEditor.vue | 32 +-
.../ComputeResourceReservationList.vue | 18 +-
.../ComputeResourceReservationsSummary.vue | 2 +-
.../GroupComputeResourcePreference.vue | 64 +-
.../applications/ApplicationDeploymentEditor.vue | 84 +-
.../applications/ApplicationDeploymentsList.vue | 28 +-
.../applications/ApplicationEditorContainer.vue | 112 +-
.../applications/ApplicationInputFieldEditor.vue | 28 +-
.../applications/ApplicationInterfaceEditor.vue | 38 +-
.../applications/ApplicationModuleEditor.vue | 12 +-
.../applications/ApplicationOutputFieldEditor.vue | 27 +-
.../credentials/SSHCredentialSelector.vue | 4 +-
.../dashboards/ApplicationsDashboard.vue | 6 +-
.../ComputeResourcePreferenceDashboard.vue | 20 +-
.../dashboards/CredentialStoreDashboard.vue | 14 +-
.../GatewayResourceProfileEditor.vue | 6 +-
.../GatewayResourceProfileEditorContainer.vue | 22 +-
.../gatewayprofile/StoragePreferenceEditor.vue | 6 +-
.../gatewayprofile/StoragePreferenceList.vue | 28 +-
.../src/components/notices/NoticeEditor.vue | 22 +-
.../notices/NoticesManagementContainer.vue | 26 +-
.../statistics/ExperimentDetailsView.vue | 177 +-
.../statistics/ExperimentStatisticsContainer.vue | 74 +-
.../components/users/ExtendedUserProfilePanel.vue | 2 +-
.../components/users/GroupMembershipDisplay.vue | 12 +-
.../IdentityServiceUserManagementContainer.vue | 24 +-
.../UnverifiedEmailUserManagementContainer.vue | 26 +-
.../src/components/users/UserDetailsContainer.vue | 32 +-
.../components/users/UserGroupMembershipEditor.vue | 14 +-
.../src/components/users/UserProfilePanel.vue | 8 +-
.../ExperimentStatisticsContainer.spec.js | 78 +-
.../django_airavata/apps/api/admin.py | 26 -
.../django_airavata/apps/api/authentication.py | 33 -
.../django_airavata/apps/api/downloads.py | 33 +-
.../django_airavata/apps/api/exceptions.py | 79 +-
.../django_airavata/apps/api/grpc_adapters.py | 53 -
.../django_airavata/apps/api/grpc_requests.py | 63 -
.../django_airavata/apps/api/helpers.py | 177 +-
.../django_airavata/apps/api/output_views.py | 20 +-
.../django_airavata/apps/api/proto_render.py | 98 +
.../django_airavata/apps/api/serializers.py | 3299 +-------------------
.../js/models/ApplicationDeploymentDescription.js | 35 +-
.../js/models/ApplicationInterfaceDefinition.js | 46 +-
.../js/models/ApplicationModule.js | 11 +-
.../js/models/AwsComputeResourcePreference.js | 4 +-
.../django_airavata_api/js/models/BaseEnum.js | 32 +-
.../django_airavata_api/js/models/BaseModel.js | 9 +-
.../django_airavata_api/js/models/BatchQueue.js | 26 +-
.../js/models/BatchQueueResourcePolicy.js | 42 +-
.../django_airavata_api/js/models/CommandObject.js | 2 +-
.../models/ComputationalResourceSchedulingModel.js | 101 +-
.../js/models/ComputeResourceDescription.js | 34 +-
.../js/models/ComputeResourcePolicy.js | 16 +-
.../js/models/ComputeResourceReservation.js | 32 +-
.../js/models/CredentialSummary.js | 11 +-
.../django_airavata_api/js/models/DataProduct.js | 47 +-
.../js/models/DataReplicaLocation.js | 27 +-
.../django_airavata_api/js/models/DataType.js | 1 +
.../django_airavata_api/js/models/ErrorModel.js | 12 +-
.../django_airavata_api/js/models/Experiment.js | 73 +-
.../js/models/ExperimentSearchFields.js | 1 +
.../js/models/ExperimentState.js | 19 +-
.../js/models/ExperimentStatistics.js | 24 +-
.../js/models/ExperimentStatus.js | 4 +-
.../js/models/ExperimentSummary.js | 35 +-
.../js/models/FullExperiment.js | 20 +-
.../js/models/GatewayResourceProfile.js | 15 +-
.../static/django_airavata_api/js/models/Group.js | 20 +-
.../js/models/GroupAccountSSHProvisionerConfig.js | 8 +-
.../js/models/GroupComputeResourcePreference.js | 193 +-
.../js/models/GroupPermission.js | 3 +-
.../js/models/GroupResourceProfile.js | 80 +-
.../js/models/IAMUserProfile.js | 26 +-
.../static/django_airavata_api/js/models/IOType.js | 2 +-
.../js/models/InputDataObjectType.js | 46 +-
.../js/models/IntermediateOutput.js | 6 +-
.../static/django_airavata_api/js/models/Job.js | 34 +-
.../django_airavata_api/js/models/JobState.js | 2 +-
.../django_airavata_api/js/models/JobStatus.js | 6 +-
.../django_airavata_api/js/models/Notification.js | 39 +-
.../js/models/NotificationPriority.js | 7 +-
.../js/models/OutputDataObjectType.js | 44 +-
.../js/models/ParallelismType.js | 3 +
.../static/django_airavata_api/js/models/Parser.js | 14 +-
.../django_airavata_api/js/models/ParserInput.js | 4 +-
.../django_airavata_api/js/models/ParserOutput.js | 4 +-
.../django_airavata_api/js/models/ProcessModel.js | 62 +-
.../django_airavata_api/js/models/ProcessState.js | 32 +-
.../django_airavata_api/js/models/ProcessStatus.js | 7 +-
.../js/models/ProcessWorkflow.js | 8 +-
.../django_airavata_api/js/models/Project.js | 27 +-
.../js/models/ResourcePermissionType.js | 8 +-
.../django_airavata_api/js/models/ResourceType.js | 4 +-
.../django_airavata_api/js/models/SetEnvPaths.js | 2 +-
.../django_airavata_api/js/models/SharedEntity.js | 45 +-
.../js/models/SlurmComputeResourcePreference.js | 18 +-
.../js/models/StoragePreference.js | 8 +-
.../js/models/StorageResourceDescription.js | 18 +-
.../django_airavata_api/js/models/SummaryType.js | 4 +-
.../static/django_airavata_api/js/models/Task.js | 30 +-
.../django_airavata_api/js/models/TaskState.js | 9 +-
.../django_airavata_api/js/models/TaskStatus.js | 6 +-
.../django_airavata_api/js/models/TaskTypes.js | 1 +
.../js/models/UnverifiedEmailUserProfile.js | 15 +-
.../js/models/UserConfigurationData.js | 30 +-
.../js/models/UserPermission.js | 3 +-
.../django_airavata_api/js/models/UserProfile.js | 43 +-
.../django_airavata_api/js/models/UserStatus.js | 4 +
.../js/models/UserStorageDirectory.js | 22 +-
.../js/models/UserStorageFile.js | 23 +-
.../js/models/UserStoragePath.js | 8 +-
.../js/utils/ExperimentUtils.js | 50 +-
.../tests/models/proto-direct.test.js | 129 +
.../tests/utils/ExperimentUtils.test.js | 264 +-
.../apps/api/tests/test_data_products_contract.py | 263 ++
.../api/tests/test_full_experiment_contract.py | 442 +++
.../tests/test_group_resource_profiles_contract.py | 444 +++
.../test_per_protocol_job_submission_contract.py | 304 ++
.../apps/api/tests/test_proto_render.py | 153 +
.../django_airavata/apps/api/tests/test_views.py | 43 +-
.../django_airavata/apps/api/urls.py | 91 +-
.../django_airavata/apps/api/view_utils.py | 167 +-
.../django_airavata/apps/api/views.py | 2578 +++++++++------
.../django_airavata/apps/api/web.py | 996 ++++++
.../django_airavata/apps/auth/admin.py | 5 -
.../django_airavata/apps/auth/backends.py | 339 --
.../django_airavata/apps/auth/forms.py | 158 -
.../django_airavata/apps/auth/middleware.py | 183 +-
.../auth/migrations/0020_remove_account_models.py | 47 +
.../django_airavata/apps/auth/models.py | 362 ---
.../django_airavata/apps/auth/serializers.py | 372 ---
.../django_airavata/apps/auth/signals.py | 34 -
.../js/components/ExtendedUserProfileEditor.vue | 57 -
.../ExtendedUserProfileMultiChoiceValueEditor.vue | 157 -
.../ExtendedUserProfileSingleChoiceValueEditor.vue | 159 -
.../ExtendedUserProfileTextValueEditor.vue | 63 -
...ExtendedUserProfileUserAgreementValueEditor.vue | 81 -
.../components/ExtendedUserProfileValueEditor.vue | 47 -
.../js/components/UserProfileEditor.vue | 123 -
.../js/containers/UserProfileContainer.vue | 138 -
.../django_airavata_auth/js/entry-user-profile.js | 11 -
.../static/django_airavata_auth/js/store/index.js | 18 -
.../js/store/modules/extendedUserProfile.js | 191 --
.../js/store/modules/userProfile.js | 64 -
.../django_airavata_auth/callback-error.html | 22 -
.../django_airavata_auth/create_account.html | 34 -
.../django_airavata_auth/forgot_password.html | 24 -
.../templates/django_airavata_auth/logged_out.html | 8 +
.../django_airavata_auth/login-desktop.html | 18 +-
.../auth/templates/django_airavata_auth/login.html | 16 -
.../login_username_password.html | 18 -
.../partials/externals_login_form.html | 27 -
.../django_airavata_auth/partials/form.html | 17 -
.../django_airavata_auth/partials/form_field.html | 25 -
.../partials/non_field_errors.html | 6 -
.../partials/username_password_login_form.html | 50 -
.../django_airavata_auth/reset_password.html | 23 -
.../settings_local.py.template | 14 -
.../django_airavata_auth/verify_email.html | 22 -
.../apps/auth/tests/test_backends.py | 178 --
.../apps/auth/tests/test_middleware.py | 123 -
.../django_airavata/apps/auth/tests/test_models.py | 383 ---
.../django_airavata/apps/auth/tests/test_views.py | 302 --
.../apps/auth/token_authentication.py | 85 +-
.../django_airavata/apps/auth/urls.py | 30 +-
.../django_airavata/apps/auth/utils.py | 154 +-
.../django_airavata/apps/auth/views.py | 642 +---
.../django_airavata/apps/auth/vite.config.js | 11 +-
.../js/containers/ParserDetailsContainer.vue | 2 +-
.../js/parser-components/ParserEditor.vue | 14 +-
.../js/parser-components/ParserListItem.vue | 4 +-
.../js/containers/GroupCreateContainer.vue | 2 +-
.../js/group_components/GroupList.vue | 2 +-
.../js/group_components/GroupListItem.vue | 22 +-
.../js/group_components/GroupMembersEditor.vue | 22 +-
.../ComputationalResourceSchedulingEditor.vue | 36 +-
.../js/components/experiment/ExperimentEditor.vue | 82 +-
.../js/components/experiment/ExperimentSummary.vue | 110 +-
.../experiment/GroupResourceProfileSelector.vue | 6 +-
.../components/experiment/QueueSettingsEditor.vue | 142 +-
.../experiment/input-editors/FileInputEditor.vue | 15 +-
.../input-editors/InputEditorContainer.vue | 4 +-
.../experiment/input-editors/InputFileSelector.vue | 2 +-
.../output-displays/DefaultOutputDisplay.vue | 51 +-
.../output-displays/OutputDisplayContainer.vue | 26 +-
.../WorkspaceNoticesManagementContainer.vue | 8 +-
.../js/components/project/ProjectList.vue | 2 +-
.../js/components/project/ProjectListItem.vue | 6 +-
.../storage/ExperimentStoragePathViewer.vue | 37 +-
.../components/storage/UserStorageCreateView.vue | 2 +-
.../storage/UserStorageFileSelectionContainer.vue | 2 +-
.../components/storage/UserStoragePathViewer.vue | 71 +-
.../storage-edit/UserStorageTextEditViewer.vue | 6 +-
.../js/containers/CreateExperimentContainer.vue | 8 +-
.../js/containers/DashboardContainer.vue | 22 +-
.../js/containers/EditExperimentContainer.vue | 8 +-
.../js/containers/ExperimentListContainer.vue | 35 +-
.../js/containers/RecentExperimentsContainer.vue | 10 +-
.../js/containers/UserStorageContainer.vue | 23 +-
.../js/store/modules/view-experiment.js | 38 +-
.../django_airavata_workspace/js/utils/urls.js | 10 +-
.../js/web-components/ExperimentEditor.vue | 10 +-
.../GroupResourceProfileSelector.vue | 4 +-
.../js/web-components/ProjectSelector.vue | 10 +-
.../js/web-components/QueueSettingsEditor.vue | 12 +-
.../input-editors/WebComponentInputEditorMixin.js | 2 +-
.../js/web-components/store.js | 182 +-
.../input-editors/InputEditorContainer.spec.js | 4 +-
.../tests/unit/web-components/store.spec.js | 164 +-
.../django_airavata/apps/workspace/views.py | 8 +-
.../django_airavata/context_processors.py | 41 +-
.../django_airavata/log_utils.py | 8 +
airavata-django-portal/django_airavata/settings.py | 79 +-
.../common/js/components/ApplicationCard.vue | 8 +-
.../common/js/components/ApplicationName.vue | 2 +-
.../common/js/components/ComputeResourceName.vue | 2 +-
.../common/js/components/DataProductViewer.vue | 4 +-
.../common/js/components/GatewayGroupsBadge.vue | 12 +-
.../static/common/js/components/ShareButton.vue | 60 +-
.../common/js/components/SharedEntityEditor.vue | 81 +-
.../django_airavata/templates/base.html | 2 +-
airavata-django-portal/django_airavata/urls.py | 6 +-
airavata-django-portal/requirements.txt | 26 +-
airavata-django-portal/setup.py | 14 +-
231 files changed, 7768 insertions(+), 11416 deletions(-)
diff --git a/airavata-django-portal/compose/dbinit/01-init-db.sql b/airavata-django-portal/compose/dbinit/01-init-db.sql
deleted file mode 100644
index 8df43145f..000000000
--- a/airavata-django-portal/compose/dbinit/01-init-db.sql
+++ /dev/null
@@ -1,8 +0,0 @@
-CREATE DATABASE IF NOT EXISTS django_default;
-
-CREATE USER IF NOT EXISTS 'django'@'%' IDENTIFIED BY '123456';
-ALTER USER 'django'@'%' IDENTIFIED BY '123456';
-
-GRANT ALL PRIVILEGES ON *.* TO 'django'@'%';
-
-FLUSH PRIVILEGES;
diff --git a/airavata-django-portal/compose/docker-compose.yaml b/airavata-django-portal/compose/docker-compose.yaml
deleted file mode 100644
index 25e9d2d57..000000000
--- a/airavata-django-portal/compose/docker-compose.yaml
+++ /dev/null
@@ -1,52 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-version: "3.8"
-services:
- db:
- image: mariadb:lts-ubi9
- restart: always
- command:
- --default-authentication-plugin=mysql_native_password
- --character-set-server=utf8
- --collation-server=utf8_general_ci
- ports:
- - "13306:3306"
- environment:
- MARIADB_ROOT_USER: root
- MARIADB_ROOT_PASSWORD: 123456
- MARIADB_USER: django
- MARIADB_PASSWORD: 123456
- MAX_ALLOWED_PACKET: 1073741824
- healthcheck:
- test: ["CMD-SHELL", "mariadb-admin ping --silent -u root --password=$$MARIADB_ROOT_PASSWORD"]
- interval: 10s
- timeout: 5s
- retries: 5
- volumes:
- - ./dbinit:/docker-entrypoint-initdb.d
- - mysql_data:/var/lib/mysql
-
- adminer:
- image: adminer
- restart: always
- ports:
- - 18888:8080
-
-volumes:
- mysql_data:
diff --git a/airavata-django-portal/django_airavata/__init__.py b/airavata-django-portal/django_airavata/__init__.py
index 2085355a5..e69de29bb 100644
--- a/airavata-django-portal/django_airavata/__init__.py
+++ b/airavata-django-portal/django_airavata/__init__.py
@@ -1,10 +0,0 @@
-from django.conf import settings
-
-# Only use PyMySQL as the db driver when in a local dev environment
-if settings.DEBUG:
- try:
- import pymysql
-
- pymysql.install_as_MySQLdb()
- except ImportError:
- pass
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/BatchQueueResourcePolicy.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/BatchQueueResourcePolicy.vue
index 1b55ae9b0..864f2ac9b 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/BatchQueueResourcePolicy.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/BatchQueueResourcePolicy.vue
@@ -4,20 +4,20 @@
<b-form-group
label="Maximum Allowed Nodes"
label-for="max-allowed-nodes"
- :invalid-feedback="validationFeedback.maxAllowedNodes.invalidFeedback"
- :state="validationFeedback.maxAllowedNodes.state"
+ :invalid-feedback="validationFeedback.max_allowed_nodes.invalidFeedback"
+ :state="validationFeedback.max_allowed_nodes.state"
>
<b-form-input
id="max-allowed-nodes"
type="number"
- v-model="data.maxAllowedNodes"
+ v-model="data.max_allowed_nodes"
:readonly="readonly"
@input="policyUpdated"
min="1"
- :max="batchQueue.maxNodes"
+ :max="batchQueue.max_nodes"
:formatter="numberFormatter"
- :placeholder="'Max Nodes: ' + batchQueue.maxNodes"
- :state="validationFeedback.maxAllowedNodes.state"
+ :placeholder="'Max Nodes: ' + batchQueue.max_nodes"
+ :state="validationFeedback.max_allowed_nodes.state"
>
</b-form-input>
</b-form-group>
@@ -26,20 +26,20 @@
<b-form-group
label="Maximum Allowed Cores"
label-for="max-allowed-cores"
- :invalid-feedback="validationFeedback.maxAllowedCores.invalidFeedback"
- :state="validationFeedback.maxAllowedCores.state"
+ :invalid-feedback="validationFeedback.max_allowed_cores.invalidFeedback"
+ :state="validationFeedback.max_allowed_cores.state"
>
<b-form-input
id="max-allowed-cores"
type="number"
- v-model="data.maxAllowedCores"
+ v-model="data.max_allowed_cores"
:readonly="readonly"
@input="policyUpdated"
min="1"
- :max="batchQueue.maxProcessors"
+ :max="batchQueue.max_processors"
:formatter="numberFormatter"
- :placeholder="'Max Cores: ' + batchQueue.maxProcessors"
- :state="validationFeedback.maxAllowedCores.state"
+ :placeholder="'Max Cores: ' + batchQueue.max_processors"
+ :state="validationFeedback.max_allowed_cores.state"
>
</b-form-input>
</b-form-group>
@@ -49,21 +49,21 @@
label="Maximum Allowed Wall Time"
label-for="max-allowed-walltime"
:invalid-feedback="
- validationFeedback.maxAllowedWalltime.invalidFeedback
+ validationFeedback.max_allowed_walltime.invalidFeedback
"
- :state="validationFeedback.maxAllowedWalltime.state"
+ :state="validationFeedback.max_allowed_walltime.state"
>
<b-form-input
id="max-allowed-walltime"
type="number"
- v-model="data.maxAllowedWalltime"
+ v-model="data.max_allowed_walltime"
:readonly="readonly"
@input="policyUpdated"
min="1"
- :max="batchQueue.maxRunTime"
+ :max="batchQueue.max_run_time"
:formatter="numberFormatter"
- :placeholder="'Max Wall Time: ' + batchQueue.maxRunTime"
- :state="validationFeedback.maxAllowedWalltime.state"
+ :placeholder="'Max Wall Time: ' + batchQueue.max_run_time"
+ :state="validationFeedback.max_allowed_walltime.state"
>
</b-form-input>
</b-form-group>
@@ -99,7 +99,7 @@ export default {
const localValue = this.value
? this.value.clone()
: new models.BatchQueueResourcePolicy();
- localValue.queuename = this.batchQueue.queueName;
+ localValue.queuename = this.batchQueue.queue_name;
return {
data: localValue,
};
@@ -107,9 +107,9 @@ export default {
methods: {
policyUpdated: function () {
if (
- this.data.maxAllowedNodes ||
- this.data.maxAllowedCores ||
- this.data.maxAllowedWalltime
+ this.data.max_allowed_nodes ||
+ this.data.max_allowed_cores ||
+ this.data.max_allowed_walltime
) {
this.$emit("input", this.data);
} else {
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputePreference.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputePreference.vue
index 7bbd2a2e2..be75f91bb 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputePreference.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputePreference.vue
@@ -8,9 +8,9 @@
class="group-resource-profile-name text-muted text-uppercase"
>
<i class="fa fa-server" aria-hidden="true"></i>
- {{ localGroupResourceProfile.groupResourceProfileName }}
+ {{ localGroupResourceProfile.group_resource_profile_name }}
</div>
- {{ computeResource.hostName }}
+ {{ computeResource.host_name }}
</h1>
</div>
</div>
@@ -22,16 +22,16 @@
label="Login Username"
label-for="login-username"
:invalid-feedback="
- validationFeedback.loginUserName.invalidFeedback
+ validationFeedback.login_user_name.invalidFeedback
"
- :state="validationFeedback.loginUserName.state"
+ :state="validationFeedback.login_user_name.state"
>
<b-form-input
id="login-username"
type="text"
required
- v-model="data.loginUserName"
- :state="validationFeedback.loginUserName.state"
+ v-model="data.login_user_name"
+ :state="validationFeedback.login_user_name.state"
:disabled="!userHasWriteAccess"
@input="validate"
>
@@ -42,14 +42,14 @@
label-for="credential-store-token"
>
<ssh-credential-selector
- v-model="data.resourceSpecificCredentialStoreToken"
+ v-model="data.resource_specific_credential_store_token"
v-if="localGroupResourceProfile"
:readonly="!userHasWriteAccess"
:null-option-default-credential-token="
- localGroupResourceProfile.defaultCredentialStoreToken
+ localGroupResourceProfile.default_credential_store_token
"
:null-option-disabled="
- !localGroupResourceProfile.defaultCredentialStoreToken
+ !localGroupResourceProfile.default_credential_store_token
"
>
<template
@@ -58,7 +58,7 @@
>
<span v-if="nullOptionLabelScope.defaultCredentialSummary">
Use the default SSH credential for
- {{ localGroupResourceProfile.groupResourceProfileName }} ({{
+ {{ localGroupResourceProfile.group_resource_profile_name }} ({{
nullOptionLabelScope.defaultCredentialSummary.username
}}
-
@@ -73,15 +73,15 @@
<b-form-group
label="Resource Type"
label-for="resource-type"
- :invalid-feedback="validationFeedback.resourceType.invalidFeedback"
- :state="validationFeedback.resourceType.state"
+ :invalid-feedback="validationFeedback.resource_type.invalidFeedback"
+ :state="validationFeedback.resource_type.state"
>
<b-form-select
id="resource-type"
- v-model="data.resourceType"
+ v-model="data.resource_type"
:options="resourceTypeOptions"
:disabled="!userHasWriteAccess"
- :state="validationFeedback.resourceType.state"
+ :state="validationFeedback.resource_type.state"
@change="onResourceTypeChange"
>
<template slot="first">
@@ -98,7 +98,7 @@
<b-form-input
id="allocation-number"
type="text"
- v-model="data.allocationProjectNumber"
+ v-model="data.allocation_project_number"
:disabled="!userHasWriteAccess"
>
</b-form-input>
@@ -113,7 +113,7 @@
<b-form-input
id="aws-region"
type="text"
- v-model="data.specificPreferences.region"
+ v-model="data.specific_preferences.region"
:disabled="!userHasWriteAccess"
>
</b-form-input>
@@ -125,7 +125,7 @@
<b-form-input
id="preferred-ami-id"
type="text"
- v-model="data.specificPreferences.preferredAmiId"
+ v-model="data.specific_preferences.preferred_ami_id"
:disabled="!userHasWriteAccess"
>
</b-form-input>
@@ -137,7 +137,7 @@
<b-form-input
id="preferred-instance-type"
type="text"
- v-model="data.specificPreferences.preferredInstanceType"
+ v-model="data.specific_preferences.preferred_instance_type"
:disabled="!userHasWriteAccess"
>
</b-form-input>
@@ -147,17 +147,17 @@
label="Scratch Location"
label-for="scratch-location"
:invalid-feedback="
- validationFeedback.scratchLocation.invalidFeedback
+ validationFeedback.scratch_location.invalidFeedback
"
- :state="validationFeedback.scratchLocation.state"
+ :state="validationFeedback.scratch_location.state"
>
<b-form-input
id="scratch-location"
type="text"
required
- v-model="data.scratchLocation"
+ v-model="data.scratch_location"
:disabled="!userHasWriteAccess"
- :state="validationFeedback.scratchLocation.state"
+ :state="validationFeedback.scratch_location.state"
@input="validate"
>
</b-form-input>
@@ -172,7 +172,7 @@
<div class="card-body">
<h5 class="card-title">Policy</h5>
<compute-resource-policy-editor
- :batch-queues="computeResource.batchQueues"
+ :batch-queues="computeResource.batch_queues"
:compute-resource-policy="localComputeResourcePolicy"
:batch-queue-resource-policies="localBatchQueueResourcePolicies"
:readonly="!userHasWriteAccess"
@@ -221,7 +221,7 @@
:disabled="!userHasWriteAccess"
@delete="remove">
Are you sure you want to remove the preferences for compute resource
- <strong>{{ computeResource.hostName }}</strong
+ <strong>{{ computeResource.host_name }}</strong
>?
</delete-button>
<b-button class="ml-2" variant="secondary" @click="cancel"
@@ -268,13 +268,13 @@ export default {
mounted: function () {
const computeResourcePromise = this.fetchComputeResource(this.host_id);
if (this.localGroupResourceProfile) {
- this.userHasWriteAccess = this.localGroupResourceProfile.userHasWriteAccess;
+ this.userHasWriteAccess = this.localGroupResourceProfile.user_has_write_access;
}
if (!this.value && this.id && this.host_id) {
services.GroupResourceProfileService.retrieve({lookup: this.id}).then(
(groupResourceProfile) => {
this.localGroupResourceProfile = groupResourceProfile;
- this.userHasWriteAccess = this.localGroupResourceProfile.userHasWriteAccess;
+ this.userHasWriteAccess = this.localGroupResourceProfile.user_has_write_access;
const computeResourcePreference = groupResourceProfile.getComputePreference(
this.host_id
);
@@ -308,7 +308,7 @@ export default {
data: this.value
? this.value.clone()
: new models.GroupComputeResourcePreference({
- computeResourceId: this.host_id,
+ compute_resource_id: this.host_id,
}),
localGroupResourceProfile: this.groupResourceProfile
? this.groupResourceProfile.clone()
@@ -320,8 +320,8 @@ export default {
? this.batchQueueResourcePolicies.map((pol) => pol.clone())
: [],
computeResource: {
- batchQueues: [],
- jobSubmissionInterfaces: [],
+ batch_queues: [],
+ job_submission_interfaces: [],
},
validationErrors: null,
reservationsInvalid: false,
@@ -351,7 +351,7 @@ export default {
);
},
queueNames() {
- return this.computeResource.batchQueues.map((bq) => bq.queueName);
+ return this.computeResource.batch_queues.map((bq) => bq.queue_name);
},
},
mixins: [mixins.VModelMixin],
@@ -377,20 +377,20 @@ export default {
name: "group_resource_preference",
params: {
value: groupResourceProfile,
- id: groupResourceProfile.groupResourceProfileId,
+ id: groupResourceProfile.group_resource_profile_id,
},
});
})
.catch((error) => {
if (
errors.ErrorUtils.isValidationError(error) &&
- "computePreferences" in error.details.response
+ "compute_preferences" in error.details.response
) {
- const computePreferencesIndex = groupResourceProfile.computePreferences.findIndex(
- (cp) => cp.computeResourceId === this.host_id
+ const computePreferencesIndex = groupResourceProfile.compute_preferences.findIndex(
+ (cp) => cp.compute_resource_id === this.host_id
);
this.validationErrors =
- error.details.response.computePreferences[
+ error.details.response.compute_preferences[
computePreferencesIndex
];
} else {
@@ -452,10 +452,10 @@ export default {
createDefaultComputeResourcePolicy: function (computeResourcePromise) {
computeResourcePromise.then((computeResource) => {
const defaultComputeResourcePolicy = new models.ComputeResourcePolicy();
- defaultComputeResourcePolicy.computeResourceId = this.host_id;
- defaultComputeResourcePolicy.groupResourceProfileId = this.id;
- defaultComputeResourcePolicy.allowedBatchQueues = computeResource.batchQueues.map(
- (queue) => queue.queueName
+ defaultComputeResourcePolicy.compute_resource_id = this.host_id;
+ defaultComputeResourcePolicy.group_resource_profile_id = this.id;
+ defaultComputeResourcePolicy.allowed_batch_queues = computeResource.batch_queues.map(
+ (queue) => queue.queue_name
);
this.localComputeResourcePolicy = defaultComputeResourcePolicy;
});
@@ -470,7 +470,7 @@ export default {
addReservation(reservation) {
this.data.reservations.push(reservation);
this.data.reservations.sort((a, b) =>
- a.startTime < b.startTime ? -1 : 1
+ a.start_time < b.start_time ? -1 : 1
);
},
deleteReservation(reservation) {
@@ -486,21 +486,21 @@ export default {
this.data.reservations.splice(reservationIndex, 1, reservation);
},
onResourceTypeChange() {
- if (!this.data.resourceType) {
- this.data.specificPreferences = null;
+ if (!this.data.resource_type) {
+ this.data.specific_preferences = null;
this.validate();
return;
}
if (this.data.resetSpecificPreferences) {
this.data.resetSpecificPreferences();
} else {
- const resourceTypeName = this.data.resourceType.name;
+ const resourceTypeName = this.data.resource_type.name;
const modelClassName = this._getPreferenceModelClassName(resourceTypeName);
if (modelClassName && models[modelClassName]) {
const PreferenceModel = models[modelClassName];
- this.data.specificPreferences = new PreferenceModel();
+ this.data.specific_preferences = new PreferenceModel();
} else {
- this.data.specificPreferences = null;
+ this.data.specific_preferences = null;
}
}
this.validate();
@@ -517,7 +517,7 @@ export default {
if (this.data.isResourceType) {
return this.data.isResourceType(resourceTypeName);
}
- return this.data.resourceType && this.data.resourceType.name === resourceTypeName;
+ return this.data.resource_type && this.data.resource_type.name === resourceTypeName;
},
},
beforeRouteEnter: function (to, from, next) {
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourcePolicyEditor.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourcePolicyEditor.vue
index fb83bff63..01665144a 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourcePolicyEditor.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourcePolicyEditor.vue
@@ -2,32 +2,32 @@
<b-form-group
label="Allowed Queues"
v-if="localComputeResourcePolicy"
- :invalid-feedback="validationFeedback.allowedBatchQueues.invalidFeedback"
- :state="validationFeedback.allowedBatchQueues.state"
+ :invalid-feedback="validationFeedback.allowed_batch_queues.invalidFeedback"
+ :state="validationFeedback.allowed_batch_queues.state"
>
- <div v-for="batchQueue in batchQueues" :key="batchQueue.queueName">
+ <div v-for="batchQueue in batchQueues" :key="batchQueue.queue_name">
<b-form-checkbox
:checked="
- localComputeResourcePolicy.allowedBatchQueues.includes(
- batchQueue.queueName
+ localComputeResourcePolicy.allowed_batch_queues.includes(
+ batchQueue.queue_name
)
"
:disabled="readonly"
@input="batchQueueChecked(batchQueue, $event)"
>
- {{ batchQueue.queueName }}
+ {{ batchQueue.queue_name }}
</b-form-checkbox>
<batch-queue-resource-policy
v-if="
- localComputeResourcePolicy.allowedBatchQueues.includes(
- batchQueue.queueName
+ localComputeResourcePolicy.allowed_batch_queues.includes(
+ batchQueue.queue_name
)
"
:batch-queue="batchQueue"
:readonly="readonly"
:value="
localBatchQueueResourcePolicies.find(
- (pol) => pol.queuename === batchQueue.queueName
+ (pol) => pol.queuename === batchQueue.queue_name
)
"
@input="updatedBatchQueueResourcePolicy(batchQueue, $event)"
@@ -94,27 +94,27 @@ export default {
},
allowedInvalidBatchQueueResourcePolicies() {
return this.invalidBatchQueueResourcePolicies.filter((queueName) =>
- this.localComputeResourcePolicy.allowedBatchQueues.includes(queueName)
+ this.localComputeResourcePolicy.allowed_batch_queues.includes(queueName)
);
},
},
methods: {
batchQueueChecked: function (batchQueue, checked) {
if (checked) {
- this.localComputeResourcePolicy.allowedBatchQueues.push(
- batchQueue.queueName
+ this.localComputeResourcePolicy.allowed_batch_queues.push(
+ batchQueue.queue_name
);
} else {
- const queueIndex = this.localComputeResourcePolicy.allowedBatchQueues.indexOf(
- batchQueue.queueName
+ const queueIndex = this.localComputeResourcePolicy.allowed_batch_queues.indexOf(
+ batchQueue.queue_name
);
- this.localComputeResourcePolicy.allowedBatchQueues.splice(
+ this.localComputeResourcePolicy.allowed_batch_queues.splice(
queueIndex,
1
);
// Remove batchQueueResourcePolicy if it exists
const policyIndex = this.localBatchQueueResourcePolicies.findIndex(
- (pol) => pol.queuename === batchQueue.queueName
+ (pol) => pol.queuename === batchQueue.queue_name
);
if (policyIndex >= 0) {
this.localBatchQueueResourcePolicies.splice(policyIndex, 1);
@@ -134,7 +134,7 @@ export default {
batchQueue,
batchQueueResourcePolicy
) {
- const queueName = batchQueue.queueName;
+ const queueName = batchQueue.queue_name;
if (batchQueueResourcePolicy) {
const existingPolicy = this.localBatchQueueResourcePolicies.find(
(pol) => pol.queuename === queueName
@@ -162,10 +162,10 @@ export default {
},
recordValidBatchQueueResourcePolicy(batchQueue) {
if (
- this.invalidBatchQueueResourcePolicies.includes(batchQueue.queueName)
+ this.invalidBatchQueueResourcePolicies.includes(batchQueue.queue_name)
) {
const index = this.invalidBatchQueueResourcePolicies.indexOf(
- batchQueue.queueName
+ batchQueue.queue_name
);
this.invalidBatchQueueResourcePolicies.splice(index, 1);
}
@@ -173,9 +173,9 @@ export default {
},
recordInvalidBatchQueueResourcePolicy(batchQueue) {
if (
- !this.invalidBatchQueueResourcePolicies.includes(batchQueue.queueName)
+ !this.invalidBatchQueueResourcePolicies.includes(batchQueue.queue_name)
) {
- this.invalidBatchQueueResourcePolicies.push(batchQueue.queueName);
+ this.invalidBatchQueueResourcePolicies.push(batchQueue.queue_name);
}
this.validate(); // propagate validation
},
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourcePolicySummary.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourcePolicySummary.vue
index f0ae38ed6..520b6b92d 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourcePolicySummary.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourcePolicySummary.vue
@@ -6,24 +6,24 @@
(<span title="Max Allowed Nodes"
>N:
{{
- queuePolicy.policy.maxAllowedNodes
- ? queuePolicy.policy.maxAllowedNodes
+ queuePolicy.policy.max_allowed_nodes
+ ? queuePolicy.policy.max_allowed_nodes
: "Unlimited"
}}</span
>,
<span title="Max Allowed Cores"
>C:
{{
- queuePolicy.policy.maxAllowedCores
- ? queuePolicy.policy.maxAllowedCores
+ queuePolicy.policy.max_allowed_cores
+ ? queuePolicy.policy.max_allowed_cores
: "Unlimited"
}}</span
>,
<span title="Max Allowed Walltime"
>W:
{{
- queuePolicy.policy.maxAllowedWalltime
- ? queuePolicy.policy.maxAllowedWalltime
+ queuePolicy.policy.max_allowed_walltime
+ ? queuePolicy.policy.max_allowed_walltime
: "Unlimited"
}}</span
>)
@@ -51,8 +51,8 @@ export default {
const computeResourcePolicy = this.groupResourceProfile.getComputeResourcePolicy(
this.computeResourceId
);
- if (computeResourcePolicy && computeResourcePolicy.allowedBatchQueues) {
- const queues = computeResourcePolicy.allowedBatchQueues.slice();
+ if (computeResourcePolicy && computeResourcePolicy.allowed_batch_queues) {
+ const queues = computeResourcePolicy.allowed_batch_queues.slice();
queues.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
return queues;
} else {
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourceReservationEditor.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourceReservationEditor.vue
index c58227c4b..854cc875f 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourceReservationEditor.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourceReservationEditor.vue
@@ -8,7 +8,7 @@
>
<b-form-input
id="reservation-name"
- v-model="data.reservationName"
+ v-model="data.reservation_name"
type="text"
@input="nameInputBegins = true"
:state="nameValidationState"
@@ -17,8 +17,8 @@
<b-form-group
label="Start Time"
label-for="start-time"
- :invalid-feedback="getValidationFeedback('startTime')"
- :state="getValidationState('startTime')"
+ :invalid-feedback="getValidationFeedback('start_time')"
+ :state="getValidationState('start_time')"
>
<datetime
id="start-time"
@@ -39,14 +39,14 @@
:week-start="7"
use12-hour
auto
- @input="data.startTime = stringToDate($event)"
+ @input="data.start_time = stringToDate($event)"
></datetime>
</b-form-group>
<b-form-group
label="End Time"
label-for="end-time"
- :invalid-feedback="getValidationFeedback('endTime')"
- :state="getValidationState('endTime')"
+ :invalid-feedback="getValidationFeedback('end_time')"
+ :state="getValidationState('end_time')"
>
<datetime
id="end-time"
@@ -54,7 +54,7 @@
:value="endTimeAsString"
:input-class="{
'form-control': true,
- 'is-invalid': getValidationState('endTime'),
+ 'is-invalid': getValidationState('end_time'),
}"
:format="{
year: 'numeric',
@@ -71,20 +71,20 @@
:min-datetime="startTimeAsString"
use12-hour
auto
- @input="data.endTime = stringToDate($event)"
+ @input="data.end_time = stringToDate($event)"
></datetime>
</b-form-group>
<b-form-group
label="Queues"
label-for="queues"
- :invalid-feedback="getValidationFeedback('queueNames')"
- :state="getValidationState('queueNames')"
+ :invalid-feedback="getValidationFeedback('queue_names')"
+ :state="getValidationState('queue_names')"
>
<b-form-checkbox-group
id="queues"
- v-model="data.queueNames"
+ v-model="data.queue_names"
:options="queueNameOptions"
- :state="getValidationState('queueNames')"
+ :state="getValidationState('queue_names')"
/>
</b-form-group>
</b-form>
@@ -117,19 +117,19 @@ export default {
},
computed: {
startTimeAsString() {
- return this.data.startTime.toISOString();
+ return this.data.start_time.toISOString();
},
endTimeAsString() {
- return this.data.endTime.toISOString();
+ return this.data.end_time.toISOString();
},
nameValidationFeedback() {
- return this.getValidationFeedback("reservationName");
+ return this.getValidationFeedback("reservation_name");
},
nameValidationState() {
if (this.nameInputBegins === false) {
return null;
}
- return this.getValidationState("reservationName");
+ return this.getValidationState("reservation_name");
},
queueNameOptions() {
return this.queues.slice().sort();
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourceReservationList.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourceReservationList.vue
index 8b04bcf90..434182286 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourceReservationList.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourceReservationList.vue
@@ -48,14 +48,14 @@
</template>
<template slot="item-list" slot-scope="slotProps">
<b-table hover :fields="fields" :items="slotProps.items">
- <template slot="cell(reservationName)" slot-scope="data">
+ <template slot="cell(reservation_name)" slot-scope="data">
{{ data.value }}
<b-badge v-if="data.item.isExpired">Expired</b-badge>
<b-badge v-if="data.item.isActive" variant="success">Active</b-badge>
<b-badge v-if="data.item.isUpcoming" variant="info">Upcoming</b-badge>
</template>
- <template slot="cell(queueNames)" slot-scope="data">
- <ul v-for="queueName in data.item.queueNames" :key="queueName">
+ <template slot="cell(queue_names)" slot-scope="data">
+ <ul v-for="queueName in data.item.queue_names" :key="queueName">
<li>{{ queueName }}</li>
</ul>
</template>
@@ -75,7 +75,7 @@
@delete="deleteReservation(data.item)"
>
Are you sure you want to delete reservation
- <strong>{{ data.item.reservationName }}</strong
+ <strong>{{ data.item.reservation_name }}</strong
>?
</delete-link>
</template>
@@ -142,21 +142,21 @@ export default {
return [
{
label: "Name",
- key: "reservationName",
+ key: "reservation_name",
},
{
label: "Queues",
- key: "queueNames",
+ key: "queue_names",
},
{
label: "Start Time",
- key: "startTime",
+ key: "start_time",
formatter: (value) =>
utils.dateFormatters.dateTimeInMinutesWithTimeZone.format(value),
},
{
label: "End Time",
- key: "endTime",
+ key: "end_time",
formatter: (value) =>
utils.dateFormatters.dateTimeInMinutesWithTimeZone.format(value),
},
@@ -206,7 +206,7 @@ export default {
addNewReservation() {
this.newReservation = new models.ComputeResourceReservation();
this.newReservationValid = false;
- this.newReservation.queueNames = this.queues.slice();
+ this.newReservation.queue_names = this.queues.slice();
this.showNewItemEditor = true;
},
saveNewReservation() {
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourceReservationsSummary.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourceReservationsSummary.vue
index 498475b59..94a91b567 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourceReservationsSummary.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputeResourceReservationsSummary.vue
@@ -35,7 +35,7 @@ export default {
: [];
},
activeReservationNames() {
- return this.activeReservations.map((r) => r.reservationName);
+ return this.activeReservations.map((r) => r.reservation_name);
},
upcomingReservations() {
return this.reservations
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/GroupComputeResourcePreference.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/GroupComputeResourcePreference.vue
index 2c8b077e3..153e7083a 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/GroupComputeResourcePreference.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/GroupComputeResourcePreference.vue
@@ -16,7 +16,7 @@
<b-form-input
id="profile-name"
type="text"
- v-model="data.groupResourceProfileName"
+ v-model="data.group_resource_profile_name"
:disabled="!userHasWriteAccess"
required
placeholder="Name of this Group Resource Profile"
@@ -29,7 +29,7 @@
>
<ssh-credential-selector
id="default-credential-store-token"
- v-model="data.defaultCredentialStoreToken"
+ v-model="data.default_credential_store_token"
:readonly="!userHasWriteAccess"
>
</ssh-credential-selector>
@@ -40,7 +40,7 @@
</div>
</div>
<list-layout
- :items="data.computePreferences"
+ :items="data.compute_preferences"
:newButtonDisabled="!userHasWriteAccess"
title="Compute Preferences"
new-item-button-text="New Compute Preference"
@@ -51,16 +51,16 @@
hover
:fields="computePreferencesFields"
:items="slotProps.items"
- sort-by="computeResourceId"
+ sort-by="compute_resource_id"
>
- <template slot="cell(computeResourceId)" slot-scope="row">
+ <template slot="cell(compute_resource_id)" slot-scope="row">
<compute-resource-name
- :compute-resource-id="row.item.computeResourceId"
+ :compute-resource-id="row.item.compute_resource_id"
/>
</template>
<template slot="cell(policy)" slot-scope="row">
<compute-resource-policy-summary
- :compute-resource-id="row.item.computeResourceId"
+ :compute-resource-id="row.item.compute_resource_id"
:group-resource-profile="data"
/>
</template>
@@ -76,13 +76,13 @@
params: {
value: row.item,
id: id,
- host_id: row.item.computeResourceId,
+ host_id: row.item.compute_resource_id,
groupResourceProfile: data,
computeResourcePolicy: data.getComputeResourcePolicy(
- row.item.computeResourceId
+ row.item.compute_resource_id
),
batchQueueResourcePolicies: data.getBatchQueueResourcePolicies(
- row.item.computeResourceId
+ row.item.compute_resource_id
),
},
}"
@@ -99,13 +99,13 @@
params: {
value: row.item,
id: id,
- host_id: row.item.computeResourceId,
+ host_id: row.item.compute_resource_id,
groupResourceProfile: data,
computeResourcePolicy: data.getComputeResourcePolicy(
- row.item.computeResourceId
+ row.item.compute_resource_id
),
batchQueueResourcePolicies: data.getBatchQueueResourcePolicies(
- row.item.computeResourceId
+ row.item.compute_resource_id
),
},
}"
@@ -117,13 +117,13 @@
<delete-link
class="action-link"
v-if="userHasWriteAccess"
- @delete="removeComputePreference(row.item.computeResourceId)"
+ @delete="removeComputePreference(row.item.compute_resource_id)"
>
Are you sure you want to remove the preferences for compute
resource
<strong>
<compute-resource-name
- :compute-resource-id="row.item.computeResourceId"
+ :compute-resource-id="row.item.compute_resource_id"
/> </strong
>?
</delete-link>
@@ -145,7 +145,7 @@
@delete="removeGroupResourceProfile"
>
Are you sure you want to remove Group Resource Profile
- <strong>{{ data.groupResourceProfileName }}</strong
+ <strong>{{ data.group_resource_profile_name }}</strong
>?
</delete-button>
<b-button class="ml-2" variant="secondary" @click="cancel"
@@ -183,11 +183,11 @@ export default {
},
mounted: function () {
if (this.id) {
- if (!this.value.groupResourceProfileId) {
+ if (!this.value.group_resource_profile_id) {
services.GroupResourceProfileService.retrieve({ lookup: this.id }).then(
(grp) => {
this.data = grp;
- this.userHasWriteAccess = this.data.userHasWriteAccess;
+ this.userHasWriteAccess = this.data.user_has_write_access;
}
);
}
@@ -207,20 +207,20 @@ export default {
data: data,
service: services.GroupResourceProfileService,
sharedEntity: null,
- userHasWriteAccess: data.userHasWriteAccess,
+ userHasWriteAccess: data.user_has_write_access,
computePreferencesFields: [
{
label: "Name",
- key: "computeResourceId",
+ key: "compute_resource_id",
sortable: true,
},
{
label: "Username",
- key: "loginUserName",
+ key: "login_user_name",
},
{
label: "Allocation",
- key: "allocationProjectNumber",
+ key: "allocation_project_number",
},
{
label: "Policy",
@@ -251,16 +251,16 @@ export default {
},
computed: {
excludedComputeResourceIds() {
- const currentPrefs = this.data.computePreferences
- ? this.data.computePreferences.map(
- (computePreference) => computePreference.computeResourceId
+ const currentPrefs = this.data.compute_preferences
+ ? this.data.compute_preferences.map(
+ (computePreference) => computePreference.compute_resource_id
)
: [];
return currentPrefs;
},
title: function () {
return this.id
- ? this.data.groupResourceProfileName
+ ? this.data.group_resource_profile_name
: "New Group Resource Profile";
},
owner() {
@@ -269,13 +269,13 @@ export default {
: null;
},
ownerUserId() {
- return this.owner ? this.owner.userId : null;
+ return this.owner ? this.owner.user_id : null;
},
ownerTitle() {
return this.owner
- ? this.owner.firstName +
+ ? this.owner.first_name +
" " +
- this.owner.lastName +
+ this.owner.last_name +
" (" +
this.owner.email +
")"
@@ -291,7 +291,7 @@ export default {
persist = this.service.create({ data: this.data }).then((data) => {
// Merge sharing settings with default sharing settings created when
// Group Resource Profile was created
- const groupResourceProfileId = data.groupResourceProfileId;
+ const groupResourceProfileId = data.group_resource_profile_id;
return this.$refs.shareButton.mergeAndSave(groupResourceProfileId);
});
}
@@ -307,13 +307,13 @@ export default {
},
onSelectComputeResource: function (computeResourceId) {
const computeResourcePreference = new models.GroupComputeResourcePreference();
- computeResourcePreference.computeResourceId = computeResourceId;
+ computeResourcePreference.compute_resource_id = computeResourceId;
this.$router.push({
name: "compute_preference_for_new_group_resource_profile",
params: {
value: computeResourcePreference,
id: this.id,
- host_id: computeResourcePreference.computeResourceId,
+ host_id: computeResourcePreference.compute_resource_id,
groupResourceProfile: this.data,
},
});
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentEditor.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentEditor.vue
index ecb5eba8d..100ed782f 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentEditor.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentEditor.vue
@@ -22,7 +22,7 @@
<b-form-input
id="executable-path"
type="text"
- v-model="data.executablePath"
+ v-model="data.executable_path"
required
:disabled="readonly"
></b-form-input>
@@ -44,7 +44,7 @@
>
<b-form-textarea
id="deployment-description"
- v-model="data.appDeploymentDescription"
+ v-model="data.app_deployment_description"
:rows="3"
:disabled="readonly"
></b-form-textarea>
@@ -52,43 +52,43 @@
<command-objects-editor
title="Module Load Commands"
add-button-label="Add Module Load Command"
- v-model="data.moduleLoadCmds"
+ v-model="data.module_load_cmds"
:readonly="readonly"
/>
<set-env-paths-editor
title="Library Prepend Paths"
add-button-label="Add a Library Prepend Path"
- v-model="data.libPrependPaths"
+ v-model="data.lib_prepend_paths"
:readonly="readonly"
/>
<set-env-paths-editor
title="Library Append Paths"
add-button-label="Add a Library Append Path"
- v-model="data.libAppendPaths"
+ v-model="data.lib_append_paths"
:readonly="readonly"
/>
<set-env-paths-editor
title="Environment Variables"
add-button-label="Add Environment Variable"
- v-model="data.setEnvironment"
+ v-model="data.set_environment"
:readonly="readonly"
/>
<command-objects-editor
title="Pre Job Commands"
add-button-label="Add Pre Job Command"
- v-model="data.preJobCommands"
+ v-model="data.pre_job_commands"
:readonly="readonly"
/>
<command-objects-editor
title="Post Job Commands"
add-button-label="Add Post Job Command"
- v-model="data.postJobCommands"
+ v-model="data.post_job_commands"
:readonly="readonly"
/>
<b-form-group label="Default Queue Name" label-for="default-queue-name">
<b-form-select
id="default-queue-name"
- v-model="data.defaultQueueName"
+ v-model="data.default_queue_name"
:options="queueNameOptions"
@change="defaultQueueChanged"
:disabled="readonly"
@@ -102,7 +102,7 @@
<b-form-input
id="default-node-count"
type="number"
- v-model="data.defaultNodeCount"
+ v-model="data.default_node_count"
min="0"
:max="maxNodes"
:disabled="defaultQueueAttributesDisabled"
@@ -112,7 +112,7 @@
<b-form-input
id="default-cpu-count"
type="number"
- v-model="data.defaultCPUCount"
+ v-model="data.default_cpu_count"
min="0"
:max="maxCPUCount"
:disabled="defaultQueueAttributesDisabled"
@@ -128,7 +128,7 @@
<b-form-input
id="default-walltime"
type="number"
- v-model="data.defaultWalltime"
+ v-model="data.default_walltime"
min="0"
:max="maxWalltime"
:disabled="defaultQueueAttributesDisabled"
@@ -184,9 +184,9 @@ export default {
computed: {
name() {
if (this.computeResource) {
- return this.computeResource.hostName;
+ return this.computeResource.host_name;
} else {
- return this.data.computeHostId.substring(0, 10) + "...";
+ return this.data.compute_host_id.substring(0, 10) + "...";
}
},
parallelismTypeOptions() {
@@ -201,47 +201,47 @@ export default {
if (!this.computeResource) {
return [];
}
- return this.computeResource.batchQueues.map((queue) => {
+ return this.computeResource.batch_queues.map((queue) => {
return {
- value: queue.queueName,
- text: queue.queueName,
+ value: queue.queue_name,
+ text: queue.queue_name,
};
});
},
maxNodes() {
const queue = this.computeResource
- ? this.computeResource.batchQueues.find(
- (q) => q.queueName === this.data.defaultQueueName
+ ? this.computeResource.batch_queues.find(
+ (q) => q.queue_name === this.data.default_queue_name
)
: null;
- return queue ? queue.maxNodes : 0;
+ return queue ? queue.max_nodes : 0;
},
maxCPUCount() {
const queue = this.computeResource
- ? this.computeResource.batchQueues.find(
- (q) => q.queueName === this.data.defaultQueueName
+ ? this.computeResource.batch_queues.find(
+ (q) => q.queue_name === this.data.default_queue_name
)
: null;
- return queue ? queue.maxProcessors : 0;
+ return queue ? queue.max_processors : 0;
},
maxWalltime() {
const queue = this.computeResource
- ? this.computeResource.batchQueues.find(
- (q) => q.queueName === this.data.defaultQueueName
+ ? this.computeResource.batch_queues.find(
+ (q) => q.queue_name === this.data.default_queue_name
)
: null;
- return queue ? queue.maxRuntime : 0;
+ return queue ? queue.max_run_time : 0;
},
cpuPerNode() {
const queue = this.computeResource
- ? this.computeResource.batchQueues.find(
- (q) => q.queueName === this.data.defaultQueueName
+ ? this.computeResource.batch_queues.find(
+ (q) => q.queue_name === this.data.default_queue_name
)
: null;
- return queue ? queue.cpuPerNode : 0;
+ return queue ? queue.cpu_per_node : 0;
},
defaultQueueAttributesDisabled() {
- return !this.data.defaultQueueName || this.readonly;
+ return !this.data.default_queue_name || this.readonly;
},
owner() {
return this.localSharedEntity && this.localSharedEntity.owner
@@ -249,13 +249,13 @@ export default {
: null;
},
ownerUserId() {
- return this.owner ? this.owner.userId : null;
+ return this.owner ? this.owner.user_id : null;
},
ownerTitle() {
return this.owner
- ? this.owner.firstName +
+ ? this.owner.first_name +
" " +
- this.owner.lastName +
+ this.owner.last_name +
" (" +
this.owner.email +
")"
@@ -264,7 +264,7 @@ export default {
},
created() {
services.ComputeResourceService.retrieve({
- lookup: this.data.computeHostId,
+ lookup: this.data.compute_host_id,
}).then((computeResource) => {
this.computeResource = computeResource;
});
@@ -282,16 +282,16 @@ export default {
},
defaultQueueChanged(queueName) {
if (queueName) {
- const queue = this.computeResource.batchQueues.find(
- (q) => q.queueName === queueName
+ const queue = this.computeResource.batch_queues.find(
+ (q) => q.queue_name === queueName
);
- this.data.defaultNodeCount = queue.defaultNodeCount;
- this.data.defaultCPUCount = queue.defaultCPUCount;
- this.data.defaultWalltime = queue.defaultWalltime;
+ this.data.default_node_count = queue.default_node_count;
+ this.data.default_cpu_count = queue.default_cpu_count;
+ this.data.default_walltime = queue.default_walltime;
} else {
- this.data.defaultNodeCount = null;
- this.data.defaultCPUCount = null;
- this.data.defaultWalltime = null;
+ this.data.default_node_count = null;
+ this.data.default_cpu_count = null;
+ this.data.default_walltime = null;
}
},
savedSharedEntity(newSharedEntity) {
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentsList.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentsList.vue
index 3c576c4cd..b754dc0fb 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentsList.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentsList.vue
@@ -13,17 +13,17 @@
hover
:fields="fields"
:items="slotProps.items"
- sort-by="computeHostId"
+ sort-by="compute_host_id"
>
<template slot="cell(action)" slot-scope="data">
<router-link
class="action-link"
- v-if="!data.item.userHasWriteAccess"
+ v-if="!data.item.user_has_write_access"
:to="{
name: 'application_deployment',
params: {
id: id,
- deploymentId: data.item.appDeploymentId,
+ deploymentId: data.item.app_deployment_id,
readonly: true,
},
}"
@@ -33,12 +33,12 @@
</router-link>
<router-link
class="action-link"
- v-if="data.item.userHasWriteAccess && data.item.appDeploymentId"
+ v-if="data.item.user_has_write_access && data.item.app_deployment_id"
:to="{
name: 'application_deployment',
params: {
id: id,
- deploymentId: data.item.appDeploymentId,
+ deploymentId: data.item.app_deployment_id,
readonly: false,
},
}"
@@ -48,12 +48,12 @@
</router-link>
<router-link
class="action-link"
- v-if="data.item.userHasWriteAccess && !data.item.appDeploymentId"
+ v-if="data.item.user_has_write_access && !data.item.app_deployment_id"
:to="{
name: 'new_application_deployment',
params: {
id: id,
- hostId: data.item.computeHostId,
+ hostId: data.item.compute_host_id,
readonly: false,
},
}"
@@ -62,13 +62,13 @@
<i class="fa fa-edit" aria-hidden="true"></i>
</router-link>
<delete-link
- v-if="data.item.userHasWriteAccess"
+ v-if="data.item.user_has_write_access"
@delete="removeApplicationDeployment(data.item)"
class="action-link"
>
Are you sure you want to remove the
<strong>{{
- getComputeResourceName(data.item.computeHostId)
+ getComputeResourceName(data.item.compute_host_id)
}}</strong>
deployment?
</delete-link>
@@ -123,13 +123,13 @@ export default {
return [
{
label: "Compute Resource",
- key: "computeHostId",
+ key: "compute_host_id",
sortable: true,
formatter: (value) => this.getComputeResourceName(value),
},
{
label: "Description",
- key: "appDeploymentDescription",
+ key: "app_deployment_description",
},
{
label: "Action",
@@ -144,9 +144,9 @@ export default {
// Create a set of all computeResourceIds in GroupResourceProfiles
const groupResourceProfileCompResources = {};
for (const groupResourceProfile of this.groupResourceProfiles) {
- for (const computePreference of groupResourceProfile.computePreferences) {
+ for (const computePreference of groupResourceProfile.compute_preferences) {
groupResourceProfileCompResources[
- computePreference.computeResourceId
+ computePreference.compute_resource_id
] = null;
}
}
@@ -178,7 +178,7 @@ export default {
}
},
excludedComputeResourceIds() {
- return this.deployments.map((dep) => dep.computeHostId);
+ return this.deployments.map((dep) => dep.compute_host_id);
},
},
mounted() {
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationEditorContainer.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationEditorContainer.vue
index 67243c5df..34c498a23 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationEditorContainer.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationEditorContainer.vue
@@ -45,7 +45,7 @@
v-if="appModule"
v-model="appModule"
@input="appModuleIsDirty = true"
- :readonly="!appModule.userHasWriteAccess"
+ :readonly="!appModule.user_has_write_access"
:validation-errors="appModuleValidationErrors"
/>
<router-view
@@ -53,7 +53,7 @@
v-if="appInterface"
v-model="appInterface"
@input="appInterfaceIsDirty = true"
- :readonly="!appInterface.userHasWriteAccess"
+ :readonly="!appInterface.user_has_write_access"
/>
<router-view
name="deployments"
@@ -61,7 +61,7 @@
:deployments="appDeployments"
@new="createNewDeployment"
@delete="deleteApplicationDeployment"
- :readonly="!appModule.userHasWriteAccess"
+ :readonly="!appModule.user_has_write_access"
/>
<router-view
name="deployment"
@@ -89,7 +89,7 @@
@delete="deleteApplication"
>
Are you sure you want to delete the
- <strong>{{ appModule ? appModule.appModuleName : "" }}</strong>
+ <strong>{{ appModule ? appModule.app_module_name : "" }}</strong>
application?
</delete-button>
<b-button class="editor-button" variant="secondary" @click="cancel">
@@ -139,8 +139,8 @@ export default {
computed: {
title: function () {
if (this.id) {
- return this.appModule && this.appModule.appModuleName
- ? this.appModule.appModuleName
+ return this.appModule && this.appModule.app_module_name
+ ? this.appModule.app_module_name
: "";
} else {
return "Create a New Application";
@@ -155,7 +155,7 @@ export default {
);
},
readonly() {
- return this.appModule && !this.appModule.userHasWriteAccess;
+ return this.appModule && !this.appModule.user_has_write_access;
},
},
created() {
@@ -170,9 +170,7 @@ export default {
this.initializeDeploymentEditing();
});
} else {
- this.appModule = new models.ApplicationModule({
- userHasWriteAccess: true,
- });
+ this.appModule = new models.ApplicationModule({ user_has_write_access: true });
}
},
initializeDeploymentEditing() {
@@ -213,7 +211,7 @@ export default {
updateApplicationModule(appModule) {
return services.ApplicationModuleService.update(
{
- lookup: appModule.appModuleId,
+ lookup: appModule.app_module_id,
data: appModule,
},
{ ignoreErrors: true }
@@ -264,9 +262,7 @@ export default {
.catch((error) => {
if (error.details.status === 404) {
// If there is no interface, just create a new instance
- const appInterface = new models.ApplicationInterfaceDefinition({
- userHasWriteAccess: true,
- });
+ const appInterface = new models.ApplicationInterfaceDefinition({ user_has_write_access: true });
appInterface.addStandardOutAndStandardErrorOutputs();
this.appInterface = appInterface;
this.appInterfaceIsDirty = true;
@@ -288,7 +284,7 @@ export default {
},
updateApplicationInterface(appInterface) {
return services.ApplicationInterfaceService.update({
- lookup: appInterface.applicationInterfaceId,
+ lookup: appInterface.application_interface_id,
data: appInterface,
}).then((appInterface) => {
this.appInterfaceIsDirty = false;
@@ -297,16 +293,16 @@ export default {
});
},
saveApplicationInterface(appInterface) {
- appInterface.applicationName = this.appModule.appModuleName;
- appInterface.applicationModules = [this.id];
- return appInterface.applicationInterfaceId
+ appInterface.application_name = this.appModule.app_module_name;
+ appInterface.application_modules = [this.id];
+ return appInterface.application_interface_id
? this.updateApplicationInterface(appInterface)
: this.createApplicationInterface(appInterface);
},
deleteApplicationInterface(appInterface) {
- if (appInterface.applicationInterfaceId) {
+ if (appInterface.application_interface_id) {
return services.ApplicationInterfaceService.delete({
- lookup: appInterface.applicationInterfaceId,
+ lookup: appInterface.application_interface_id,
}).then(() => (this.appInterfaceIsDirty = false));
} else {
this.appInterfaceIsDirty = false;
@@ -342,7 +338,7 @@ export default {
},
updateApplicationDeployment(appDeployment) {
return services.ApplicationDeploymentService.update({
- lookup: appDeployment.appDeploymentId,
+ lookup: appDeployment.app_deployment_id,
data: appDeployment,
}).then((appDeployment) => {
this.removeDirtyAppDeploymentComputeHostId(appDeployment);
@@ -351,21 +347,21 @@ export default {
});
},
saveApplicationDeployment(appDeployment) {
- return appDeployment.appDeploymentId
+ return appDeployment.app_deployment_id
? this.updateApplicationDeployment(appDeployment)
: this.createApplicationDeployment(appDeployment);
},
deleteApplicationDeployment(appDeployment) {
- if (appDeployment.appDeploymentId) {
+ if (appDeployment.app_deployment_id) {
return services.ApplicationDeploymentService.delete({
- lookup: appDeployment.appDeploymentId,
+ lookup: appDeployment.app_deployment_id,
}).then(() => {
this.removeDirtyAppDeploymentComputeHostId(appDeployment);
return this.loadApplicationDeployments(this.id);
});
} else {
const depIndex = this.appDeployments.findIndex(
- (dep) => dep.computeHostId === appDeployment.computeHostId
+ (dep) => dep.compute_host_id === appDeployment.compute_host_id
);
this.appDeployments.splice(depIndex, 1);
this.removeDirtyAppDeploymentComputeHostId(appDeployment);
@@ -378,22 +374,22 @@ export default {
},
replaceAppDeployment(appDeployment) {
const depIndex = this.appDeployments.findIndex(
- (dep) => dep.computeHostId === appDeployment.computeHostId
+ (dep) => dep.compute_host_id === appDeployment.compute_host_id
);
this.appDeployments.splice(depIndex, 1, appDeployment);
},
setApplicationDeploymentDirty(appDeployment) {
if (
!this.dirtyAppDeploymentComputeHostIds.includes(
- appDeployment.computeHostId
+ appDeployment.compute_host_id
)
) {
- this.dirtyAppDeploymentComputeHostIds.push(appDeployment.computeHostId);
+ this.dirtyAppDeploymentComputeHostIds.push(appDeployment.compute_host_id);
}
},
removeDirtyAppDeploymentComputeHostId(appDeployment) {
const hostIdIndex = this.dirtyAppDeploymentComputeHostIds.indexOf(
- appDeployment.computeHostId
+ appDeployment.compute_host_id
);
if (hostIdIndex >= 0) {
this.dirtyAppDeploymentComputeHostIds.splice(hostIdIndex, 1);
@@ -407,22 +403,22 @@ export default {
},
loadApplicationDeploymentSharedEntity(appDeployment) {
return services.SharedEntityService.retrieve({
- lookup: appDeployment.appDeploymentId,
+ lookup: appDeployment.app_deployment_id,
}).then((sharedEntity) => {
this.appDeploymentsSharedEntities[
- appDeployment.computeHostId
+ appDeployment.compute_host_id
] = sharedEntity;
this.removeAppDeploymentSharedEntityDirty(sharedEntity, appDeployment);
return sharedEntity;
});
},
setCurrentApplicationDeploymentSharedEntity(appDeployment) {
- if (appDeployment.computeHostId in this.appDeploymentsSharedEntities) {
+ if (appDeployment.compute_host_id in this.appDeploymentsSharedEntities) {
this.currentDeploymentSharedEntity = this.appDeploymentsSharedEntities[
- appDeployment.computeHostId
+ appDeployment.compute_host_id
];
return Promise.resolve(this.currentDeploymentSharedEntity);
- } else if (appDeployment.appDeploymentId) {
+ } else if (appDeployment.app_deployment_id) {
return this.loadApplicationDeploymentSharedEntity(appDeployment).then(
(sharedEntity) => (this.currentDeploymentSharedEntity = sharedEntity)
);
@@ -453,7 +449,7 @@ export default {
mergeSharedEntity(sharedEntity, appDeployment) {
return services.SharedEntityService.merge({
data: sharedEntity,
- lookup: appDeployment.appDeploymentId,
+ lookup: appDeployment.app_deployment_id,
}).then((sharedEntity) => {
this.replaceAppDeploymentSharedEntity(sharedEntity, appDeployment);
this.removeAppDeploymentSharedEntityDirty(sharedEntity, appDeployment);
@@ -463,7 +459,7 @@ export default {
updateSharedEntity(sharedEntity, appDeployment) {
return services.SharedEntityService.update({
data: sharedEntity,
- lookup: appDeployment.appDeploymentId,
+ lookup: appDeployment.app_deployment_id,
}).then((sharedEntity) => {
this.replaceAppDeploymentSharedEntity(sharedEntity, appDeployment);
this.removeAppDeploymentSharedEntityDirty(sharedEntity, appDeployment);
@@ -471,24 +467,24 @@ export default {
});
},
saveSharedEntity(sharedEntity, appDeployment) {
- return sharedEntity.entityId
+ return sharedEntity.entity_id
? this.updateSharedEntity(sharedEntity, appDeployment)
: this.mergeSharedEntity(sharedEntity, appDeployment);
},
setApplicationDeploymentSharedEntityDirty(sharedEntity, appDeployment) {
if (
!this.dirtyAppDeploymentSharedEntityComputeHostIds.includes(
- appDeployment.computeHostId
+ appDeployment.compute_host_id
)
) {
this.dirtyAppDeploymentSharedEntityComputeHostIds.push(
- appDeployment.computeHostId
+ appDeployment.compute_host_id
);
}
},
removeAppDeploymentSharedEntityDirty(sharedEntity, appDeployment) {
const hostIdIndex = this.dirtyAppDeploymentSharedEntityComputeHostIds.indexOf(
- appDeployment.computeHostId
+ appDeployment.compute_host_id
);
if (hostIdIndex >= 0) {
this.dirtyAppDeploymentSharedEntityComputeHostIds.splice(
@@ -499,12 +495,12 @@ export default {
},
replaceAppDeploymentSharedEntity(sharedEntity, appDeployment) {
this.appDeploymentsSharedEntities[
- appDeployment.computeHostId
+ appDeployment.compute_host_id
] = sharedEntity;
},
setCurrentDeploymentFromAppDeploymentId(appDeploymentId) {
this.currentDeployment = this.appDeployments.find(
- (dep) => dep.appDeploymentId === appDeploymentId
+ (dep) => dep.app_deployment_id === appDeploymentId
);
if (!this.currentDeployment) {
throw new Error(
@@ -515,15 +511,13 @@ export default {
},
setCurrentDeploymentFromComputeHostId(computeHostId) {
this.currentDeployment = this.appDeployments.find(
- (dep) => dep.computeHostId === computeHostId
+ (dep) => dep.compute_host_id === computeHostId
);
if (!this.currentDeployment) {
// Create a new deployment
- const deployment = new models.ApplicationDeploymentDescription({
- userHasWriteAccess: true,
- });
- deployment.appModuleId = this.id;
- deployment.computeHostId = computeHostId;
+ const deployment = new models.ApplicationDeploymentDescription({ user_has_write_access: true });
+ deployment.app_module_id = this.id;
+ deployment.compute_host_id = computeHostId;
this.currentDeployment = deployment;
this.appDeployments.push(deployment);
this.setApplicationDeploymentDirty(deployment);
@@ -561,23 +555,23 @@ export default {
return Promise.all(
this.dirtyAppDeploymentComputeHostIds.map((computeHostId) => {
const deployment = this.appDeployments.find(
- (dep) => dep.computeHostId === computeHostId
+ (dep) => dep.compute_host_id === computeHostId
);
return this.saveApplicationDeployment(deployment).catch(
(error) => {
// Navigate to the route that has the error
- if (deployment.appDeploymentId) {
+ if (deployment.app_deployment_id) {
this.$router.push({
name: "application_deployment",
params: {
id: this.id,
- deploymentId: deployment.appDeploymentId,
+ deploymentId: deployment.app_deployment_id,
},
});
} else {
this.$router.push({
name: "new_application_deployment",
- params: { id: this.id, hostId: deployment.computeHostId },
+ params: { id: this.id, hostId: deployment.compute_host_id },
});
}
return Promise.reject(error);
@@ -594,17 +588,17 @@ export default {
computeHostId
];
const deployment = this.appDeployments.find(
- (dep) => dep.computeHostId === computeHostId
+ (dep) => dep.compute_host_id === computeHostId
);
return this.saveSharedEntity(sharedEntity, deployment).catch(
(error) => {
// Navigate to the route that has the error
- if (deployment.appDeploymentId) {
+ if (deployment.app_deployment_id) {
this.$router.push({
name: "application_deployment",
params: {
id: this.id,
- deploymentId: deployment.appDeploymentId,
+ deploymentId: deployment.app_deployment_id,
},
});
} else {
@@ -612,7 +606,7 @@ export default {
name: "new_application_deployment",
params: {
id: this.id,
- hostId: deployment.computeHostId,
+ hostId: deployment.compute_host_id,
},
});
}
@@ -631,19 +625,19 @@ export default {
duration: 5,
})
);
- if (!this.id && this.appModule.appModuleId) {
+ if (!this.id && this.appModule.app_module_id) {
// if we just create a new module, navigate to app module route now
// that we have an id
this.$router.push({
name: "application_module",
- params: { id: this.appModule.appModuleId },
+ params: { id: this.appModule.app_module_id },
});
}
if (this.hostId) {
// If creating a new deployment, navigate to the deployments list
this.$router.push({
name: "application_deployments",
- params: { id: this.appModule.appModuleId },
+ params: { id: this.appModule.app_module_id },
});
} else {
// Reinitialize deployment editing so that deployment being edited is
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationInputFieldEditor.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationInputFieldEditor.vue
index e87e4f1b4..72d5c6bbe 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationInputFieldEditor.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationInputFieldEditor.vue
@@ -54,7 +54,7 @@
<b-form-input
:id="id + '-override-filename'"
type="text"
- v-model="data.overrideFilename"
+ v-model="data.override_filename"
:disabled="readonly"
></b-form-input>
</b-form-group>
@@ -62,7 +62,7 @@
<b-form-input
:id="id + '-argument'"
type="text"
- v-model="data.applicationArgument"
+ v-model="data.application_argument"
:disabled="readonly"
></b-form-input>
</b-form-group>
@@ -74,7 +74,7 @@
>
<b-form-radio-group
:id="id + '-required-command-line'"
- v-model="data.requiredToAddedToCommandLine"
+ v-model="data.required_to_added_to_command_line"
:options="trueFalseOptions"
:disabled="readonly"
>
@@ -88,7 +88,7 @@
>
<b-form-radio-group
:id="id + '-required'"
- v-model="data.isRequired"
+ v-model="data.is_required"
:options="trueFalseOptions"
:disabled="readonly"
>
@@ -101,7 +101,7 @@
>
<b-form-radio-group
:id="id + '-read-only'"
- v-model="data.isReadOnly"
+ v-model="data.is_read_only"
:options="trueFalseOptions"
:disabled="readonly"
>
@@ -114,7 +114,7 @@
>
<b-form-textarea
:id="id + '-user-friendly-description'"
- v-model="data.userFriendlyDescription"
+ v-model="data.user_friendly_description"
:rows="3"
:disabled="readonly"
/>
@@ -126,7 +126,7 @@
>
<json-editor
:id="id + '-metadata'"
- v-model="data.metaData"
+ v-model="metadata"
:rows="5"
:disabled="readonly"
/>
@@ -186,6 +186,20 @@ export default {
showOverrideFilenameField() {
return this.data.type === models.DataType.URI;
},
+ // meta_data is a raw JSON string on the wire; JSONEditor works with objects.
+ metadata: {
+ get() {
+ if (!this.data.meta_data) {
+ return null;
+ }
+ return typeof this.data.meta_data === "string"
+ ? JSON.parse(this.data.meta_data)
+ : this.data.meta_data;
+ },
+ set(value) {
+ this.data.meta_data = value ? JSON.stringify(value) : null;
+ },
+ },
},
methods: {
doFocus() {
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationInterfaceEditor.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationInterfaceEditor.vue
index 3114370fa..caf3a2f25 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationInterfaceEditor.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationInterfaceEditor.vue
@@ -13,7 +13,7 @@
>
<b-form-radio-group
id="archive-directory"
- v-model="data.archiveWorkingDirectory"
+ v-model="data.archive_working_directory"
:options="trueFalseOptions"
:disabled="readonly"
>
@@ -27,7 +27,7 @@
>
<b-form-radio-group
id="show-queue-settings"
- v-model="data.showQueueSettings"
+ v-model="data.show_queue_settings"
:options="trueFalseOptions"
:disabled="readonly"
>
@@ -42,7 +42,7 @@
description="Select function to automatically compute queue settings."
>
<b-form-select
- v-model="data.queueSettingsCalculatorId"
+ v-model="data.queue_settings_calculator_id"
:options="queueSettingsCalculatorOptions"
:disabled="queueSettingsCalculatorOptions.length === 0"
>
@@ -63,15 +63,15 @@
<b-form-textarea
id="application-description"
:rows="5"
- v-model="data.applicationDescription"
+ v-model="data.application_description"
:state="
- !data.applicationDescription ||
- data.applicationDescription.length < 500
+ !data.application_description ||
+ data.application_description.length < 500
"
>
</b-form-textarea>
- <b-form-valid-feedback v-if="!!data.applicationDescription">
- {{ data.applicationDescription.length }} / 500
+ <b-form-valid-feedback v-if="!!data.application_description">
+ {{ data.application_description.length }} / 500
</b-form-valid-feedback>
<b-form-invalid-feedback>
Application instructions text is limited to 500 characters maximum.
@@ -82,13 +82,13 @@
<div class="col">
<h1 class="h5 mb-4">Input Fields</h1>
<draggable
- v-model="data.applicationInputs"
+ v-model="data.application_inputs"
:options="dragOptions"
@start="onDragStart"
@end="onDragEnd"
>
<application-input-field-editor
- v-for="input in data.applicationInputs"
+ v-for="input in data.application_inputs"
:value="input"
:key="input.key"
:focus="input.key === focusApplicationInputKey"
@@ -115,7 +115,7 @@
<div class="col">
<h1 class="h5 mb-4">Output Fields</h1>
<application-output-field-editor
- v-for="output in data.applicationOutputs"
+ v-for="output in data.application_outputs"
:value="output"
:key="output.key"
:focus="output.key === focusApplicationOutputKey"
@@ -206,38 +206,38 @@ export default {
this.$emit("cancel");
},
updatedInput(newValue) {
- const input = this.data.applicationInputs.find(
+ const input = this.data.application_inputs.find(
(input) => input.key === newValue.key
);
Object.assign(input, newValue);
},
addApplicationInput() {
const appInput = new models.InputDataObjectType();
- this.data.applicationInputs.push(appInput);
+ this.data.application_inputs.push(appInput);
this.focusApplicationInputKey = appInput.key;
},
deleteInput(input) {
- const inputIndex = this.data.applicationInputs.findIndex(
+ const inputIndex = this.data.application_inputs.findIndex(
(inp) => inp.key === input.key
);
- this.data.applicationInputs.splice(inputIndex, 1);
+ this.data.application_inputs.splice(inputIndex, 1);
},
updatedOutput(newValue) {
- const output = this.data.applicationOutputs.find(
+ const output = this.data.application_outputs.find(
(o) => o.key === newValue.key
);
Object.assign(output, newValue);
},
addApplicationOutput() {
const newOutput = new models.OutputDataObjectType();
- this.data.applicationOutputs.push(newOutput);
+ this.data.application_outputs.push(newOutput);
this.focusApplicationOutputKey = newOutput.key;
},
deleteOutput(output) {
- const outputIndex = this.data.applicationOutputs.findIndex(
+ const outputIndex = this.data.application_outputs.findIndex(
(o) => o.key === output.key
);
- this.data.applicationOutputs.splice(outputIndex, 1);
+ this.data.application_outputs.splice(outputIndex, 1);
},
onDragStart() {
this.collapseApplicationInputs = true;
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationModuleEditor.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationModuleEditor.vue
index 6660c2e71..15298587c 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationModuleEditor.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationModuleEditor.vue
@@ -6,16 +6,16 @@
<b-form-group
label="Application Name"
label-for="application-name"
- :invalid-feedback="validationFeedback.appModuleName.invalidFeedback"
- :state="validationFeedback.appModuleName.state"
+ :invalid-feedback="validationFeedback.app_module_name.invalidFeedback"
+ :state="validationFeedback.app_module_name.state"
>
<b-form-input
id="application-name"
type="text"
- v-model="data.appModuleName"
+ v-model="data.app_module_name"
required
:disabled="readonly"
- :state="validationFeedback.appModuleName.state"
+ :state="validationFeedback.app_module_name.state"
></b-form-input>
</b-form-group>
<b-form-group
@@ -25,7 +25,7 @@
<b-form-input
id="application-version"
type="text"
- v-model="data.appModuleVersion"
+ v-model="data.app_module_version"
:disabled="readonly"
></b-form-input>
</b-form-group>
@@ -35,7 +35,7 @@
>
<b-form-textarea
id="application-description"
- v-model="data.appModuleDescription"
+ v-model="data.app_module_description"
:rows="3"
:disabled="readonly"
></b-form-textarea>
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationOutputFieldEditor.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationOutputFieldEditor.vue
index d17d98a00..543bd8a52 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationOutputFieldEditor.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationOutputFieldEditor.vue
@@ -41,7 +41,7 @@
<b-form-input
:id="id + '-argument'"
type="text"
- v-model="data.applicationArgument"
+ v-model="data.application_argument"
:disabled="readonly"
></b-form-input>
</b-form-group>
@@ -53,7 +53,7 @@
>
<b-form-radio-group
:id="id + '-required'"
- v-model="data.isRequired"
+ v-model="data.is_required"
:options="trueFalseOptions"
:disabled="readonly"
>
@@ -66,7 +66,7 @@
>
<b-form-radio-group
:id="id + '-required-command-line'"
- v-model="data.requiredToAddedToCommandLine"
+ v-model="data.required_to_added_to_command_line"
:options="trueFalseOptions"
:disabled="readonly"
>
@@ -80,7 +80,7 @@
>
<json-editor
:id="id + '-metadata'"
- v-model="data.metaData"
+ v-model="metadata"
:rows="5"
:disabled="readonly"
/>
@@ -129,6 +129,20 @@ export default {
id() {
return "id-" + this.data.key;
},
+ // meta_data is a raw JSON string on the wire; JSONEditor works with objects.
+ metadata: {
+ get() {
+ if (!this.data.meta_data) {
+ return null;
+ }
+ return typeof this.data.meta_data === "string"
+ ? JSON.parse(this.data.meta_data)
+ : this.data.meta_data;
+ },
+ set(value) {
+ this.data.meta_data = value ? JSON.stringify(value) : null;
+ },
+ },
},
methods: {
doFocus() {
@@ -139,10 +153,9 @@ export default {
this.$emit("delete");
},
setPlainText() {
- const metadata = this.data.metaData || {};
+ const metadata = this.metadata || {};
metadata["file-metadata"] = { "mime-type": "text/plain" };
- // Clone so that JSONEditor updates with new value
- this.data.metaData = JSON.parse(JSON.stringify(metadata));
+ this.metadata = metadata;
},
},
mounted() {
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/credentials/SSHCredentialSelector.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/credentials/SSHCredentialSelector.vue
index 39411fc8e..9ccfb1617 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/credentials/SSHCredentialSelector.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/credentials/SSHCredentialSelector.vue
@@ -111,9 +111,9 @@ export default {
},
copySSHPublicKeyText() {
return this.selectedCredential
- ? this.selectedCredential.publicKey.trim()
+ ? this.selectedCredential.public_key.trim()
: this.defaultCredentialSummary
- ? this.defaultCredentialSummary.publicKey.trim()
+ ? this.defaultCredentialSummary.public_key.trim()
: null;
},
},
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/dashboards/ApplicationsDashboard.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/dashboards/ApplicationsDashboard.vue
index 5962b7f1e..7044a8bd6 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/dashboards/ApplicationsDashboard.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/dashboards/ApplicationsDashboard.vue
@@ -12,7 +12,7 @@
<application-card
v-for="item in slotProps.items"
v-bind:app-module="item"
- v-bind:key="item.appModuleId"
+ v-bind:key="item.app_module_id"
v-on:app-selected="clickHandler(item)"
>
</application-card>
@@ -43,7 +43,7 @@ export default {
if (this.appModules) {
return utils.StringUtils.sortIgnoreCase(
this.appModules.slice(),
- (a) => a.appModuleName
+ (a) => a.app_module_name
);
} else {
return [];
@@ -57,7 +57,7 @@ export default {
clickHandler(item) {
this.$router.push({
name: "application_module",
- params: { id: item.appModuleId },
+ params: { id: item.app_module_id },
});
},
newApplicationHandler() {
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/dashboards/ComputeResourcePreferenceDashboard.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/dashboards/ComputeResourcePreferenceDashboard.vue
index f7d565490..6469c1a0c 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/dashboards/ComputeResourcePreferenceDashboard.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/dashboards/ComputeResourcePreferenceDashboard.vue
@@ -7,18 +7,18 @@
>
<template slot="item-list" slot-scope="slotProps">
<b-table striped hover :fields="fields" :items="slotProps.items">
- <template slot="cell(updatedTime)" slot-scope="data">
+ <template slot="cell(updated_time)" slot-scope="data">
<human-date :date="data.value" />
</template>
<template slot="cell(action)" slot-scope="data">
<router-link
class="action-link"
- v-if="data.item.userHasWriteAccess"
+ v-if="data.item.user_has_write_access"
:to="{
name: 'group_resource_preference',
params: {
value: data.item,
- id: data.item.groupResourceProfileId,
+ id: data.item.group_resource_profile_id,
},
}"
>
@@ -27,12 +27,12 @@
</router-link>
<router-link
class="action-link"
- v-if="!data.item.userHasWriteAccess"
+ v-if="!data.item.user_has_write_access"
:to="{
name: 'group_resource_preference',
params: {
value: data.item,
- id: data.item.groupResourceProfileId,
+ id: data.item.group_resource_profile_id,
},
}"
>
@@ -40,12 +40,12 @@
<i class="fa fa-eye" aria-hidden="true"></i>
</router-link>
<delete-link
- v-if="data.item.userHasWriteAccess"
+ v-if="data.item.user_has_write_access"
class="action-link"
@delete="removeGroupResourceProfile(data.item)"
>
Are you sure you want to delete Group Resource Profile
- <strong>{{ data.item.groupResourceProfileName }}</strong
+ <strong>{{ data.item.group_resource_profile_name }}</strong
>?
</delete-link>
</template>
@@ -71,11 +71,11 @@ export default {
fields: [
{
label: "Name",
- key: "groupResourceProfileName",
+ key: "group_resource_profile_name",
},
{
label: "Updated",
- key: "updatedTime",
+ key: "updated_time",
},
{
label: "Action",
@@ -99,7 +99,7 @@ export default {
},
removeGroupResourceProfile: function (groupResourceProfile) {
services.GroupResourceProfileService.delete({
- lookup: groupResourceProfile.groupResourceProfileId,
+ lookup: groupResourceProfile.group_resource_profile_id,
})
.then(() => services.GroupResourceProfileService.list())
.then(
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/dashboards/CredentialStoreDashboard.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/dashboards/CredentialStoreDashboard.vue
index 3505a7661..6b0958e17 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/dashboards/CredentialStoreDashboard.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/dashboards/CredentialStoreDashboard.vue
@@ -24,16 +24,16 @@
:auto-add-admin-groups="false"
/>
</template>
- <template slot="cell(persistedTime)" slot-scope="data">
+ <template slot="cell(persisted_time)" slot-scope="data">
<human-date :date="data.value" />
</template>
<template slot="cell(action)" slot-scope="data">
<clipboard-copy-link
- :text="data.item.publicKey.trim()"
+ :text="data.item.public_key.trim()"
class="mr-1"
/>
<delete-link
- v-if="data.item.userHasWriteAccess"
+ v-if="data.item.user_has_write_access"
@delete="deleteSSHCredential(data.item)"
>
Are you sure you want to delete the
@@ -61,7 +61,7 @@
<share-button :entity-id="data.item.token" :disallow-editing-admin-groups="false" :auto-add-admin-groups="false"/>
</template>
<template slot="cell(action)" slot-scope="data">
- <delete-link v-if="data.item.userHasWriteAccess" @delete="deletePasswordCredential(data.item)">
+ <delete-link v-if="data.item.user_has_write_access" @delete="deletePasswordCredential(data.item)">
Are you sure you want to delete the
<strong>{{ data.item.description }}</strong> password credential?
</delete-link>
@@ -116,7 +116,7 @@ export default {
},
{
label: "Created",
- key: "persistedTime",
+ key: "persisted_time",
},
{
label: "Sharing",
@@ -169,7 +169,7 @@ export default {
showNewSharedSSHCredentialModel(){
if (!this.adminsGroup){
services.GroupService.list({limit: -1}).then((groups) => {
- this.adminsGroup = groups.filter((g) => g.isGatewayAdminsGroup)[0];
+ this.adminsGroup = groups.filter((g) => g.is_gateway_admins_group)[0];
this.$refs.newSharedSSHCredentialModal.show();
});
}
@@ -186,7 +186,7 @@ export default {
lookup: session.Session.username,
}).then((userProfile) => {
sharedEntity.owner = userProfile;
- sharedEntity.isOwner = session.Session.username == sharedEntity.owner.userId;
+ sharedEntity.is_owner = session.Session.username == sharedEntity.owner.user_id;
sharedEntity.addGroup({
group: this.adminsGroup,
permissionType: models.ResourcePermissionType.MANAGE_SHARING,
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/GatewayResourceProfileEditor.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/GatewayResourceProfileEditor.vue
index aa5378f4a..6cb47c7fd 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/GatewayResourceProfileEditor.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/GatewayResourceProfileEditor.vue
@@ -2,7 +2,7 @@
<div>
<div class="row">
<div class="col">
- <h1 class="h4 mb-4">Gateway Resource Profile - {{ data.gatewayID }}</h1>
+ <h1 class="h4 mb-4">Gateway Resource Profile - {{ data.gateway_id }}</h1>
<b-form-group
label="Default SSH Credential"
label-for="default-credential-store-token"
@@ -10,8 +10,8 @@
>
<ssh-credential-selector
id="default-credential-store-token"
- v-model="data.credentialStoreToken"
- :readonly="!data.userHasWriteAccess"
+ v-model="data.credential_store_token"
+ :readonly="!data.user_has_write_access"
/>
</b-form-group>
</div>
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/GatewayResourceProfileEditorContainer.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/GatewayResourceProfileEditorContainer.vue
index e1d247d39..a858b5d00 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/GatewayResourceProfileEditorContainer.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/GatewayResourceProfileEditorContainer.vue
@@ -18,14 +18,14 @@
<div class="card-body">
<storage-preference-list
v-if="gatewayResourceProfile"
- :storagePreferences="gatewayResourceProfile.storagePreferences"
+ :storagePreferences="gatewayResourceProfile.storage_preferences"
:default-credential-store-token="
- gatewayResourceProfile.credentialStoreToken
+ gatewayResourceProfile.credential_store_token
"
@updated="updatedStoragePreference"
@added="addedStoragePreference"
@delete="deleteStoragePreference"
- :readonly="!gatewayResourceProfile.userHasWriteAccess"
+ :readonly="!gatewayResourceProfile.user_has_write_access"
/>
</div>
</div>
@@ -33,7 +33,7 @@
</div>
<div
class="row"
- v-if="gatewayResourceProfile && gatewayResourceProfile.userHasWriteAccess"
+ v-if="gatewayResourceProfile && gatewayResourceProfile.user_has_write_access"
>
<div class="col">
<b-button variant="primary" @click="save"> Save </b-button>
@@ -79,11 +79,11 @@ export default {
this.gatewayResourceProfile = this.gatewayResourceProfileClone.clone();
},
updatedStoragePreference(updatedStoragePreference) {
- const index = this.gatewayResourceProfile.storagePreferences.findIndex(
+ const index = this.gatewayResourceProfile.storage_preferences.findIndex(
(sp) =>
- sp.storageResourceId === updatedStoragePreference.storageResourceId
+ sp.storage_resource_id === updatedStoragePreference.storage_resource_id
);
- this.gatewayResourceProfile.storagePreferences.splice(
+ this.gatewayResourceProfile.storage_preferences.splice(
index,
1,
updatedStoragePreference
@@ -93,17 +93,17 @@ export default {
services.StoragePreferenceService.create({
data: newStoragePreference,
}).then((sp) => {
- this.gatewayResourceProfile.storagePreferences.push(sp);
+ this.gatewayResourceProfile.storage_preferences.push(sp);
});
},
deleteStoragePreference(storageResourceId) {
services.StoragePreferenceService.delete({
lookup: storageResourceId,
}).then(() => {
- const index = this.gatewayResourceProfile.storagePreferences.findIndex(
- (sp) => sp.storageResourceId === storageResourceId
+ const index = this.gatewayResourceProfile.storage_preferences.findIndex(
+ (sp) => sp.storage_resource_id === storageResourceId
);
- this.gatewayResourceProfile.storagePreferences.splice(index, 1);
+ this.gatewayResourceProfile.storage_preferences.splice(index, 1);
});
},
},
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/StoragePreferenceEditor.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/StoragePreferenceEditor.vue
index 70d752521..c61dad7ed 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/StoragePreferenceEditor.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/StoragePreferenceEditor.vue
@@ -3,7 +3,7 @@
<b-form-group label="Login username" label-for="login-username">
<b-form-input
id="login-username"
- v-model="data.loginUserName"
+ v-model="data.login_user_name"
type="text"
/>
</b-form-group>
@@ -13,7 +13,7 @@
>
<b-form-input
id="filesystem-root-location"
- v-model="data.fileSystemRootLocation"
+ v-model="data.file_system_root_location"
type="text"
/>
</b-form-group>
@@ -24,7 +24,7 @@
>
<ssh-credential-selector
id="default-credential-store-token"
- v-model="data.resourceSpecificCredentialStoreToken"
+ v-model="data.resource_specific_credential_store_token"
:null-option-default-credential-token="defaultCredentialStoreToken"
:null-option-disabled="!defaultCredentialStoreToken"
>
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/StoragePreferenceList.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/StoragePreferenceList.vue
index 9a2def8fd..6789534cb 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/StoragePreferenceList.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/StoragePreferenceList.vue
@@ -11,7 +11,7 @@
<b-form-group label="Storage Resource" label-for="storage-resource">
<b-form-select
id="storage-resource"
- v-model="newStoragePreference.storageResourceId"
+ v-model="newStoragePreference.storage_resource_id"
:options="storageResourceOptions"
/>
</b-form-group>
@@ -37,17 +37,17 @@
hover
:fields="fields"
:items="slotProps.items"
- sort-by="storageResourceId"
+ sort-by="storage_resource_id"
>
<template
- slot="cell(resourceSpecificCredentialStoreToken)"
+ slot="cell(resource_specific_credential_store_token)"
slot-scope="data"
>
{{ data.value }}
<b-badge
v-if="
defaultCredentialStoreToken &&
- !data.item.resourceSpecificCredentialStoreToken
+ !data.item.resource_specific_credential_store_token
"
>
Default
@@ -65,11 +65,11 @@
<delete-link
v-if="!readonly"
class="action-link"
- @delete="deleteStoragePreference(data.item.storageResourceId)"
+ @delete="deleteStoragePreference(data.item.storage_resource_id)"
>
Are you sure you want to delete the storage preference for
<strong>{{
- getStorageResourceName(data.item.storageResourceId)
+ getStorageResourceName(data.item.storage_resource_id)
}}</strong
>?
</delete-link>
@@ -128,22 +128,22 @@ export default {
return [
{
label: "Name",
- key: "storageResourceId",
+ key: "storage_resource_id",
sortable: true,
formatter: (value) => this.getStorageResourceName(value),
},
{
label: "Username",
- key: "loginUserName",
+ key: "login_user_name",
},
{
label: "SSH Credential",
- key: "resourceSpecificCredentialStoreToken",
+ key: "resource_specific_credential_store_token",
formatter: (value) => this.getCredentialName(value),
},
{
label: "File System Location",
- key: "fileSystemRootLocation",
+ key: "file_system_root_location",
},
{
label: "Action",
@@ -154,12 +154,12 @@ export default {
decoratedStoragePreferences() {
return this.storagePreferences.map((sp) => {
const spClone = sp.clone();
- spClone._showDetails = this.showingDetails[spClone.storageResourceId];
+ spClone._showDetails = this.showingDetails[spClone.storage_resource_id];
return spClone;
});
},
currentStoragePreferenceIds() {
- return this.storagePreferences.map((sp) => sp.storageResourceId);
+ return this.storagePreferences.map((sp) => sp.storage_resource_id);
},
storageResourceOptions() {
const options = [];
@@ -225,8 +225,8 @@ export default {
},
toggleDetails(row) {
row.toggleDetails();
- this.showingDetails[row.item.storageResourceId] = !this.showingDetails[
- row.item.storageResourceId
+ this.showingDetails[row.item.storage_resource_id] = !this.showingDetails[
+ row.item.storage_resource_id
];
},
deleteStoragePreference(storageResourceId) {
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/notices/NoticeEditor.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/notices/NoticeEditor.vue
index 9daedcad7..df017662e 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/notices/NoticeEditor.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/notices/NoticeEditor.vue
@@ -29,7 +29,7 @@
<b-form-textarea
id="notice-message"
type="text"
- v-model="data.notificationMessage"
+ v-model="data.notification_message"
required
placeholder="Notice Message"
:state="getValidationState('notificationMessage')"
@@ -103,12 +103,12 @@
<b-form-group
label="Show In Dashboard"
label-for="showInDashboard"
- :state="getValidationState('showInDashboard')"
+ :state="getValidationState('show_in_dashboard')"
>
<b-form-checkbox
id="showInDashboard"
- v-model="data.showInDashboard"
- :state="getValidationState('showInDashboard')"
+ v-model="data.show_in_dashboard"
+ :state="getValidationState('show_in_dashboard')"
>
</b-form-checkbox>
</b-form-group>
@@ -158,21 +158,21 @@ export default {
},
created() {
//checks whether the component is used for editing or updating the notificaion
- if (this.value.notificationId != null) {
+ if (this.value.notification_id != null) {
this.editNotification = true;
this.inputPublishedTime = new moment(
- this.value.publishedTime.toISOString()
+ this.value.published_time.toISOString()
)
.utc()
.format();
this.inputExpirationTime = new moment(
- this.value.expirationTime.toISOString()
+ this.value.expiration_time.toISOString()
)
.utc()
.format();
this.data.priority = this.value.priority.name;
- this.data.showInDashboard = this.value.showInDashboard;
- this.today = new moment(this.value.expirationTime.toISOString()).format();
+ this.data.show_in_dashboard = this.value.show_in_dashboard;
+ this.today = new moment(this.value.expiration_time.toISOString()).format();
}
},
data() {
@@ -227,10 +227,10 @@ export default {
},
watch: {
inputExpirationTime() {
- this.data.expirationTime = this.inputExpirationTime;
+ this.data.expiration_time = this.inputExpirationTime;
},
inputPublishedTime() {
- this.data.publishedTime = this.inputPublishedTime;
+ this.data.published_time = this.inputPublishedTime;
},
},
};
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/notices/NoticesManagementContainer.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/notices/NoticesManagementContainer.vue
index 1f5aadb6f..43672dc64 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/notices/NoticesManagementContainer.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/notices/NoticesManagementContainer.vue
@@ -31,20 +31,20 @@
</template>
<template slot="item-list">
<b-table hover :fields="fields" :items="items">
- <template slot="cell(publishedTime)" slot-scope="data">
+ <template slot="cell(published_time)" slot-scope="data">
<human-date :date="data.value" /> </template
>row
- <template slot="cell(expirationTime)" slot-scope="data">
+ <template slot="cell(expiration_time)" slot-scope="data">
<human-date :date="data.value" />
</template>
<template slot="cell(action)" slot-scope="data">
- <template v-if="data.item.userHasWriteAccess">
+ <template v-if="data.item.user_has_write_access">
<b-link class="action-link" @click="toggleDetails(data)">
Edit
<i class="fa fa-edit" aria-hidden="true"></i>
</b-link>
<delete-link
- @delete="deleteNotice(data.item.notificationId)"
+ @delete="deleteNotice(data.item.notification_id)"
>
Are you sure you want to delete the notice?
</delete-link>
@@ -121,15 +121,15 @@ export default {
},
{
label: "Message",
- key: "notificationMessage",
+ key: "notification_message",
},
{
label: "Publish Date",
- key: "publishedTime",
+ key: "published_time",
},
{
label: "Expiry Date",
- key: "expirationTime",
+ key: "expiration_time",
},
{
label: "Priority",
@@ -137,7 +137,7 @@ export default {
},
{
label: "Show In Dashboard",
- key: "showInDashboard",
+ key: "show_in_dashboard",
},
{
label: "Action",
@@ -165,10 +165,10 @@ export default {
const validation = this.updatedNotice.validate();
if (Object.keys(validation).length === 0) {
const index = this.notices.findIndex(
- (sp) => sp.notificationId === this.updatedNotice.notificationId
+ (sp) => sp.notification_id === this.updatedNotice.notification_id
);
services.ManageNotificationService.update({
- lookup: this.updatedNotice.notificationId,
+ lookup: this.updatedNotice.notification_id,
data: this.updatedNotice,
}).then((sp) => {
this.notices.splice(index, 1, sp);
@@ -187,7 +187,7 @@ export default {
lookup: notificationId,
}).then(() => {
const index = this.notices.findIndex(
- (sp) => sp.notificationId === notificationId
+ (sp) => sp.notification_id === notificationId
);
this.notices.splice(index, 1);
});
@@ -196,8 +196,8 @@ export default {
(this.updatedNotice = new models.Notification()),
(this.updatedNotice = row.item);
row.toggleDetails();
- this.showingDetails[row.item.notificationId] = !this.showingDetails[
- row.item.notificationId
+ this.showingDetails[row.item.notification_id] = !this.showingDetails[
+ row.item.notification_id
];
},
},
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentDetailsView.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentDetailsView.vue
index 1f8062014..80a908779 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentDetailsView.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentDetailsView.vue
@@ -5,12 +5,12 @@
<tr>
<th scope="row">Name</th>
<td>
- <div :title="experiment.experimentId">
- {{ experiment.experimentName }}
+ <div :title="experiment.experiment_id">
+ {{ experiment.experiment_name }}
</div>
<small class="text-muted">
- ID: {{ experiment.experimentId }} (<clipboard-copy-link
- :text="experiment.experimentId"
+ ID: {{ experiment.experiment_id }} (<clipboard-copy-link
+ :text="experiment.experiment_id"
:link-classes="['text-reset']"
>
copy
@@ -35,7 +35,7 @@
</tr>
<tr>
<th scope="row">Owner</th>
- <td>{{ experiment.userName }}</td>
+ <td>{{ experiment.user_name }}</td>
</tr>
<tr>
<th scope="row">Application</th>
@@ -43,7 +43,8 @@
{{ fullExperiment.applicationName }}
</td>
<td v-else class="font-italic text-muted">
- Unable to load interface {{ fullExperiment.experiment.executionId }}
+ Unable to load interface
+ {{ fullExperiment.experiment.execution_id }}
</td>
</tr>
<tr>
@@ -67,7 +68,7 @@
</tr>
<tr
v-if="
- fullExperiment.jobDetails && fullExperiment.jobDetails.length > 0
+ fullExperiment.job_details && fullExperiment.job_details.length > 0
"
>
<th scope="row">Job</th>
@@ -81,14 +82,14 @@
</thead>
<tbody>
<tr
- v-for="(jobDetail, index) in fullExperiment.jobDetails"
- :key="jobDetail.jobId"
+ v-for="(jobDetail, index) in fullExperiment.job_details"
+ :key="jobDetail.job_id"
>
- <td>{{ jobDetail.jobName }}</td>
- <td>{{ jobDetail.jobId }}</td>
+ <td>{{ jobDetail.job_name }}</td>
+ <td>{{ jobDetail.job_id }}</td>
<td>{{ jobDetail.jobStatusStateName }}</td>
<td>
- <span :title="jobDetail.creationTime.toString()">{{
+ <span :title="jobDetail.creation_time.toString()">{{
jobCreationTimes[index]
}}</span>
</td>
@@ -101,47 +102,47 @@
<th scope="row">Notification List</th>
<td>
{{
- experiment.emailAddresses
- ? experiment.emailAddresses.join(", ")
+ experiment.email_addresses
+ ? experiment.email_addresses.join(", ")
: ""
}}
</td>
</tr>
<tr
v-if="
- fullExperiment.jobDetails && fullExperiment.jobDetails.length > 0
+ fullExperiment.job_details && fullExperiment.job_details.length > 0
"
>
<th scope="row">Working Dir</th>
<td>
<div
- v-for="jobDetail in fullExperiment.jobDetails"
- :key="jobDetail.jobId"
+ v-for="jobDetail in fullExperiment.job_details"
+ :key="jobDetail.job_id"
>
- {{ jobDetail.jobName }}: {{ jobDetail.workingDir }}
+ {{ jobDetail.job_name }}: {{ jobDetail.working_dir }}
</div>
</td>
</tr>
<tr
v-if="
- fullExperiment.jobDetails && fullExperiment.jobDetails.length > 0
+ fullExperiment.job_details && fullExperiment.job_details.length > 0
"
>
<th scope="row">Job Description</th>
<td>
<b-card
- v-for="jobDetail in fullExperiment.jobDetails"
- :key="jobDetail.jobId"
- :header="jobDetail.jobName"
+ v-for="jobDetail in fullExperiment.job_details"
+ :key="jobDetail.job_id"
+ :header="jobDetail.job_name"
>
- <pre>{{ jobDetail.jobDescription }}</pre>
+ <pre>{{ jobDetail.job_description }}</pre>
</b-card>
</td>
</tr>
<tr>
<th scope="row">Creation Time</th>
<td>
- <span :title="experiment.creationTime.toString()">{{
+ <span :title="experiment.creation_time.toString()">{{
creationTime
}}</span>
</td>
@@ -151,7 +152,7 @@
<td>
<span
:title="
- fullExperiment.experimentStatus.timeOfStateChange.toString()
+ fullExperiment.experimentStatus.time_of_state_change.toString()
"
>{{ lastModifiedTime }}</span
>
@@ -161,8 +162,8 @@
<th scope="row">Wall Time Limit</th>
<td>
{{
- experiment.userConfigurationData.computationalResourceScheduling
- .wallTimeLimit
+ experiment.user_configuration_data.computational_resource_scheduling
+ .wall_time_limit
}}
minutes
</td>
@@ -171,8 +172,8 @@
<th scope="row">CPU Count</th>
<td>
{{
- experiment.userConfigurationData.computationalResourceScheduling
- .totalCPUCount
+ experiment.user_configuration_data.computational_resource_scheduling
+ .total_cpu_count
}}
</td>
</tr>
@@ -180,21 +181,21 @@
<th scope="row">Node Count</th>
<td>
{{
- experiment.userConfigurationData.computationalResourceScheduling
- .nodeCount
+ experiment.user_configuration_data.computational_resource_scheduling
+ .node_count
}}
</td>
</tr>
<tr
v-if="
- experiment.userConfigurationData.computationalResourceScheduling
- .totalPhysicalMemory
+ experiment.user_configuration_data.computational_resource_scheduling
+ .total_physical_memory
"
>
<th scope="row">Total Physical Memory</th>
<td>
{{
- experiment.userConfigurationData.computationalResourceScheduling.totalPhysicalMemory.toLocaleString()
+ experiment.user_configuration_data.computational_resource_scheduling.total_physical_memory.toLocaleString()
}}
MB
</td>
@@ -203,8 +204,8 @@
<th scope="row">Queue</th>
<td>
{{
- experiment.userConfigurationData.computationalResourceScheduling
- .queueName
+ experiment.user_configuration_data.computational_resource_scheduling
+ .queue_name
}}
</td>
</tr>
@@ -213,7 +214,7 @@
<td>
<ul>
<li
- v-for="input in experiment.experimentInputs"
+ v-for="input in experiment.experiment_inputs"
:key="input.name"
>
{{ input.name }}:
@@ -225,7 +226,7 @@
v-else-if="input.type.isFileValueType"
:data-product="dp"
:input-file="true"
- :key="dp.productUri"
+ :key="dp.product_uri"
/>
</li>
</ul>
@@ -236,7 +237,7 @@
<td>
<ul>
<li
- v-for="output in experiment.experimentOutputs"
+ v-for="output in experiment.experiment_outputs"
:key="output.name"
>
{{ output.name }}:
@@ -247,7 +248,7 @@
v-for="dp in outputDataProducts[output.name]"
v-else-if="output.type.isFileValueType"
:data-product="dp"
- :key="dp.productUri"
+ :key="dp.product_uri"
/>
</li>
</ul>
@@ -269,23 +270,23 @@
<td>
<b-card
v-for="error in experiment.errors"
- :key="error.errorId"
+ :key="error.error_id"
header="Error"
>
- <p>{{ error.userFriendlyMessage }}</p>
- <pre class="pre-scrollable">{{ error.actualErrorMessage }}</pre>
+ <p>{{ error.user_friendly_message }}</p>
+ <pre class="pre-scrollable">{{ error.actual_error_message }}</pre>
</b-card>
</td>
</tr>
<template v-if="failedJobs.length > 0">
- <tr v-for="job in failedJobs" :key="job.jobId">
+ <tr v-for="job in failedJobs" :key="job.job_id">
<th scope="row">Job Submission Response</th>
<td>
- <b-card v-if="job.stdOut" :header="job.jobName + ' STDOUT'">
- <pre class="pre-scrollable">{{ job.stdOut }}</pre>
+ <b-card v-if="job.std_out" :header="job.job_name + ' STDOUT'">
+ <pre class="pre-scrollable">{{ job.std_out }}</pre>
</b-card>
- <b-card v-if="job.stdErr" :header="job.jobName + ' STDERR'">
- <pre class="pre-scrollable">{{ job.stdErr }}</pre>
+ <b-card v-if="job.std_err" :header="job.job_name + ' STDERR'">
+ <pre class="pre-scrollable">{{ job.std_err }}</pre>
</b-card>
</td>
</tr>
@@ -295,23 +296,23 @@
<h2 class="h5 mb-3">Process Details</h2>
<b-card
v-for="process in experiment.processes"
- :key="process.processId"
- :header="process.processId"
+ :key="process.process_id"
+ :header="process.process_id"
>
<b-card
v-for="task in process.sortedTasks"
- :key="task.taskId"
- :header="task.taskId"
+ :key="task.task_id"
+ :header="task.task_id"
>
<table class="table table-sm">
<tbody>
<tr>
<th scope="row">Task Id</th>
- <td>{{ task.taskId }}</td>
+ <td>{{ task.task_id }}</td>
</tr>
<tr>
<th scope="row">Task Type</th>
- <td>{{ task.taskType.name }}</td>
+ <td>{{ task.task_type.name }}</td>
</tr>
<tr>
<th scope="row">Task Status</th>
@@ -320,25 +321,25 @@
<tr>
<th scope="row">Task Status Time</th>
<td>
- <human-date :date="task.latestStatus.timeOfStateChange" />
+ <human-date :date="task.latestStatus.time_of_state_change" />
</td>
</tr>
<tr>
<th scope="row">Task Status Reason</th>
<td>{{ task.latestStatus.reason }}</td>
</tr>
- <template v-if="task.taskErrors && task.taskErrors.length > 0">
+ <template v-if="task.task_errors && task.task_errors.length > 0">
<tr>
<th scope="row">Task Errors</th>
<td>
<b-card
- v-for="error in task.taskErrors"
- :key="error.errorId"
- :header="error.errorId"
+ v-for="error in task.task_errors"
+ :key="error.error_id"
+ :header="error.error_id"
>
- <p>{{ error.userFriendlyMessage }}</p>
+ <p>{{ error.user_friendly_message }}</p>
<pre class="pre-scrollable">{{
- error.actualErrorMessage
+ error.actual_error_message
}}</pre>
</b-card>
</td>
@@ -350,10 +351,10 @@
<td>
<b-card
v-for="job in task.jobs"
- :key="job.jobId"
- :header="job.jobName"
+ :key="job.job_id"
+ :header="job.job_name"
>
- <pre>{{ job.jobDescription }}</pre>
+ <pre>{{ job.job_description }}</pre>
</b-card>
</td>
</tr>
@@ -363,12 +364,12 @@
</b-card>
<b-card
- v-for="error in process.processErrors"
- :key="error.errorId"
- :header="'Process Error ' + error.errorId"
+ v-for="error in process.process_errors"
+ :key="error.error_id"
+ :header="'Process Error ' + error.error_id"
>
- <p>{{ error.userFriendlyMessage }}</p>
- <pre class="pre-scrollable">{{ error.actualErrorMessage }}</pre>
+ <p>{{ error.user_friendly_message }}</p>
+ <pre class="pre-scrollable">{{ error.actual_error_message }}</pre>
</b-card>
</b-card>
</div>
@@ -402,11 +403,11 @@ export default {
computed: {
inputDataProducts() {
const result = {};
- if (this.fullExperiment && this.fullExperiment.inputDataProducts) {
- this.fullExperiment.experiment.experimentInputs.forEach((input) => {
+ if (this.fullExperiment && this.fullExperiment.input_data_products) {
+ this.fullExperiment.experiment.experiment_inputs.forEach((input) => {
result[input.name] = this.getDataProducts(
input,
- this.fullExperiment.inputDataProducts
+ this.fullExperiment.input_data_products
);
});
}
@@ -414,45 +415,45 @@ export default {
},
outputDataProducts() {
const result = {};
- if (this.fullExperiment && this.fullExperiment.outputDataProducts) {
- this.fullExperiment.experiment.experimentOutputs.forEach((output) => {
+ if (this.fullExperiment && this.fullExperiment.output_data_products) {
+ this.fullExperiment.experiment.experiment_outputs.forEach((output) => {
result[output.name] = this.getDataProducts(
output,
- this.fullExperiment.outputDataProducts
+ this.fullExperiment.output_data_products
);
});
}
return result;
},
creationTime: function () {
- return moment(this.fullExperiment.experiment.creationTime).fromNow();
+ return moment(this.fullExperiment.experiment.creation_time).fromNow();
},
lastModifiedTime: function () {
return moment(
- this.fullExperiment.experimentStatus.timeOfStateChange
+ this.fullExperiment.experimentStatus.time_of_state_change
).fromNow();
},
jobCreationTimes: function () {
- return this.fullExperiment.jobDetails.map((jobDetail) =>
- moment(jobDetail.creationTime).fromNow()
+ return this.fullExperiment.job_details.map((jobDetail) =>
+ moment(jobDetail.creation_time).fromNow()
);
},
failedJobs() {
- if (this.fullExperiment && this.fullExperiment.jobDetails) {
- return this.fullExperiment.jobDetails.filter(
+ if (this.fullExperiment && this.fullExperiment.job_details) {
+ return this.fullExperiment.job_details.filter(
(job) =>
this.experiment.latestStatus.state ===
models.ExperimentState.FAILED ||
(job.latestJobStatus &&
- job.latestJobStatus.jobState === models.JobState.FAILED)
+ job.latestJobStatus.job_state === models.JobState.FAILED)
);
} else {
return [];
}
},
experimentDataDir() {
- if (this.experiment && this.experiment.userConfigurationData) {
- return this.experiment.userConfigurationData.experimentDataDir;
+ if (this.experiment && this.experiment.user_configuration_data) {
+ return this.experiment.user_configuration_data.experiment_data_dir;
} else {
return null;
}
@@ -463,10 +464,10 @@ export default {
},
created() {
services.FullExperimentService.retrieve({
- lookup: this.experiment.experimentId,
+ lookup: this.experiment.experiment_id,
}).then((fullExperiment) => (this.fullExperiment = fullExperiment));
services.ExperimentArchiveService.get({
- experimentId: this.experiment.experimentId,
+ experimentId: this.experiment.experiment_id,
}).then((result) => {
this.experimentArchive = result;
});
@@ -480,12 +481,12 @@ export default {
if (io.type === models.DataType.URI_COLLECTION) {
const dataProductURIs = io.value.split(",");
dataProducts = dataProductURIs.map((uri) =>
- collection.find((dp) => dp.productUri === uri)
+ collection.find((dp) => dp.product_uri === uri)
);
} else {
const dataProductURI = io.value;
dataProducts = collection.filter(
- (dp) => dp.productUri === dataProductURI
+ (dp) => dp.product_uri === dataProductURI
);
}
return dataProducts
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentStatisticsContainer.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentStatisticsContainer.vue
index db4628e8a..0d80a0044 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentStatisticsContainer.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentStatisticsContainer.vue
@@ -178,9 +178,9 @@
<experiment-statistics-card
bg-variant="primary"
header-text-variant="white"
- :count="experimentStatistics.allExperimentCount || 0"
+ :count="experimentStatistics.all_experiment_count || 0"
title="Total Experiments"
- @click="selectExperiments('allExperiments')"
+ @click="selectExperiments('all_experiments')"
>
<span slot="link-text">All</span>
</experiment-statistics-card>
@@ -188,10 +188,10 @@
<div class="col-xl-2 col-md-4">
<experiment-statistics-card
bg-variant="light"
- :count="experimentStatistics.createdExperimentCount || 0"
+ :count="experimentStatistics.created_experiment_count || 0"
:states="createdStates"
title="Created Experiments"
- @click="selectExperiments('createdExperiments')"
+ @click="selectExperiments('created_experiments')"
>
</experiment-statistics-card>
</div>
@@ -199,10 +199,10 @@
<experiment-statistics-card
bg-variant="light"
header-text-variant="success"
- :count="experimentStatistics.runningExperimentCount || 0"
+ :count="experimentStatistics.running_experiment_count || 0"
:states="runningStates"
title="Running Experiments"
- @click="selectExperiments('runningExperiments')"
+ @click="selectExperiments('running_experiments')"
>
</experiment-statistics-card>
</div>
@@ -211,10 +211,10 @@
bg-variant="success"
header-text-variant="white"
link-variant="success"
- :count="experimentStatistics.completedExperimentCount || 0"
+ :count="experimentStatistics.completed_experiment_count || 0"
:states="completedStates"
title="Completed Experiments"
- @click="selectExperiments('completedExperiments')"
+ @click="selectExperiments('completed_experiments')"
>
</experiment-statistics-card>
</div>
@@ -223,10 +223,10 @@
bg-variant="warning"
header-text-variant="white"
link-variant="warning"
- :count="experimentStatistics.cancelledExperimentCount || 0"
+ :count="experimentStatistics.cancelled_experiment_count || 0"
:states="canceledStates"
title="Cancelled Experiments"
- @click="selectExperiments('cancelledExperiments')"
+ @click="selectExperiments('cancelled_experiments')"
>
</experiment-statistics-card>
</div>
@@ -235,10 +235,10 @@
bg-variant="danger"
header-text-variant="white"
link-variant="danger"
- :count="experimentStatistics.failedExperimentCount || 0"
+ :count="experimentStatistics.failed_experiment_count || 0"
:states="failedStates"
title="Failed Experiments"
- @click="selectExperiments('failedExperiments')"
+ @click="selectExperiments('failed_experiments')"
>
</experiment-statistics-card>
</div>
@@ -247,21 +247,21 @@
<div class="col">
<b-card>
<b-table :fields="fields" :items="items">
- <template slot="cell(executionId)" slot-scope="data">
+ <template slot="cell(execution_id)" slot-scope="data">
<application-name :application-interface-id="data.value" />
</template>
- <template slot="cell(resourceHostId)" slot-scope="data">
+ <template slot="cell(resource_host_id)" slot-scope="data">
<compute-resource-name :compute-resource-id="data.value" />
</template>
- <template slot="cell(creationTime)" slot-scope="data">
+ <template slot="cell(creation_time)" slot-scope="data">
<human-date :date="data.value" />
</template>
- <template slot="cell(experimentStatus)" slot-scope="data">
+ <template slot="cell(experiment_status)" slot-scope="data">
<experiment-status-badge :status-name="data.value.name" />
</template>
<template slot="cell(actions)" slot-scope="data">
<b-link
- @click="showExperimentDetails(data.item.experimentId)"
+ @click="showExperimentDetails(data.item.experiment_id)"
>
View Details
<i class="far fa-chart-bar" aria-hidden="true"></i>
@@ -270,7 +270,7 @@
</b-table>
</b-card>
<pager
- v-if="experimentStatistics.allExperimentCount > 0"
+ v-if="experimentStatistics.all_experiment_count > 0"
:paginator="experimentStatisticsPaginator"
@next="experimentStatisticsPaginator.next()"
@previous="experimentStatisticsPaginator.previous()"
@@ -280,13 +280,13 @@
</b-tab>
<b-tab
v-for="experimentTab in experimentDetailTabs"
- :key="experimentTab.experiment.experimentId"
+ :key="experimentTab.experiment.experiment_id"
>
<template slot="title">
{{ experimentTab.tabTitle }}
<b-link
@click="
- removeExperimentDetailTab(experimentTab.experiment.experimentId)
+ removeExperimentDetailTab(experimentTab.experiment.experiment_id)
"
class="text-secondary"
>
@@ -393,23 +393,23 @@ export default {
label: "Name",
},
{
- key: "userName",
+ key: "user_name",
label: "Owner",
},
{
- key: "executionId",
+ key: "execution_id",
label: "Application",
},
{
- key: "resourceHostId",
+ key: "resource_host_id",
label: "Resource",
},
{
- key: "creationTime",
+ key: "creation_time",
label: "Creation Time",
},
{
- key: "experimentStatus",
+ key: "experiment_status",
label: "Status",
},
{
@@ -446,8 +446,8 @@ export default {
if (this.appInterfaces) {
const options = this.appInterfaces.map((appInterface) => {
return {
- value: appInterface.applicationInterfaceId,
- text: appInterface.applicationName,
+ value: appInterface.application_interface_id,
+ text: appInterface.application_name,
};
});
return utils.StringUtils.sortIgnoreCase(options, (o) => o.text);
@@ -461,7 +461,7 @@ export default {
// First create a Set of all compute resource ids in the GRPs
const groupResourceProfileCompResources = new Set(
this.groupResourceProfiles.flatMap((grp) =>
- grp.computePreferences.map((cp) => cp.computeResourceId)
+ grp.compute_preferences.map((cp) => cp.compute_resource_id)
)
);
const options = this.computeResourceNames
@@ -478,21 +478,21 @@ export default {
}
},
selectedExperimentsTabTitle() {
- if (this.selectedExperimentSummariesKey === "allExperiments") {
+ if (this.selectedExperimentSummariesKey === "all_experiments") {
return "All Experiments";
- } else if (this.selectedExperimentSummariesKey === "createdExperiments") {
+ } else if (this.selectedExperimentSummariesKey === "created_experiments") {
return "Created Experiments";
- } else if (this.selectedExperimentSummariesKey === "runningExperiments") {
+ } else if (this.selectedExperimentSummariesKey === "running_experiments") {
return "Running Experiments";
} else if (
- this.selectedExperimentSummariesKey === "completedExperiments"
+ this.selectedExperimentSummariesKey === "completed_experiments"
) {
return "Completed Experiments";
} else if (
- this.selectedExperimentSummariesKey === "cancelledExperiments"
+ this.selectedExperimentSummariesKey === "cancelled_experiments"
) {
return "Cancelled Experiments";
- } else if (this.selectedExperimentSummariesKey === "failedExperiments") {
+ } else if (this.selectedExperimentSummariesKey === "failed_experiments") {
return "Failed Experiments";
} else {
return "Experiments";
@@ -592,7 +592,7 @@ export default {
{ ignoreErrors: true }
);
this.experimentDetailTabs.push({
- tabTitle: tabTitle || exp.experimentName,
+ tabTitle: tabTitle || exp.experiment_name,
experiment: exp,
});
this.selectExperimentDetailsTab(experimentId);
@@ -635,7 +635,7 @@ export default {
);
}
this.showExperimentDetails(
- searchResults.results[0].experimentId,
+ searchResults.results[0].experiment_id,
`Job ${jobId}`
);
}
@@ -651,7 +651,7 @@ export default {
},
getExperimentDetailTabsIndex(experimentId) {
return this.experimentDetailTabs.findIndex(
- (tab) => tab.experiment.experimentId === experimentId
+ (tab) => tab.experiment.experiment_id === experimentId
);
},
removeExperimentDetailTab(experimentId) {
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/ExtendedUserProfilePanel.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/ExtendedUserProfilePanel.vue
index 6ee8234ef..b4f0b25b6 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/ExtendedUserProfilePanel.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/ExtendedUserProfilePanel.vue
@@ -43,7 +43,7 @@ export default {
created() {
this.loadExtendedUserProfileFields();
this.loadExtendedUserProfileValues({
- username: this.iamUserProfile.userId,
+ username: this.iamUserProfile.user_id,
});
},
computed: {
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/GroupMembershipDisplay.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/GroupMembershipDisplay.vue
index 2af0308e8..9f0654cd9 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/GroupMembershipDisplay.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/GroupMembershipDisplay.vue
@@ -30,20 +30,20 @@ export default {
},
computed: {
adminsGroup() {
- return this.groups.find((g) => g.isGatewayAdminsGroup);
+ return this.groups.find((g) => g.is_gateway_admins_group);
},
readOnlyAdminsGroup() {
- return this.groups.find((g) => g.isReadOnlyGatewayAdminsGroup);
+ return this.groups.find((g) => g.is_read_only_gateway_admins_group);
},
defaultUsersGroup() {
- return this.groups.find((g) => g.isDefaultGatewayUsersGroup);
+ return this.groups.find((g) => g.is_default_gateway_users_group);
},
nonGatewayGroups() {
return this.groups.filter((g) => {
return (
- !g.isGatewayAdminsGroup &&
- !g.isReadOnlyGatewayAdminsGroup &&
- !g.isDefaultGatewayUsersGroup
+ !g.is_gateway_admins_group &&
+ !g.is_read_only_gateway_admins_group &&
+ !g.is_default_gateway_users_group
);
});
},
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/IdentityServiceUserManagementContainer.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/IdentityServiceUserManagementContainer.vue
index 11a2e24b1..808b89b13 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/IdentityServiceUserManagementContainer.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/IdentityServiceUserManagementContainer.vue
@@ -26,7 +26,7 @@
<div class="card">
<div class="card-body">
<b-table hover :fields="fields" :items="items" :fixed="true">
- <template slot="cell(creationTime)" slot-scope="data">
+ <template slot="cell(creation_time)" slot-scope="data">
<human-date :date="data.value" />
</template>
<template slot="cell(groups)" slot-scope="data">
@@ -34,7 +34,7 @@
</template>
<template slot="cell(action)" slot-scope="data">
<b-button
- v-if="data.item.userHasWriteAccess"
+ v-if="data.item.user_has_write_access"
@click="toggleDetails(data)"
>
Edit
@@ -98,15 +98,15 @@ export default {
return [
{
label: "First Name",
- key: "firstName",
+ key: "first_name",
},
{
label: "Last Name",
- key: "lastName",
+ key: "last_name",
},
{
label: "Username",
- key: "userId",
+ key: "user_id",
},
{
label: "Email",
@@ -118,7 +118,7 @@ export default {
},
{
label: "Email Verified",
- key: "emailVerified",
+ key: "email_verified",
},
{
label: "Groups",
@@ -126,7 +126,7 @@ export default {
},
{
label: "Created",
- key: "creationTime",
+ key: "creation_time",
},
{
label: "Action",
@@ -139,14 +139,14 @@ export default {
? this.usersPaginator.results.map((u) => {
const user = u.clone();
user._showDetails =
- this.showingDetails[u.airavataInternalUserId] || false;
+ this.showingDetails[u.airavata_internal_user_id] || false;
return user;
})
: [];
},
editableGroups() {
return this.allGroups
- ? this.allGroups.filter((g) => g.isAdmin || g.isOwner)
+ ? this.allGroups.filter((g) => g.is_admin || g.is_owner)
: [];
},
currentOffset() {
@@ -162,7 +162,7 @@ export default {
},
groupsUpdated(user) {
services.IAMUserProfileService.update({
- lookup: user.userId,
+ lookup: user.user_id,
data: user,
}).finally(() => {
this.reloadUserProfiles();
@@ -182,8 +182,8 @@ export default {
},
toggleDetails(row) {
row.toggleDetails();
- this.showingDetails[row.item.airavataInternalUserId] = !this
- .showingDetails[row.item.airavataInternalUserId];
+ this.showingDetails[row.item.airavata_internal_user_id] = !this
+ .showingDetails[row.item.airavata_internal_user_id];
},
searchUsers() {
// Reset paginator when starting a search
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UnverifiedEmailUserManagementContainer.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UnverifiedEmailUserManagementContainer.vue
index d13822794..4f8e1f577 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UnverifiedEmailUserManagementContainer.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UnverifiedEmailUserManagementContainer.vue
@@ -5,12 +5,12 @@
<div class="card">
<div class="card-body">
<b-table hover :fields="fields" :items="items" :fixed="true">
- <template slot="cell(creationTime)" slot-scope="data">
+ <template slot="cell(creation_time)" slot-scope="data">
<human-date :date="data.value" />
</template>
<template slot="cell(action)" slot-scope="data">
<b-button
- v-if="data.item.userHasWriteAccess"
+ v-if="data.item.user_has_write_access"
@click="toggleDetails(data)"
>
Edit
@@ -18,14 +18,14 @@
</template>
<template slot="row-details" slot-scope="data">
<enable-user-panel
- v-if="!data.item.enabled && !data.item.emailVerified"
- :username="data.item.userId"
+ v-if="!data.item.enabled && !data.item.email_verified"
+ :username="data.item.user_id"
:email="data.item.email"
@enable-user="enableUser"
/>
<delete-user-panel
- v-if="!data.item.enabled && !data.item.emailVerified"
- :username="data.item.userId"
+ v-if="!data.item.enabled && !data.item.email_verified"
+ :username="data.item.user_id"
@delete-user="deleteUser"
/>
</template>
@@ -71,15 +71,15 @@ export default {
return [
{
label: "First Name",
- key: "firstName",
+ key: "first_name",
},
{
label: "Last Name",
- key: "lastName",
+ key: "last_name",
},
{
label: "Username",
- key: "userId",
+ key: "user_id",
},
{
label: "Email",
@@ -87,11 +87,11 @@ export default {
},
{
label: "Email Verified",
- key: "emailVerified",
+ key: "email_verified",
},
{
label: "Created",
- key: "creationTime",
+ key: "creation_time",
},
{
label: "Action",
@@ -127,8 +127,8 @@ export default {
},
toggleDetails(row) {
row.toggleDetails();
- this.showingDetails[row.item.userId] = !this.showingDetails[
- row.item.userId
+ this.showingDetails[row.item.user_id] = !this.showingDetails[
+ row.item.user_id
];
},
},
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UserDetailsContainer.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UserDetailsContainer.vue
index 452e44d71..e972e835a 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UserDetailsContainer.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UserDetailsContainer.vue
@@ -2,7 +2,7 @@
<b-tabs content-class="mt-3 px-2">
<b-tab
title="User Profile"
- :active="iamUserProfile.airavataUserProfileExists"
+ :active="iamUserProfile.airavata_user_profile_exists"
>
<b-alert
variant="warning"
@@ -18,42 +18,42 @@
<strong>Troubleshooting</strong> tab to fix the user's username.
</b-alert>
<edit-groups-panel
- v-if="iamUserProfile.airavataUserProfileExists"
+ v-if="iamUserProfile.airavata_user_profile_exists"
:value="localIAMUserProfile.groups"
:editable-groups="editableGroups"
- :airavata-internal-user-id="iamUserProfile.airavataInternalUserId"
+ :airavata-internal-user-id="iamUserProfile.airavata_internal_user_id"
@save="groupsUpdated"
/>
<user-profile-panel :iamUserProfile="iamUserProfile" />
<extended-user-profile-panel :iamUserProfile="iamUserProfile" />
<external-idp-user-info-panel
v-if="hasExternalIDPUserInfo"
- :externalIDPUserInfo="localIAMUserProfile.externalIDPUserInfo"
+ :externalIDPUserInfo="localIAMUserProfile.external_idp_user_info"
/>
</b-tab>
<b-tab
title="Troubleshooting"
- :active="!iamUserProfile.airavataUserProfileExists"
+ :active="!iamUserProfile.airavata_user_profile_exists"
>
<activate-user-panel
v-if="
iamUserProfile.enabled &&
- iamUserProfile.emailVerified &&
+ iamUserProfile.email_verified &&
iamUserProfile.userProfileComplete &&
- !iamUserProfile.airavataUserProfileExists
+ !iamUserProfile.airavata_user_profile_exists
"
- :username="iamUserProfile.userId"
+ :username="iamUserProfile.user_id"
@activate-user="$emit('enable-user', $event)"
/>
<enable-user-panel
- v-if="!iamUserProfile.enabled && !iamUserProfile.emailVerified"
- :username="iamUserProfile.userId"
+ v-if="!iamUserProfile.enabled && !iamUserProfile.email_verified"
+ :username="iamUserProfile.user_id"
:email="iamUserProfile.email"
@enable-user="$emit('enable-user', $event)"
/>
<delete-user-panel
- v-if="!iamUserProfile.enabled && !iamUserProfile.emailVerified"
- :username="iamUserProfile.userId"
+ v-if="!iamUserProfile.enabled && !iamUserProfile.email_verified"
+ :username="iamUserProfile.user_id"
@delete-user="$emit('delete-user', $event)"
/>
<b-alert variant="danger" show v-if="isUsernameInvalid">
@@ -61,9 +61,9 @@
they can complete their user profile.
</b-alert>
<change-username-panel
- :username="iamUserProfile.userId"
+ :username="iamUserProfile.user_id"
:email="iamUserProfile.email"
- :airavata-user-profile-exists="iamUserProfile.airavataUserProfileExists"
+ :airavata-user-profile-exists="iamUserProfile.airavata_user_profile_exists"
@update-username="$emit('update-username', $event)"
/>
</b-tab>
@@ -121,12 +121,12 @@ export default {
computed: {
hasExternalIDPUserInfo() {
return (
- Object.keys(this.localIAMUserProfile.externalIDPUserInfo).length !== 0
+ Object.keys(this.localIAMUserProfile.external_idp_user_info).length !== 0
);
},
isUsernameInvalid() {
return (
- this.iamUserProfile.userProfileInvalidFields.indexOf("username") >= 0
+ this.iamUserProfile.user_profile_invalid_fields.indexOf("username") >= 0
);
},
},
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UserGroupMembershipEditor.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UserGroupMembershipEditor.vue
index 40b891523..a630f6c31 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UserGroupMembershipEditor.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UserGroupMembershipEditor.vue
@@ -71,9 +71,9 @@ export default {
return this.combinedGroups
? this.combinedGroups.filter((g) => {
return (
- !g.isDefaultGatewayUsersGroup &&
- !g.isGatewayAdminsGroup &&
- !g.isReadOnlyGatewayAdminsGroup
+ !g.is_default_gateway_users_group &&
+ !g.is_gateway_admins_group &&
+ !g.is_read_only_gateway_admins_group
);
})
: [];
@@ -85,7 +85,7 @@ export default {
return utils.StringUtils.sortIgnoreCase(options, (o) => o.text);
},
gatewayUsersGroup() {
- return this.combinedGroups.find((g) => g.isDefaultGatewayUsersGroup);
+ return this.combinedGroups.find((g) => g.is_default_gateway_users_group);
},
gatewayUsersGroupOption() {
return this.gatewayUsersGroup
@@ -93,13 +93,13 @@ export default {
: null;
},
adminsGroup() {
- return this.combinedGroups.find((g) => g.isGatewayAdminsGroup);
+ return this.combinedGroups.find((g) => g.is_gateway_admins_group);
},
adminsGroupOption() {
return this.adminsGroup ? this.createGroupOption(this.adminsGroup) : null;
},
readOnlyAdminsGroup() {
- return this.combinedGroups.find((g) => g.isReadOnlyGatewayAdminsGroup);
+ return this.combinedGroups.find((g) => g.is_read_only_gateway_admins_group);
},
readOnlyAdminsGroupOption() {
return this.readOnlyAdminsGroup
@@ -132,7 +132,7 @@ export default {
value: group.id,
disabled:
!group.userHasWriteAccess ||
- group.ownerId === this.airavataInternalUserId,
+ group.owner_id === this.airavataInternalUserId,
};
},
},
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UserProfilePanel.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UserProfilePanel.vue
index 346895623..7cb7219fb 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UserProfilePanel.vue
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UserProfilePanel.vue
@@ -30,7 +30,7 @@ export default {
return [
{
name: "Username",
- value: this.iamUserProfile.userId,
+ value: this.iamUserProfile.user_id,
valid: this.isValid("username"),
},
{
@@ -40,12 +40,12 @@ export default {
},
{
name: "First Name",
- value: this.iamUserProfile.firstName,
+ value: this.iamUserProfile.first_name,
valid: this.isValid("first_name"),
},
{
name: "Last Name",
- value: this.iamUserProfile.lastName,
+ value: this.iamUserProfile.last_name,
valid: this.isValid("last_name"),
},
];
@@ -55,7 +55,7 @@ export default {
methods: {
isValid(fieldName) {
return (
- this.iamUserProfile.userProfileInvalidFields.indexOf(fieldName) < 0
+ this.iamUserProfile.user_profile_invalid_fields.indexOf(fieldName) < 0
);
},
},
diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/tests/unit/components/statistics/ExperimentStatisticsContainer.spec.js b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/tests/unit/components/statistics/ExperimentStatisticsContainer.spec.js
index 922c8225d..c721f5484 100644
--- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/tests/unit/components/statistics/ExperimentStatisticsContainer.spec.js
+++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/tests/unit/components/statistics/ExperimentStatisticsContainer.spec.js
@@ -66,18 +66,18 @@ test("load experiment by job id when job id matches unique experiment", async ()
next: null,
previous: null,
results: {
- allExperimentCount: 0,
- completedExperimentCount: 0,
- cancelledExperimentCount: 0,
- failedExperimentCount: 0,
- createdExperimentCount: 0,
- runningExperimentCount: 0,
- allExperiments: [],
- completedExperiments: [],
- failedExperiments: [],
- cancelledExperiments: [],
- createdExperiments: [],
- runningExperiments: [],
+ all_experiment_count: 0,
+ completed_experiment_count: 0,
+ cancelled_experiment_count: 0,
+ failed_experiment_count: 0,
+ created_experiment_count: 0,
+ running_experiment_count: 0,
+ all_experiments: [],
+ completed_experiments: [],
+ failed_experiments: [],
+ cancelled_experiments: [],
+ created_experiments: [],
+ running_experiments: [],
},
limit: 50,
offset: 0,
@@ -92,19 +92,19 @@ test("load experiment by job id when job id matches unique experiment", async ()
count: 1,
next: null,
previous: null,
- results: [{ experimentId: "test-experiment-id" }],
+ results: [{ experiment_id: "test-experiment-id" }],
},
models.ExperimentSummary
)
);
// Mock just enough of Experiment and FullExperiment to get ExperimentDetailsView to render
const experiment = new models.Experiment({
- experimentId: "test-experiment-id",
- experimentName: "Test Experiment",
- creationTime: Date.now(),
- experimentStatus: [
+ experiment_id: "test-experiment-id",
+ experiment_name: "Test Experiment",
+ creation_time: Date.now(),
+ experiment_status: [
new ExperimentStatus({
- timeOfStateChange: Date.now(),
+ time_of_state_change: Date.now(),
state: models.ExperimentState.COMPLETED,
}),
],
@@ -112,7 +112,7 @@ test("load experiment by job id when job id matches unique experiment", async ()
services.ExperimentService.retrieve.mockResolvedValue(experiment);
services.FullExperimentService.retrieve.mockResolvedValue(
new models.FullExperiment({
- experimentId: "test-experiment-id",
+ experiment_id: "test-experiment-id",
experiment,
})
);
@@ -150,14 +150,14 @@ test("load experiment by job id when job id matches unique experiment", async ()
// Double check that the experiment services were called to load the experiment
expect(services.ExperimentService.retrieve).toHaveBeenCalledWith(
{
- lookup: experiment.experimentId,
+ lookup: experiment.experiment_id,
},
{
ignoreErrors: true,
}
);
expect(services.FullExperimentService.retrieve).toHaveBeenCalledWith({
- lookup: experiment.experimentId,
+ lookup: experiment.experiment_id,
});
});
@@ -171,18 +171,18 @@ test("Hostname filter only shows compute resources that are configured in a GRP"
next: null,
previous: null,
results: {
- allExperimentCount: 0,
- completedExperimentCount: 0,
- cancelledExperimentCount: 0,
- failedExperimentCount: 0,
- createdExperimentCount: 0,
- runningExperimentCount: 0,
- allExperiments: [],
- completedExperiments: [],
- failedExperiments: [],
- cancelledExperiments: [],
- createdExperiments: [],
- runningExperiments: [],
+ all_experiment_count: 0,
+ completed_experiment_count: 0,
+ cancelled_experiment_count: 0,
+ failed_experiment_count: 0,
+ created_experiment_count: 0,
+ running_experiment_count: 0,
+ all_experiments: [],
+ completed_experiments: [],
+ failed_experiments: [],
+ cancelled_experiments: [],
+ created_experiments: [],
+ running_experiments: [],
},
limit: 50,
offset: 0,
@@ -200,22 +200,22 @@ test("Hostname filter only shows compute resources that are configured in a GRP"
services.GroupResourceProfileService.list.mockResolvedValue([
new models.GroupResourceProfile({
- computePreferences: [
+ compute_preferences: [
new models.GroupComputeResourcePreference({
- computeResourceId: "compute1-abcd",
+ compute_resource_id: "compute1-abcd",
}),
new models.GroupComputeResourcePreference({
- computeResourceId: "compute3-abcd",
+ compute_resource_id: "compute3-abcd",
}),
],
}),
new models.GroupResourceProfile({
- computePreferences: [
+ compute_preferences: [
new models.GroupComputeResourcePreference({
- computeResourceId: "compute1-abcd",
+ compute_resource_id: "compute1-abcd",
}),
new models.GroupComputeResourcePreference({
- computeResourceId: "compute4-abcd",
+ compute_resource_id: "compute4-abcd",
}),
],
}),
diff --git a/airavata-django-portal/django_airavata/apps/api/admin.py b/airavata-django-portal/django_airavata/apps/api/admin.py
deleted file mode 100644
index a5d03645c..000000000
--- a/airavata-django-portal/django_airavata/apps/api/admin.py
+++ /dev/null
@@ -1,26 +0,0 @@
-
-# Register your models here.
-
-from django.contrib import admin
-
-from .models import ApplicationTemplate, ApplicationTemplateContextProcessor
-
-
-class ApplicationTemplateContextProcessorInline(admin.StackedInline):
- model = ApplicationTemplateContextProcessor
- extra = 1
-
-
-class ApplicationTemplateAdmin(admin.ModelAdmin):
- fields = ['application_module_id', 'template_path']
- list_display = ['application_module_id', 'template_path', 'updated_by', 'updated']
- inlines = [ApplicationTemplateContextProcessorInline]
-
- def save_model(self, request, obj, form, change):
- obj.updated_by = request.user
- if not obj.pk:
- obj.created_by = request.user
- return super().save_model(request, obj, form, change)
-
-
-admin.site.register(ApplicationTemplate, ApplicationTemplateAdmin)
diff --git a/airavata-django-portal/django_airavata/apps/api/authentication.py b/airavata-django-portal/django_airavata/apps/api/authentication.py
deleted file mode 100644
index 2cf95e4d6..000000000
--- a/airavata-django-portal/django_airavata/apps/api/authentication.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import logging
-
-from django.contrib.auth import authenticate
-from rest_framework import authentication, exceptions
-
-from django_airavata.apps.auth import utils
-from django_airavata.apps.auth.middleware import set_admin_group_attributes
-
-logger = logging.getLogger(__name__)
-
-
-class OAuthAuthentication(authentication.BaseAuthentication):
- def authenticate(self, request):
-
- if 'HTTP_AUTHORIZATION' in request.META:
- try:
- user = authenticate(request=request)
- if user is None:
- raise exceptions.AuthenticationFailed(
- "Token failed to authenticate")
- _, token = request.META.get('HTTP_AUTHORIZATION').split()
-
- logger.debug(f"OAuthAuthentication authenticated user {user}")
- # Set request attributes that are normally set by middleware
- request.authz_token = utils.get_authz_token(request, user=user, access_token=token)
- request.user = user
- set_admin_group_attributes(request)
- return (user, token)
- except Exception as e:
- raise exceptions.AuthenticationFailed(
- "Token failed to authenticate") from e
- else:
- return None
diff --git a/airavata-django-portal/django_airavata/apps/api/downloads.py b/airavata-django-portal/django_airavata/apps/api/downloads.py
index 43fa30959..dbef27283 100644
--- a/airavata-django-portal/django_airavata/apps/api/downloads.py
+++ b/airavata-django-portal/django_airavata/apps/api/downloads.py
@@ -9,11 +9,12 @@ through the ``download``/``download-file`` views instead.
import io
import logging
import os
+import zipfile
-import zipstream
from django.http import StreamingHttpResponse
from django.utils.text import get_valid_filename
-from rest_framework.decorators import api_view
+
+from django_airavata.apps.api.web import api_view
from .views import _user_storage_path
@@ -63,16 +64,26 @@ def _join(base, rel):
def _zip_response(storage, filename, entries):
- zf = zipstream.ZipFile(compression=zipstream.ZIP_DEFLATED, allowZip64=True)
- for archive_name, abs_path, size in entries:
- zf.write_iter(archive_name, _read_bytes(storage, abs_path), buffer_size=size or 0)
- response = StreamingHttpResponse(zf, content_type='application/zip')
+ # Files are already fully read into memory (storage.download_file().content),
+ # so build the whole archive in a BytesIO with stdlib zipfile and stream the
+ # buffer back. NOTE: this buffers the entire zip in memory — fine for dev, but
+ # for large directories in production this should be replaced with a true
+ # streaming zip (the previous zipstream-new behavior).
+ buf = io.BytesIO()
+ with zipfile.ZipFile(buf, 'w', zipfile.ZIP_DEFLATED, allowZip64=True) as zf:
+ for archive_name, abs_path, size in entries:
+ zf.writestr(archive_name, storage.download_file(abs_path).content)
+ buf.seek(0)
+ response = StreamingHttpResponse(
+ _iter_buffer(buf), content_type='application/zip')
response['Content-Disposition'] = f'attachment; filename={filename}'
return response
-def _read_bytes(storage, abs_path):
- """Yield a stored file's bytes in buffer-sized chunks for the zip stream."""
- content = storage.download_file(abs_path).content
- for i in range(0, len(content), io.DEFAULT_BUFFER_SIZE):
- yield content[i:i + io.DEFAULT_BUFFER_SIZE]
+def _iter_buffer(buf):
+ """Yield the in-memory archive in buffer-sized chunks."""
+ while True:
+ chunk = buf.read(io.DEFAULT_BUFFER_SIZE)
+ if not chunk:
+ break
+ yield chunk
diff --git a/airavata-django-portal/django_airavata/apps/api/exceptions.py b/airavata-django-portal/django_airavata/apps/api/exceptions.py
index 3b703f469..7a673b54b 100644
--- a/airavata-django-portal/django_airavata/apps/api/exceptions.py
+++ b/airavata-django-portal/django_airavata/apps/api/exceptions.py
@@ -1,79 +1,12 @@
-import logging
-import sys
+from http import HTTPStatus
-import grpc
-from django.core.exceptions import ObjectDoesNotExist
from django.http import JsonResponse
-from rest_framework import status
-from rest_framework.exceptions import NotAuthenticated
-from rest_framework.response import Response
-from rest_framework.views import exception_handler
-log = logging.getLogger(__name__)
-# Map gRPC status codes to HTTP responses (the portal talks only to the gRPC
-# facade now; the legacy Thrift exception handlers are gone).
-GRPC_STATUS_TO_HTTP = {
- grpc.StatusCode.NOT_FOUND: status.HTTP_404_NOT_FOUND,
- grpc.StatusCode.PERMISSION_DENIED: status.HTTP_403_FORBIDDEN,
- grpc.StatusCode.UNAUTHENTICATED: status.HTTP_401_UNAUTHORIZED,
- grpc.StatusCode.INVALID_ARGUMENT: status.HTTP_400_BAD_REQUEST,
- grpc.StatusCode.FAILED_PRECONDITION: status.HTTP_400_BAD_REQUEST,
- grpc.StatusCode.ALREADY_EXISTS: status.HTTP_409_CONFLICT,
- grpc.StatusCode.UNIMPLEMENTED: status.HTTP_501_NOT_IMPLEMENTED,
-}
-
-
-def custom_exception_handler(exc, context):
- # Call REST framework's default exception handler first,
- # to get the standard error response.
- response = exception_handler(exc, context)
-
- if isinstance(exc, grpc.RpcError):
- code = exc.code()
- detail = exc.details() or str(exc)
- if code == grpc.StatusCode.UNAVAILABLE:
- log.warning("gRPC UNAVAILABLE", exc_info=exc)
- return Response(
- {'detail': detail, 'apiServerDown': True},
- status=status.HTTP_500_INTERNAL_SERVER_ERROR)
- http_status = GRPC_STATUS_TO_HTTP.get(
- code, status.HTTP_500_INTERNAL_SERVER_ERROR)
- if http_status >= 500:
- log.error("gRPC error %s", code, exc_info=exc,
- extra={'request': context['request']})
- else:
- log.warning("gRPC error %s", code, exc_info=exc)
- return Response({'detail': detail}, status=http_status)
-
- if isinstance(exc, ObjectDoesNotExist):
- log.warning("ObjectDoesNotExist", exc_info=exc)
- return Response(
- {'detail': str(exc)},
- status=status.HTTP_404_NOT_FOUND)
-
- if isinstance(exc, NotAuthenticated):
- log.debug("NotAuthenticated", exc_info=exc)
- if response is not None:
- response.data['is_authenticated'] = False
-
- if isinstance(exc, UnicodeEncodeError):
- fse = sys.getfilesystemencoding()
- if fse != 'utf-8':
- log.error(f"filesystem encoding is {fse}, not 'utf-8'. File paths with Unicode characters will produce errors.")
-
- # Generic handler
- if response is None:
- log.error("API exception", exc_info=exc, extra={'request': context['request']})
- return Response(
- {'detail': str(exc)},
- status=status.HTTP_500_INTERNAL_SERVER_ERROR
- )
-
- return response
-
-
-# For non-Django REST Framework error responses
+# For ad-hoc JSON error responses from function views that don't go through the
+# web.py dispatch exception mapping (e.g. the tus upload-finish handler). The
+# grpc->HTTP mapping that ``custom_exception_handler`` used to provide now lives
+# in ``web.exception_to_response`` (``web.GRPC_STATUS_TO_HTTP``).
def generic_json_exception_response(
- exc, status=status.HTTP_500_INTERNAL_SERVER_ERROR):
+ exc, status=HTTPStatus.INTERNAL_SERVER_ERROR):
return JsonResponse({'detail': str(exc)}, status=status)
diff --git a/airavata-django-portal/django_airavata/apps/api/grpc_adapters.py b/airavata-django-portal/django_airavata/apps/api/grpc_adapters.py
deleted file mode 100644
index 817b8dea8..000000000
--- a/airavata-django-portal/django_airavata/apps/api/grpc_adapters.py
+++ /dev/null
@@ -1,53 +0,0 @@
-"""Map gRPC ``FileMetadataResponse`` messages to the plain-dict shape the user
-storage serializers read.
-
-The user-storage file/directory serializers consume dicts keyed the way the
-legacy ``user_storage.listdir`` produced; these helpers convert the gRPC
-``FileMetadataResponse`` into that dict shape. (All the Thrift-attribute-shape
-read adapters that once lived here are gone — every serializer is proto-native.)
-"""
-
-
-# --- User storage file/directory listings -----------------------------------
-# The storage serializers (UserStorageFileSerializer / UserStorageDirectorySerializer)
-# read plain dicts keyed the way the legacy user_storage.listdir produced. The gRPC
-# FileMetadataResponse carries name/path/size/modified_time(epoch ms)/content_type/
-# data_product_uri; map it to that dict shape. ``relative_path`` overrides the path the
-# serializer reports (e.g. experiment-dir listings expose a path relative to the data dir).
-
-def _epoch_millis_to_datetime(value):
- """Epoch milliseconds -> aware UTC datetime, or None when unset (0)."""
- if not value:
- return None
- import datetime
- return datetime.datetime.fromtimestamp(value / 1000, tz=datetime.timezone.utc)
-
-
-def user_storage_file(pb, relative_path=None):
- """gRPC ``FileMetadataResponse`` (a file) -> UserStorageFileSerializer dict."""
- modified = _epoch_millis_to_datetime(pb.modified_time)
- return {
- 'name': pb.name,
- 'path': relative_path if relative_path is not None else pb.path,
- 'data-product-uri': pb.data_product_uri or None,
- # The adaptor exposes only a modified time; reuse it for created time so
- # the serializer's createdTime/modifiedTime both render (SFTP has no ctime).
- 'created_time': modified,
- 'modified_time': modified,
- 'mime_type': pb.content_type or None,
- 'size': pb.size,
- 'hidden': False,
- }
-
-
-def user_storage_directory(pb, relative_path=None):
- """gRPC ``FileMetadataResponse`` (a directory) -> UserStorageDirectorySerializer dict."""
- modified = _epoch_millis_to_datetime(pb.modified_time)
- return {
- 'name': pb.name,
- 'path': relative_path if relative_path is not None else pb.path,
- 'created_time': modified,
- 'modified_time': modified,
- 'size': pb.size,
- 'hidden': False,
- }
diff --git a/airavata-django-portal/django_airavata/apps/api/grpc_requests.py b/airavata-django-portal/django_airavata/apps/api/grpc_requests.py
deleted file mode 100644
index 6165b2286..000000000
--- a/airavata-django-portal/django_airavata/apps/api/grpc_requests.py
+++ /dev/null
@@ -1,63 +0,0 @@
-"""Adapters from the Thrift-shaped objects the DRF serializers produce to the
-gRPC protobuf request messages the facade expects.
-
-Track D (D3 writes): the ``apps/api`` serializers were generated from the Thrift
-models, so ``serializer.save()`` yields a Thrift model instance (Thrift attribute
-names: ``projectID``, ``gatewayId``, ...). These adapters convert that instance
-into the corresponding protobuf message (``project_id``, ``gateway_id``, ...) so
-the gRPC facade can send it. They are the write-direction mirror of
-``grpc_adapters`` and are removed once the serializers are made protobuf-native.
-
-proto3 scalar fields cannot hold ``None``, so optional Thrift values that may be
-``None`` are coerced to the proto default (``''``/``0``/``[]``).
-"""
-
-import importlib
-
-_GEN = "airavata_sdk.generated.org.apache.airavata.model"
-
-
-def _pb2(path):
- return importlib.import_module(f"{_GEN}.{path}")
-
-
-def password_credential(gateway_id, portal_user_name, login_user_name,
- password, description):
- """Build a proto ``PasswordCredential`` from the create-password request."""
- return _pb2("credential.store.credential_store_pb2").PasswordCredential(
- gateway_id=gateway_id or '',
- portal_user_name=portal_user_name or '',
- login_user_name=login_user_name or '',
- password=password or '',
- description=description or '',
- )
-
-
-def data_product_for_upload(*, gateway_id, owner_name, product_name, file_path,
- storage_resource_id, content_type=None, product_size=0):
- """Build a proto ``DataProductModel`` to register for a freshly uploaded file.
-
- The gRPC ``storage.upload_file`` only transfers the bytes and returns a
- minimal ``DataProductModel``; the portal registers the full data product via
- ``research.register_data_product`` so the file gets a canonical product URI.
- Mirrors the legacy ``user_storage._create_data_product`` shape: a single
- GATEWAY_DATA_STORE / TRANSIENT replica pointing at ``file_path``, with the
- content type recorded under ``mime-type`` metadata.
- """
- rc = _pb2("data.replica.replica_catalog_pb2")
- product_metadata = {"mime-type": content_type} if content_type else {}
- return rc.DataProductModel(
- gateway_id=gateway_id,
- owner_name=owner_name,
- product_name=product_name,
- data_product_type=rc.DataProductType.FILE,
- product_size=product_size or 0,
- product_metadata=product_metadata,
- replica_locations=[rc.DataReplicaLocationModel(
- replica_name="{} gateway data store copy".format(product_name),
- replica_location_category=rc.ReplicaLocationCategory.GATEWAY_DATA_STORE,
- replica_persistent_type=rc.ReplicaPersistentType.TRANSIENT,
- storage_resource_id=storage_resource_id or '',
- file_path=file_path,
- )],
- )
diff --git a/airavata-django-portal/django_airavata/apps/api/helpers.py b/airavata-django-portal/django_airavata/apps/api/helpers.py
index ee19990e8..1c932afc1 100644
--- a/airavata-django-portal/django_airavata/apps/api/helpers.py
+++ b/airavata-django-portal/django_airavata/apps/api/helpers.py
@@ -1,73 +1,152 @@
import logging
-from django.conf import settings
-from django.core.exceptions import ObjectDoesNotExist
+from django.core.cache import cache
-from . import models
+from airavata_sdk.helpers import compute_resources
logger = logging.getLogger(__name__)
+# Per-user workspace preferences (most-recent project/group/compute + per-app
+# favorites) live in the cache, not the DB (was api_workspacepreferences /
+# api_applicationpreferences). Pure UX state; cache eviction just reseeds the
+# defaults on the next read.
+def _prefs_key(username):
+ return f"workspace_prefs:{username}"
+
+
+def _load_prefs(username):
+ return cache.get(_prefs_key(username))
+
+
+def _store_prefs(username, data):
+ cache.set(_prefs_key(username), data)
+
+
+class _ApplicationPreference:
+ """Cache-backed stand-in for the old ApplicationPreferences row.
+
+ Exposes the ``application_id`` / ``favorite`` attributes the serializer and
+ favorite/unfavorite views read; ``save()`` writes the favorite flag back
+ through the owning preferences object.
+ """
+
+ def __init__(self, prefs, application_id, favorite):
+ self._prefs = prefs
+ self.application_id = application_id
+ self.favorite = favorite
+
+ def save(self):
+ self._prefs._set_favorite(self.application_id, self.favorite)
+
+
+class _ApplicationPreferencesManager:
+ """Mimics the ORM reverse-FK manager (``applicationpreferences_set``)."""
+
+ def __init__(self, prefs):
+ self._prefs = prefs
+
+ def all(self):
+ return [
+ _ApplicationPreference(self._prefs, app_id, favorite)
+ for app_id, favorite in self._prefs._favorites.items()
+ ]
+
+ def get(self, application_id):
+ if application_id not in self._prefs._favorites:
+ from django.core.exceptions import ObjectDoesNotExist
+ raise ObjectDoesNotExist()
+ return _ApplicationPreference(
+ self._prefs, application_id,
+ self._prefs._favorites[application_id])
+
+ def create(self, username=None, application_id=None, favorite=False):
+ self._prefs._set_favorite(application_id, favorite)
+ return _ApplicationPreference(self._prefs, application_id, favorite)
+
+
+class WorkspacePreferences:
+ """Cache-backed stand-in for the old WorkspacePreferences row.
+
+ Preserves the attribute/method surface every call site relies on:
+ ``most_recent_*`` mutable attributes, ``save()``, and an
+ ``applicationpreferences_set`` reverse-manager.
+ """
+
+ def __init__(self, username, data):
+ self.username = username
+ self.most_recent_project_id = data.get("most_recent_project_id")
+ self.most_recent_group_resource_profile_id = data.get(
+ "most_recent_group_resource_profile_id")
+ self.most_recent_compute_resource_id = data.get(
+ "most_recent_compute_resource_id")
+ self._favorites = dict(data.get("application_preferences", {}))
+ self.applicationpreferences_set = _ApplicationPreferencesManager(self)
+
+ def _as_dict(self):
+ return {
+ "most_recent_project_id": self.most_recent_project_id,
+ "most_recent_group_resource_profile_id":
+ self.most_recent_group_resource_profile_id,
+ "most_recent_compute_resource_id":
+ self.most_recent_compute_resource_id,
+ "application_preferences": self._favorites,
+ }
+
+ def save(self):
+ _store_prefs(self.username, self._as_dict())
+
+ def _set_favorite(self, application_id, favorite):
+ self._favorites[application_id] = favorite
+ self.save()
+
+
class WorkspacePreferencesHelper:
+ """Read/write a user's workspace preferences.
+
+ The record lives in this portal's cache; the server-side lookups needed to
+ seed/validate it (first writeable project, accessible group resource
+ profiles) are delegated to the SDK ``compute_resources`` helpers.
+ """
def get(self, request):
- try:
- workspace_preferences = models.WorkspacePreferences.objects.get(
- username=request.user.username)
- self._check(request, workspace_preferences)
- except ObjectDoesNotExist:
- workspace_preferences = self._create_default(request)
+ username = request.user.username
+ data = _load_prefs(username)
+ if data is None:
+ workspace_preferences = self._create_default(request, username)
workspace_preferences.save()
+ else:
+ workspace_preferences = WorkspacePreferences(username, data)
+ self._check(request, workspace_preferences)
return workspace_preferences
- def _create_default(self, request):
- workspace_preferences = models.WorkspacePreferences.create(
- request.user.username)
- most_recent_project = self._get_most_recent_project(request)
- workspace_preferences.most_recent_project_id = (
- most_recent_project.project_id if most_recent_project else None)
- first_grp = \
- self._get_first_group_resource_profile(request)
- workspace_preferences.most_recent_group_resource_profile_id = \
- first_grp.group_resource_profile_id if first_grp else None
- return workspace_preferences
-
- def _get_most_recent_project(self, request):
- "Return most recent writeable project."
- projects = request.airavata.research.get_user_projects(
- gateway_id=settings.GATEWAY_ID, user_name=request.user.username,
- limit=-1, offset=0)
- for project in projects:
- if self._can_write(request, project.project_id):
- return project
- return None
-
- def _get_first_group_resource_profile(self, request):
- "Return first accessible group resource profile"
-
- group_resource_profiles = \
- request.airavata.compute.get_group_resource_list()
- if len(group_resource_profiles) > 0:
- return group_resource_profiles[0]
- else:
- return None
+ def _create_default(self, request, username):
+ defaults = compute_resources.resolve_workspace_defaults(
+ request.airavata)
+ return WorkspacePreferences(username, {
+ "most_recent_project_id": defaults["most_recent_project_id"],
+ "most_recent_group_resource_profile_id":
+ defaults["most_recent_group_resource_profile_id"],
+ })
def _check(self, request, prefs):
"Validate preference values and update as needed."
if (not prefs.most_recent_project_id or
not self._can_write(request, prefs.most_recent_project_id)):
- most_recent_project = self._get_most_recent_project(request)
- if most_recent_project is not None:
- logger.info("_check: updating most_recent_project_id to {}".format(most_recent_project.project_id))
- prefs.most_recent_project_id = most_recent_project.project_id
+ most_recent_project_id = (
+ compute_resources.most_recent_writeable_project_id(
+ request.airavata))
+ if most_recent_project_id is not None:
+ logger.info("_check: updating most_recent_project_id to {}".format(most_recent_project_id))
+ prefs.most_recent_project_id = most_recent_project_id
prefs.save()
else:
logger.warning("_check: no writeable projects found, unsetting most_recent_project_id")
prefs.most_recent_project_id = None
prefs.save()
- group_resource_profiles = \
- request.airavata.compute.get_group_resource_list()
- group_resource_profile_ids = [g.group_resource_profile_id for g in group_resource_profiles]
+ group_resource_profile_ids = (
+ compute_resources.accessible_group_resource_profile_ids(
+ request.airavata))
if (not prefs.most_recent_group_resource_profile_id or
prefs.most_recent_group_resource_profile_id not in group_resource_profile_ids):
first_grp_id = (group_resource_profile_ids[0]
@@ -80,9 +159,7 @@ class WorkspacePreferencesHelper:
prefs.save()
def _can_write(self, request, entity_id):
- return request.airavata.sharing.user_has_access(
- resource_id=entity_id, user_id=request.user.username,
- permission_type="WRITE")
+ return compute_resources.user_can_write(request.airavata, entity_id)
def _can_read(self, request, entity_id):
return request.airavata.sharing.user_has_access(
diff --git a/airavata-django-portal/django_airavata/apps/api/output_views.py b/airavata-django-portal/django_airavata/apps/api/output_views.py
index 0df73208f..7833dc6bf 100644
--- a/airavata-django-portal/django_airavata/apps/api/output_views.py
+++ b/airavata-django-portal/django_airavata/apps/api/output_views.py
@@ -1,6 +1,5 @@
import collections
import inspect
-import io
import json
import logging
import os
@@ -11,11 +10,10 @@ import papermill as pm
from airavata_sdk.generated.org.apache.airavata.model.application.io.application_io_pb2 import ( # noqa: E501
DataType,
)
+from airavata_sdk.helpers import research_resources, storage_resources
from django.conf import settings
from nbconvert import HTMLExporter
-from . import view_utils
-
logger = logging.getLogger(__name__)
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -177,7 +175,8 @@ def generate_data(request,
**kwargs):
output_view_provider = _get_output_view_provider(output_view_provider_id)
# TODO if output_view_provider is None, return 404
- experiment = request.airavata.research.get_experiment(experiment_id)
+ experiment = research_resources.get_experiment_proto(
+ request.airavata, experiment_id)
experiment_output = [o
for o in experiment.experiment_outputs
if o.name == experiment_output_name]
@@ -219,16 +218,9 @@ def _generate_data(request,
DataType.STDERR) and
experiment_output.value.startswith("airavata-dp")):
data_product_uris = experiment_output.value.split(",")
- data_products = map(
- lambda dpid: request.airavata.research.get_data_product(dpid),
- data_product_uris)
- for data_product in data_products:
- file_path = view_utils.data_product_file_path(data_product)
- if file_path and request.airavata.storage.file_exists(file_path):
- resp = request.airavata.storage.download_file(file_path)
- output_file = io.BytesIO(resp.content)
- output_file.name = resp.name or os.path.basename(file_path)
- output_files.append(output_file)
+ output_files.extend(
+ storage_resources.download_data_product_files(
+ request.airavata, data_product_uris))
generate_data_func = output_view_provider.generate_data
method_sig = inspect.signature(generate_data_func)
diff --git a/airavata-django-portal/django_airavata/apps/api/proto_render.py b/airavata-django-portal/django_airavata/apps/api/proto_render.py
new file mode 100644
index 000000000..41b8e2d03
--- /dev/null
+++ b/airavata-django-portal/django_airavata/apps/api/proto_render.py
@@ -0,0 +1,98 @@
+"""Generic proto-direct → snake_case JSON rendering for migrated ViewSets.
+
+:func:`to_jsonable` turns an SDK return value (a proto ``Message``, a
+:class:`~airavata_sdk.helpers._envelope.WithAccess` envelope, a composed pydantic
+``BaseModel``, or a list/dict of those) into plain JSON-serializable Python with
+snake_case keys; :class:`ProtoJSONRenderer` applies it on the DRF response path.
+
+The ``MessageToDict`` options below are the source-of-truth read contract; the
+defaults (enums → member NAMES, int64 → decimal STRING) are deliberate and
+relied on by every migrated ViewSet — document any change.
+
+``preserving_proto_field_name=True`` (REQUIRED)
+ Emit proto field names verbatim (``project_id``) instead of the
+ lowerCamelCase JSON names — this is what makes the output snake_case.
+
+``always_print_fields_with_no_presence=True``
+ Emit every singular field even at its default value, so the JSON shape is
+ STABLE regardless of which fields the backend populated (the frontend reads a
+ fixed key set). Repeated/map and explicit-presence fields are unaffected — an
+ unset message stays absent, an empty list stays ``[]``.
+
+Enums render as the member NAME string (rename-stable, frontend-readable);
+int64 / uint64 / fixed64 render as decimal STRINGS (they exceed JS ``Number``
+safe-integer range), e.g. ``creation_time`` epoch-millis as ``"1705320000000"``.
+"""
+
+import json
+
+from django.core.serializers.json import DjangoJSONEncoder
+from google.protobuf.json_format import MessageToDict
+from google.protobuf.message import Message
+
+try: # pydantic is optional on this path; only composed shapes use it
+ from pydantic import BaseModel as _PydanticBaseModel
+except Exception: # pragma: no cover - pydantic always present in practice
+ _PydanticBaseModel = None
+
+from airavata_sdk.helpers._envelope import WithAccess, WithGroupAccess
+
+# The single source of truth for how every proto on the read path is rendered.
+_MESSAGE_TO_DICT_OPTS = dict(
+ preserving_proto_field_name=True,
+ always_print_fields_with_no_presence=True,
+)
+
+
+def proto_to_dict(message: Message) -> dict:
+ return MessageToDict(message, **_MESSAGE_TO_DICT_OPTS)
+
+
+def to_jsonable(obj):
+ """Convert an SDK return value into JSON-serializable snake_case Python.
+
+ An envelope (``WithAccess`` / ``WithGroupAccess``) renders its proto and
+ merges its access scalars on top — the extras are exactly the cross-service
+ fields kept OUT of the proto, so keys never collide. A ``dict`` recurses
+ values but passes keys through unchanged (callers here already use snake_case).
+ """
+ if isinstance(obj, Message):
+ return proto_to_dict(obj)
+ if isinstance(obj, WithAccess):
+ base = to_jsonable(obj.message)
+ base["is_owner"] = obj.is_owner
+ base["user_has_write_access"] = obj.user_has_write_access
+ return base
+ if isinstance(obj, WithGroupAccess):
+ base = to_jsonable(obj.message)
+ base["is_admin"] = obj.is_admin
+ base["is_owner"] = obj.is_owner
+ base["is_member"] = obj.is_member
+ base["is_gateway_admins_group"] = obj.is_gateway_admins_group
+ base["is_read_only_gateway_admins_group"] = \
+ obj.is_read_only_gateway_admins_group
+ base["is_default_gateway_users_group"] = \
+ obj.is_default_gateway_users_group
+ return base
+ if isinstance(obj, (list, tuple)):
+ return [to_jsonable(x) for x in obj]
+ if isinstance(obj, dict):
+ return {k: to_jsonable(v) for k, v in obj.items()}
+ if _PydanticBaseModel is not None and isinstance(obj, _PydanticBaseModel):
+ # Recurse field-by-field (NOT a flat ``model_dump()``) so a composed
+ # model may carry protos / ``WithAccess`` envelopes / nested dicts that
+ # the SAME renderer flattens. Plain JSON-able fields are unchanged.
+ return {
+ name: to_jsonable(getattr(obj, name))
+ for name in type(obj).model_fields
+ }
+ return obj
+
+
+class ProtoJSONRenderer:
+ """Plain JSON renderer that runs :func:`to_jsonable` over the data, then
+ JSON-encodes it to bytes. Page views call ``.render(data) -> bytes``."""
+
+ def render(self, data, accepted_media_type=None, renderer_context=None):
+ return json.dumps(
+ to_jsonable(data), cls=DjangoJSONEncoder).encode('utf-8')
diff --git a/airavata-django-portal/django_airavata/apps/api/serializers.py b/airavata-django-portal/django_airavata/apps/api/serializers.py
index 5cbe68179..39c301537 100644
--- a/airavata-django-portal/django_airavata/apps/api/serializers.py
+++ b/airavata-django-portal/django_airavata/apps/api/serializers.py
@@ -1,63 +1,8 @@
-import datetime
-import enum
import json
import logging
-import os
-from urllib.parse import quote
-
-from airavata_sdk.helpers import experiment_orchestration
-from django.conf import settings
-from django.contrib.auth import get_user_model
-from django.urls import reverse
-from rest_framework import serializers
-
-from . import models, view_utils
log = logging.getLogger(__name__)
-# Directory under user storage where uploaded experiment input files are staged
-# (matches the legacy airavata_django_portal_sdk convention).
-TMP_INPUT_FILE_UPLOAD_DIR = "tmp"
-
-
-# Historical Thrift enum member -> integer tables. The REST contract emits
-# these Thrift enum integers (e.g. dataProductType FILE == 0), which differ from
-# the proto enum integers; the proto-native serializers bridge by member NAME via
-# proto_enum_int_field / proto_enum_keyed_map_field. Hardcoded so the portal no
-# longer depends on the legacy Thrift model types for the enum values.
-_THRIFT_ENUM_INTS = {
- 'ApplicationParallelismType': {'CCM': 4, 'CRAY_MPI': 5, 'MPI': 1, 'OPENMP': 2, 'OPENMP_MPI': 3, 'SERIAL': 0},
- 'DataMovementProtocol': {'GridFTP': 3, 'LOCAL': 0, 'SCP': 1, 'SFTP': 2, 'UNICORE_STORAGE_SERVICE': 4},
- 'DataProductType': {'COLLECTION': 1, 'FILE': 0},
- 'DataType': {'FLOAT': 2, 'INTEGER': 1, 'STDERR': 6, 'STDOUT': 5, 'STRING': 0, 'URI': 3, 'URI_COLLECTION': 4},
- 'ExperimentState': {'CANCELED': 6, 'CANCELING': 5, 'COMPLETED': 7, 'CREATED': 0, 'EXECUTING': 4, 'FAILED': 8, 'LAUNCHED': 3, 'SCHEDULED': 2, 'VALIDATED': 1},
- 'ExperimentType': {'SINGLE_APPLICATION': 0, 'WORKFLOW': 1},
- 'FileSystems': {'ARCHIVE': 4, 'HOME': 0, 'LOCALTMP': 2, 'SCRATCH': 3, 'WORK': 1},
- 'IOType': {'FILE': 0, 'PROPERTY': 1},
- 'JobManagerCommand': {'CHECK_JOB': 3, 'DELETION': 2, 'JOB_MONITORING': 1, 'SHOW_CLUSTER_INFO': 7, 'SHOW_NO_OF_PENDING_JOBS': 9, 'SHOW_NO_OF_RUNNING_JOBS': 8, 'SHOW_QUEUE': 4, 'SHOW_RESERVATION': 5, 'SHOW_START': 6, 'SUBMISSION': 0},
- 'JobState': {'ACTIVE': 2, 'CANCELED': 4, 'COMPLETE': 3, 'FAILED': 5, 'NON_CRITICAL_FAIL': 8, 'QUEUED': 1, 'SUBMITTED': 0, 'SUSPENDED': 6, 'UNKNOWN': 7},
- 'JobSubmissionProtocol': {'CLOUD': 4, 'GLOBUS': 2, 'LOCAL': 0, 'LOCAL_FORK': 6, 'SSH': 1, 'SSH_FORK': 5, 'UNICORE': 3},
- 'MonitorMode': {'CLOUD_JOB_MONITOR': 1, 'FORK': 4, 'JOB_EMAIL_NOTIFICATION_MONITOR': 2, 'LOCAL': 5, 'POLL_JOB_MANAGER': 0, 'XSEDE_AMQP_SUBSCRIBE': 3},
- 'ProcessState': {'CANCELED': 13, 'CANCELLING': 12, 'COMPLETED': 10, 'CONFIGURING_WORKSPACE': 4, 'CREATED': 0, 'DEQUEUING': 15, 'EXECUTING': 6, 'FAILED': 11, 'INPUT_DATA_STAGING': 5, 'MONITORING': 7, 'OUTPUT_DATA_STAGING': 8, 'POST_PROCESSING': 9, 'PRE_PROCESSING': 3, 'QUEUED': 14, 'REQUEUED': 16, 'STARTED': 2, 'VALIDATED': 1},
- 'ProviderName': {'AWSEC2': 1, 'EC2': 0, 'RACKSPACE': 2},
- 'ReplicaLocationCategory': {'COMPUTE_RESOURCE': 1, 'GATEWAY_DATA_STORE': 0, 'LONG_TERM_STORAGE_RESOURCE': 2, 'OTHER': 3},
- 'ReplicaPersistentType': {'PERSISTENT': 1, 'TRANSIENT': 0},
- 'ResourceJobManagerType': {'AIRAVATA_CUSTOM': 6, 'CLOUD': 5, 'FORK': 0, 'HTCONDOR': 7, 'LSF': 3, 'PBS': 1, 'SLURM': 2, 'UGE': 4},
- 'ResourcePermissionType': {'MANAGE_SHARING': 3, 'OWNER': 2, 'READ': 1, 'WRITE': 0},
- 'ResourceType': {'AWS': 1, 'SLURM': 0},
- 'SecurityProtocol': {'GSI': 2, 'KERBEROS': 3, 'LOCAL': 5, 'OAUTH': 4, 'SSH_KEYS': 1, 'USERNAME_PASSWORD': 0},
- 'Status': {'ACTIVE': 0, 'APPROVED': 2, 'CONFIRMED': 1, 'DECLINED': 12, 'DELETED': 3, 'DENIED': 7, 'DUPLICATE': 4, 'EXPIRED': 13, 'GRACE_PERIOD': 5, 'INVITED': 6, 'PENDING': 8, 'PENDING_APPROVAL': 9, 'PENDING_CONFIRMATION': 10, 'SUSPENDED': 11},
- 'TaskState': {'CANCELED': 4, 'COMPLETED': 2, 'CREATED': 0, 'EXECUTING': 1, 'FAILED': 3},
- 'TaskTypes': {'DATA_STAGING': 1, 'ENV_CLEANUP': 3, 'ENV_SETUP': 0, 'JOB_SUBMISSION': 2, 'MONITORING': 4, 'OUTPUT_FETCHING': 5},
-}
-
-
-# The share/revoke set logic uses these as comparable sentinels (the sharing
-# facade is addressed by the member NAME, e.g. "WRITE"); a plain IntEnum mirroring
-# the historical Thrift values keeps the portal free of the Thrift model type.
-ResourcePermissionType = enum.IntEnum(
- 'ResourcePermissionType', _THRIFT_ENUM_INTS['ResourcePermissionType'])
-
def user_has_access(request, resource_id, permission="WRITE"):
"""gRPC sharing access check (Track D — replaces the Thrift userHasAccess).
@@ -73,3106 +18,152 @@ def user_has_access(request, resource_id, permission="WRITE"):
permission_type=permission)
-class FullyEncodedHyperlinkedIdentityField(
- serializers.HyperlinkedIdentityField):
- def get_url(self, obj, view_name, request, format):
- if hasattr(obj, self.lookup_field):
- lookup_value = getattr(obj, self.lookup_field)
- else:
- lookup_value = obj.get(self.lookup_field)
- try:
- encoded_lookup_value = quote(lookup_value, safe="")
- except Exception:
- log.warning(
- "Failed to encode lookup_value [{}] for lookup_field "
- "[{}] of object [{}]".format(
- lookup_value, self.lookup_field, obj))
- raise
- # Bit of a hack. Django's URL reversing does URL encoding but it
- # doesn't encode all characters including some like '/' that are used
- # in URL mappings.
- kwargs = {self.lookup_url_kwarg: "__PLACEHOLDER__"}
- url = self.reverse(view_name, kwargs=kwargs,
- request=request, format=format)
- return url.replace("__PLACEHOLDER__", encoded_lookup_value)
-
-
-class UTCPosixTimestampDateTimeField(serializers.DateTimeField):
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.default = self.current_time_ms
- self.initial = self.initial_value
- self.required = False
-
- def to_representation(self, obj):
- # Create datetime instance from milliseconds that is aware of timezon
- dt = datetime.datetime.fromtimestamp(obj / 1000, datetime.timezone.utc)
- return super().to_representation(dt)
-
- def to_internal_value(self, data):
- dt = super().to_internal_value(data)
- return int(dt.timestamp() * 1000)
-
- def initial_value(self):
- return self.to_representation(self.current_time_ms())
-
- def current_time_ms(self):
- return int(datetime.datetime.utcnow().timestamp() * 1000)
-
-
-class ProtoTimestampField(UTCPosixTimestampDateTimeField):
- """Renders a protobuf int64 epoch-millis field as the same ISO timestamp the
- Thrift-generated serializers produced.
-
- proto3 scalar int fields default to ``0`` (never None), so an unset timestamp
- reads as ``0``. When ``null_if_zero`` is set the field treats ``0`` as the
- Thrift ``None`` and renders ``null`` (matching the old ``allow_null`` fields
- whose adapters mapped ``pb.<time> or None``); otherwise ``0`` renders as the
- epoch like the old non-nullable fields did.
- """
-
- def __init__(self, *args, null_if_zero=False, **kwargs):
- self.null_if_zero = null_if_zero
- if null_if_zero:
- kwargs.setdefault('allow_null', True)
- super().__init__(*args, **kwargs)
-
- def to_representation(self, obj):
- if self.null_if_zero and not obj:
- return None
- return super().to_representation(obj)
-
-
-class ProtoEnumNameField(serializers.Field):
- """Renders a protobuf enum field as the enum member NAME, the same string the
- Thrift-generated ``ThriftEnumField`` / ``EnumChoiceField`` emitted.
-
- The instance is the protobuf message and ``source`` is the proto enum field
- name; ``to_representation`` receives that field's integer value and resolves
- it to the member name. Construct via :func:`proto_enum_name_field`, which
- snapshots the proto enum descriptor into the plain ``by_number``/``by_name``
- dicts this field holds (the descriptor itself cannot be deep-copied, and DRF
- deep-copies field instances when binding them). ``proto_prefix`` strips a
- proto-only member prefix (proto3 namespaces members that would otherwise
- collide, e.g. ``NOTIFICATION_PRIORITY_LOW`` -> ``LOW``); the bare-named
- ``*_UNKNOWN`` zero sentinel renders ``None`` to match the old nullable fields.
- """
-
- def __init__(self, by_number, by_name, proto_prefix='', **kwargs):
- self._by_number = by_number
- self._by_name = by_name
- self.proto_prefix = proto_prefix
- super().__init__(**kwargs)
-
- def to_representation(self, value):
- name = self._by_number[value]
- if self.proto_prefix and name.startswith(self.proto_prefix):
- name = name[len(self.proto_prefix):]
- if name.endswith('UNKNOWN') and value == 0:
- return None
- return name
-
- def to_internal_value(self, data):
- # Writes pass the member name; map back to the proto integer value.
- name = data
- if self.proto_prefix and (self.proto_prefix + name) in self._by_name:
- name = self.proto_prefix + name
- try:
- return self._by_name[name]
- except KeyError:
- self.fail('invalid_choice', input=data)
-
-
-def proto_enum_name_field(enum_descriptor, proto_prefix='', **kwargs):
- """Build a :class:`ProtoEnumNameField` from a proto enum descriptor.
-
- Snapshots the descriptor into plain int<->name dicts so the resulting field
- is deep-copyable (DRF deep-copies fields when binding them to a serializer).
- """
- return ProtoEnumNameField(
- by_number={v.number: v.name for v in enum_descriptor.values},
- by_name={v.name: v.number for v in enum_descriptor.values},
- proto_prefix=proto_prefix, **kwargs)
-
-
-class ProtoIntOrNoneField(serializers.IntegerField):
- """Renders a protobuf int field as a raw integer, mapping the proto-0 default
- to ``None`` to match the old auto-generated ``IntegerField`` whose adapter fed
- it ``pb.<field> or None``.
- """
-
- def __init__(self, *args, **kwargs):
- kwargs.setdefault('allow_null', True)
- kwargs.setdefault('read_only', True)
- super().__init__(*args, **kwargs)
-
- def to_representation(self, value):
- if not value:
- return None
- return super().to_representation(value)
-
-
-class ProtoEnumIntField(serializers.Field):
- """Renders a protobuf enum field as the corresponding THRIFT enum integer.
-
- Many serializers historically rendered an enum as a raw integer (an
- auto-generated ``IntegerField``, not a name). proto and Thrift assign
- different integers to the same member, so the adapter bridged by NAME to the
- Thrift integer; this field does the same in one step via the
- ``proto_to_thrift`` map (proto int -> Thrift int) built by
- :func:`proto_enum_int_field`. proto-only members and the zero sentinel map to
- ``None`` (these fields were nullable).
- """
-
- def __init__(self, proto_to_thrift, thrift_to_proto, **kwargs):
- self._proto_to_thrift = proto_to_thrift
- self._thrift_to_proto = thrift_to_proto
- super().__init__(**kwargs)
-
- def to_representation(self, value):
- return self._proto_to_thrift.get(value)
-
- def to_internal_value(self, data):
- # Writes pass the Thrift integer; map it back to the proto integer.
- return self._thrift_to_proto.get(int(data), 0)
-
-
-def proto_enum_int_field(enum_descriptor, thrift_ints, proto_prefix='',
- name_map=None, **kwargs):
- """Build a :class:`ProtoEnumIntField` bridging a proto enum to the historical
- Thrift enum INTEGER by member NAME (stripping ``proto_prefix`` from
- proto-namespaced members). ``thrift_ints`` is the ``{member name: thrift int}``
- table (see :data:`_THRIFT_ENUM_INTS`); members absent from it map to ``None``.
-
- ``name_map`` overrides the proto-member-name -> Thrift-member-name mapping for
- enums whose member names diverge beyond a simple prefix (proto3 namespacing of
- colliding members, e.g. proto ``DATA_MOVEMENT_PROTOCOL_LOCAL`` -> Thrift
- ``LOCAL``, proto ``JSP_CLOUD`` -> Thrift ``CLOUD``).
- """
- name_map = name_map or {}
- proto_to_thrift = {}
- thrift_to_proto = {}
- for v in enum_descriptor.values:
- if v.name in name_map:
- name = name_map[v.name]
- else:
- name = v.name
- if proto_prefix and name.startswith(proto_prefix):
- name = name[len(proto_prefix):]
- thrift_int = thrift_ints.get(name)
- if thrift_int is not None:
- proto_to_thrift[v.number] = thrift_int
- thrift_to_proto[thrift_int] = v.number
- else:
- proto_to_thrift[v.number] = None
- return ProtoEnumIntField(
- proto_to_thrift=proto_to_thrift, thrift_to_proto=thrift_to_proto,
- **kwargs)
-
-
-# proto enum member name -> Thrift member name for the protocol enums whose names
-# diverge beyond a simple prefix (proto3 namespaces colliding members). Used by
-# the compute/storage resource and resource-preference serializers.
-_JOB_SUBMISSION_PROTOCOL_NAME_MAP = {'JSP_CLOUD': 'CLOUD'}
-_DATA_MOVEMENT_PROTOCOL_NAME_MAP = {'DATA_MOVEMENT_PROTOCOL_LOCAL': 'LOCAL'}
-
-
-def job_submission_protocol_field(**kwargs):
- """A :class:`ProtoEnumIntField` rendering proto ``JobSubmissionProtocol`` as
- the Thrift integer (proto ``JSP_CLOUD`` -> Thrift ``CLOUD``)."""
- from airavata_sdk.generated.org.apache.airavata.model.appcatalog.computeresource import ( # noqa: E501
- compute_resource_pb2,
- )
- return proto_enum_int_field(
- compute_resource_pb2.JobSubmissionProtocol.DESCRIPTOR,
- _THRIFT_ENUM_INTS['JobSubmissionProtocol'],
- proto_prefix='JOB_SUBMISSION_PROTOCOL_',
- name_map=_JOB_SUBMISSION_PROTOCOL_NAME_MAP, **kwargs)
-
-
-def data_movement_protocol_field(**kwargs):
- """A :class:`ProtoEnumIntField` rendering proto ``DataMovementProtocol`` as
- the Thrift integer (proto ``DATA_MOVEMENT_PROTOCOL_LOCAL`` -> Thrift ``LOCAL``;
- proto-only ``GRID_FTP`` -> None)."""
- from airavata_sdk.generated.org.apache.airavata.model.data.movement import (
- data_movement_pb2,
- )
- return proto_enum_int_field(
- data_movement_pb2.DataMovementProtocol.DESCRIPTOR,
- _THRIFT_ENUM_INTS['DataMovementProtocol'],
- proto_prefix='DATA_MOVEMENT_PROTOCOL_',
- name_map=_DATA_MOVEMENT_PROTOCOL_NAME_MAP, **kwargs)
-
-
-class ProtoFileSystemsMapField(serializers.Field):
- """Renders a proto ``map<int32, string>`` whose int key holds a proto
- ``FileSystems`` value as the ``{Thrift FileSystems int (as a string): path}``
- dict the old i32-keyed Thrift map produced.
-
- proto and Thrift assign different integers to the same member (proto HOME=1
- vs Thrift HOME=0), so the key is bridged by NAME; the JSON key is the Thrift
- integer as a string (DRF ``DictField`` rendered ``str(key)`` for the i32 map).
- """
-
- def __init__(self, **kwargs):
- kwargs.setdefault('read_only', True)
- super().__init__(**kwargs)
- self._proto_to_thrift = None
-
- def _key_map(self):
- if self._proto_to_thrift is None:
- from airavata_sdk.generated.org.apache.airavata.model.appcatalog.computeresource import ( # noqa: E501
- compute_resource_pb2,
- )
- proto_fs = compute_resource_pb2.FileSystems
- thrift_fs = _THRIFT_ENUM_INTS['FileSystems']
- self._proto_to_thrift = {
- proto_fs.Value(name): thrift_fs[name]
- for name in proto_fs.keys() if name in thrift_fs
- }
- return self._proto_to_thrift
-
- def to_representation(self, value):
- key_map = self._key_map()
- return {
- str(key_map[k]): v for k, v in value.items() if k in key_map}
-
-
-class ProtoEnumKeyedMapField(serializers.Field):
- """Renders a proto ``map<int32, string>`` whose int key holds a proto enum
- value as the ``{str(Thrift enum member): value}`` dict the old enum-keyed
- Thrift map produced (e.g. ``{'JobManagerCommand.SUBMISSION': 'sbatch'}``).
-
- Build via :func:`proto_enum_keyed_map_field`, which snapshots the proto-int ->
- Thrift-member-str mapping. (Unlike ``ProtoFileSystemsMapField``, which mirrors
- an i32-keyed Thrift map and emits the digit, this mirrors an enum-keyed Thrift
- map and emits ``str(member)``.)
- """
-
- def __init__(self, key_labels, **kwargs):
- self._key_labels = key_labels
- kwargs.setdefault('read_only', True)
- super().__init__(**kwargs)
-
- def to_representation(self, value):
- return {
- self._key_labels[k]: v
- for k, v in value.items() if k in self._key_labels}
-
-
-def proto_enum_keyed_map_field(proto_enum_descriptor, thrift_enum_name,
- thrift_ints, **kwargs):
- """Build a :class:`ProtoEnumKeyedMapField` mapping each proto enum int key to
- ``"<ThriftEnum>.<member>"`` — the string the old enum-keyed Thrift map's
- ``DictField`` rendered (``str`` of a Thrift ``IntEnum`` member) — by member
- name; members absent from ``thrift_ints`` (unknown/zero sentinels) are dropped.
- """
- key_labels = {}
- for v in proto_enum_descriptor.values:
- if v.name in thrift_ints:
- key_labels[v.number] = "{}.{}".format(thrift_enum_name, v.name)
- return ProtoEnumKeyedMapField(key_labels=key_labels, **kwargs)
-
-
-class StoredJSONField(serializers.JSONField):
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- def to_representation(self, value):
- try:
- if value:
- return json.loads(value)
- else:
- return value
- except Exception:
- return value
-
- def to_internal_value(self, data):
- try:
- return json.dumps(data)
- except (TypeError, ValueError):
- self.fail('invalid')
-
-
-class ProtoStoredJSONField(StoredJSONField):
- """:class:`StoredJSONField` for a proto string field: the proto-empty default
- ``''`` renders ``null`` (the old adapters mapped ``pb.meta_data or None``)."""
-
- def to_representation(self, value):
- if not value:
- return None
- return super().to_representation(value)
-
-
-class OrderedListField(serializers.ListField):
-
- def __init__(self, *args, **kwargs):
- self.order_by = kwargs.pop('order_by', None)
- super().__init__(*args, **kwargs)
-
- def to_representation(self, instance):
- rep = super().to_representation(instance)
- if rep is not None:
- rep.sort(key=lambda item: item[self.order_by])
- return rep
-
- def to_internal_value(self, data):
- validated_data = super().to_internal_value(data)
- # Update order field based on order in array
- items = validated_data if validated_data else []
- for i in range(len(items)):
- items[i][self.order_by] = i
- return validated_data
-
-
-def _group_manager_pb2():
- from airavata_sdk.generated.org.apache.airavata.model.group import (
- group_manager_pb2,
- )
- return group_manager_pb2
-
-
-class GroupSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``GroupModel`` message.
-
- On update the added/removed member/admin diffs the view needs are stashed on
- the serializer instance (``self.added_members`` etc.) — a protobuf message
- can't carry arbitrary attributes the way the old Thrift instance did.
- """
-
- id = serializers.CharField(read_only=True)
- name = serializers.CharField()
- ownerId = serializers.CharField(source='owner_id', read_only=True)
- description = serializers.CharField(
- allow_blank=True, allow_null=True, required=False)
- members = serializers.ListField(
- child=serializers.CharField(), required=False)
- admins = serializers.ListField(
- child=serializers.CharField(), required=False)
- url = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:group-detail',
- lookup_field='id',
- lookup_url_kwarg='group_id')
- isAdmin = serializers.SerializerMethodField()
- isOwner = serializers.SerializerMethodField()
- isMember = serializers.SerializerMethodField()
- isGatewayAdminsGroup = serializers.SerializerMethodField()
- isReadOnlyGatewayAdminsGroup = serializers.SerializerMethodField()
- isDefaultGatewayUsersGroup = serializers.SerializerMethodField()
-
- def to_representation(self, instance):
- ret = super().to_representation(instance)
- if ret.get('description') == '':
- ret['description'] = None
- return ret
-
- def create(self, validated_data):
- return _group_manager_pb2().GroupModel(
- name=validated_data.get('name', '') or '',
- description=validated_data.get('description', '') or '',
- members=list(validated_data.get('members', []) or []),
- admins=list(validated_data.get('admins', []) or []),
- owner_id=(self.context['request'].user.username + "@" +
- settings.GATEWAY_ID),
- )
-
- def update(self, instance, validated_data):
- if 'name' in validated_data:
- instance.name = validated_data['name'] or ''
- if 'description' in validated_data:
- instance.description = validated_data['description'] or ''
- # Calculate added and removed members/admins; stash on the serializer for
- # the view (a proto message can't carry the old Thrift ``_added_*`` attrs).
- old_members = set(instance.members)
- new_members = set(validated_data.get('members', instance.members))
- self.removed_members = list(old_members - new_members)
- self.added_members = list(new_members - old_members)
- instance.members[:] = list(validated_data.get('members', instance.members))
- old_admins = set(instance.admins)
- new_admins = set(validated_data.get('admins', instance.admins))
- self.removed_admins = list(old_admins - new_admins)
- self.added_admins = list(new_admins - old_admins)
- instance.admins[:] = list(validated_data.get('admins', instance.admins))
- # Add new admins that aren't members to the added_members list.
- extra = list(new_admins - new_members)
- self.added_members.extend(extra)
- instance.members.extend(extra)
- return instance
-
- def get_isAdmin(self, group):
- request = self.context['request']
- return request.airavata.sharing.gm_has_admin_access(
- group.id,
- request.user.username + "@" + settings.GATEWAY_ID)
-
- def get_isOwner(self, group):
- request = self.context['request']
- return group.owner_id == (request.user.username +
- "@" +
- settings.GATEWAY_ID)
-
- def get_isMember(self, group):
- request = self.context['request']
- username = request.user.username + "@" + settings.GATEWAY_ID
- return group.members and username in group.members
-
- def get_isGatewayAdminsGroup(self, group):
- return group.id == self._gateway_groups()['adminsGroupId']
-
- def get_isReadOnlyGatewayAdminsGroup(self, group):
- return group.id == self._gateway_groups()['readOnlyAdminsGroupId']
-
- def get_isDefaultGatewayUsersGroup(self, group):
- return group.id == self._gateway_groups()['defaultGatewayUsersGroupId']
-
- def _gateway_groups(self):
- request = self.context['request']
- # gateway_groups_middleware sets this session variable
- if 'GATEWAY_GROUPS' in request.session:
- return request.session['GATEWAY_GROUPS']
- else:
- gg = request.airavata.compute.get_gateway_groups()
- return {
- 'adminsGroupId': gg.admins_group_id,
- 'readOnlyAdminsGroupId': gg.read_only_admins_group_id,
- 'defaultGatewayUsersGroupId': gg.default_gateway_users_group_id,
- }
-
-
-class ProjectSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``Project`` message.
-
- Reads protobuf fields directly (``project_id``, ``creation_time``, ...) and
- emits the historical Thrift-named JSON keys (``projectID``, ``creationTime``,
- ...) so the REST contract with the Vue frontend is unchanged. ``save()``
- returns a proto ``Project`` the view passes straight to the gRPC facade.
- """
-
- projectID = serializers.CharField(source='project_id', read_only=True)
- owner = serializers.CharField(read_only=True)
- gatewayId = serializers.CharField(source='gateway_id', read_only=True)
- name = serializers.CharField()
- description = serializers.CharField(
- allow_blank=True, allow_null=True, required=False)
- creationTime = ProtoTimestampField(
- source='creation_time', null_if_zero=True, read_only=True)
- sharedUsers = serializers.ListField(
- source='shared_users', child=serializers.CharField(),
- read_only=True)
- sharedGroups = serializers.ListField(
- source='shared_groups', child=serializers.CharField(),
- read_only=True)
- url = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:project-detail',
- lookup_field='project_id',
- lookup_url_kwarg='project_id')
- experiments = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:project-experiments',
- lookup_field='project_id',
- lookup_url_kwarg='project_id')
- userHasWriteAccess = serializers.SerializerMethodField()
- isOwner = serializers.SerializerMethodField()
-
- def create(self, validated_data):
- from airavata_sdk.generated.org.apache.airavata.model.workspace import (
- workspace_pb2,
- )
- return workspace_pb2.Project(
- owner=validated_data.get('owner', '') or '',
- gateway_id=validated_data.get('gateway_id', '') or '',
- name=validated_data.get('name', '') or '',
- description=validated_data.get('description', '') or '',
- )
-
- def update(self, instance, validated_data):
- if 'name' in validated_data:
- instance.name = validated_data['name'] or ''
- if 'description' in validated_data:
- instance.description = validated_data['description'] or ''
- return instance
-
- def get_userHasWriteAccess(self, project):
- return user_has_access(self.context['request'], project.project_id)
-
- def get_isOwner(self, project):
- request = self.context['request']
- return project.owner == request.user.username
-
-
-class ApplicationModuleSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``ApplicationModule`` message.
-
- Reads the protobuf directly and emits the historical Thrift-named JSON keys.
- ``save()`` returns a proto ``ApplicationModule`` the view passes to the facade.
- """
-
- appModuleId = serializers.CharField(source='app_module_id', read_only=True)
- appModuleName = serializers.CharField(source='app_module_name')
- appModuleVersion = serializers.CharField(
- source='app_module_version', allow_blank=True, allow_null=True,
- required=False)
- appModuleDescription = serializers.CharField(
- source='app_module_description', allow_blank=True, allow_null=True,
- required=False)
- url = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:application-detail',
- lookup_field='app_module_id',
- lookup_url_kwarg='app_module_id')
- applicationInterface = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:application-application-interface',
- lookup_field='app_module_id',
- lookup_url_kwarg='app_module_id')
- applicationDeployments = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:application-application-deployments',
- lookup_field='app_module_id',
- lookup_url_kwarg='app_module_id')
- userHasWriteAccess = serializers.SerializerMethodField()
-
- def create(self, validated_data):
- from airavata_sdk.generated.org.apache.airavata.model.appcatalog.appdeployment import ( # noqa: E501
- app_deployment_pb2,
- )
- return app_deployment_pb2.ApplicationModule(
- app_module_name=validated_data.get('app_module_name', '') or '',
- app_module_version=validated_data.get('app_module_version', '') or '',
- app_module_description=validated_data.get(
- 'app_module_description', '') or '',
- )
-
- def update(self, instance, validated_data):
- if 'app_module_name' in validated_data:
- instance.app_module_name = validated_data['app_module_name'] or ''
- if 'app_module_version' in validated_data:
- instance.app_module_version = (
- validated_data['app_module_version'] or '')
- if 'app_module_description' in validated_data:
- instance.app_module_description = (
- validated_data['app_module_description'] or '')
- return instance
-
- def get_userHasWriteAccess(self, appModule):
- request = self.context['request']
- return request.is_gateway_admin
-
-
-class EnumChoiceField(serializers.ChoiceField):
- def __init__(self, enum_class, **kwargs):
- self.enum_class = enum_class
- kwargs['choices'] = [(member.name, member.name) for member in enum_class]
- super().__init__(**kwargs)
-
- def to_internal_value(self, data):
- if isinstance(data, int):
- try:
- return self.enum_class(data)
- except ValueError:
- self.fail('invalid_choice', input=data)
- try:
- return self.enum_class[data]
- except KeyError:
- self.fail('invalid_choice', input=data)
-
- def to_representation(self, value):
- return value.name
-
-
-def _application_io_pb2():
- from airavata_sdk.generated.org.apache.airavata.model.application.io import (
- application_io_pb2,
- )
- return application_io_pb2
-
-
-def _app_interface_pb2():
- from airavata_sdk.generated.org.apache.airavata.model.appcatalog.appinterface import ( # noqa: E501
- app_interface_pb2,
- )
- return app_interface_pb2
-
-
-def _data_type_field(**kwargs):
- # DataType renders as the member NAME (proto STRING/INTEGER/... == Thrift names;
- # proto prefixes only the zero DATA_TYPE_UNKNOWN sentinel).
- return proto_enum_name_field(
- _application_io_pb2().DataType.DESCRIPTOR,
- proto_prefix='DATA_TYPE_', **kwargs)
-
-
-def _proto_input_data_object(d):
- io = _application_io_pb2()
- return io.InputDataObjectType(
- name=d.get('name', '') or '',
- value=d.get('value', '') or '',
- type=d.get('type', 0) or 0,
- application_argument=d.get('application_argument', '') or '',
- standard_input=bool(d.get('standard_input', False)),
- user_friendly_description=d.get('user_friendly_description', '') or '',
- meta_data=d.get('meta_data', '') or '',
- input_order=d.get('input_order', 0) or 0,
- is_required=bool(d.get('is_required', False)),
- required_to_added_to_command_line=bool(
- d.get('required_to_added_to_command_line', False)),
- data_staged=bool(d.get('data_staged', False)),
- storage_resource_id=d.get('storage_resource_id', '') or '',
- is_read_only=bool(d.get('is_read_only', False)),
- override_filename=d.get('override_filename', '') or '',
- )
-
-
-def _proto_output_data_object(d):
- io = _application_io_pb2()
- return io.OutputDataObjectType(
- name=d.get('name', '') or '',
- value=d.get('value', '') or '',
- type=d.get('type', 0) or 0,
- application_argument=d.get('application_argument', '') or '',
- is_required=bool(d.get('is_required', False)),
- required_to_added_to_command_line=bool(
- d.get('required_to_added_to_command_line', False)),
- data_movement=bool(d.get('data_movement', False)),
- location=d.get('location', '') or '',
- search_query=d.get('search_query', '') or '',
- output_streaming=bool(d.get('output_streaming', False)),
- storage_resource_id=d.get('storage_resource_id', '') or '',
- meta_data=d.get('meta_data', '') or '',
- )
-
-
-class InputDataObjectTypeSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``InputDataObjectType`` message."""
-
- name = serializers.CharField()
- value = serializers.CharField(allow_blank=True, allow_null=True, required=False)
- type = _data_type_field(required=False)
- applicationArgument = serializers.CharField(source='application_argument', allow_blank=True, allow_null=True, required=False)
- standardInput = serializers.BooleanField(source='standard_input', default=False)
- userFriendlyDescription = serializers.CharField(source='user_friendly_description', allow_blank=True, allow_null=True, required=False)
- metaData = ProtoStoredJSONField(source='meta_data', allow_null=True, required=False)
- inputOrder = serializers.IntegerField(source='input_order', required=False, allow_null=True)
- isRequired = serializers.BooleanField(source='is_required', default=False)
- requiredToAddedToCommandLine = serializers.BooleanField(source='required_to_added_to_command_line', default=False)
- dataStaged = serializers.BooleanField(source='data_staged', default=False)
- storageResourceId = serializers.CharField(source='storage_resource_id', allow_blank=True, allow_null=True, required=False)
- isReadOnly = serializers.BooleanField(source='is_read_only', default=False)
- overrideFilename = serializers.CharField(source='override_filename', allow_blank=True, allow_null=True, required=False)
-
- def create(self, validated_data):
- return _proto_input_data_object(validated_data)
-
-
-class OutputDataObjectTypeSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``OutputDataObjectType`` message."""
-
- name = serializers.CharField()
- value = serializers.CharField(allow_blank=True, allow_null=True, required=False)
- type = _data_type_field(required=False)
- applicationArgument = serializers.CharField(source='application_argument', allow_blank=True, allow_null=True, required=False)
- isRequired = serializers.BooleanField(source='is_required', default=False)
- requiredToAddedToCommandLine = serializers.BooleanField(source='required_to_added_to_command_line', default=False)
- dataMovement = serializers.BooleanField(source='data_movement', default=False)
- location = serializers.CharField(allow_blank=True, allow_null=True, required=False)
- searchQuery = serializers.CharField(source='search_query', allow_blank=True, allow_null=True, required=False)
- outputStreaming = serializers.BooleanField(source='output_streaming', default=False)
- storageResourceId = serializers.CharField(source='storage_resource_id', allow_blank=True, allow_null=True, required=False)
- metaData = ProtoStoredJSONField(source='meta_data', allow_null=True, required=False)
-
- def create(self, validated_data):
- return _proto_output_data_object(validated_data)
-
-
-class ApplicationInterfaceDescriptionSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``ApplicationInterfaceDescription``."""
-
- applicationInterfaceId = serializers.CharField(source='application_interface_id', required=False, allow_null=True, allow_blank=True)
- applicationName = serializers.CharField(source='application_name')
- applicationDescription = serializers.CharField(source='application_description', allow_blank=True, allow_null=True, required=False)
- applicationModules = serializers.ListField(source='application_modules', child=serializers.CharField(), allow_null=True, required=False)
- applicationInputs = InputDataObjectTypeSerializer(source='application_inputs', many=True, allow_null=True, required=False)
- applicationOutputs = OutputDataObjectTypeSerializer(source='application_outputs', many=True, allow_null=True, required=False)
- archiveWorkingDirectory = serializers.BooleanField(source='archive_working_directory', default=False)
- hasOptionalFileInputs = serializers.BooleanField(source='has_optional_file_inputs', default=False, read_only=True)
-
- url = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:application-interface-detail',
- lookup_field='application_interface_id',
- lookup_url_kwarg='app_interface_id', read_only=True)
- userHasWriteAccess = serializers.SerializerMethodField()
- showQueueSettings = serializers.BooleanField(required=False)
- queueSettingsCalculatorId = serializers.CharField(allow_null=True, required=False)
-
- def create(self, validated_data):
- io = _application_io_pb2() # noqa: F841 (imported for side-effect symmetry)
- inputs_data = validated_data.pop('application_inputs', None)
- outputs_data = validated_data.pop('application_outputs', None)
- # Remove Django-specific (non-proto) fields.
- validated_data.pop('showQueueSettings', None)
- validated_data.pop('queueSettingsCalculatorId', None)
- ai = _app_interface_pb2()
- application_interface = ai.ApplicationInterfaceDescription(
- application_interface_id=validated_data.get(
- 'application_interface_id', '') or '',
- application_name=validated_data.get('application_name', '') or '',
- application_description=validated_data.get(
- 'application_description', '') or '',
- application_modules=list(
- validated_data.get('application_modules', []) or []),
- archive_working_directory=bool(
- validated_data.get('archive_working_directory', False)),
- )
- if inputs_data is not None:
- application_interface.application_inputs.extend(
- _proto_input_data_object(inp) for inp in inputs_data)
- if outputs_data is not None:
- application_interface.application_outputs.extend(
- _proto_output_data_object(out) for out in outputs_data)
- return application_interface
-
- def update(self, instance, validated_data):
- defaults = {}
- if "showQueueSettings" in validated_data:
- defaults["show_queue_settings"] = validated_data.pop("showQueueSettings")
- if "queueSettingsCalculatorId" in validated_data:
- defaults["queue_settings_calculator_id"] = validated_data.pop("queueSettingsCalculatorId")
- application_module_id = instance.application_modules[0]
- if defaults:
- models.ApplicationSettings.objects.update_or_create(
- application_module_id=application_module_id, defaults=defaults
- )
-
- inputs_data = validated_data.pop('application_inputs', None)
- outputs_data = validated_data.pop('application_outputs', None)
-
- for proto_field in ('application_interface_id', 'application_name',
- 'application_description', 'archive_working_directory'):
- if proto_field in validated_data:
- value = validated_data[proto_field]
- if proto_field == 'archive_working_directory':
- value = bool(value)
- else:
- value = value or ''
- setattr(instance, proto_field, value)
- if 'application_modules' in validated_data:
- instance.application_modules[:] = list(
- validated_data['application_modules'] or [])
-
- if inputs_data is not None:
- del instance.application_inputs[:]
- instance.application_inputs.extend(
- _proto_input_data_object(inp) for inp in inputs_data)
- if outputs_data is not None:
- del instance.application_outputs[:]
- instance.application_outputs.extend(
- _proto_output_data_object(out) for out in outputs_data)
-
- return instance
-
- def get_userHasWriteAccess(self, appInterface):
- request = self.context['request']
- return request.is_gateway_admin
-
-
-def _app_deployment_pb2():
- from airavata_sdk.generated.org.apache.airavata.model.appcatalog.appdeployment import ( # noqa: E501
- app_deployment_pb2,
- )
- return app_deployment_pb2
-
-
-def _parallelism_field(**kwargs):
- from airavata_sdk.generated.org.apache.airavata.model.parallelism import (
- parallelism_pb2,
- )
- return proto_enum_int_field(
- parallelism_pb2.ApplicationParallelismType.DESCRIPTOR,
- _THRIFT_ENUM_INTS['ApplicationParallelismType'],
- proto_prefix='APPLICATION_PARALLELISM_TYPE_', **kwargs)
-
-
-class CommandObjectSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``CommandObject`` message."""
-
- command = serializers.CharField(
- allow_blank=True, allow_null=True, required=False)
- commandOrder = serializers.IntegerField(
- source='command_order', allow_null=True, required=False)
-
- def create(self, validated_data):
- return _app_deployment_pb2().CommandObject(
- command=validated_data.get('command', '') or '',
- command_order=validated_data.get('command_order', 0) or 0,
- )
-
-
-class SetEnvPathsSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``SetEnvPaths`` message."""
-
- name = serializers.CharField(
- allow_blank=True, allow_null=True, required=False)
- value = serializers.CharField(
- allow_blank=True, allow_null=True, required=False)
- envPathOrder = serializers.IntegerField(
- source='env_path_order', allow_null=True, required=False)
-
- def create(self, validated_data):
- return _app_deployment_pb2().SetEnvPaths(
- name=validated_data.get('name', '') or '',
- value=validated_data.get('value', '') or '',
- env_path_order=validated_data.get('env_path_order', 0) or 0,
- )
-
-
-class ApplicationDeploymentDescriptionSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``ApplicationDeploymentDescription``."""
-
- appDeploymentId = serializers.CharField(
- source='app_deployment_id', allow_blank=True, allow_null=True,
- required=False)
- appModuleId = serializers.CharField(
- source='app_module_id', allow_blank=True, allow_null=True,
- required=False)
- computeHostId = serializers.CharField(
- source='compute_host_id', allow_blank=True, allow_null=True,
- required=False)
- executablePath = serializers.CharField(
- source='executable_path', allow_blank=True, allow_null=True,
- required=False)
- parallelism = _parallelism_field(required=False, allow_null=True)
- appDeploymentDescription = serializers.CharField(
- source='app_deployment_description', allow_blank=True, allow_null=True,
- required=False)
- moduleLoadCmds = OrderedListField(
- source='module_load_cmds', order_by='commandOrder',
- child=CommandObjectSerializer(), allow_null=True, required=False)
- libPrependPaths = OrderedListField(
- source='lib_prepend_paths', order_by='envPathOrder',
- child=SetEnvPathsSerializer(), allow_null=True, required=False)
- libAppendPaths = OrderedListField(
- source='lib_append_paths', order_by='envPathOrder',
- child=SetEnvPathsSerializer(), allow_null=True, required=False)
- setEnvironment = OrderedListField(
- source='set_environment', order_by='envPathOrder',
- child=SetEnvPathsSerializer(), allow_null=True, required=False)
- preJobCommands = OrderedListField(
- source='pre_job_commands', order_by='commandOrder',
- child=CommandObjectSerializer(), allow_null=True, required=False)
- postJobCommands = OrderedListField(
- source='post_job_commands', order_by='commandOrder',
- child=CommandObjectSerializer(), allow_null=True, required=False)
- defaultQueueName = serializers.CharField(
- source='default_queue_name', allow_blank=True, allow_null=True,
- required=False)
- defaultNodeCount = ProtoIntOrNoneField(source='default_node_count')
- defaultCPUCount = ProtoIntOrNoneField(source='default_cpu_count')
- defaultWalltime = ProtoIntOrNoneField(source='default_walltime')
- editableByUser = serializers.BooleanField(
- source='editable_by_user', required=False, default=False)
- url = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:application-deployment-detail',
- lookup_field='app_deployment_id',
- lookup_url_kwarg='app_deployment_id')
- queues = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:application-deployment-queues',
- lookup_field='app_deployment_id',
- lookup_url_kwarg='app_deployment_id')
- userHasWriteAccess = serializers.SerializerMethodField()
-
- def to_representation(self, instance):
- ret = super().to_representation(instance)
- # The proto string default '' must render as null for the optional
- # default-queue-name field (the old adapter mapped pb.<f> or None).
- if ret.get('defaultQueueName') == '':
- ret['defaultQueueName'] = None
- return ret
-
- def get_userHasWriteAccess(self, appDeployment):
- return user_has_access(
- self.context['request'], appDeployment.app_deployment_id)
-
- def create(self, validated_data):
- a = _app_deployment_pb2()
- return a.ApplicationDeploymentDescription(
- app_module_id=validated_data.get('app_module_id', '') or '',
- compute_host_id=validated_data.get('compute_host_id', '') or '',
- executable_path=validated_data.get('executable_path', '') or '',
- parallelism=validated_data.get('parallelism', 0) or 0,
- app_deployment_description=validated_data.get(
- 'app_deployment_description', '') or '',
- module_load_cmds=[
- CommandObjectSerializer().create(c)
- for c in validated_data.get('module_load_cmds', []) or []],
- lib_prepend_paths=[
- SetEnvPathsSerializer().create(p)
- for p in validated_data.get('lib_prepend_paths', []) or []],
- lib_append_paths=[
- SetEnvPathsSerializer().create(p)
- for p in validated_data.get('lib_append_paths', []) or []],
- set_environment=[
- SetEnvPathsSerializer().create(p)
- for p in validated_data.get('set_environment', []) or []],
- pre_job_commands=[
- CommandObjectSerializer().create(c)
- for c in validated_data.get('pre_job_commands', []) or []],
- post_job_commands=[
- CommandObjectSerializer().create(c)
- for c in validated_data.get('post_job_commands', []) or []],
- default_queue_name=validated_data.get('default_queue_name', '') or '',
- default_node_count=validated_data.get('default_node_count', 0) or 0,
- default_cpu_count=validated_data.get('default_cpu_count', 0) or 0,
- default_walltime=validated_data.get('default_walltime', 0) or 0,
- editable_by_user=bool(validated_data.get('editable_by_user', False)),
- )
-
- def update(self, instance, validated_data):
- return self.create(validated_data)
-
-
-class BatchQueueSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``BatchQueue`` message."""
-
- queueName = serializers.CharField(
- source='queue_name', allow_blank=True, allow_null=True, required=False)
- queueDescription = serializers.CharField(
- source='queue_description', allow_blank=True, allow_null=True,
- required=False)
- maxRunTime = serializers.IntegerField(
- source='max_run_time', allow_null=True, required=False)
- maxNodes = serializers.IntegerField(
- source='max_nodes', allow_null=True, required=False)
- maxProcessors = serializers.IntegerField(
- source='max_processors', allow_null=True, required=False)
- maxJobsInQueue = serializers.IntegerField(
- source='max_jobs_in_queue', allow_null=True, required=False)
- maxMemory = serializers.IntegerField(
- source='max_memory', allow_null=True, required=False)
- cpuPerNode = serializers.IntegerField(
- source='cpu_per_node', allow_null=True, required=False)
- defaultNodeCount = serializers.IntegerField(
- source='default_node_count', allow_null=True, required=False)
- defaultCPUCount = serializers.IntegerField(
- source='default_cpu_count', allow_null=True, required=False)
- defaultWalltime = serializers.IntegerField(
- source='default_walltime', allow_null=True, required=False)
- queueSpecificMacros = serializers.CharField(
- source='queue_specific_macros', allow_blank=True, allow_null=True,
- required=False)
- isDefaultQueue = serializers.BooleanField(
- source='is_default_queue', required=False, default=False)
-
-
-class JobSubmissionInterfaceSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``JobSubmissionInterface`` message."""
-
- jobSubmissionInterfaceId = serializers.CharField(
- source='job_submission_interface_id', allow_blank=True, allow_null=True,
- required=False)
- jobSubmissionProtocol = job_submission_protocol_field(
- source='job_submission_protocol', required=False, allow_null=True)
- priorityOrder = serializers.IntegerField(
- source='priority_order', allow_null=True, required=False)
-
-
-class DataMovementInterfaceSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``DataMovementInterface`` message."""
-
- dataMovementInterfaceId = serializers.CharField(
- source='data_movement_interface_id', allow_blank=True, allow_null=True,
- required=False)
- dataMovementProtocol = data_movement_protocol_field(
- source='data_movement_protocol', required=False, allow_null=True)
- priorityOrder = serializers.IntegerField(
- source='priority_order', allow_null=True, required=False)
- creationTime = ProtoIntOrNoneField(source='creation_time')
- updateTime = ProtoIntOrNoneField(source='update_time')
- storageResourceId = serializers.CharField(
- source='storage_resource_id', allow_blank=True, allow_null=True,
- required=False)
-
-
-class ComputeResourceDescriptionSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``ComputeResourceDescription`` message."""
-
- computeResourceId = serializers.CharField(
- source='compute_resource_id', allow_blank=True, allow_null=True,
- required=False)
- hostName = serializers.CharField(
- source='host_name', allow_blank=True, allow_null=True, required=False)
- hostAliases = serializers.ListField(
- source='host_aliases', child=serializers.CharField(), required=False)
- ipAddresses = serializers.ListField(
- source='ip_addresses', child=serializers.CharField(), required=False)
- resourceDescription = serializers.CharField(
- source='resource_description', allow_blank=True, allow_null=True,
- required=False)
- enabled = serializers.BooleanField(required=False, default=False)
- batchQueues = BatchQueueSerializer(
- source='batch_queues', many=True, required=False)
- fileSystems = ProtoFileSystemsMapField(source='file_systems', required=False)
- jobSubmissionInterfaces = JobSubmissionInterfaceSerializer(
- source='job_submission_interfaces', many=True, required=False)
- dataMovementInterfaces = DataMovementInterfaceSerializer(
- source='data_movement_interfaces', many=True, required=False)
- maxMemoryPerNode = serializers.IntegerField(
- source='max_memory_per_node', allow_null=True, required=False)
- gatewayUsageReporting = serializers.BooleanField(
- source='gateway_usage_reporting', required=False, default=False)
- gatewayUsageModuleLoadCommand = serializers.CharField(
- source='gateway_usage_module_load_command', allow_blank=True,
- allow_null=True, required=False)
- gatewayUsageExecutable = serializers.CharField(
- source='gateway_usage_executable', allow_blank=True, allow_null=True,
- required=False)
- cpusPerNode = serializers.IntegerField(
- source='cpus_per_node', allow_null=True, required=False)
- defaultNodeCount = serializers.IntegerField(
- source='default_node_count', allow_null=True, required=False)
- defaultCPUCount = serializers.IntegerField(
- source='default_cpu_count', allow_null=True, required=False)
- defaultWalltime = serializers.IntegerField(
- source='default_walltime', allow_null=True, required=False)
-
-
-# --- Per-protocol job-submission / data-movement interface details ----------
-# Admin-only detail views rendering a single protocol's submission/movement model.
-# SecurityProtocol/ResourceJobManagerType/ProviderName are prefix-aligned; MonitorMode
-# names diverge (proto MONITOR_FORK/MONITOR_LOCAL -> Thrift FORK/LOCAL).
-_MONITOR_MODE_NAME_MAP = {'MONITOR_FORK': 'FORK', 'MONITOR_LOCAL': 'LOCAL'}
-
-
-def _security_protocol_field(**kwargs):
- from airavata_sdk.generated.org.apache.airavata.model.data.movement import (
- data_movement_pb2,
- )
- return proto_enum_int_field(
- data_movement_pb2.SecurityProtocol.DESCRIPTOR,
- _THRIFT_ENUM_INTS['SecurityProtocol'],
- proto_prefix='SECURITY_PROTOCOL_', **kwargs)
-
-
-def _resource_job_manager_type_field(**kwargs):
- from airavata_sdk.generated.org.apache.airavata.model.appcatalog.computeresource import ( # noqa: E501
- compute_resource_pb2,
- )
- return proto_enum_int_field(
- compute_resource_pb2.ResourceJobManagerType.DESCRIPTOR,
- _THRIFT_ENUM_INTS['ResourceJobManagerType'],
- proto_prefix='RESOURCE_JOB_MANAGER_TYPE_', **kwargs)
-
-
-def _provider_name_field(**kwargs):
- from airavata_sdk.generated.org.apache.airavata.model.appcatalog.computeresource import ( # noqa: E501
- compute_resource_pb2,
- )
- return proto_enum_int_field(
- compute_resource_pb2.ProviderName.DESCRIPTOR,
- _THRIFT_ENUM_INTS['ProviderName'],
- proto_prefix='PROVIDER_NAME_', **kwargs)
-
-
-def _monitor_mode_field(**kwargs):
- from airavata_sdk.generated.org.apache.airavata.model.appcatalog.computeresource import ( # noqa: E501
- compute_resource_pb2,
- )
- return proto_enum_int_field(
- compute_resource_pb2.MonitorMode.DESCRIPTOR,
- _THRIFT_ENUM_INTS['MonitorMode'],
- name_map=_MONITOR_MODE_NAME_MAP, **kwargs)
-
-
-class ResourceJobManagerSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``ResourceJobManager`` message."""
-
- resourceJobManagerId = serializers.CharField(
- source='resource_job_manager_id', allow_blank=True, allow_null=True,
- required=False)
- resourceJobManagerType = _resource_job_manager_type_field(
- source='resource_job_manager_type', required=False, allow_null=True)
- pushMonitoringEndpoint = serializers.CharField(
- source='push_monitoring_endpoint', allow_blank=True, allow_null=True,
- required=False)
- jobManagerBinPath = serializers.CharField(
- source='job_manager_bin_path', allow_blank=True, allow_null=True,
- required=False)
- jobManagerCommands = serializers.SerializerMethodField()
- parallelismPrefix = serializers.SerializerMethodField()
-
- def get_jobManagerCommands(self, pb):
- from airavata_sdk.generated.org.apache.airavata.model.appcatalog.computeresource import ( # noqa: E501
- compute_resource_pb2,
- )
- return proto_enum_keyed_map_field(
- compute_resource_pb2.JobManagerCommand.DESCRIPTOR,
- 'JobManagerCommand', _THRIFT_ENUM_INTS['JobManagerCommand'],
- ).to_representation(pb.job_manager_commands)
-
- def get_parallelismPrefix(self, pb):
- from airavata_sdk.generated.org.apache.airavata.model.parallelism import (
- parallelism_pb2,
- )
- return proto_enum_keyed_map_field(
- parallelism_pb2.ApplicationParallelismType.DESCRIPTOR,
- 'ApplicationParallelismType',
- _THRIFT_ENUM_INTS['ApplicationParallelismType'],
- ).to_representation(pb.parallelism_prefix)
-
-
-class LocalJobSubmissionSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``LOCALSubmission`` message."""
-
- jobSubmissionInterfaceId = serializers.CharField(
- source='job_submission_interface_id', allow_blank=True, allow_null=True,
- required=False)
- resourceJobManager = ResourceJobManagerSerializer(
- source='resource_job_manager', required=False)
- securityProtocol = _security_protocol_field(
- source='security_protocol', required=False, allow_null=True)
-
-
-class SshJobSubmissionSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``SSHJobSubmission`` message."""
-
- jobSubmissionInterfaceId = serializers.CharField(
- source='job_submission_interface_id', allow_blank=True, allow_null=True,
- required=False)
- securityProtocol = _security_protocol_field(
- source='security_protocol', required=False, allow_null=True)
- resourceJobManager = ResourceJobManagerSerializer(
- source='resource_job_manager', required=False)
- alternativeSSHHostName = serializers.CharField(
- source='alternative_ssh_host_name', allow_blank=True, allow_null=True,
- required=False)
- sshPort = ProtoIntOrNoneField(source='ssh_port')
- monitorMode = _monitor_mode_field(
- source='monitor_mode', required=False, allow_null=True)
- batchQueueEmailSenders = serializers.ListField(
- source='batch_queue_email_senders', child=serializers.CharField(),
- required=False)
-
-
-class CloudJobSubmissionSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``CloudJobSubmission`` message."""
-
- jobSubmissionInterfaceId = serializers.CharField(
- source='job_submission_interface_id', allow_blank=True, allow_null=True,
- required=False)
- securityProtocol = _security_protocol_field(
- source='security_protocol', required=False, allow_null=True)
- nodeId = serializers.CharField(
- source='node_id', allow_blank=True, allow_null=True, required=False)
- executableType = serializers.CharField(
- source='executable_type', allow_blank=True, allow_null=True,
- required=False)
- providerName = _provider_name_field(
- source='provider_name', required=False, allow_null=True)
- userAccountName = serializers.CharField(
- source='user_account_name', allow_blank=True, allow_null=True,
- required=False)
-
-
-class UnicoreJobSubmissionSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``UnicoreJobSubmission`` message."""
-
- jobSubmissionInterfaceId = serializers.CharField(
- source='job_submission_interface_id', allow_blank=True, allow_null=True,
- required=False)
- securityProtocol = _security_protocol_field(
- source='security_protocol', required=False, allow_null=True)
- unicoreEndPointURL = serializers.CharField(
- source='unicore_end_point_url', allow_blank=True, allow_null=True,
- required=False)
-
-
-class LocalDataMovementSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``LOCALDataMovement`` message."""
-
- dataMovementInterfaceId = serializers.CharField(
- source='data_movement_interface_id', allow_blank=True, allow_null=True,
- required=False)
-
-
-class ScpDataMovementSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``SCPDataMovement`` message."""
-
- dataMovementInterfaceId = serializers.CharField(
- source='data_movement_interface_id', allow_blank=True, allow_null=True,
- required=False)
- securityProtocol = _security_protocol_field(
- source='security_protocol', required=False, allow_null=True)
- alternativeSCPHostName = serializers.CharField(
- source='alternative_scp_host_name', allow_blank=True, allow_null=True,
- required=False)
- sshPort = ProtoIntOrNoneField(source='ssh_port')
-
-
-class GridFtpDataMovementSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``GridFTPDataMovement`` message."""
-
- dataMovementInterfaceId = serializers.CharField(
- source='data_movement_interface_id', allow_blank=True, allow_null=True,
- required=False)
- securityProtocol = _security_protocol_field(
- source='security_protocol', required=False, allow_null=True)
- gridFTPEndPoints = serializers.ListField(
- source='grid_ftp_end_points', child=serializers.CharField(),
- required=False)
-
-
-def _status_pb2():
- from airavata_sdk.generated.org.apache.airavata.model.status import status_pb2
- return status_pb2
-
-
-def _experiment_state_field(**kwargs):
- return proto_enum_int_field(
- _status_pb2().ExperimentState.DESCRIPTOR,
- _THRIFT_ENUM_INTS['ExperimentState'],
- proto_prefix='EXPERIMENT_STATE_', **kwargs)
-
-
-def _process_state_field(**kwargs):
- return proto_enum_int_field(
- _status_pb2().ProcessState.DESCRIPTOR,
- _THRIFT_ENUM_INTS['ProcessState'],
- proto_prefix='PROCESS_STATE_', **kwargs)
-
-
-def _task_state_field(**kwargs):
- return proto_enum_int_field(
- _status_pb2().TaskState.DESCRIPTOR, _THRIFT_ENUM_INTS['TaskState'],
- proto_prefix='TASK_STATE_', **kwargs)
-
-
-def _job_state_field(**kwargs):
- return proto_enum_int_field(
- _status_pb2().JobState.DESCRIPTOR, _THRIFT_ENUM_INTS['JobState'],
- proto_prefix='JOB_STATE_', **kwargs)
-
-
-class ExperimentStatusSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``ExperimentStatus`` message."""
-
- state = _experiment_state_field(required=False, allow_null=True)
- timeOfStateChange = UTCPosixTimestampDateTimeField(source='time_of_state_change')
- reason = serializers.CharField(allow_blank=True, allow_null=True, required=False)
- statusId = serializers.CharField(source='status_id', allow_blank=True, allow_null=True, required=False)
-
-
-class ProcessStatusSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``ProcessStatus`` message."""
-
- state = _process_state_field(required=False, allow_null=True)
- timeOfStateChange = UTCPosixTimestampDateTimeField(source='time_of_state_change')
- reason = serializers.CharField(allow_blank=True, allow_null=True, required=False)
- statusId = serializers.CharField(source='status_id', allow_blank=True, allow_null=True, required=False)
- processId = serializers.CharField(source='process_id', allow_blank=True, allow_null=True, required=False)
-
-
-class _NestedProcessStatusSerializer(serializers.Serializer):
- """``ProcessStatus`` nested in the experiment tree (timeOfStateChange is the
- raw epoch-millis int, matching the old auto-generated field)."""
-
- state = _process_state_field(required=False, allow_null=True)
- timeOfStateChange = serializers.IntegerField(source='time_of_state_change', allow_null=True, required=False)
- reason = serializers.CharField(allow_blank=True, allow_null=True, required=False)
- statusId = serializers.CharField(source='status_id', allow_blank=True, allow_null=True, required=False)
- processId = serializers.CharField(source='process_id', allow_blank=True, allow_null=True, required=False)
-
-
-class _TaskStatusSerializer(serializers.Serializer):
- state = _task_state_field(required=False, allow_null=True)
- timeOfStateChange = serializers.IntegerField(source='time_of_state_change', allow_null=True, required=False)
- reason = serializers.CharField(allow_blank=True, allow_null=True, required=False)
- statusId = serializers.CharField(source='status_id', allow_blank=True, allow_null=True, required=False)
-
-
-class _JobStatusSerializer(serializers.Serializer):
- jobState = _job_state_field(source='job_state', required=False, allow_null=True)
- timeOfStateChange = serializers.IntegerField(source='time_of_state_change', allow_null=True, required=False)
- reason = serializers.CharField(allow_blank=True, allow_null=True, required=False)
- statusId = serializers.CharField(source='status_id', allow_blank=True, allow_null=True, required=False)
-
-
-class _ErrorModelSerializer(serializers.Serializer):
- errorId = serializers.CharField(source='error_id', allow_blank=True, allow_null=True, required=False)
- creationTime = ProtoIntOrNoneField(source='creation_time')
- actualErrorMessage = serializers.CharField(source='actual_error_message', allow_blank=True, allow_null=True, required=False)
- userFriendlyMessage = serializers.CharField(source='user_friendly_message', allow_blank=True, allow_null=True, required=False)
- transientOrPersistent = serializers.BooleanField(source='transient_or_persistent', required=False, default=False)
- rootCauseErrorIdList = serializers.ListField(source='root_cause_error_id_list', child=serializers.CharField(), required=False)
-
-
-class _ComputationalResourceSchedulingSerializer(serializers.Serializer):
- resourceHostId = serializers.CharField(source='resource_host_id', allow_blank=True, allow_null=True, required=False)
- totalCPUCount = serializers.IntegerField(source='total_cpu_count', allow_null=True, required=False)
- nodeCount = serializers.IntegerField(source='node_count', allow_null=True, required=False)
- numberOfThreads = serializers.IntegerField(source='number_of_threads', allow_null=True, required=False)
- queueName = serializers.CharField(source='queue_name', allow_blank=True, allow_null=True, required=False)
- wallTimeLimit = serializers.IntegerField(source='wall_time_limit', allow_null=True, required=False)
- totalPhysicalMemory = serializers.IntegerField(source='total_physical_memory', allow_null=True, required=False)
- chessisNumber = serializers.CharField(source='chessis_number', allow_blank=True, allow_null=True, required=False)
- staticWorkingDir = serializers.CharField(source='static_working_dir', allow_blank=True, allow_null=True, required=False)
- overrideLoginUserName = serializers.CharField(source='override_login_user_name', allow_blank=True, allow_null=True, required=False)
- overrideScratchLocation = serializers.CharField(source='override_scratch_location', allow_blank=True, allow_null=True, required=False)
- overrideAllocationProjectNumber = serializers.CharField(source='override_allocation_project_number', allow_blank=True, allow_null=True, required=False)
- mGroupCount = serializers.IntegerField(source='m_group_count', allow_null=True, required=False)
-
- def create(self, validated_data):
- from airavata_sdk.generated.org.apache.airavata.model.scheduling import (
- scheduling_pb2,
- )
- d = validated_data
- return scheduling_pb2.ComputationalResourceSchedulingModel(
- resource_host_id=d.get('resource_host_id', '') or '',
- total_cpu_count=d.get('total_cpu_count', 0) or 0,
- node_count=d.get('node_count', 0) or 0,
- number_of_threads=d.get('number_of_threads', 0) or 0,
- queue_name=d.get('queue_name', '') or '',
- wall_time_limit=d.get('wall_time_limit', 0) or 0,
- total_physical_memory=d.get('total_physical_memory', 0) or 0,
- chessis_number=d.get('chessis_number', '') or '',
- static_working_dir=d.get('static_working_dir', '') or '',
- override_login_user_name=d.get('override_login_user_name', '') or '',
- override_scratch_location=d.get('override_scratch_location', '') or '',
- override_allocation_project_number=d.get('override_allocation_project_number', '') or '',
- m_group_count=d.get('m_group_count', 0) or 0,
- )
-
-
-class _UserConfigurationDataSerializer(serializers.Serializer):
- airavataAutoSchedule = serializers.BooleanField(source='airavata_auto_schedule', required=False, default=False)
- overrideManualScheduledParams = serializers.BooleanField(source='override_manual_scheduled_params', required=False, default=False)
- shareExperimentPublicly = serializers.BooleanField(source='share_experiment_publicly', required=False, default=False)
- computationalResourceScheduling = _ComputationalResourceSchedulingSerializer(
- source='computational_resource_scheduling', required=False)
- throttleResources = serializers.BooleanField(source='throttle_resources', required=False, default=False)
- userDN = serializers.CharField(source='user_dn', allow_blank=True, allow_null=True, required=False)
- generateCert = serializers.BooleanField(source='generate_cert', required=False, default=False)
- inputStorageResourceId = serializers.CharField(source='input_storage_resource_id', allow_blank=True, allow_null=True, required=False)
- outputStorageResourceId = serializers.CharField(source='output_storage_resource_id', allow_blank=True, allow_null=True, required=False)
- experimentDataDir = serializers.CharField(source='experiment_data_dir', allow_blank=True, allow_null=True, required=False)
- useUserCRPref = serializers.BooleanField(source='use_user_cr_pref', required=False, default=False)
- groupResourceProfileId = serializers.CharField(source='group_resource_profile_id', allow_blank=True, allow_null=True, required=False)
- autoScheduledCompResourceSchedulingList = _ComputationalResourceSchedulingSerializer(source='auto_scheduled_comp_resource_scheduling_list', many=True, required=False)
-
- def to_representation(self, ucd):
- ret = super().to_representation(ucd)
- # proto3 singular sub-message is always present; the old adapter rendered
- # computationalResourceScheduling only when HasField, else None.
- if not ucd.HasField('computational_resource_scheduling'):
- ret['computationalResourceScheduling'] = None
- return ret
-
-
-class JobSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``JobModel`` message."""
-
- jobId = serializers.CharField(source='job_id', allow_blank=True, allow_null=True, required=False)
- taskId = serializers.CharField(source='task_id', allow_blank=True, allow_null=True, required=False)
- processId = serializers.CharField(source='process_id', allow_blank=True, allow_null=True, required=False)
- jobDescription = serializers.CharField(source='job_description', allow_blank=True, allow_null=True, required=False)
- creationTime = ProtoTimestampField(source='creation_time', null_if_zero=True)
- jobStatuses = _JobStatusSerializer(source='job_statuses', many=True, required=False)
- computeResourceConsumed = serializers.CharField(source='compute_resource_consumed', allow_blank=True, allow_null=True, required=False)
- jobName = serializers.CharField(source='job_name', allow_blank=True, allow_null=True, required=False)
- workingDir = serializers.CharField(source='working_dir', allow_blank=True, allow_null=True, required=False)
- stdOut = serializers.CharField(source='std_out', allow_blank=True, allow_null=True, required=False)
- stdErr = serializers.CharField(source='std_err', allow_blank=True, allow_null=True, required=False)
- exitCode = serializers.IntegerField(source='exit_code', allow_null=True, required=False)
-
-
-class _NestedJobSerializer(JobSerializer):
- """``JobModel`` nested in the process tree: ``creationTime`` is the raw
- epoch-millis int (the old auto-generated field), unlike the standalone
- ``JobSerializer`` (jobs action) which renders ISO."""
-
- creationTime = ProtoIntOrNoneField(source='creation_time')
-
-
-class _TaskModelSerializer(serializers.Serializer):
- taskId = serializers.CharField(source='task_id', allow_blank=True, allow_null=True, required=False)
- taskType = serializers.SerializerMethodField()
- parentProcessId = serializers.CharField(source='parent_process_id', allow_blank=True, allow_null=True, required=False)
- creationTime = ProtoIntOrNoneField(source='creation_time')
- lastUpdateTime = ProtoIntOrNoneField(source='last_update_time')
- taskStatuses = _TaskStatusSerializer(source='task_statuses', many=True, required=False)
- taskDetail = serializers.CharField(source='task_detail', allow_blank=True, allow_null=True, required=False)
- subTaskModel = serializers.CharField(source='sub_task_model', allow_blank=True, allow_null=True, required=False)
- taskErrors = _ErrorModelSerializer(source='task_errors', many=True, required=False)
- jobs = _NestedJobSerializer(many=True, required=False)
- maxRetry = serializers.IntegerField(source='max_retry', allow_null=True, required=False)
- currentRetry = serializers.IntegerField(source='current_retry', allow_null=True, required=False)
-
- def get_taskType(self, task):
- from airavata_sdk.generated.org.apache.airavata.model.task import task_pb2
- field = proto_enum_int_field(
- task_pb2.TaskTypes.DESCRIPTOR, _THRIFT_ENUM_INTS['TaskTypes'],
- proto_prefix='TASK_TYPES_')
- return field.to_representation(task.task_type)
-
-
-class _ProcessModelSerializer(serializers.Serializer):
- processId = serializers.CharField(source='process_id', allow_blank=True, allow_null=True, required=False)
- experimentId = serializers.CharField(source='experiment_id', allow_blank=True, allow_null=True, required=False)
- creationTime = ProtoIntOrNoneField(source='creation_time')
- lastUpdateTime = ProtoIntOrNoneField(source='last_update_time')
- processStatuses = _NestedProcessStatusSerializer(source='process_statuses', many=True, required=False)
- processDetail = serializers.CharField(source='process_detail', allow_blank=True, allow_null=True, required=False)
- applicationInterfaceId = serializers.CharField(source='application_interface_id', allow_blank=True, allow_null=True, required=False)
- applicationDeploymentId = serializers.CharField(source='application_deployment_id', allow_blank=True, allow_null=True, required=False)
- computeResourceId = serializers.CharField(source='compute_resource_id', allow_blank=True, allow_null=True, required=False)
- processInputs = InputDataObjectTypeSerializer(source='process_inputs', many=True, required=False)
- processOutputs = OutputDataObjectTypeSerializer(source='process_outputs', many=True, required=False)
- processResourceSchedule = serializers.SerializerMethodField()
- tasks = _TaskModelSerializer(many=True, required=False)
- taskDag = serializers.CharField(source='task_dag', allow_blank=True, allow_null=True, required=False)
- processErrors = _ErrorModelSerializer(source='process_errors', many=True, required=False)
- gatewayExecutionId = serializers.CharField(source='gateway_execution_id', allow_blank=True, allow_null=True, required=False)
- enableEmailNotification = serializers.BooleanField(source='enable_email_notification', required=False, default=False)
- emailAddresses = serializers.ListField(source='email_addresses', child=serializers.CharField(), required=False)
- inputStorageResourceId = serializers.CharField(source='input_storage_resource_id', allow_blank=True, allow_null=True, required=False)
- outputStorageResourceId = serializers.CharField(source='output_storage_resource_id', allow_blank=True, allow_null=True, required=False)
- userDn = serializers.CharField(source='user_dn', allow_blank=True, allow_null=True, required=False)
- generateCert = serializers.BooleanField(source='generate_cert', required=False, default=False)
- experimentDataDir = serializers.CharField(source='experiment_data_dir', allow_blank=True, allow_null=True, required=False)
- userName = serializers.CharField(source='user_name', allow_blank=True, allow_null=True, required=False)
- useUserCRPref = serializers.BooleanField(source='use_user_cr_pref', required=False, default=False)
- groupResourceProfileId = serializers.CharField(source='group_resource_profile_id', allow_blank=True, allow_null=True, required=False)
- processWorkflows = serializers.SerializerMethodField()
-
- def get_processResourceSchedule(self, proc):
- if not proc.HasField('process_resource_schedule'):
- return None
- return _ComputationalResourceSchedulingSerializer(
- proc.process_resource_schedule, context=self.context).data
-
- def get_processWorkflows(self, proc):
- # The legacy workflow-engine subsystem is not adapted (rarely populated);
- # an empty list matches the Thrift default for non-workflow processes.
- return []
-
-
-def _experiment_type_field(**kwargs):
- from airavata_sdk.generated.org.apache.airavata.model.experiment import (
- experiment_pb2,
- )
- return proto_enum_int_field(
- experiment_pb2.ExperimentType.DESCRIPTOR,
- _THRIFT_ENUM_INTS['ExperimentType'],
- proto_prefix='EXPERIMENT_TYPE_', **kwargs)
-
-
-def _experiment_pb2():
- from airavata_sdk.generated.org.apache.airavata.model.experiment import (
- experiment_pb2,
- )
- return experiment_pb2
-
-
-class ExperimentSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``ExperimentModel`` message.
-
- The deepest read model: the processes -> tasks -> jobs tree (each with its
- status list), user configuration + scheduling, inputs/outputs, status, and
- errors. ``save()`` returns a proto ``ExperimentModel`` for the facade.
- """
-
- experimentId = serializers.CharField(source='experiment_id', read_only=True)
- projectId = serializers.CharField(source='project_id')
- gatewayId = serializers.CharField(source='gateway_id', read_only=True)
- experimentType = _experiment_type_field(source='experiment_type', required=False, allow_null=True)
- userName = serializers.CharField(source='user_name', read_only=True)
- experimentName = serializers.CharField(source='experiment_name')
- creationTime = ProtoTimestampField(source='creation_time', null_if_zero=True, read_only=True)
- description = serializers.CharField(allow_blank=True, allow_null=True, required=False)
- executionId = serializers.CharField(source='execution_id', allow_blank=True, allow_null=True, required=False)
- gatewayExecutionId = serializers.CharField(source='gateway_execution_id', allow_blank=True, allow_null=True, required=False)
- gatewayInstanceId = serializers.CharField(source='gateway_instance_id', allow_blank=True, allow_null=True, required=False)
- enableEmailNotification = serializers.BooleanField(source='enable_email_notification', required=False, default=False)
- emailAddresses = serializers.ListField(source='email_addresses', child=serializers.CharField(), required=False)
- userConfigurationData = _UserConfigurationDataSerializer(
- source='user_configuration_data', required=False)
- experimentInputs = OrderedListField(
- source='experiment_inputs', order_by='inputOrder',
- child=InputDataObjectTypeSerializer(), required=False)
- experimentOutputs = OutputDataObjectTypeSerializer(
- source='experiment_outputs', many=True, required=False)
- experimentStatus = ExperimentStatusSerializer(
- source='experiment_status', many=True, required=False)
- errors = _ErrorModelSerializer(many=True, required=False)
- processes = _ProcessModelSerializer(many=True, required=False)
- workflow = serializers.SerializerMethodField()
- url = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:experiment-detail',
- lookup_field='experiment_id', lookup_url_kwarg='experiment_id')
- full_experiment = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:full-experiment-detail',
- lookup_field='experiment_id', lookup_url_kwarg='experiment_id')
- project = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:project-detail',
- lookup_field='project_id', lookup_url_kwarg='project_id')
- jobs = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:experiment-jobs',
- lookup_field='experiment_id', lookup_url_kwarg='experiment_id')
- shared_entity = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:shared-entity-detail',
- lookup_field='experiment_id', lookup_url_kwarg='entity_id')
- userHasWriteAccess = serializers.SerializerMethodField()
-
- def get_workflow(self, experiment):
- # The legacy workflow-engine subsystem is not adapted (rarely populated).
- return None
-
- def get_userHasWriteAccess(self, experiment):
- return user_has_access(self.context['request'], experiment.experiment_id)
-
- def to_representation(self, experiment):
- result = super().to_representation(experiment)
- # proto3 singular sub-message is always present; the old adapter rendered
- # userConfigurationData only when HasField, else None.
- if not experiment.HasField('user_configuration_data'):
- result['userConfigurationData'] = None
- self._add_intermediate_output_information(experiment, result)
- return result
-
- def create(self, validated_data):
- return _experiment_request(validated_data)
-
- def update(self, instance, validated_data):
- return _experiment_request(validated_data)
-
- def _add_intermediate_output_information(self, experiment, representation):
- request = self.context['request']
- from airavata_sdk.generated.org.apache.airavata.model.status import (
- status_pb2,
- )
- # If experiment is EXECUTING, add intermediateOutput information to
- # experiment outputs.
- if (experiment.experiment_status and
- experiment.experiment_status[-1].state ==
- status_pb2.ExperimentState.EXPERIMENT_STATE_EXECUTING):
- for output in representation["experimentOutputs"]:
- output["intermediateOutput"] = {"processStatus": None}
- try:
- can_fetch = experiment_orchestration.can_fetch_intermediate_output(request.airavata, experiment, output["name"])
- output["intermediateOutput"]["canFetch"] = can_fetch
- process_status = experiment_orchestration.get_intermediate_output_process_status(
- request.airavata, experiment, output["name"])
- if process_status:
- serializer = ProcessStatusSerializer(
- process_status, context={'request': request})
- output["intermediateOutput"]["processStatus"] = serializer.data
- data_products = experiment_orchestration.get_intermediate_output_data_products(
- request.airavata, experiment, output["name"])
- data_product_serializer = DataProductSerializer(
- data_products, context={'request': request}, many=True)
- output["intermediateOutput"]["dataProducts"] = data_product_serializer.data
- except Exception:
- log.debug("Failed to get intermediate output status", exc_info=True)
-
-
-def _experiment_request(validated_data):
- """Build a proto ``ExperimentModel`` from validated write data.
-
- Only the user-submittable fields are carried; status / errors / processes /
- workflow are server-managed (the old write adapter dropped them too).
- """
- e = _experiment_pb2()
- d = validated_data
- ucd = d.get('user_configuration_data')
- kwargs = dict(
- experiment_id=d.get('experiment_id', '') or '',
- project_id=d.get('project_id', '') or '',
- gateway_id=d.get('gateway_id', '') or '',
- experiment_type=d.get('experiment_type', 0) or 0,
- user_name=d.get('user_name', '') or '',
- experiment_name=d.get('experiment_name', '') or '',
- description=d.get('description', '') or '',
- execution_id=d.get('execution_id', '') or '',
- enable_email_notification=bool(d.get('enable_email_notification', False)),
- email_addresses=list(d.get('email_addresses', []) or []),
- experiment_inputs=[
- _proto_input_data_object(i)
- for i in d.get('experiment_inputs', []) or []],
- experiment_outputs=[
- _proto_output_data_object(o)
- for o in d.get('experiment_outputs', []) or []],
- )
- if ucd is not None:
- kwargs['user_configuration_data'] = _user_configuration_request(ucd)
- return e.ExperimentModel(**kwargs)
-
-
-def _user_configuration_request(d):
- e = _experiment_pb2()
- crs = d.get('computational_resource_scheduling')
- kwargs = dict(
- airavata_auto_schedule=bool(d.get('airavata_auto_schedule', False)),
- override_manual_scheduled_params=bool(d.get('override_manual_scheduled_params', False)),
- share_experiment_publicly=bool(d.get('share_experiment_publicly', False)),
- throttle_resources=bool(d.get('throttle_resources', False)),
- user_dn=d.get('user_dn', '') or '',
- generate_cert=bool(d.get('generate_cert', False)),
- input_storage_resource_id=d.get('input_storage_resource_id', '') or '',
- output_storage_resource_id=d.get('output_storage_resource_id', '') or '',
- experiment_data_dir=d.get('experiment_data_dir', '') or '',
- use_user_cr_pref=bool(d.get('use_user_cr_pref', False)),
- group_resource_profile_id=d.get('group_resource_profile_id', '') or '',
- )
- if crs is not None:
- kwargs['computational_resource_scheduling'] = (
- _ComputationalResourceSchedulingSerializer().create(crs))
- return e.UserConfigurationDataModel(**kwargs)
-
-
-def _replica_catalog_pb2():
- from airavata_sdk.generated.org.apache.airavata.model.data.replica import (
- replica_catalog_pb2,
- )
- return replica_catalog_pb2
-
-
-def _data_product_type_field(**kwargs):
- return proto_enum_int_field(
- _replica_catalog_pb2().DataProductType.DESCRIPTOR,
- _THRIFT_ENUM_INTS['DataProductType'],
- proto_prefix='DATA_PRODUCT_TYPE_', **kwargs)
-
-
-def _replica_location_category_field(**kwargs):
- return proto_enum_int_field(
- _replica_catalog_pb2().ReplicaLocationCategory.DESCRIPTOR,
- _THRIFT_ENUM_INTS['ReplicaLocationCategory'],
- proto_prefix='REPLICA_LOCATION_CATEGORY_', **kwargs)
-
-
-def _replica_persistent_type_field(**kwargs):
- return proto_enum_int_field(
- _replica_catalog_pb2().ReplicaPersistentType.DESCRIPTOR,
- _THRIFT_ENUM_INTS['ReplicaPersistentType'],
- proto_prefix='REPLICA_PERSISTENT_TYPE_', **kwargs)
-
-
-class DataReplicaLocationSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``DataReplicaLocationModel``."""
-
- replicaId = serializers.CharField(source='replica_id', allow_blank=True, allow_null=True, required=False)
- productUri = serializers.CharField(source='product_uri', allow_blank=True, allow_null=True, required=False)
- replicaName = serializers.CharField(source='replica_name', allow_blank=True, allow_null=True, required=False)
- replicaDescription = serializers.CharField(source='replica_description', allow_blank=True, allow_null=True, required=False)
- creationTime = ProtoTimestampField(source='creation_time', null_if_zero=True)
- lastModifiedTime = ProtoTimestampField(source='last_modified_time', null_if_zero=True)
- validUntilTime = ProtoIntOrNoneField(source='valid_until_time')
- replicaLocationCategory = _replica_location_category_field(source='replica_location_category', required=False, allow_null=True)
- replicaPersistentType = _replica_persistent_type_field(source='replica_persistent_type', required=False, allow_null=True)
- storageResourceId = serializers.CharField(source='storage_resource_id', allow_blank=True, allow_null=True, required=False)
- filePath = serializers.CharField(source='file_path', allow_blank=True, allow_null=True, required=False)
- replicaMetadata = serializers.DictField(source='replica_metadata', required=False)
-
- def to_representation(self, instance):
- ret = super().to_representation(instance)
- # The old adapter mapped these optional proto strings to None when empty.
- for f in ('replicaId', 'productUri', 'replicaName', 'replicaDescription',
- 'storageResourceId', 'filePath'):
- if ret.get(f) == '':
- ret[f] = None
- return ret
-
-
-class DataProductSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``DataProductModel``."""
-
- productUri = serializers.CharField(source='product_uri', allow_blank=True, allow_null=True, required=False)
- gatewayId = serializers.CharField(source='gateway_id', allow_blank=True, allow_null=True, required=False)
- parentProductUri = serializers.CharField(source='parent_product_uri', allow_blank=True, allow_null=True, required=False)
- productName = serializers.CharField(source='product_name', allow_blank=True, allow_null=True, required=False)
- productDescription = serializers.CharField(source='product_description', allow_blank=True, allow_null=True, required=False)
- ownerName = serializers.CharField(source='owner_name', allow_blank=True, allow_null=True, required=False)
- dataProductType = _data_product_type_field(source='data_product_type', required=False, allow_null=True)
- productSize = ProtoIntOrNoneField(source='product_size')
- creationTime = ProtoTimestampField(source='creation_time', null_if_zero=True)
- # The serializer declares both modifiedTime and lastModifiedTime; both map to
- # the proto last_modified_time.
- modifiedTime = ProtoTimestampField(source='last_modified_time', null_if_zero=True)
- lastModifiedTime = ProtoTimestampField(source='last_modified_time', null_if_zero=True)
- productMetadata = serializers.DictField(source='product_metadata', required=False)
- replicaLocations = DataReplicaLocationSerializer(source='replica_locations', many=True, required=False)
- downloadURL = serializers.SerializerMethodField()
- isInputFileUpload = serializers.SerializerMethodField()
- filesize = serializers.SerializerMethodField()
- userHasWriteAccess = serializers.SerializerMethodField()
-
- def to_representation(self, instance):
- ret = super().to_representation(instance)
- for f in ('parentProductUri', 'productName', 'productDescription',
- 'ownerName'):
- if ret.get(f) == '':
- ret[f] = None
- return ret
-
- def get_downloadURL(self, data_product):
- """Lazy portal URL to the byte-streaming download endpoint.
-
- Returns None when the data product has no replica. Resolving the bytes
- is deferred to the endpoint, so this getter makes no backend call.
- """
- request = self.context['request']
- if not data_product.replica_locations:
- return None
- base = request.build_absolute_uri(
- reverse('django_airavata_api:download-file'))
- return base + '?data-product-uri=' + quote(data_product.product_uri)
-
- def get_isInputFileUpload(self, data_product):
- """Return True if this is an uploaded input file.
-
- Derived from the data product alone (no backend call): an uploaded
- input file lives directly under the input-staging directory
- (TMP_INPUT_FILE_UPLOAD_DIR == "tmp"), so the first replica's file path
- has that directory as its immediate parent.
- """
- replicas = data_product.replica_locations
- if not replicas or not replicas[0].file_path:
- return False
- parent = os.path.dirname(replicas[0].file_path)
- return os.path.basename(parent) == TMP_INPUT_FILE_UPLOAD_DIR
-
- def get_filesize(self, data_product):
- # product_size comes from the data product registry; no backend call.
- return data_product.product_size or 0
-
- def get_userHasWriteAccess(self, data_product):
- """Whether the requesting user may write this data product.
-
- Derived without a backend file-metadata call: the owner always has
- write access; in a shared directory only gateway admins do; otherwise
- (a user's own private storage) write is allowed.
- """
- request = self.context['request']
- owner = data_product.owner_name
- if owner and owner == request.user.username:
- return True
- replicas = data_product.replica_locations
- if replicas and replicas[0].file_path:
- if view_utils.is_shared_path(replicas[0].file_path):
- # Only admins can edit files in a shared directory.
- return request.is_gateway_admin
- return True
-
-
-# TODO move this into airavata_sdk?
-class FullExperiment:
- """Experiment with referenced data models."""
-
- def __init__(self, experimentModel, project=None, outputDataProducts=None,
- inputDataProducts=None, applicationModule=None,
- computeResource=None, jobDetails=None, outputViews=None):
- self.experiment = experimentModel
- self.experimentId = experimentModel.experiment_id
- self.project = project
- self.outputDataProducts = outputDataProducts
- self.inputDataProducts = inputDataProducts
- self.applicationModule = applicationModule
- self.computeResource = computeResource
- self.jobDetails = jobDetails
- self.outputViews = outputViews
-
-
-class FullExperimentSerializer(serializers.Serializer):
- url = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:full-experiment-detail',
- lookup_field='experimentId',
- lookup_url_kwarg='experiment_id')
- experiment = ExperimentSerializer()
- experimentId = serializers.CharField(read_only=True)
- outputDataProducts = DataProductSerializer(many=True, read_only=True)
- inputDataProducts = DataProductSerializer(many=True, read_only=True)
- applicationModule = ApplicationModuleSerializer(read_only=True)
- computeResource = ComputeResourceDescriptionSerializer(read_only=True)
- project = ProjectSerializer(read_only=True)
- jobDetails = JobSerializer(many=True, read_only=True)
- outputViews = serializers.DictField(read_only=True)
-
- def create(self, validated_data):
- raise Exception("Not implemented")
-
- def update(self, instance, validated_data):
- raise Exception("Not implemented")
-
-
-class BaseExperimentSummarySerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``ExperimentSummaryModel`` message.
-
- Read-only; used directly for the experiment-statistics summary lists (where
- the timestamps render as ISO strings — see :class:`ExperimentSummarySerializer`
- for the experiment-search variant's int rendering).
- """
-
- experimentId = serializers.CharField(source='experiment_id', read_only=True)
- projectId = serializers.CharField(source='project_id', read_only=True)
- gatewayId = serializers.CharField(source='gateway_id', read_only=True)
- creationTime = ProtoTimestampField(
- source='creation_time', null_if_zero=True, read_only=True)
- userName = serializers.CharField(source='user_name', read_only=True)
- name = serializers.CharField(read_only=True)
- description = serializers.CharField(read_only=True)
- executionId = serializers.CharField(source='execution_id', read_only=True)
- resourceHostId = serializers.CharField(
- source='resource_host_id', read_only=True)
- experimentStatus = serializers.CharField(
- source='experiment_status', read_only=True)
- statusUpdateTime = ProtoTimestampField(
- source='status_update_time', null_if_zero=True, read_only=True)
- url = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:experiment-detail',
- lookup_field='experiment_id',
- lookup_url_kwarg='experiment_id')
- project = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:project-detail',
- lookup_field='project_id',
- lookup_url_kwarg='project_id')
-
-
-class ExperimentSummarySerializer(BaseExperimentSummarySerializer):
- # The experiment-search list historically rendered these timestamps as raw
- # epoch-millis ints (the Thrift metaclass regenerated them as IntegerField on
- # this subclass, shadowing the base's ISO field); preserve that exactly.
- creationTime = ProtoIntOrNoneField(source='creation_time')
- statusUpdateTime = ProtoIntOrNoneField(source='status_update_time')
- userHasWriteAccess = serializers.SerializerMethodField()
-
- def get_userHasWriteAccess(self, experiment):
- return user_has_access(
- self.context['request'], experiment.experiment_id)
-
-
-def _user_profile_pb2():
- from airavata_sdk.generated.org.apache.airavata.model.user import (
- user_profile_pb2,
- )
- return user_profile_pb2
-
-
-def _user_status_field(**kwargs):
- return proto_enum_int_field(
- _user_profile_pb2().Status.DESCRIPTOR, _THRIFT_ENUM_INTS['Status'],
- proto_prefix='STATUS_', **kwargs)
-
-
-class UserProfileSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``UserProfile`` message.
-
- Preserves the Thrift serializer's attribute quirks byte-for-byte: ``State``
- (capitalised), ``orginationAffiliation`` (the Thrift misspelling), and
- ``labeledURI`` — a Thrift *list* field fed the proto string, so the old
- auto-generated ListField iterated it character by character; reproduced here.
- The ``nsfDemographics``/``customDashboard`` structs render null.
- """
-
- userModelVersion = serializers.CharField(source='user_model_version', allow_blank=True, allow_null=True, required=False)
- airavataInternalUserId = serializers.CharField(source='airavata_internal_user_id', allow_blank=True, allow_null=True, required=False)
- userId = serializers.CharField(source='user_id', allow_blank=True, allow_null=True, required=False)
- gatewayId = serializers.CharField(source='gateway_id', allow_blank=True, allow_null=True, required=False)
- emails = serializers.ListField(child=serializers.CharField(), required=False)
- firstName = serializers.CharField(source='first_name', allow_blank=True, allow_null=True, required=False)
- lastName = serializers.CharField(source='last_name', allow_blank=True, allow_null=True, required=False)
- middleName = serializers.CharField(source='middle_name', allow_blank=True, allow_null=True, required=False)
- namePrefix = serializers.CharField(source='name_prefix', allow_blank=True, allow_null=True, required=False)
- nameSuffix = serializers.CharField(source='name_suffix', allow_blank=True, allow_null=True, required=False)
- orcidId = serializers.CharField(source='orcid_id', allow_blank=True, allow_null=True, required=False)
- phones = serializers.ListField(child=serializers.CharField(), required=False)
- country = serializers.CharField(allow_blank=True, allow_null=True, required=False)
- nationality = serializers.ListField(child=serializers.CharField(), required=False)
- homeOrganization = serializers.CharField(source='home_organization', allow_blank=True, allow_null=True, required=False)
- orginationAffiliation = serializers.CharField(source='origination_affiliation', allow_blank=True, allow_null=True, required=False)
- creationTime = ProtoTimestampField(source='creation_time', null_if_zero=True)
- lastAccessTime = ProtoTimestampField(source='last_access_time', null_if_zero=True)
- validUntil = ProtoIntOrNoneField(source='valid_until')
- State = _user_status_field(source='state', required=False, allow_null=True)
- comments = serializers.CharField(allow_blank=True, allow_null=True, required=False)
- labeledURI = serializers.ListField(source='labeled_uri', child=serializers.CharField(), required=False)
- gpgKey = serializers.CharField(source='gpg_key', allow_blank=True, allow_null=True, required=False)
- timeZone = serializers.CharField(source='time_zone', allow_blank=True, allow_null=True, required=False)
- nsfDemographics = serializers.SerializerMethodField()
- customDashboard = serializers.SerializerMethodField()
-
- def to_representation(self, instance):
- ret = super().to_representation(instance)
- # The old adapter mapped optional proto strings to None when empty.
- for f in ('userModelVersion', 'firstName', 'lastName', 'middleName',
- 'namePrefix', 'nameSuffix', 'orcidId', 'country',
- 'homeOrganization', 'orginationAffiliation', 'comments',
- 'gpgKey', 'timeZone'):
- if ret.get(f) == '':
- ret[f] = None
- return ret
-
- def get_nsfDemographics(self, instance):
- return None
-
- def get_customDashboard(self, instance):
- return None
-
-
-def _grp_pb2():
- from airavata_sdk.generated.org.apache.airavata.model.appcatalog.groupresourceprofile import ( # noqa: E501
- group_resource_profile_pb2,
- )
- return group_resource_profile_pb2
-
-
-def _resource_type_field(**kwargs):
- return proto_enum_int_field(
- _grp_pb2().ResourceType.DESCRIPTOR, _THRIFT_ENUM_INTS['ResourceType'],
- proto_prefix='RESOURCE_TYPE_', **kwargs)
-
-
-class ComputeResourceReservationSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``ComputeResourceReservation``."""
-
- reservationId = serializers.CharField(source='reservation_id', allow_blank=True, allow_null=True, required=False)
- reservationName = serializers.CharField(source='reservation_name', allow_blank=True, allow_null=True, required=False)
- queueNames = serializers.ListField(source='queue_names', child=serializers.CharField(), required=False)
- startTime = ProtoIntOrNoneField(source='start_time')
- endTime = ProtoIntOrNoneField(source='end_time')
-
- def create(self, validated_data):
- d = validated_data
- return _grp_pb2().ComputeResourceReservation(
- reservation_id=d.get('reservation_id', '') or '',
- reservation_name=d.get('reservation_name', '') or '',
- queue_names=list(d.get('queue_names', []) or []),
- start_time=d.get('start_time', 0) or 0,
- end_time=d.get('end_time', 0) or 0,
- )
-
-
-class _GroupAccountSSHProvisionerConfigSerializer(serializers.Serializer):
- resourceId = serializers.CharField(source='resource_id', allow_blank=True, allow_null=True, required=False)
- groupResourceProfileId = serializers.CharField(source='group_resource_profile_id', allow_blank=True, allow_null=True, required=False)
- configName = serializers.CharField(source='config_name', allow_blank=True, allow_null=True, required=False)
- configValue = serializers.CharField(source='config_value', allow_blank=True, allow_null=True, required=False)
-
- def create(self, validated_data):
- d = validated_data
- return _grp_pb2().GroupAccountSSHProvisionerConfig(
- resource_id=d.get('resource_id', '') or '',
- group_resource_profile_id=d.get('group_resource_profile_id', '') or '',
- config_name=d.get('config_name', '') or '',
- config_value=d.get('config_value', '') or '',
- )
-
-
-class GroupComputeResourcePreferenceSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``GroupComputeResourcePreference``.
-
- The proto ``specific_preferences`` is a oneof of a SLURM or AWS sub-message;
- the read output flattens ``allocationProjectNumber`` to the top level and
- wraps the rendered preferences as ``{'slurm': {...}}`` / AWS fields, matching
- the historical Thrift-union serializer byte-for-byte.
- """
-
- computeResourceId = serializers.CharField(source='compute_resource_id', allow_blank=True, allow_null=True, required=False)
- groupResourceProfileId = serializers.CharField(source='group_resource_profile_id', allow_blank=True, allow_null=True, required=False)
- overridebyAiravata = serializers.BooleanField(source='override_by_airavata', required=False, default=False)
- loginUserName = serializers.CharField(source='login_user_name', allow_blank=True, allow_null=True, required=False)
- scratchLocation = serializers.CharField(source='scratch_location', allow_blank=True, allow_null=True, required=False)
- preferredJobSubmissionProtocol = job_submission_protocol_field(source='preferred_job_submission_protocol', required=False, allow_null=True)
- preferredDataMovementProtocol = data_movement_protocol_field(source='preferred_data_movement_protocol', required=False, allow_null=True)
- resourceSpecificCredentialStoreToken = serializers.CharField(source='resource_specific_credential_store_token', allow_blank=True, allow_null=True, required=False)
- resourceType = _resource_type_field(source='resource_type', required=False, allow_null=True)
- specificPreferences = serializers.SerializerMethodField()
- reservations = serializers.SerializerMethodField()
-
- def get_specificPreferences(self, pref):
- if not pref.HasField('specific_preferences'):
- return None
- sp = pref.specific_preferences
- which = sp.WhichOneof('preferences')
- if which == 'slurm':
- # The old union serializer always rendered both members (the inactive
- # one as null); preserve that.
- return {'slurm': self._slurm(sp.slurm), 'aws': None}
- if which == 'aws':
- return self._aws(sp.aws)
- return None
-
- def get_reservations(self, pref):
- # The top-level reservations field is always empty here: reservations live
- # inside the SLURM union member (matching the old serializer's behaviour
- # where the compute-pref object had no top-level ``reservations`` attr).
- return []
-
- def to_representation(self, instance):
- ret = super().to_representation(instance)
- # Flatten allocationProjectNumber out of the SLURM union member, as the
- # old union serializer did.
- if (instance.HasField('specific_preferences') and
- instance.specific_preferences.WhichOneof('preferences') == 'slurm'):
- ret['allocationProjectNumber'] = (
- instance.specific_preferences.slurm.allocation_project_number)
- return ret
-
- def to_internal_value(self, data):
- # specificPreferences / allocationProjectNumber / reservations are
- # read-flatten outputs (SerializerMethodField); carry the raw write input
- # through so create() can rebuild the proto union.
- ret = super().to_internal_value(data)
- if isinstance(data, dict):
- for k in ('specificPreferences', 'allocationProjectNumber',
- 'reservations'):
- if k in data:
- ret[k] = data[k]
- return ret
-
- @staticmethod
- def _slurm(s):
- return {
- 'allocationProjectNumber': s.allocation_project_number,
- 'preferredBatchQueue': s.preferred_batch_queue,
- 'qualityOfService': s.quality_of_service,
- 'usageReportingGatewayId': s.usage_reporting_gateway_id,
- 'sshAccountProvisioner': s.ssh_account_provisioner,
- 'groupSSHAccountProvisionerConfigs': [
- {
- 'resourceId': c.resource_id,
- 'groupResourceProfileId': c.group_resource_profile_id,
- 'configName': c.config_name,
- 'configValue': c.config_value,
- }
- for c in s.group_ssh_account_provisioner_configs],
- 'sshAccountProvisionerAdditionalInfo': s.ssh_account_provisioner_additional_info,
- 'reservations': [
- {
- 'reservationId': r.reservation_id,
- 'reservationName': r.reservation_name,
- 'queueNames': list(r.queue_names),
- 'startTime': r.start_time or None,
- 'endTime': r.end_time or None,
- }
- for r in s.reservations],
- }
-
- @staticmethod
- def _aws(a):
- return {
- 'region': a.region,
- 'preferredAmiId': a.preferred_ami_id,
- 'preferredInstanceType': a.preferred_instance_type,
- }
-
- def create(self, validated_data):
- return _build_group_compute_resource_preference(validated_data)
-
-
-def _build_group_compute_resource_preference(d):
- """Build a proto ``GroupComputeResourcePreference`` from validated write data.
-
- The frontend sends ``specificPreferences`` (a ``{'slurm': {...}}`` / AWS
- dict) plus a flattened ``allocationProjectNumber`` and a ``resourceType``;
- map them into the proto oneof.
- """
- grp = _grp_pb2()
- sp = d.get('specificPreferences')
- resource_type = d.get('resource_type', 0) or 0
- msg = grp.GroupComputeResourcePreference(
- compute_resource_id=d.get('compute_resource_id', '') or '',
- group_resource_profile_id=d.get('group_resource_profile_id', '') or '',
- override_by_airavata=bool(d.get('override_by_airavata', False)),
- login_user_name=d.get('login_user_name', '') or '',
- scratch_location=d.get('scratch_location', '') or '',
- preferred_job_submission_protocol=d.get('preferred_job_submission_protocol', 0) or 0,
- preferred_data_movement_protocol=d.get('preferred_data_movement_protocol', 0) or 0,
- resource_specific_credential_store_token=d.get('resource_specific_credential_store_token', '') or '',
- resource_type=resource_type,
- )
- # Resolve the union: prefer an explicit specificPreferences, else infer from
- # the flattened allocationProjectNumber / aws fields.
- slurm_data = None
- aws_data = None
- if isinstance(sp, dict):
- if 'slurm' in sp and isinstance(sp['slurm'], dict):
- slurm_data = dict(sp['slurm'])
- elif 'aws' in sp and isinstance(sp['aws'], dict):
- aws_data = dict(sp['aws'])
- elif 'region' in sp or 'preferredAmiId' in sp:
- aws_data = dict(sp)
- elif sp:
- slurm_data = dict(sp)
- if slurm_data is None and aws_data is None:
- # Infer from the flattened fields the read output produced.
- proto_resource_type = grp.ResourceType
- if resource_type == proto_resource_type.AWS or 'region' in d:
- aws_data = {}
- elif 'allocationProjectNumber' in d or resource_type == proto_resource_type.SLURM:
- slurm_data = {}
- if 'allocationProjectNumber' in d and slurm_data is not None:
- slurm_data.setdefault('allocationProjectNumber', d['allocationProjectNumber'])
- if slurm_data is not None:
- msg.specific_preferences.CopyFrom(grp.EnvironmentSpecificPreferences(
- slurm=_build_slurm_pref(slurm_data)))
- elif aws_data is not None:
- msg.specific_preferences.CopyFrom(grp.EnvironmentSpecificPreferences(
- aws=_build_aws_pref(aws_data)))
- return msg
-
-
-def _build_slurm_pref(s):
- grp = _grp_pb2()
- return grp.SlurmComputeResourcePreference(
- allocation_project_number=s.get('allocationProjectNumber', '') or '',
- preferred_batch_queue=s.get('preferredBatchQueue', '') or '',
- quality_of_service=s.get('qualityOfService', '') or '',
- usage_reporting_gateway_id=s.get('usageReportingGatewayId', '') or '',
- ssh_account_provisioner=s.get('sshAccountProvisioner', '') or '',
- group_ssh_account_provisioner_configs=[
- grp.GroupAccountSSHProvisionerConfig(
- resource_id=c.get('resourceId', '') or '',
- group_resource_profile_id=c.get('groupResourceProfileId', '') or '',
- config_name=c.get('configName', '') or '',
- config_value=c.get('configValue', '') or '',
- )
- for c in (s.get('groupSSHAccountProvisionerConfigs', []) or [])],
- ssh_account_provisioner_additional_info=s.get('sshAccountProvisionerAdditionalInfo', '') or '',
- reservations=[
- grp.ComputeResourceReservation(
- reservation_id=r.get('reservationId', '') or '',
- reservation_name=r.get('reservationName', '') or '',
- queue_names=list(r.get('queueNames', []) or []),
- start_time=r.get('startTime', 0) or 0,
- end_time=r.get('endTime', 0) or 0,
- )
- for r in (s.get('reservations', []) or [])],
- )
-
-
-def _build_aws_pref(a):
- return _grp_pb2().AwsComputeResourcePreference(
- region=a.get('region', '') or '',
- preferred_ami_id=a.get('preferredAmiId', '') or '',
- preferred_instance_type=a.get('preferredInstanceType', '') or '',
- )
-
-
-class _ComputeResourcePolicySerializer(serializers.Serializer):
- resourcePolicyId = serializers.CharField(source='resource_policy_id', allow_blank=True, allow_null=True, required=False)
- computeResourceId = serializers.CharField(source='compute_resource_id', allow_blank=True, allow_null=True, required=False)
- groupResourceProfileId = serializers.CharField(source='group_resource_profile_id', allow_blank=True, allow_null=True, required=False)
- allowedBatchQueues = serializers.ListField(source='allowed_batch_queues', child=serializers.CharField(), required=False)
-
- def create(self, validated_data):
- d = validated_data
- return _grp_pb2().ComputeResourcePolicy(
- resource_policy_id=d.get('resource_policy_id', '') or '',
- compute_resource_id=d.get('compute_resource_id', '') or '',
- group_resource_profile_id=d.get('group_resource_profile_id', '') or '',
- allowed_batch_queues=list(d.get('allowed_batch_queues', []) or []),
- )
-
-
-class _BatchQueueResourcePolicySerializer(serializers.Serializer):
- resourcePolicyId = serializers.CharField(source='resource_policy_id', allow_blank=True, allow_null=True, required=False)
- computeResourceId = serializers.CharField(source='compute_resource_id', allow_blank=True, allow_null=True, required=False)
- groupResourceProfileId = serializers.CharField(source='group_resource_profile_id', allow_blank=True, allow_null=True, required=False)
- queuename = serializers.CharField(allow_blank=True, allow_null=True, required=False)
- maxAllowedNodes = serializers.IntegerField(source='max_allowed_nodes', allow_null=True, required=False)
- maxAllowedCores = serializers.IntegerField(source='max_allowed_cores', allow_null=True, required=False)
- maxAllowedWalltime = serializers.IntegerField(source='max_allowed_walltime', allow_null=True, required=False)
-
- def create(self, validated_data):
- d = validated_data
- return _grp_pb2().BatchQueueResourcePolicy(
- resource_policy_id=d.get('resource_policy_id', '') or '',
- compute_resource_id=d.get('compute_resource_id', '') or '',
- group_resource_profile_id=d.get('group_resource_profile_id', '') or '',
- queuename=d.get('queuename', '') or '',
- max_allowed_nodes=d.get('max_allowed_nodes', 0) or 0,
- max_allowed_cores=d.get('max_allowed_cores', 0) or 0,
- max_allowed_walltime=d.get('max_allowed_walltime', 0) or 0,
- )
-
-
-class GroupResourceProfileSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``GroupResourceProfile`` message."""
-
- gatewayId = serializers.CharField(source='gateway_id', allow_blank=True, allow_null=True, required=False)
- groupResourceProfileId = serializers.CharField(source='group_resource_profile_id', allow_blank=True, allow_null=True, required=False)
- groupResourceProfileName = serializers.CharField(source='group_resource_profile_name')
- computePreferences = GroupComputeResourcePreferenceSerializer(source='compute_preferences', many=True, required=False)
- computeResourcePolicies = _ComputeResourcePolicySerializer(source='compute_resource_policies', many=True, required=False)
- batchQueueResourcePolicies = _BatchQueueResourcePolicySerializer(source='batch_queue_resource_policies', many=True, required=False)
- creationTime = ProtoTimestampField(source='creation_time', null_if_zero=True, read_only=True)
- updatedTime = ProtoTimestampField(source='updated_time', null_if_zero=True, read_only=True)
- defaultCredentialStoreToken = serializers.CharField(source='default_credential_store_token', allow_blank=True, allow_null=True, required=False)
- url = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:group-resource-profile-detail',
- lookup_field='group_resource_profile_id',
- lookup_url_kwarg='group_resource_profile_id')
- userHasWriteAccess = serializers.SerializerMethodField()
-
- def to_representation(self, instance):
- ret = super().to_representation(instance)
- if ret.get('defaultCredentialStoreToken') == '':
- ret['defaultCredentialStoreToken'] = None
- return ret
-
- def create(self, validated_data):
- return _build_group_resource_profile(validated_data)
-
- def update(self, instance, validated_data):
- return _build_group_resource_profile(validated_data)
-
- def get_userHasWriteAccess(self, groupResourceProfile):
- request = self.context['request']
- write_access = user_has_access(
- request, groupResourceProfile.group_resource_profile_id, "WRITE")
- if not write_access:
- return False
- # Check that the user has READ access to all credential tokens.
- tokens = set([groupResourceProfile.default_credential_store_token] +
- [cp.resource_specific_credential_store_token
- for cp in groupResourceProfile.compute_preferences])
-
- def check_token(token):
- return not token or user_has_access(request, token, "READ")
-
- return all(map(check_token, tokens))
-
-
-def _build_group_resource_profile(d):
- grp = _grp_pb2()
- return grp.GroupResourceProfile(
- gateway_id=d.get('gateway_id', '') or '',
- group_resource_profile_id=d.get('group_resource_profile_id', '') or '',
- group_resource_profile_name=d.get('group_resource_profile_name', '') or '',
- compute_preferences=[
- _build_group_compute_resource_preference(p)
- for p in d.get('compute_preferences', []) or []],
- compute_resource_policies=[
- _ComputeResourcePolicySerializer().create(p)
- for p in d.get('compute_resource_policies', []) or []],
- batch_queue_resource_policies=[
- _BatchQueueResourcePolicySerializer().create(p)
- for p in d.get('batch_queue_resource_policies', []) or []],
- default_credential_store_token=d.get('default_credential_store_token', '') or '',
- )
-
-
-class UserPermissionSerializer(serializers.Serializer):
- user = UserProfileSerializer()
- permissionType = serializers.IntegerField()
-
-
-class GroupPermissionSerializer(serializers.Serializer):
- group = GroupSerializer()
- permissionType = serializers.IntegerField()
-
-
-class SharedEntitySerializer(serializers.Serializer):
- entityId = serializers.CharField(read_only=True)
- userPermissions = UserPermissionSerializer(many=True)
- groupPermissions = GroupPermissionSerializer(many=True)
- owner = UserProfileSerializer(read_only=True)
- isOwner = serializers.SerializerMethodField()
- hasSharingPermission = serializers.SerializerMethodField()
-
- def create(self, validated_data):
- raise Exception("Not implemented")
-
- def update(self, instance, validated_data):
- # Compute lists of ids to grant/revoke READ/WRITE/MANAGE_SHARING
- # permission
- existing_user_permissions = {
- user['user'].airavata_internal_user_id: user['permissionType']
- for user in instance['userPermissions']}
- new_user_permissions = {
- user['user']['airavata_internal_user_id']:
- user['permissionType']
- for user in validated_data['userPermissions']}
-
- (
- user_grant_read_permission,
- user_grant_write_permission,
- user_grant_manage_sharing_permission,
- user_revoke_read_permission,
- user_revoke_write_permission,
- user_revoke_manage_sharing_permission) = self._compute_all_revokes_and_grants(
- existing_user_permissions,
- new_user_permissions)
-
- existing_group_permissions = {
- group['group'].id: group['permissionType']
- for group in instance['groupPermissions']}
- new_group_permissions = {
- group['group']['id']: group['permissionType']
- for group in validated_data['groupPermissions']}
- UserProfile = _user_profile_pb2().UserProfile
- GroupModel = _group_manager_pb2().GroupModel
-
- (
- group_grant_read_permission,
- group_grant_write_permission,
- group_grant_manage_sharing_permission,
- group_revoke_read_permission,
- group_revoke_write_permission,
- group_revoke_manage_sharing_permission) = self._compute_all_revokes_and_grants(
- existing_group_permissions,
- new_group_permissions)
-
- instance['_user_grant_read_permission'] = user_grant_read_permission
- instance['_user_grant_write_permission'] = user_grant_write_permission
- instance['_user_grant_manage_sharing_permission'] = user_grant_manage_sharing_permission
- instance['_user_revoke_read_permission'] = user_revoke_read_permission
- instance['_user_revoke_write_permission'] = user_revoke_write_permission
- instance['_user_revoke_manage_sharing_permission'] = user_revoke_manage_sharing_permission
- instance['_group_grant_read_permission'] = group_grant_read_permission
- instance['_group_grant_write_permission'] = group_grant_write_permission
- instance['_group_grant_manage_sharing_permission'] = group_grant_manage_sharing_permission
- instance['_group_revoke_read_permission'] = group_revoke_read_permission
- instance['_group_revoke_write_permission'] = group_revoke_write_permission
- instance['_group_revoke_manage_sharing_permission'] = group_revoke_manage_sharing_permission
- instance['userPermissions'] = [
- {'user': UserProfile(**data['user']),
- 'permissionType': data['permissionType']}
- for data in validated_data.get(
- 'userPermissions', instance['userPermissions'])]
- instance['groupPermissions'] = [
- {'group': GroupModel(**data['group']),
- 'permissionType': data['permissionType']}
- for data in validated_data.get('groupPermissions', instance['groupPermissions'])]
- return instance
-
- def _compute_all_revokes_and_grants(self, existing_permissions,
- new_permissions):
- grant_read_permission = []
- grant_write_permission = []
- grant_manage_sharing_permission = []
- revoke_read_permission = []
- revoke_write_permission = []
- revoke_manage_sharing_permission = []
- # Union the two sets of user/group ids
- all_ids = existing_permissions.keys() | new_permissions.keys()
- for id in all_ids:
- revokes, grants = self._compute_revokes_and_grants(
- existing_permissions.get(id),
- new_permissions.get(id)
- )
- if ResourcePermissionType.READ in revokes:
- revoke_read_permission.append(id)
- if ResourcePermissionType.WRITE in revokes:
- revoke_write_permission.append(id)
- if ResourcePermissionType.MANAGE_SHARING in revokes:
- revoke_manage_sharing_permission.append(id)
- if ResourcePermissionType.READ in grants:
- grant_read_permission.append(id)
- if ResourcePermissionType.WRITE in grants:
- grant_write_permission.append(id)
- if ResourcePermissionType.MANAGE_SHARING in grants:
- grant_manage_sharing_permission.append(id)
- return (
- grant_read_permission,
- grant_write_permission,
- grant_manage_sharing_permission,
- revoke_read_permission,
- revoke_write_permission,
- revoke_manage_sharing_permission)
-
- def _compute_revokes_and_grants(self, current_permission=None,
- new_permission=None):
- read_permissions = set((ResourcePermissionType.READ,))
- write_permissions = set((ResourcePermissionType.READ,
- ResourcePermissionType.WRITE))
- manage_share_permissions = set(
- (ResourcePermissionType.READ,
- ResourcePermissionType.WRITE,
- ResourcePermissionType.MANAGE_SHARING))
- current_permissions_set = set()
- new_permissions_set = set()
- if current_permission == ResourcePermissionType.READ:
- current_permissions_set = read_permissions
- elif current_permission == ResourcePermissionType.WRITE:
- current_permissions_set = write_permissions
- elif current_permission == ResourcePermissionType.MANAGE_SHARING:
- current_permissions_set = manage_share_permissions
- if new_permission == ResourcePermissionType.READ:
- new_permissions_set = read_permissions
- elif new_permission == ResourcePermissionType.WRITE:
- new_permissions_set = write_permissions
- elif new_permission == ResourcePermissionType.MANAGE_SHARING:
- new_permissions_set = manage_share_permissions
-
- # return tuple: permissions to revoke and permissions to grant
- return (current_permissions_set - new_permissions_set,
- new_permissions_set - current_permissions_set)
-
- def get_isOwner(self, shared_entity):
- request = self.context['request']
- return shared_entity['owner'].user_id == request.user.username
-
- def get_hasSharingPermission(self, shared_entity):
- request = self.context['request']
- return user_has_access(
- request, shared_entity['entityId'], "MANAGE_SHARING")
-
-
-def _credential_store_pb2():
- from airavata_sdk.generated.org.apache.airavata.model.credential.store import (
- credential_store_pb2,
+def _credential_store_pb2():
+ from airavata_sdk.generated.org.apache.airavata.model.credential.store import (
+ credential_store_pb2,
)
return credential_store_pb2
-class CredentialSummarySerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``CredentialSummary`` message."""
-
- type = proto_enum_name_field(
- _credential_store_pb2().SummaryType.DESCRIPTOR, read_only=True)
- gatewayId = serializers.CharField(source='gateway_id', read_only=True)
- username = serializers.CharField(read_only=True)
- publicKey = serializers.CharField(source='public_key', read_only=True)
- persistedTime = ProtoTimestampField(
- source='persisted_time', read_only=True)
- token = serializers.CharField(read_only=True)
- description = serializers.CharField(read_only=True)
- userHasWriteAccess = serializers.SerializerMethodField()
-
- def get_userHasWriteAccess(self, credential_summary):
- return user_has_access(
- self.context['request'], credential_summary.token)
-
-
-def _gateway_profile_pb2():
- from airavata_sdk.generated.org.apache.airavata.model.appcatalog.gatewayprofile import ( # noqa: E501
- gateway_profile_pb2,
- )
- return gateway_profile_pb2
-
-
-class StoragePreferenceSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``StoragePreference`` message."""
-
- storageResourceId = serializers.CharField(
- source='storage_resource_id', allow_blank=True, allow_null=True,
- required=False)
- loginUserName = serializers.CharField(
- source='login_user_name', allow_blank=True, allow_null=True,
- required=False)
- fileSystemRootLocation = serializers.CharField(
- source='file_system_root_location', allow_blank=True, allow_null=True,
- required=False)
- resourceSpecificCredentialStoreToken = serializers.CharField(
- source='resource_specific_credential_store_token', allow_blank=True,
- allow_null=True, required=False)
- url = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:storage-preference-detail',
- lookup_field='storage_resource_id',
- lookup_url_kwarg='storage_resource_id')
-
- def to_representation(self, instance):
- ret = super().to_representation(instance)
- # Convert empty string to null (preserves the old serializer's behavior)
- if ret['resourceSpecificCredentialStoreToken'] == '':
- ret['resourceSpecificCredentialStoreToken'] = None
- return ret
-
- def create(self, validated_data):
- gp = _gateway_profile_pb2()
- return gp.StoragePreference(
- storage_resource_id=validated_data.get(
- 'storage_resource_id', '') or '',
- login_user_name=validated_data.get('login_user_name', '') or '',
- file_system_root_location=validated_data.get(
- 'file_system_root_location', '') or '',
- resource_specific_credential_store_token=validated_data.get(
- 'resource_specific_credential_store_token', '') or '',
- )
-
- def update(self, instance, validated_data):
- return self.create(validated_data)
-
-
-class ComputeResourcePreferenceSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``ComputeResourcePreference`` message."""
-
- computeResourceId = serializers.CharField(
- source='compute_resource_id', allow_blank=True, allow_null=True,
- required=False)
- overridebyAiravata = serializers.BooleanField(
- source='override_by_airavata', required=False, default=False)
- loginUserName = serializers.CharField(
- source='login_user_name', allow_blank=True, allow_null=True,
- required=False)
- preferredJobSubmissionProtocol = job_submission_protocol_field(
- source='preferred_job_submission_protocol', required=False,
- allow_null=True)
- preferredDataMovementProtocol = data_movement_protocol_field(
- source='preferred_data_movement_protocol', required=False,
- allow_null=True)
- preferredBatchQueue = serializers.CharField(
- source='preferred_batch_queue', allow_blank=True, allow_null=True,
- required=False)
- scratchLocation = serializers.CharField(
- source='scratch_location', allow_blank=True, allow_null=True,
- required=False)
- allocationProjectNumber = serializers.CharField(
- source='allocation_project_number', allow_blank=True, allow_null=True,
- required=False)
- resourceSpecificCredentialStoreToken = serializers.CharField(
- source='resource_specific_credential_store_token', allow_blank=True,
- allow_null=True, required=False)
- usageReportingGatewayId = serializers.CharField(
- source='usage_reporting_gateway_id', allow_blank=True, allow_null=True,
- required=False)
- qualityOfService = serializers.CharField(
- source='quality_of_service', allow_blank=True, allow_null=True,
- required=False)
- reservation = serializers.CharField(
- allow_blank=True, allow_null=True, required=False)
- reservationStartTime = ProtoIntOrNoneField(source='reservation_start_time')
- reservationEndTime = ProtoIntOrNoneField(source='reservation_end_time')
- sshAccountProvisioner = serializers.CharField(
- source='ssh_account_provisioner', allow_blank=True, allow_null=True,
- required=False)
- sshAccountProvisionerConfig = serializers.DictField(
- source='ssh_account_provisioner_config', required=False)
- sshAccountProvisionerAdditionalInfo = serializers.CharField(
- source='ssh_account_provisioner_additional_info', allow_blank=True,
- allow_null=True, required=False)
-
- def create(self, validated_data):
- gp = _gateway_profile_pb2()
- return gp.ComputeResourcePreference(
- compute_resource_id=validated_data.get(
- 'compute_resource_id', '') or '',
- override_by_airavata=bool(
- validated_data.get('override_by_airavata', False)),
- login_user_name=validated_data.get('login_user_name', '') or '',
- preferred_job_submission_protocol=validated_data.get(
- 'preferred_job_submission_protocol', 0) or 0,
- preferred_data_movement_protocol=validated_data.get(
- 'preferred_data_movement_protocol', 0) or 0,
- preferred_batch_queue=validated_data.get(
- 'preferred_batch_queue', '') or '',
- scratch_location=validated_data.get('scratch_location', '') or '',
- allocation_project_number=validated_data.get(
- 'allocation_project_number', '') or '',
- resource_specific_credential_store_token=validated_data.get(
- 'resource_specific_credential_store_token', '') or '',
- usage_reporting_gateway_id=validated_data.get(
- 'usage_reporting_gateway_id', '') or '',
- quality_of_service=validated_data.get('quality_of_service', '') or '',
- reservation=validated_data.get('reservation', '') or '',
- reservation_start_time=validated_data.get(
- 'reservation_start_time', 0) or 0,
- reservation_end_time=validated_data.get(
- 'reservation_end_time', 0) or 0,
- ssh_account_provisioner=validated_data.get(
- 'ssh_account_provisioner', '') or '',
- ssh_account_provisioner_config=dict(
- validated_data.get('ssh_account_provisioner_config', {}) or {}),
- ssh_account_provisioner_additional_info=validated_data.get(
- 'ssh_account_provisioner_additional_info', '') or '',
- )
-
- def update(self, instance, validated_data):
- return self.create(validated_data)
-
-
-class GatewayResourceProfileSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``GatewayResourceProfile`` message."""
-
- gatewayID = serializers.CharField(
- source='gateway_id', allow_blank=True, allow_null=True, required=False)
- credentialStoreToken = serializers.CharField(
- source='credential_store_token', allow_blank=True, allow_null=True,
- required=False)
- computeResourcePreferences = ComputeResourcePreferenceSerializer(
- source='compute_resource_preferences', many=True, required=False)
- storagePreferences = StoragePreferenceSerializer(
- source='storage_preferences', many=True, required=False)
- identityServerTenant = serializers.CharField(
- source='identity_server_tenant', allow_blank=True, allow_null=True,
- required=False)
- identityServerPwdCredToken = serializers.CharField(
- source='identity_server_pwd_cred_token', allow_blank=True,
- allow_null=True, required=False)
- userHasWriteAccess = serializers.SerializerMethodField()
-
- def get_userHasWriteAccess(self, gatewayResourceProfile):
- request = self.context['request']
- return request.is_gateway_admin
-
- def create(self, validated_data):
- gp = _gateway_profile_pb2()
- return gp.GatewayResourceProfile(
- gateway_id=validated_data.get('gateway_id', '') or '',
- credential_store_token=validated_data.get(
- 'credential_store_token', '') or '',
- compute_resource_preferences=[
- ComputeResourcePreferenceSerializer().create(p)
- for p in validated_data.get(
- 'compute_resource_preferences', []) or []],
- storage_preferences=[
- StoragePreferenceSerializer().create(p)
- for p in validated_data.get('storage_preferences', []) or []],
- identity_server_tenant=validated_data.get(
- 'identity_server_tenant', '') or '',
- identity_server_pwd_cred_token=validated_data.get(
- 'identity_server_pwd_cred_token', '') or '',
- )
-
- def update(self, instance, validated_data):
- return self.create(validated_data)
-
-
-class StorageResourceSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``StorageResourceDescription`` message."""
-
- storageResourceId = serializers.CharField(
- source='storage_resource_id', allow_blank=True, allow_null=True,
- required=False)
- hostName = serializers.CharField(
- source='host_name', allow_blank=True, allow_null=True, required=False)
- storageResourceDescription = serializers.CharField(
- source='storage_resource_description', allow_blank=True, allow_null=True,
- required=False)
- enabled = serializers.BooleanField(required=False, default=False)
- dataMovementInterfaces = DataMovementInterfaceSerializer(
- source='data_movement_interfaces', many=True, required=False)
- # top-level creation/update render as ISO (non-nullable UTC fields).
- creationTime = ProtoTimestampField(source='creation_time', required=False)
- updateTime = ProtoTimestampField(source='update_time', required=False)
- url = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:storage-resource-detail',
- lookup_field='storage_resource_id',
- lookup_url_kwarg='storage_resource_id')
-
-
-def _parser_pb2():
- from airavata_sdk.generated.org.apache.airavata.model.appcatalog.parser import (
- parser_pb2,
- )
- return parser_pb2
-
-
-class ParserInputSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``ParserInput`` message."""
-
- id = serializers.CharField(allow_blank=True, allow_null=True, required=False)
- name = serializers.CharField(allow_blank=True, allow_null=True, required=False)
- requiredInput = serializers.BooleanField(
- source='required_input', required=False, default=False)
- parserId = serializers.CharField(
- source='parser_id', allow_blank=True, allow_null=True, required=False)
- # IOType renders as the Thrift integer (proto FILE=1 -> Thrift FILE=0).
- type = proto_enum_int_field(
- _parser_pb2().IOType.DESCRIPTOR, _THRIFT_ENUM_INTS['IOType'], 'IO_TYPE_',
- required=False, allow_null=True)
-
-
-class ParserOutputSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``ParserOutput`` message."""
-
- id = serializers.CharField(allow_blank=True, allow_null=True, required=False)
- name = serializers.CharField(allow_blank=True, allow_null=True, required=False)
- requiredOutput = serializers.BooleanField(
- source='required_output', required=False, default=False)
- parserId = serializers.CharField(
- source='parser_id', allow_blank=True, allow_null=True, required=False)
- type = proto_enum_int_field(
- _parser_pb2().IOType.DESCRIPTOR, _THRIFT_ENUM_INTS['IOType'], 'IO_TYPE_',
- required=False, allow_null=True)
-
-
-class ParserSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``Parser`` message."""
-
- id = serializers.CharField(allow_blank=True, allow_null=True, required=False)
- imageName = serializers.CharField(
- source='image_name', allow_blank=True, allow_null=True, required=False)
- outputDirPath = serializers.CharField(
- source='output_dir_path', allow_blank=True, allow_null=True,
- required=False)
- inputDirPath = serializers.CharField(
- source='input_dir_path', allow_blank=True, allow_null=True,
- required=False)
- executionCommand = serializers.CharField(
- source='execution_command', allow_blank=True, allow_null=True,
- required=False)
- inputFiles = ParserInputSerializer(
- source='input_files', many=True, required=False)
- outputFiles = ParserOutputSerializer(
- source='output_files', many=True, required=False)
- gatewayId = serializers.CharField(
- source='gateway_id', allow_blank=True, allow_null=True, required=False)
- url = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:parser-detail',
- lookup_field='id',
- lookup_url_kwarg='parser_id')
-
- def create(self, validated_data):
- pp = _parser_pb2()
- return pp.Parser(
- id=validated_data.get('id', '') or '',
- image_name=validated_data.get('image_name', '') or '',
- output_dir_path=validated_data.get('output_dir_path', '') or '',
- input_dir_path=validated_data.get('input_dir_path', '') or '',
- execution_command=validated_data.get('execution_command', '') or '',
- gateway_id=validated_data.get('gateway_id', '') or '',
- input_files=[
- pp.ParserInput(
- id=i.get('id', '') or '',
- name=i.get('name', '') or '',
- required_input=bool(i.get('required_input', False)),
- parser_id=i.get('parser_id', '') or '',
- type=i.get('type', 0) or 0,
- ) for i in validated_data.get('input_files', []) or []],
- output_files=[
- pp.ParserOutput(
- id=o.get('id', '') or '',
- name=o.get('name', '') or '',
- required_output=bool(o.get('required_output', False)),
- parser_id=o.get('parser_id', '') or '',
- type=o.get('type', 0) or 0,
- ) for o in validated_data.get('output_files', []) or []],
- )
-
- def update(self, instance, validated_data):
- return self.create(validated_data)
-
-
-class UserHasWriteAccessToPathSerializer(serializers.Serializer):
- userHasWriteAccess = serializers.SerializerMethodField()
-
- def get_userHasWriteAccess(self, instance):
- request = self.context['request']
- if "userHasWriteAccess" in instance:
- return instance["userHasWriteAccess"]
- is_shared_path = view_utils.is_shared_path(instance["path"])
- if is_shared_path:
- return request.is_gateway_admin
- else:
- return True
-
-
-class UserStorageFileSerializer(UserHasWriteAccessToPathSerializer):
- name = serializers.CharField()
- downloadURL = serializers.SerializerMethodField()
- dataProductURI = serializers.CharField(source='data-product-uri')
- createdTime = serializers.DateTimeField(source='created_time')
- modifiedTime = serializers.DateTimeField(source='modified_time')
- mimeType = serializers.CharField(source='mime_type')
- size = serializers.IntegerField()
- hidden = serializers.BooleanField()
-
- def get_downloadURL(self, file):
- """Lazy portal URL to the byte-streaming download endpoint for this file.
-
- Returns None when the file has no data product URI; resolving the bytes is
- deferred to the endpoint, so this getter makes no backend call.
- """
- request = self.context['request']
- data_product_uri = file.get('data-product-uri')
- if not data_product_uri:
- return None
- base = request.build_absolute_uri(
- reverse('django_airavata_api:download-file'))
- return base + '?data-product-uri=' + quote(data_product_uri)
-
-
-class UserStorageDirectorySerializer(UserHasWriteAccessToPathSerializer):
- name = serializers.CharField()
- path = serializers.CharField()
- createdTime = serializers.DateTimeField(source='created_time')
- modifiedTime = serializers.DateTimeField(source='modified_time')
- size = serializers.IntegerField()
- hidden = serializers.BooleanField()
- url = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:user-storage-items',
- lookup_field='path',
- lookup_url_kwarg='path')
- isSharedDir = serializers.SerializerMethodField()
-
- def get_isSharedDir(self, directory):
- if "isSharedDir" in directory:
- return directory["isSharedDir"]
- return view_utils.is_shared_dir(directory["path"])
-
-
-class UserStoragePathSerializer(UserHasWriteAccessToPathSerializer):
- isDir = serializers.BooleanField()
- directories = UserStorageDirectorySerializer(many=True)
- files = UserStorageFileSerializer(many=True)
- parts = serializers.ListField(child=serializers.CharField())
- path = serializers.CharField(required=False)
- # uploaded is populated after a file upload
- uploaded = DataProductSerializer(read_only=True)
-
-
-# Fields for ExperimentStorageFileSerializer are the same as UserStorageFileSerializer
-ExperimentStorageFileSerializer = UserStorageFileSerializer
-
-
-class ExperimentStorageDirectorySerializer(serializers.Serializer):
- name = serializers.CharField()
- path = serializers.CharField()
- createdTime = serializers.DateTimeField(source='created_time')
- modifiedTime = serializers.DateTimeField(source='modified_time')
- size = serializers.IntegerField()
- url = serializers.SerializerMethodField()
-
- def get_url(self, dir):
-
- request = self.context['request']
- return request.build_absolute_uri(
- reverse("django_airavata_api:experiment-storage-items", kwargs={
- "experiment_id": dir['experiment_id'],
- "path": dir['path']
- }))
-
-
-class ExperimentStoragePathSerializer(serializers.Serializer):
- isDir = serializers.BooleanField()
- directories = ExperimentStorageDirectorySerializer(many=True)
- files = ExperimentStorageFileSerializer(many=True)
- parts = serializers.ListField(child=serializers.CharField())
-
-
-# ModelSerializers
-class ApplicationPreferencesSerializer(serializers.ModelSerializer):
- class Meta:
- model = models.ApplicationPreferences
- exclude = ('id', 'username', 'workspace_preferences')
-
-
-class WorkspacePreferencesSerializer(serializers.ModelSerializer):
- application_preferences = ApplicationPreferencesSerializer(
- source="applicationpreferences_set", many=True)
-
- class Meta:
- model = models.WorkspacePreferences
- exclude = ('username',)
-
-
-class IAMUserProfile(serializers.Serializer):
- airavataInternalUserId = serializers.CharField()
- userId = serializers.CharField()
- gatewayId = serializers.CharField()
- email = serializers.CharField()
- firstName = serializers.CharField()
- lastName = serializers.CharField()
- enabled = serializers.BooleanField()
- emailVerified = serializers.BooleanField()
- airavataUserProfileExists = serializers.BooleanField()
- creationTime = UTCPosixTimestampDateTimeField()
- groups = GroupSerializer(many=True)
- url = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:iam-user-profile-detail',
- lookup_field='userId',
- lookup_url_kwarg='user_id')
- userHasWriteAccess = serializers.SerializerMethodField()
- newUsername = serializers.CharField(write_only=True, required=False)
- externalIDPUserInfo = serializers.SerializerMethodField()
- userProfileInvalidFields = serializers.SerializerMethodField()
-
- def update(self, instance, validated_data):
- existing_group_ids = [group.id for group in instance['groups']]
- new_group_ids = [group['id'] for group in validated_data['groups']]
- instance['_added_group_ids'] = list(
- set(new_group_ids) - set(existing_group_ids))
- instance['_removed_group_ids'] = list(
- set(existing_group_ids) - set(new_group_ids))
- return instance
-
- def get_userHasWriteAccess(self, userProfile):
- request = self.context['request']
- return request.is_gateway_admin
-
- def get_externalIDPUserInfo(self, userProfile):
- result = {}
- try:
- if get_user_model().objects.filter(username=userProfile['userId']).exists():
- django_user = get_user_model().objects.get(username=userProfile['userId'])
- claims = django_user.user_profile.idp_userinfo.all()
- if claims.exists():
- result['idp_alias'] = claims.first().idp_alias
- result['userinfo'] = {}
- for claim in claims:
- result['userinfo'][claim.claim] = claim.value
- except Exception as e:
- log.warning(f"Failed to load idp_userinfo for {userProfile['userId']}", exc_info=e)
- return result
-
- def get_userProfileInvalidFields(self, userProfile):
- try:
- User = get_user_model()
- if User.objects.filter(username=userProfile['userId']).exists():
- django_user = User.objects.get(username=userProfile['userId'])
- if hasattr(django_user, 'user_profile'):
- return django_user.user_profile.invalid_fields
- else:
- # For backwards compatibility, return True if no user_profile
- return []
- except Exception as e:
- log.warning(f"Failed to get user_profile.invalid_fields for {userProfile['userId']}", exc_info=e)
- return []
-
-
-class AckNotificationSerializer(serializers.ModelSerializer):
- class Meta:
- model = models.User_Notifications
-
-
-def _notification_workspace_pb2():
- from airavata_sdk.generated.org.apache.airavata.model.workspace import (
- workspace_pb2,
- )
- return workspace_pb2
-
-
-class NotificationSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``Notification`` message."""
-
- notificationId = serializers.CharField(
- source='notification_id', read_only=True)
- gatewayId = serializers.CharField(
- source='gateway_id', allow_blank=True, allow_null=True, required=False)
- title = serializers.CharField(
- allow_blank=True, allow_null=True, required=False)
- notificationMessage = serializers.CharField(
- source='notification_message', allow_blank=True, allow_null=True,
- required=False)
- creationTime = ProtoTimestampField(
- source='creation_time', null_if_zero=True, required=False)
- publishedTime = ProtoTimestampField(source='published_time', required=False)
- expirationTime = ProtoTimestampField(source='expiration_time', required=False)
- # priority renders as the member NAME (proto LOW/NORMAL/HIGH == Thrift names).
- priority = proto_enum_name_field(
- _notification_workspace_pb2().NotificationPriority.DESCRIPTOR,
- proto_prefix='NOTIFICATION_PRIORITY_', required=False)
- url = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:manage-notifications-detail',
- lookup_field='notification_id',
- lookup_url_kwarg='notification_id')
- userHasWriteAccess = serializers.SerializerMethodField()
- showInDashboard = serializers.SerializerMethodField()
-
- def get_userHasWriteAccess(self, notification):
- request = self.context['request']
- return request.is_gateway_admin
-
- def get_showInDashboard(self, notification):
- extensions = models.NotificationExtension.objects.filter(
- notification_id=notification.notification_id)
- return bool(extensions) and extensions[0].showInDashboard
-
- def validate(self, attrs):
- attrs.pop("showInDashboard", None)
- return attrs
-
- def create(self, validated_data):
- w = _notification_workspace_pb2()
- return w.Notification(
- gateway_id=validated_data.get('gateway_id', '') or '',
- title=validated_data.get('title', '') or '',
- notification_message=validated_data.get(
- 'notification_message', '') or '',
- creation_time=validated_data.get('creation_time', 0) or 0,
- published_time=validated_data.get('published_time', 0) or 0,
- expiration_time=validated_data.get('expiration_time', 0) or 0,
- priority=validated_data.get('priority', 0) or 0,
- )
-
- def update(self, instance, validated_data):
- for proto_field in ('gateway_id', 'title', 'notification_message',
- 'creation_time', 'published_time', 'expiration_time',
- 'priority'):
- if proto_field in validated_data:
- value = validated_data[proto_field]
- if proto_field.endswith('_time') or proto_field == 'priority':
- value = value or 0
- else:
- value = value or ''
- setattr(instance, proto_field, value)
- return instance
-
- def update_notification_extension(self, request, notification):
- if "showInDashboard" in request.data:
- existing_entries = models.NotificationExtension.objects.filter(
- notification_id=notification.notification_id)
-
- if len(existing_entries) > 0:
- existing_entries.update(
- showInDashboard=request.data["showInDashboard"]
- )
- else:
- models.NotificationExtension.objects.create(
- notification_id=notification.notification_id,
- showInDashboard=request.data["showInDashboard"]
- )
-
-
-class ExperimentStatisticsSerializer(serializers.Serializer):
- """Proto-native serializer for the gRPC ``ExperimentStatistics`` message."""
-
- allExperimentCount = serializers.IntegerField(
- source='all_experiment_count', read_only=True)
- completedExperimentCount = serializers.IntegerField(
- source='completed_experiment_count', read_only=True)
- cancelledExperimentCount = serializers.IntegerField(
- source='cancelled_experiment_count', read_only=True)
- failedExperimentCount = serializers.IntegerField(
- source='failed_experiment_count', read_only=True)
- createdExperimentCount = serializers.IntegerField(
- source='created_experiment_count', read_only=True)
- runningExperimentCount = serializers.IntegerField(
- source='running_experiment_count', read_only=True)
- allExperiments = BaseExperimentSummarySerializer(
- source='all_experiments', many=True, read_only=True)
- completedExperiments = BaseExperimentSummarySerializer(
- source='completed_experiments', many=True, read_only=True)
- failedExperiments = BaseExperimentSummarySerializer(
- source='failed_experiments', many=True, read_only=True)
- cancelledExperiments = BaseExperimentSummarySerializer(
- source='cancelled_experiments', many=True, read_only=True)
- createdExperiments = BaseExperimentSummarySerializer(
- source='created_experiments', many=True, read_only=True)
- runningExperiments = BaseExperimentSummarySerializer(
- source='running_experiments', many=True, read_only=True)
-
-
-class UnverifiedEmailUserProfile(serializers.Serializer):
- userId = serializers.CharField()
- gatewayId = serializers.CharField()
- email = serializers.CharField()
- firstName = serializers.CharField()
- lastName = serializers.CharField()
- enabled = serializers.BooleanField()
- emailVerified = serializers.BooleanField()
- creationTime = UTCPosixTimestampDateTimeField()
- url = FullyEncodedHyperlinkedIdentityField(
- view_name='django_airavata_api:unverified-email-user-profile-detail',
- lookup_field='userId',
- lookup_url_kwarg='user_id')
- userHasWriteAccess = serializers.SerializerMethodField()
-
- def get_userHasWriteAccess(self, userProfile):
- request = self.context['request']
- return request.is_gateway_admin
-
-
-class LogRecordSerializer(serializers.Serializer):
- level = serializers.CharField()
- message = serializers.CharField()
- details = StoredJSONField()
- stacktrace = serializers.ListField(child=serializers.CharField())
-
-
-class SettingsSerializer(serializers.Serializer):
- fileUploadMaxFileSize = serializers.IntegerField()
- tusEndpoint = serializers.CharField()
- pgaUrl = serializers.CharField()
-
-
-class QueueSettingsCalculatorSerializer(serializers.Serializer):
- id = serializers.CharField()
- name = serializers.CharField()
+def application_preferences_data(application_preferences):
+ # Same field set the old ModelSerializer emitted (exclude id/username/fk).
+ return {
+ 'application_id': application_preferences.application_id,
+ 'favorite': application_preferences.favorite,
+ }
+
+
+def workspace_preferences_data(workspace_preferences):
+ # Read-only; matches the old ModelSerializer (exclude username, nest the
+ # application_preferences child list).
+ return {
+ 'most_recent_project_id':
+ workspace_preferences.most_recent_project_id,
+ 'most_recent_group_resource_profile_id':
+ workspace_preferences.most_recent_group_resource_profile_id,
+ 'most_recent_compute_resource_id':
+ workspace_preferences.most_recent_compute_resource_id,
+ 'application_preferences': [
+ application_preferences_data(ap)
+ for ap in workspace_preferences.applicationpreferences_set.all()],
+ }
+
+
+# IAM user write path (read/output is the SDK pydantic IAMUser). The old
+# camelCase IAMUserProfile body is validated for its required field set; the
+# group-membership diff drives the add/remove the view applies.
+_IAM_USER_REQUIRED_FIELDS = (
+ 'airavataInternalUserId', 'userId', 'gatewayId', 'email', 'firstName',
+ 'lastName', 'enabled', 'emailVerified', 'airavataUserProfileExists',
+ 'creationTime', 'groups',
+)
+
+
+def validate_iam_user_body(data):
+ """Validate the camelCase IAM user body, reproducing the old serializer's
+ required-field 400 shape (``{field: ['This field is required.']}``)."""
+ if not isinstance(data, dict):
+ raise ValidationError("Invalid request body.")
+ errors = {}
+ for field in _IAM_USER_REQUIRED_FIELDS:
+ if data.get(field) is None:
+ errors[field] = ['This field is required.']
+ if errors:
+ raise ValidationError(errors)
+ return data
+
+
+def iam_user_group_diff(existing_groups, data):
+ """Compute the added/removed group-id diff the view applies.
+
+ ``existing_groups`` are the proto ``GroupModel`` objects the user belongs to;
+ the new ids are read from the request ``groups`` dicts by ``id`` (the field
+ the frontend sends). Returns ``(added_group_ids, removed_group_ids)``.
+ """
+ existing_group_ids = [group.id for group in existing_groups]
+ new_group_ids = [group['id'] for group in data.get('groups', [])]
+ added_group_ids = list(set(new_group_ids) - set(existing_group_ids))
+ removed_group_ids = list(set(existing_group_ids) - set(new_group_ids))
+ return added_group_ids, removed_group_ids
+
+
+def parse_update_username(data):
+ """Validate an update-username body (the full profile plus ``newUsername``),
+ returning ``(user_id, new_username)``."""
+ validated = validate_iam_user_body(data)
+ new_username = validated.get('newUsername')
+ if not new_username:
+ raise ValidationError({'newUsername': ['This field is required.']})
+ return validated['userId'], new_username
+
+
+class ValidationError(Exception):
+ """Carries a DRF-style error mapping (``{field: [messages]}`` or a string)
+ so plain validators can produce the 400 body the frontend expects."""
+
+ def __init__(self, detail):
+ self.detail = detail
+ super().__init__(detail)
+
+
+def settings_data(file_upload_max_file_size, tus_endpoint, pga_url):
+ # camelCase keys preserved verbatim (frontend Settings.js contract).
+ return {
+ 'fileUploadMaxFileSize': file_upload_max_file_size,
+ 'tusEndpoint': tus_endpoint,
+ 'pgaUrl': pga_url,
+ }
+
+
+def parse_log_record(data):
+ """Validate a posted frontend log record, preserving the legacy
+ ``LogRecordSerializer`` shape. ``details`` is stored as a JSON string (the
+ old ``StoredJSONField.to_internal_value``) for logging; ``render_log_record``
+ decodes it back for the echo response.
+ """
+ errors = {}
+ if not isinstance(data, dict):
+ raise ValidationError("Invalid log record.")
+ level = data.get('level')
+ message = data.get('message')
+ stacktrace = data.get('stacktrace')
+ if not level:
+ errors['level'] = ['This field is required.']
+ if not message:
+ errors['message'] = ['This field is required.']
+ if 'details' not in data:
+ errors['details'] = ['This field is required.']
+ if stacktrace is None:
+ errors['stacktrace'] = ['This field is required.']
+ elif not isinstance(stacktrace, list):
+ errors['stacktrace'] = ['Expected a list of items.']
+ if errors:
+ raise ValidationError(errors)
+ try:
+ details = json.dumps(data['details'])
+ except (TypeError, ValueError):
+ raise ValidationError({'details': ['Value must be valid JSON.']})
+ return {
+ 'level': level,
+ 'message': message,
+ 'details': details,
+ 'stacktrace': [str(s) for s in stacktrace],
+ }
+
+
+def render_log_record(validated):
+ # Mirror the old serializer's read path: details JSON-decoded, rest verbatim.
+ try:
+ details = json.loads(validated['details']) if validated['details'] else validated['details']
+ except Exception:
+ details = validated['details']
+ return {
+ 'level': validated['level'],
+ 'message': validated['message'],
+ 'details': details,
+ 'stacktrace': validated['stacktrace'],
+ }
+
+
+def queue_settings_calculator_data(calculator):
+ return {'id': calculator.id, 'name': calculator.name}
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationDeploymentDescription.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationDeploymentDescription.js
index 87561c555..6ae994281 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationDeploymentDescription.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationDeploymentDescription.js
@@ -4,56 +4,57 @@ import CommandObject from "./CommandObject";
import SetEnvPaths from "./SetEnvPaths";
const FIELDS = [
- "appDeploymentId",
- "appModuleId",
- "computeHostId",
- "executablePath",
+ "app_deployment_id",
+ "app_module_id",
+ "compute_host_id",
+ "executable_path",
{
name: "parallelism",
type: ParallelismType,
default: ParallelismType.SERIAL,
},
- "appDeploymentDescription",
+ "app_deployment_description",
{
- name: "moduleLoadCmds",
+ name: "module_load_cmds",
type: CommandObject,
list: true,
},
{
- name: "libPrependPaths",
+ name: "lib_prepend_paths",
type: SetEnvPaths,
list: true,
},
{
- name: "libAppendPaths",
+ name: "lib_append_paths",
type: SetEnvPaths,
list: true,
},
{
- name: "setEnvironment",
+ name: "set_environment",
type: SetEnvPaths,
list: true,
},
{
- name: "preJobCommands",
+ name: "pre_job_commands",
type: CommandObject,
list: true,
},
{
- name: "postJobCommands",
+ name: "post_job_commands",
type: CommandObject,
list: true,
},
- "defaultQueueName",
- "defaultNodeCount",
- "defaultCPUCount",
- "defaultWalltime",
+ "default_queue_name",
+ "default_node_count",
+ "default_cpu_count",
+ "default_walltime",
{
- name: "editableByUser",
+ name: "editable_by_user",
type: "boolean",
default: false,
},
- "userHasWriteAccess",
+ // WithAccess-merged scalar (not on the proto).
+ "user_has_write_access",
];
export default class ApplicationDeploymentDescription extends BaseModel {
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationInterfaceDefinition.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationInterfaceDefinition.js
index d75164cb0..0d9af0091 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationInterfaceDefinition.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationInterfaceDefinition.js
@@ -5,47 +5,51 @@ import DataType from "./DataType";
import Experiment from "./Experiment";
const FIELDS = [
- "applicationInterfaceId",
- "applicationName",
- "applicationDescription",
+ "application_interface_id",
+ "application_name",
+ "application_description",
{
- name: "applicationModules",
+ name: "application_modules",
type: "string",
list: true,
},
- // When saving/updating, the order of the inputs in the applicationInputs
- // array determines the 'inputOrder' that will be applied to each input on the
- // backend. Updating 'inputOrder' will have no effect.
+ // When saving/updating, the order of the inputs in the application_inputs
+ // array determines the 'input_order' that will be applied to each input on
+ // the backend. Updating 'input_order' will have no effect.
{
- name: "applicationInputs",
+ name: "application_inputs",
type: InputDataObjectType,
list: true,
default: BaseModel.defaultNewInstance(Array),
},
{
- name: "applicationOutputs",
+ name: "application_outputs",
type: OutputDataObjectType,
list: true,
default: BaseModel.defaultNewInstance(Array),
},
{
- name: "archiveWorkingDirectory",
+ name: "archive_working_directory",
type: "boolean",
default: false,
},
{
- name: "hasOptionalFileInputs",
+ name: "has_optional_file_inputs",
type: "boolean",
default: false,
},
- "userHasWriteAccess",
+ // WithAccess-merged scalar (not on the proto).
+ "user_has_write_access",
+ // Portal-only queue-settings overrides: not on the proto and not merged into
+ // the read response; the backend persists them from the write request body
+ // (snake_case keys) into the ApplicationSettings model.
{
- name: "showQueueSettings",
+ name: "show_queue_settings",
type: "boolean",
default: true,
},
{
- name: "queueSettingsCalculatorId",
+ name: "queue_settings_calculator_id",
type: "string",
default: null,
},
@@ -77,26 +81,26 @@ export default class ApplicationInterfaceDefinition extends BaseModel {
},
},
});
- if (!this.applicationOutputs) {
- this.applicationOutputs = [];
+ if (!this.application_outputs) {
+ this.application_outputs = [];
}
- this.applicationOutputs.push(stdout, stderr);
+ this.application_outputs.push(stdout, stderr);
}
createExperiment() {
const experiment = new Experiment();
experiment.populateInputsOutputsFromApplicationInterface(this);
- experiment.executionId = this.applicationInterfaceId;
+ experiment.execution_id = this.application_interface_id;
return experiment;
}
get applicationModuleId() {
- if (!this.applicationModules || this.applicationModules.length > 1) {
+ if (!this.application_modules || this.application_modules.length > 1) {
throw new Error(
`No unique application module exists for interface
- ${this.applicationName}: modules=${this.applicationModules}`
+ ${this.application_name}: modules=${this.application_modules}`
);
}
- return this.applicationModules[0];
+ return this.application_modules[0];
}
}
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationModule.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationModule.js
index b7fe38c12..f60ce9b13 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationModule.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationModule.js
@@ -1,11 +1,12 @@
import BaseModel from "./BaseModel";
const FIELDS = [
- "appModuleId",
- "appModuleName",
- "appModuleVersion",
- "appModuleDescription",
- "userHasWriteAccess",
+ "app_module_id",
+ "app_module_name",
+ "app_module_version",
+ "app_module_description",
+ // WithAccess-merged scalar (not on the proto).
+ "user_has_write_access",
];
export default class ApplicationModule extends BaseModel {
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/AwsComputeResourcePreference.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/AwsComputeResourcePreference.js
index 8ba728871..2cb7e8159 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/AwsComputeResourcePreference.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/AwsComputeResourcePreference.js
@@ -2,8 +2,8 @@ import BaseModel from "./BaseModel";
const FIELDS = [
"region",
- "preferredAmiId",
- "preferredInstanceType",
+ "preferred_ami_id",
+ "preferred_instance_type",
];
export default class AwsComputeResourcePreference extends BaseModel {
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/BaseEnum.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/BaseEnum.js
index b48822d21..4838911ba 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/BaseEnum.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/BaseEnum.js
@@ -1,5 +1,4 @@
export default class BaseEnum {
- // TODO: add parameter
constructor(name, value, writeName = false) {
this.name = name;
this.value = value;
@@ -10,21 +9,38 @@ export default class BaseEnum {
toJSON() {
return this.writeName ? this.name : this.value;
}
+ // Wire enum values are full proto member names ("EXPERIMENT_STATE_EXECUTING");
+ // byName also accepts the stripped short alias ("EXECUTING") so component-level
+ // constant lookups keep resolving.
static byName(name) {
- return this.values.find((x) => x.name === name);
+ return (
+ this.values.find((x) => x.name === name) ||
+ this.values.find((x) => this.shortAlias(x.name) === name)
+ );
}
static byValue(value) {
return this.values.find((x) => x.value === value);
}
- // This must be called to initialize static methods on the Enum subclass
+
+ // The 0-sentinel is the only member that always carries the full
+ // SCREAMING_SNAKE(className) prefix; non-zero members carry it inconsistently
+ // (ExperimentState.EXPERIMENT_STATE_CREATED, but DataType.STRING). Strip the
+ // prefix when present so `ExperimentState.EXECUTING` resolves either way.
+ static shortAlias(name) {
+ const prefix = this.name.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toUpperCase() + "_";
+ return name.startsWith(prefix) ? name.slice(prefix.length) : name;
+ }
+
+ // names: full proto member names in proto order. Each value is registered
+ // under its full name AND aliased to its stripped short name on the class, so
+ // both byName(fullName)/this[fullName] and this[shortName] resolve.
static init(names, writeName = false) {
const enums = names.map((name, index) => new this(name, index, writeName));
Object.freeze(enums);
- Object.defineProperty(this, "values", {
- get: function () {
- return enums;
- },
+ Object.defineProperty(this, "values", { get: () => enums });
+ this.values.forEach((v) => {
+ this[v.name] = v;
+ this[this.shortAlias(v.name)] = v;
});
- this.values.forEach((v) => (this[v.name] = v));
}
}
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js
index 571a2afd6..0d00c166c 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js
@@ -71,9 +71,12 @@ export default class BaseModel {
}
convertDateField(fieldValue, fieldDefault) {
- return typeof fieldValue !== "undefined"
- ? new Date(fieldValue)
- : fieldDefault;
+ // Wire timestamps are epoch-millis strings ("1705320000000", "0" for unset);
+ // new Date(millisString) would parse it as a date string and yield Invalid Date.
+ if (fieldValue === null || typeof fieldValue === "undefined") {
+ return fieldDefault;
+ }
+ return new Date(Number(fieldValue));
}
convertModelField(modelClass, fieldValue, fieldDefault) {
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/BatchQueue.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/BatchQueue.js
index 0f31b6a0c..a7d0209cf 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/BatchQueue.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/BatchQueue.js
@@ -1,19 +1,19 @@
import BaseModel from "./BaseModel";
const FIELDS = [
- "queueName",
- "queueDescription",
- "maxRunTime",
- "maxNodes",
- "maxProcessors",
- "maxJobsInQueue",
- "maxMemory",
- "cpuPerNode",
- "defaultNodeCount",
- "defaultCPUCount",
- "defaultWalltime",
- "queueSpecificMacros",
- "isDefaultQueue",
+ "queue_name",
+ "queue_description",
+ "max_run_time",
+ "max_nodes",
+ "max_processors",
+ "max_jobs_in_queue",
+ "max_memory",
+ "cpu_per_node",
+ "default_node_count",
+ "default_cpu_count",
+ "default_walltime",
+ "queue_specific_macros",
+ "is_default_queue",
];
export default class BatchQueue extends BaseModel {
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/BatchQueueResourcePolicy.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/BatchQueueResourcePolicy.js
index 3cf8f262d..f6496176d 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/BatchQueueResourcePolicy.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/BatchQueueResourcePolicy.js
@@ -1,13 +1,13 @@
import BaseModel from "./BaseModel";
const FIELDS = [
- "resourcePolicyId",
- "computeResourceId",
- "groupResourceProfileId",
+ "resource_policy_id",
+ "compute_resource_id",
+ "group_resource_profile_id",
"queuename",
- "maxAllowedNodes",
- "maxAllowedCores",
- "maxAllowedWalltime",
+ "max_allowed_nodes",
+ "max_allowed_cores",
+ "max_allowed_walltime",
];
export default class BatchQueueResourcePolicy extends BaseModel {
@@ -17,26 +17,26 @@ export default class BatchQueueResourcePolicy extends BaseModel {
validate(batchQueue) {
let validationResults = {};
- if (this.maxAllowedNodes && this.maxAllowedNodes < 1) {
- validationResults["maxAllowedNodes"] = "Must be at least 1.";
- } else if (this.maxAllowedNodes > batchQueue.maxNodes) {
+ if (this.max_allowed_nodes && this.max_allowed_nodes < 1) {
+ validationResults["max_allowed_nodes"] = "Must be at least 1.";
+ } else if (this.max_allowed_nodes > batchQueue.max_nodes) {
validationResults[
- "maxAllowedNodes"
- ] = `Must be at most ${batchQueue.maxNodes}.`;
+ "max_allowed_nodes"
+ ] = `Must be at most ${batchQueue.max_nodes}.`;
}
- if (this.maxAllowedCores && this.maxAllowedCores < 1) {
- validationResults["maxAllowedCores"] = "Must be at least 1.";
- } else if (this.maxAllowedCores > batchQueue.maxProcessors) {
+ if (this.max_allowed_cores && this.max_allowed_cores < 1) {
+ validationResults["max_allowed_cores"] = "Must be at least 1.";
+ } else if (this.max_allowed_cores > batchQueue.max_processors) {
validationResults[
- "maxAllowedCores"
- ] = `Must be at most ${batchQueue.maxProcessors}.`;
+ "max_allowed_cores"
+ ] = `Must be at most ${batchQueue.max_processors}.`;
}
- if (this.maxAllowedWalltime && this.maxAllowedWalltime < 1) {
- validationResults["maxAllowedWalltime"] = "Must be at least 1.";
- } else if (this.maxAllowedWalltime > batchQueue.maxRunTime) {
+ if (this.max_allowed_walltime && this.max_allowed_walltime < 1) {
+ validationResults["max_allowed_walltime"] = "Must be at least 1.";
+ } else if (this.max_allowed_walltime > batchQueue.max_run_time) {
validationResults[
- "maxAllowedWalltime"
- ] = `Must be at most ${batchQueue.maxRunTime}.`;
+ "max_allowed_walltime"
+ ] = `Must be at most ${batchQueue.max_run_time}.`;
}
return validationResults;
}
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/CommandObject.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/CommandObject.js
index fbd43fb75..9ef8163ad 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/CommandObject.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/CommandObject.js
@@ -1,7 +1,7 @@
import BaseModel from "./BaseModel";
import uuidv4 from "uuid/v4";
-const FIELDS = ["command", "commandOrder"];
+const FIELDS = ["command", "command_order"];
export default class CommandObject extends BaseModel {
constructor(data = {}) {
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ComputationalResourceSchedulingModel.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ComputationalResourceSchedulingModel.js
index 5df9bc237..2a88cc8fe 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ComputationalResourceSchedulingModel.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ComputationalResourceSchedulingModel.js
@@ -1,18 +1,19 @@
import BaseModel from "./BaseModel";
const FIELDS = [
- "resourceHostId",
- "totalCPUCount",
- "nodeCount",
- "numberOfThreads",
- "queueName",
- "wallTimeLimit",
- "totalPhysicalMemory",
- "chessisNumber",
- "staticWorkingDir",
- "overrideLoginUserName",
- "overrideScratchLocation",
- "overrideAllocationProjectNumber",
+ "resource_host_id",
+ "total_cpu_count",
+ "node_count",
+ "number_of_threads",
+ "queue_name",
+ "wall_time_limit",
+ "total_physical_memory",
+ "chessis_number",
+ "static_working_dir",
+ "override_login_user_name",
+ "override_scratch_location",
+ "override_allocation_project_number",
+ "m_group_count",
];
export default class ComputationalResourceSchedulingModel extends BaseModel {
@@ -22,78 +23,80 @@ export default class ComputationalResourceSchedulingModel extends BaseModel {
validate(queueInfo = null, batchQueueResourcePolicy = null) {
const validationResults = {};
- if (this.isEmpty(this.resourceHostId)) {
- validationResults["resourceHostId"] = "Please select a compute resource.";
+ if (this.isEmpty(this.resource_host_id)) {
+ validationResults["resource_host_id"] =
+ "Please select a compute resource.";
}
- if (this.isEmpty(this.queueName)) {
- validationResults["queueName"] = "Please select a queue.";
+ if (this.isEmpty(this.queue_name)) {
+ validationResults["queue_name"] = "Please select a queue.";
}
- if (!(this.nodeCount > 0)) {
- validationResults["nodeCount"] = "Enter a node count greater than 0.";
+ if (!(this.node_count > 0)) {
+ validationResults["node_count"] = "Enter a node count greater than 0.";
} else if (
batchQueueResourcePolicy &&
- this.nodeCount > batchQueueResourcePolicy.maxAllowedNodes
+ this.node_count > batchQueueResourcePolicy.max_allowed_nodes
) {
validationResults[
- "nodeCount"
- ] = `Enter a node count no greater than ${batchQueueResourcePolicy.maxAllowedNodes}.`;
+ "node_count"
+ ] = `Enter a node count no greater than ${batchQueueResourcePolicy.max_allowed_nodes}.`;
} else if (
queueInfo &&
- queueInfo.maxNodes &&
- this.nodeCount > queueInfo.maxNodes
+ queueInfo.max_nodes &&
+ this.node_count > queueInfo.max_nodes
) {
validationResults[
- "nodeCount"
- ] = `Enter a node count no greater than ${queueInfo.maxNodes}.`;
+ "node_count"
+ ] = `Enter a node count no greater than ${queueInfo.max_nodes}.`;
}
- if (!(this.totalCPUCount > 0)) {
- validationResults["totalCPUCount"] = "Enter a core count greater than 0.";
+ if (!(this.total_cpu_count > 0)) {
+ validationResults["total_cpu_count"] =
+ "Enter a core count greater than 0.";
} else if (
batchQueueResourcePolicy &&
- this.totalCPUCount > batchQueueResourcePolicy.maxAllowedCores
+ this.total_cpu_count > batchQueueResourcePolicy.max_allowed_cores
) {
validationResults[
- "totalCPUCount"
- ] = `Enter a core count no greater than ${batchQueueResourcePolicy.maxAllowedCores}.`;
+ "total_cpu_count"
+ ] = `Enter a core count no greater than ${batchQueueResourcePolicy.max_allowed_cores}.`;
} else if (
queueInfo &&
- queueInfo.maxProcessors &&
- this.totalCPUCount > queueInfo.maxProcessors
+ queueInfo.max_processors &&
+ this.total_cpu_count > queueInfo.max_processors
) {
validationResults[
- "totalCPUCount"
- ] = `Enter a core count no greater than ${queueInfo.maxProcessors}.`;
+ "total_cpu_count"
+ ] = `Enter a core count no greater than ${queueInfo.max_processors}.`;
}
- if (!(this.wallTimeLimit > 0)) {
- validationResults["wallTimeLimit"] =
+ if (!(this.wall_time_limit > 0)) {
+ validationResults["wall_time_limit"] =
"Enter a wall time limit greater than 0.";
} else if (
batchQueueResourcePolicy &&
- this.wallTimeLimit > batchQueueResourcePolicy.maxAllowedWalltime
+ this.wall_time_limit > batchQueueResourcePolicy.max_allowed_walltime
) {
validationResults[
- "wallTimeLimit"
- ] = `Enter a wall time limit no greater than ${batchQueueResourcePolicy.maxAllowedWalltime}.`;
+ "wall_time_limit"
+ ] = `Enter a wall time limit no greater than ${batchQueueResourcePolicy.max_allowed_walltime}.`;
} else if (
queueInfo &&
- queueInfo.maxRunTime &&
- this.wallTimeLimit > queueInfo.maxRunTime
+ queueInfo.max_run_time &&
+ this.wall_time_limit > queueInfo.max_run_time
) {
validationResults[
- "wallTimeLimit"
- ] = `Enter a wall time limit no greater than ${queueInfo.maxRunTime}.`;
+ "wall_time_limit"
+ ] = `Enter a wall time limit no greater than ${queueInfo.max_run_time}.`;
}
- if (!(this.totalPhysicalMemory >= 0)) {
- validationResults["totalPhysicalMemory"] =
+ if (!(this.total_physical_memory >= 0)) {
+ validationResults["total_physical_memory"] =
"Enter a total physical memory greater than or equal to 0.";
} else if (
queueInfo &&
- queueInfo.maxMemory &&
- this.totalPhysicalMemory > queueInfo.maxMemory
+ queueInfo.max_memory &&
+ this.total_physical_memory > queueInfo.max_memory
) {
validationResults[
- "totalPhysicalMemory"
- ] = `Enter a total physical memory no greater than ${queueInfo.maxMemory}.`;
+ "total_physical_memory"
+ ] = `Enter a total physical memory no greater than ${queueInfo.max_memory}.`;
}
return validationResults;
}
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ComputeResourceDescription.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ComputeResourceDescription.js
index 81b751cd6..70b0a58ab 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ComputeResourceDescription.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ComputeResourceDescription.js
@@ -2,37 +2,37 @@ import BaseModel from "./BaseModel";
import BatchQueue from "./BatchQueue";
const FIELDS = [
- "computeResourceId",
- "hostName",
+ "compute_resource_id",
+ "host_name",
{
- name: "hostAliases",
+ name: "host_aliases",
type: "string",
list: true,
},
{
- name: "ipAddresses",
+ name: "ip_addresses",
type: "string",
list: true,
},
- "resourceDescription",
+ "resource_description",
"enabled",
{
- name: "batchQueues",
+ name: "batch_queues",
type: BatchQueue,
list: true,
},
// TODO: map these
- // 'fileSystems',
- // 'jobSubmissionInterfaces',
- // 'dataMovementInterfaces',
- "maxMemoryPerNode",
- "gatewayUsageReporting",
- "gatewayUsageModuleLoadCommand",
- "gatewayUsageExecutable",
- "cpusPerNode",
- "defaultNodeCount",
- "defaultCPUCount",
- "defaultWalltime",
+ // 'file_systems',
+ // 'job_submission_interfaces',
+ // 'data_movement_interfaces',
+ "max_memory_per_node",
+ "gateway_usage_reporting",
+ "gateway_usage_module_load_command",
+ "gateway_usage_executable",
+ "cpus_per_node",
+ "default_node_count",
+ "default_cpu_count",
+ "default_walltime",
];
export default class ComputeResourceDescription extends BaseModel {
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ComputeResourcePolicy.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ComputeResourcePolicy.js
index b40d6a0e3..a1d34cd47 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ComputeResourcePolicy.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ComputeResourcePolicy.js
@@ -1,11 +1,11 @@
import BaseModel from "./BaseModel";
const FIELDS = [
- "resourcePolicyId",
- "computeResourceId",
- "groupResourceProfileId",
+ "resource_policy_id",
+ "compute_resource_id",
+ "group_resource_profile_id",
{
- name: "allowedBatchQueues",
+ name: "allowed_batch_queues",
type: "string",
list: true,
},
@@ -18,15 +18,15 @@ export default class ComputeResourcePolicy extends BaseModel {
populateParentIdsOnBatchQueueResourcePolicy(batchQueueResourcePolicy) {
// For new BatchQueueResourcePolicy instances, set the parent ids
- batchQueueResourcePolicy.groupResourceProfileId = this.groupResourceProfileId;
- batchQueueResourcePolicy.computeResourceId = this.computeResourceId;
+ batchQueueResourcePolicy.group_resource_profile_id = this.group_resource_profile_id;
+ batchQueueResourcePolicy.compute_resource_id = this.compute_resource_id;
return batchQueueResourcePolicy;
}
validate() {
let validationResults = {};
- if (!this.allowedBatchQueues || this.allowedBatchQueues.length === 0) {
- validationResults["allowedBatchQueues"] =
+ if (!this.allowed_batch_queues || this.allowed_batch_queues.length === 0) {
+ validationResults["allowed_batch_queues"] =
"Must select at least one queue.";
}
return validationResults;
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ComputeResourceReservation.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ComputeResourceReservation.js
index fbd7c5d82..613bc6579 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ComputeResourceReservation.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ComputeResourceReservation.js
@@ -9,21 +9,21 @@ function currentTimeTopOfHour() {
return d;
}
const FIELDS = [
- "reservationId",
- "reservationName",
+ "reservation_id",
+ "reservation_name",
{
- name: "queueNames",
+ name: "queue_names",
type: "string",
list: true,
},
{
- name: "startTime",
- type: Date,
+ name: "start_time",
+ type: "date",
default: () => currentTimeTopOfHour(),
},
{
- name: "endTime",
- type: Date,
+ name: "end_time",
+ type: "date",
default: () => currentTimeTopOfHour(),
},
];
@@ -38,28 +38,28 @@ export default class ComputeResourceReservation extends BaseModel {
}
validate() {
let validationResults = {};
- if (this.isEmpty(this.reservationName)) {
- validationResults["reservationName"] =
+ if (this.isEmpty(this.reservation_name)) {
+ validationResults["reservation_name"] =
"Please provide the name of this reservation.";
}
- if (this.startTime > this.endTime) {
- validationResults["endTime"] = "End time must be later than start time.";
+ if (this.start_time > this.end_time) {
+ validationResults["end_time"] = "End time must be later than start time.";
}
- if (this.isEmpty(this.queueNames)) {
- validationResults["queueNames"] = "Please select at least one queue.";
+ if (this.isEmpty(this.queue_names)) {
+ validationResults["queue_names"] = "Please select at least one queue.";
}
return validationResults;
}
get isExpired() {
const now = new Date();
- return now > this.endTime;
+ return now > this.end_time;
}
get isActive() {
const now = new Date();
- return this.startTime < now && now < this.endTime;
+ return this.start_time < now && now < this.end_time;
}
get isUpcoming() {
const now = new Date();
- return now < this.startTime;
+ return now < this.start_time;
}
}
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/CredentialSummary.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/CredentialSummary.js
index 83d38a988..aaa549d8e 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/CredentialSummary.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/CredentialSummary.js
@@ -6,16 +6,17 @@ const FIELDS = [
name: "type",
type: SummaryType,
},
- "gatewayId",
+ "gateway_id",
"username",
- "publicKey",
+ "public_key",
{
- name: "persistedTime",
- type: Date,
+ name: "persisted_time",
+ type: "date",
},
"token",
"description",
- "userHasWriteAccess",
+ // merged onto the proto server-side by the WithAccess envelope.
+ "user_has_write_access",
];
export default class CredentialSummary extends BaseModel {
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/DataProduct.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/DataProduct.js
index 507d5bdb8..bbef3076a 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/DataProduct.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/DataProduct.js
@@ -4,32 +4,37 @@ import DataReplicaLocation from "./DataReplicaLocation";
import URL from "url-parse";
const FIELDS = [
- "productUri",
- "gatewayId",
- "parentProductUri",
- "productName",
- "productDescription",
- "ownerName",
- "dataProductType",
- "productSize",
+ "product_uri",
+ "gateway_id",
+ "parent_product_uri",
+ "product_name",
+ "product_description",
+ "owner_name",
+ // wire enum NAME ("FILE" / "COLLECTION"); 0-sentinel "DATA_PRODUCT_TYPE_UNKNOWN".
+ "data_product_type",
+ "product_size",
{
- name: "creationTime",
+ name: "creation_time",
type: "date",
},
{
- name: "lastModifiedTime",
+ name: "last_modified_time",
type: "date",
},
- "productMetadata",
+ // proto map<string,string>, arrives as a JSON object (e.g. {"mime-type": ...}).
+ "product_metadata",
{
- name: "replicaLocations",
+ name: "replica_locations",
type: DataReplicaLocation,
list: true,
},
- "downloadURL",
- "isInputFileUpload",
- "filesize",
- "userHasWriteAccess",
+ // merged onto the proto server-side by the WithAccess envelope.
+ "is_owner",
+ {
+ name: "user_has_write_access",
+ type: "boolean",
+ default: true,
+ },
];
const FILENAME_REGEX = /[^/]+$/;
@@ -42,9 +47,9 @@ export default class DataProduct extends BaseModel {
}
get filename() {
- if (this.replicaLocations && this.replicaLocations.length > 0) {
- const firstReplicaLocation = this.replicaLocations[0];
- const fileURL = new URL(firstReplicaLocation.filePath);
+ if (this.replica_locations && this.replica_locations.length > 0) {
+ const firstReplicaLocation = this.replica_locations[0];
+ const fileURL = new URL(firstReplicaLocation.file_path);
const filenameMatch = FILENAME_REGEX.exec(fileURL.pathname);
if (filenameMatch) {
return filenameMatch[0];
@@ -62,8 +67,8 @@ export default class DataProduct extends BaseModel {
}
get mimeType() {
- return this.productMetadata && this.productMetadata["mime-type"]
- ? this.productMetadata["mime-type"]
+ return this.product_metadata && this.product_metadata["mime-type"]
+ ? this.product_metadata["mime-type"]
: null;
}
}
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/DataReplicaLocation.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/DataReplicaLocation.js
index 064fead2a..c3ed6c078 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/DataReplicaLocation.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/DataReplicaLocation.js
@@ -1,27 +1,30 @@
import BaseModel from "./BaseModel";
const FIELDS = [
- "replicaId",
- "productUri",
- "replicaName",
- "replicaDescription",
+ "replica_id",
+ "product_uri",
+ "replica_name",
+ "replica_description",
{
- name: "creationTime",
+ name: "creation_time",
type: "date",
},
{
- name: "lastModifiedTime",
+ name: "last_modified_time",
type: "date",
},
{
- name: "validUntilTime",
+ name: "valid_until_time",
type: "date",
},
- "replicaLocationCategory",
- "replicaPersistentType",
- "storageResourceId",
- "filePath",
- "replicaMetadata",
+ // wire enum NAMEs ("GATEWAY_DATA_STORE" / "TRANSIENT"); 0-sentinels are
+ // "REPLICA_LOCATION_CATEGORY_UNKNOWN" / "REPLICA_PERSISTENT_TYPE_UNKNOWN".
+ "replica_location_category",
+ "replica_persistent_type",
+ "storage_resource_id",
+ "file_path",
+ // proto map<string,string>, arrives as a JSON object.
+ "replica_metadata",
];
export default class DataReplicaLocation extends BaseModel {
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/DataType.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/DataType.js
index 78e425f37..80d70ade0 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/DataType.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/DataType.js
@@ -18,6 +18,7 @@ export default class DataType extends BaseEnum {
}
}
DataType.init([
+ "DATA_TYPE_UNKNOWN",
"STRING",
"INTEGER",
"FLOAT",
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ErrorModel.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ErrorModel.js
index 7b3d7765a..50fdb5714 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ErrorModel.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ErrorModel.js
@@ -1,16 +1,16 @@
import BaseModel from "./BaseModel";
const FIELDS = [
- "errorId",
+ "error_id",
{
- name: "creationTime",
+ name: "creation_time",
type: "date",
},
- "actualErrorMessage",
- "userFriendlyMessage",
- "transientOrPersistent",
+ "actual_error_message",
+ "user_friendly_message",
+ "transient_or_persistent",
{
- name: "rootCauseErrorIdList",
+ name: "root_cause_error_id_list",
type: "string",
list: true,
},
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/Experiment.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/Experiment.js
index 71696876a..a6b674438 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/Experiment.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/Experiment.js
@@ -8,50 +8,51 @@ import ProcessModel from "./ProcessModel";
import UserConfigurationData from "./UserConfigurationData";
const FIELDS = [
- "experimentId",
- "projectId",
- "gatewayId",
+ "experiment_id",
+ "project_id",
+ "gateway_id",
+ // wire enum NAME ("SINGLE_APPLICATION"); 0-sentinel "EXPERIMENT_TYPE_UNKNOWN".
{
- name: "experimentType",
- type: "number",
- default: 0,
+ name: "experiment_type",
+ type: "string",
+ default: "EXPERIMENT_TYPE_UNKNOWN",
},
- "userName",
- "experimentName",
+ "user_name",
+ "experiment_name",
{
- name: "creationTime",
+ name: "creation_time",
type: "date",
},
"description",
- "executionId",
+ "execution_id",
{
- name: "enableEmailNotification",
+ name: "enable_email_notification",
type: "boolean",
default: false,
},
{
- name: "emailAddresses",
+ name: "email_addresses",
type: "string",
list: true,
},
{
- name: "userConfigurationData",
+ name: "user_configuration_data",
type: UserConfigurationData,
default: BaseModel.defaultNewInstance(UserConfigurationData),
},
{
- name: "experimentInputs",
+ name: "experiment_inputs",
type: InputDataObjectType,
list: true,
default: BaseModel.defaultNewInstance(Array),
},
{
- name: "experimentOutputs",
+ name: "experiment_outputs",
type: OutputDataObjectType,
list: true,
},
{
- name: "experimentStatus",
+ name: "experiment_status",
type: ExperimentStatus,
list: true,
},
@@ -66,8 +67,9 @@ const FIELDS = [
list: true,
},
"workflow",
+ // merged onto the proto server-side by the WithAccess envelope.
{
- name: "userHasWriteAccess",
+ name: "user_has_write_access",
type: "boolean",
default: true,
},
@@ -81,19 +83,19 @@ export default class Experiment extends BaseModel {
validate() {
let validationResults = {};
- if (this.isEmpty(this.experimentName)) {
- validationResults["experimentName"] =
+ if (this.isEmpty(this.experiment_name)) {
+ validationResults["experiment_name"] =
"Please provide a name for this experiment.";
}
- if (this.isEmpty(this.projectId)) {
- validationResults["projectId"] = "Please select a project.";
+ if (this.isEmpty(this.project_id)) {
+ validationResults["project_id"] = "Please select a project.";
}
return validationResults;
}
get latestStatus() {
- if (this.experimentStatus && this.experimentStatus.length > 0) {
- return this.experimentStatus[this.experimentStatus.length - 1];
+ if (this.experiment_status && this.experiment_status.length > 0) {
+ return this.experiment_status[this.experiment_status.length - 1];
} else {
return null;
}
@@ -127,7 +129,7 @@ export default class Experiment extends BaseModel {
return (
(!this.latestStatus ||
this.latestStatus.state === ExperimentState.CREATED) &&
- this.userHasWriteAccess
+ this.user_has_write_access
);
}
@@ -144,40 +146,39 @@ export default class Experiment extends BaseModel {
}
get resourceHostId() {
- return this.userConfigurationData &&
- this.userConfigurationData.computationalResourceScheduling
- ? this.userConfigurationData.computationalResourceScheduling
- .resourceHostId
+ return this.user_configuration_data &&
+ this.user_configuration_data.computational_resource_scheduling
+ ? this.user_configuration_data.computational_resource_scheduling
+ .resource_host_id
: null;
}
populateInputsOutputsFromApplicationInterface(applicationInterface) {
- // Copy application inputs and outputs to the experiment
- this.experimentInputs = applicationInterface.applicationInputs.map(
+ this.experiment_inputs = applicationInterface.application_inputs.map(
(input) => input.clone()
);
this.evaluateInputDependencies();
- this.experimentOutputs = applicationInterface.applicationOutputs.slice();
+ this.experiment_outputs = applicationInterface.application_outputs.slice();
}
evaluateInputDependencies() {
- const inputValues = this._collectInputValues(this.experimentInputs);
- for (const input of this.experimentInputs) {
+ const inputValues = this._collectInputValues(this.experiment_inputs);
+ for (const input of this.experiment_inputs) {
input.evaluateDependencies(inputValues);
}
}
getExperimentInput(inputName) {
- return this.experimentInputs.find(inp => inp.name === inputName);
+ return this.experiment_inputs.find(inp => inp.name === inputName);
}
getExperimentOutput(outputName) {
- return this.experimentOutputs.find(out => out.name === outputName);
+ return this.experiment_outputs.find(out => out.name === outputName);
}
_collectInputValues() {
const result = {};
- this.experimentInputs.forEach((inp) => {
+ this.experiment_inputs.forEach((inp) => {
result[inp.name] = inp.value;
});
return result;
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentSearchFields.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentSearchFields.js
index 95b6b57c1..b4cb61147 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentSearchFields.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentSearchFields.js
@@ -2,6 +2,7 @@ import BaseEnum from "./BaseEnum";
export default class ExperimentSearchFields extends BaseEnum {}
ExperimentSearchFields.init([
+ "EXPERIMENT_SEARCH_FIELDS_UNKNOWN",
"EXPERIMENT_NAME",
"EXPERIMENT_DESC",
"APPLICATION_ID",
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentState.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentState.js
index 6ac0150e4..d8bec5ba1 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentState.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentState.js
@@ -20,13 +20,14 @@ export default class ExperimentState extends BaseEnum {
}
}
ExperimentState.init([
- "CREATED",
- "VALIDATED",
- "SCHEDULED",
- "LAUNCHED",
- "EXECUTING",
- "CANCELING",
- "CANCELED",
- "COMPLETED",
- "FAILED",
+ "EXPERIMENT_STATE_UNKNOWN",
+ "EXPERIMENT_STATE_CREATED",
+ "EXPERIMENT_STATE_VALIDATED",
+ "EXPERIMENT_STATE_SCHEDULED",
+ "EXPERIMENT_STATE_LAUNCHED",
+ "EXPERIMENT_STATE_EXECUTING",
+ "EXPERIMENT_STATE_CANCELING",
+ "EXPERIMENT_STATE_CANCELED",
+ "EXPERIMENT_STATE_COMPLETED",
+ "EXPERIMENT_STATE_FAILED",
]);
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStatistics.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStatistics.js
index 08bd5dd6a..00b758e18 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStatistics.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStatistics.js
@@ -2,38 +2,38 @@ import BaseModel from "./BaseModel";
import ExperimentSummary from "./ExperimentSummary";
const FIELDS = [
- "allExperimentCount",
- "completedExperimentCount",
- "cancelledExperimentCount",
- "failedExperimentCount",
- "createdExperimentCount",
- "runningExperimentCount",
+ "all_experiment_count",
+ "completed_experiment_count",
+ "cancelled_experiment_count",
+ "failed_experiment_count",
+ "created_experiment_count",
+ "running_experiment_count",
{
- name: "allExperiments",
+ name: "all_experiments",
type: ExperimentSummary,
list: true,
},
{
- name: "completedExperiments",
+ name: "completed_experiments",
type: ExperimentSummary,
list: true,
},
{
- name: "failedExperiments",
+ name: "failed_experiments",
type: ExperimentSummary,
list: true,
},
{
- name: "cancelledExperiments",
+ name: "cancelled_experiments",
type: ExperimentSummary,
list: true,
},
{
- name: "createdExperiments",
+ name: "created_experiments",
type: ExperimentSummary,
list: true,
},
- { name: "runningExperiments", type: ExperimentSummary, list: true },
+ { name: "running_experiments", type: ExperimentSummary, list: true },
];
export default class ExperimentStatistics extends BaseModel {
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStatus.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStatus.js
index a18761836..291110d09 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStatus.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStatus.js
@@ -7,11 +7,11 @@ const FIELDS = [
type: ExperimentState,
},
{
- name: "timeOfStateChange",
+ name: "time_of_state_change",
type: "date",
},
"reason",
- "statusId",
+ "status_id",
];
export default class ExperimentStatus extends BaseModel {
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentSummary.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentSummary.js
index 68d56a587..286e2feb8 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentSummary.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentSummary.js
@@ -4,28 +4,29 @@ import ExperimentStatus from "./ExperimentStatus";
import ExperimentState from "./ExperimentState";
const FIELDS = [
- "experimentId",
- "projectId",
- "gatewayId",
+ "experiment_id",
+ "project_id",
+ "gateway_id",
{
- name: "creationTime",
+ name: "creation_time",
type: "date",
},
- "userName",
+ "user_name",
"name",
"description",
- "executionId",
- "resourceHostId",
+ "execution_id",
+ "resource_host_id",
{
- name: "experimentStatus",
+ name: "experiment_status",
type: ExperimentState,
},
{
- name: "statusUpdateTime",
+ name: "status_update_time",
type: "date",
},
+ // merged onto the proto server-side by the WithAccess envelope.
{
- name: "userHasWriteAccess",
+ name: "user_has_write_access",
type: "boolean",
default: false,
},
@@ -42,16 +43,16 @@ export default class ExperimentSummary extends BaseModel {
convertToExperiment() {
// Purpose of this is to be able to access computed properties on
- // Experiment.js
+ // Experiment.js. The summary carries a single experiment_status enum +
+ // status_update_time; Experiment expects an experiment_status LIST of
+ // ExperimentStatus, so reshape those two while passing the rest through.
return new Experiment(
Object.assign({}, this, {
- // Most properties are named the same as on Experiment, but the
- // following require some conversion
- experimentName: this.name,
- experimentStatus: [
+ experiment_name: this.name,
+ experiment_status: [
new ExperimentStatus({
- state: this.experimentStatus,
- timeOfStateChange: this.statusUpdateTime,
+ state: this.experiment_status,
+ time_of_state_change: this.status_update_time,
}),
],
})
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/FullExperiment.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/FullExperiment.js
index 03aa10e38..34fff3c48 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/FullExperiment.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/FullExperiment.js
@@ -7,7 +7,7 @@ import Job from "./Job";
import Project from "./Project";
const FIELDS = [
- "experimentId",
+ "experiment_id",
{
name: "experiment",
type: Experiment,
@@ -17,30 +17,30 @@ const FIELDS = [
type: Project,
},
{
- name: "applicationModule",
+ name: "application_module",
type: ApplicationModule,
},
{
- name: "computeResource",
+ name: "compute_resource",
type: ComputeResourceDescription,
},
{
- name: "outputDataProducts",
+ name: "output_data_products",
type: DataProduct,
list: true,
},
{
- name: "inputDataProducts",
+ name: "input_data_products",
type: DataProduct,
list: true,
},
{
- name: "jobDetails",
+ name: "job_details",
type: Job,
list: true,
},
{
- name: "outputViews",
+ name: "output_views",
type: Object,
},
];
@@ -55,11 +55,13 @@ export default class FullExperiment extends BaseModel {
}
get applicationName() {
- return this.applicationModule ? this.applicationModule.appModuleName : null;
+ return this.application_module
+ ? this.application_module.app_module_name
+ : null;
}
get computeHostName() {
- return this.computeResource ? this.computeResource.hostName : null;
+ return this.compute_resource ? this.compute_resource.host_name : null;
}
get resourceHostId() {
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GatewayResourceProfile.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GatewayResourceProfile.js
index 35e881ffa..4e698efa6 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GatewayResourceProfile.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GatewayResourceProfile.js
@@ -2,17 +2,18 @@ import BaseModel from "./BaseModel";
import StoragePreference from "./StoragePreference";
const FIELDS = [
- "gatewayID",
- "credentialStoreToken",
- "computeResourcePreferences",
+ "gateway_id",
+ "credential_store_token",
+ "compute_resource_preferences",
{
- name: "storagePreferences",
+ name: "storage_preferences",
type: StoragePreference,
list: true,
},
- "identityServerTenant",
- "identityServerPwdCredToken",
- "userHasWriteAccess",
+ "identity_server_tenant",
+ "identity_server_pwd_cred_token",
+ // merged onto the proto server-side by the WithAccess envelope.
+ "user_has_write_access",
];
export default class GatewayResourceProfile extends BaseModel {
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/Group.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/Group.js
index 533745a5e..3f6d44da6 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/Group.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/Group.js
@@ -3,7 +3,7 @@ import BaseModel from "./BaseModel";
const FIELDS = [
"id",
"name",
- "ownerId",
+ "owner_id",
"description",
{
name: "members",
@@ -17,24 +17,26 @@ const FIELDS = [
list: true,
default: BaseModel.defaultNewInstance(Array),
},
+ // The six access flags are merged onto the GroupModel proto server-side by the
+ // WithGroupAccess envelope (not on the proto itself).
{
- name: "isOwner",
+ name: "is_owner",
type: "boolean",
default: true,
},
{
- name: "isAdmin",
+ name: "is_admin",
type: "boolean",
default: false,
},
{
- name: "isMember",
+ name: "is_member",
type: "boolean",
default: true,
},
- "isGatewayAdminsGroup",
- "isReadOnlyGatewayAdminsGroup",
- "isDefaultGatewayUsersGroup",
+ "is_gateway_admins_group",
+ "is_read_only_gateway_admins_group",
+ "is_default_gateway_users_group",
];
export default class Group extends BaseModel {
@@ -55,10 +57,10 @@ export default class Group extends BaseModel {
* Return true if group is either the "Gateway Admins" or the "Readonly Admins" group.
*/
get isAdminGroup() {
- return this.isReadOnlyGatewayAdminsGroup || this.isGatewayAdminsGroup;
+ return this.is_read_only_gateway_admins_group || this.is_gateway_admins_group;
}
get userHasWriteAccess() {
- return this.isOwner || this.isAdmin;
+ return this.is_owner || this.is_admin;
}
}
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GroupAccountSSHProvisionerConfig.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GroupAccountSSHProvisionerConfig.js
index d43346f7e..74d4b2c95 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GroupAccountSSHProvisionerConfig.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GroupAccountSSHProvisionerConfig.js
@@ -1,10 +1,10 @@
import BaseModel from "./BaseModel";
const FIELDS = [
- "resourceId",
- "groupResourceProfileId",
- "configName",
- "configValue",
+ "resource_id",
+ "group_resource_profile_id",
+ "config_name",
+ "config_value",
];
export default class GroupAccountSSHProvisionerConfig extends BaseModel {
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GroupComputeResourcePreference.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GroupComputeResourcePreference.js
index f13a317fe..0975be131 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GroupComputeResourcePreference.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GroupComputeResourcePreference.js
@@ -4,25 +4,26 @@ import SlurmComputeResourcePreference from "./SlurmComputeResourcePreference";
import AwsComputeResourcePreference from "./AwsComputeResourcePreference";
const FIELDS = [
- "computeResourceId",
- "groupResourceProfileId",
+ "compute_resource_id",
+ "group_resource_profile_id",
{
- name: "overridebyAiravata",
+ name: "override_by_airavata",
type: "boolean",
default: true,
},
- "loginUserName",
- "preferredJobSubmissionProtocol",
- "preferredDataMovementProtocol",
- "scratchLocation",
- "resourceSpecificCredentialStoreToken",
+ "login_user_name",
+ // wire enum member NAMES ("SSH"/"SFTP"); sentinels *_PROTOCOL_UNKNOWN.
+ "preferred_job_submission_protocol",
+ "preferred_data_movement_protocol",
+ "scratch_location",
+ "resource_specific_credential_store_token",
{
- name: "resourceType",
+ name: "resource_type",
type: ResourceType,
- required: true,
},
+ // oneof wrapper {slurm:{...}} | {aws:{...}}; coerced into a child model below.
{
- name: "specificPreferences",
+ name: "specific_preferences",
type: null,
},
];
@@ -34,153 +35,115 @@ const PREFERENCE_MODEL_MAP = {
export default class GroupComputeResourcePreference extends BaseModel {
constructor(data = {}) {
- const topLevelAllocationProjectNumber = data.allocationProjectNumber;
- const rawSpecificPreferences = data.specificPreferences;
+ const rawSpecificPreferences = data.specific_preferences;
super(FIELDS, data);
- const specificPrefsToUse = rawSpecificPreferences !== undefined && rawSpecificPreferences !== null
- ? rawSpecificPreferences
- : (data.specificPreferences !== undefined && data.specificPreferences !== null ? data.specificPreferences : null);
-
- if (specificPrefsToUse !== null) {
- this.specificPreferences = specificPrefsToUse;
- }
-
- if (this.resourceType && typeof this.resourceType === 'number') {
- this.resourceType = ResourceType.values.find(rt => rt.value === this.resourceType) || this.resourceType;
- }
-
- if (topLevelAllocationProjectNumber) {
- if (this.resourceType && this.resourceType.name === 'SLURM') {
- if (!this.specificPreferences) {
- this.specificPreferences = {};
- }
- if (typeof this.specificPreferences === 'object' && !(this.specificPreferences instanceof BaseModel)) {
- if (!this.specificPreferences.allocationProjectNumber) {
- this.specificPreferences.allocationProjectNumber = topLevelAllocationProjectNumber;
- }
- }
- } else if (!this.resourceType && topLevelAllocationProjectNumber) {
- this.resourceType = ResourceType.SLURM;
- if (!this.specificPreferences) {
- this.specificPreferences = {};
- }
- if (typeof this.specificPreferences === 'object' && !(this.specificPreferences instanceof BaseModel)) {
- if (!this.specificPreferences.allocationProjectNumber) {
- this.specificPreferences.allocationProjectNumber = topLevelAllocationProjectNumber;
- }
- }
- }
+ if (rawSpecificPreferences !== undefined && rawSpecificPreferences !== null) {
+ this.specific_preferences = rawSpecificPreferences;
}
this._coerceSpecificPreferences();
}
toJSON() {
- const json = {...this};
- if (this.resourceType && this.resourceType.value !== undefined) {
- json.resourceType = this.resourceType.value;
- } else if (this.resourceType && this.resourceType.name) {
- json.resourceType = this.resourceType.name;
+ const json = { ...this };
+ if (this.resource_type && this.resource_type.value !== undefined) {
+ json.resource_type = this.resource_type.value;
+ } else if (this.resource_type && this.resource_type.name) {
+ json.resource_type = this.resource_type.name;
}
- let specificPrefsPayload = this.specificPreferences;
+ let specificPrefsPayload = this.specific_preferences;
if (
- this.specificPreferences &&
- typeof this.specificPreferences.toJSON === "function"
+ this.specific_preferences &&
+ typeof this.specific_preferences.toJSON === "function"
) {
- specificPrefsPayload = this.specificPreferences.toJSON();
+ specificPrefsPayload = this.specific_preferences.toJSON();
}
+ // re-wrap into the proto oneof shape the wire expects.
if (specificPrefsPayload && this.isResourceType("SLURM")) {
- json.specificPreferences = {slurm: specificPrefsPayload};
+ json.specific_preferences = { slurm: specificPrefsPayload };
} else if (specificPrefsPayload && this.isResourceType("AWS")) {
- json.specificPreferences = {aws: specificPrefsPayload};
+ json.specific_preferences = { aws: specificPrefsPayload };
} else if (specificPrefsPayload) {
- json.specificPreferences = specificPrefsPayload;
+ json.specific_preferences = specificPrefsPayload;
} else {
- json.specificPreferences = null;
+ json.specific_preferences = null;
}
return json;
}
_coerceSpecificPreferences() {
- // Ensure resourceType is properly set
- if (this.resourceType && typeof this.resourceType === 'number') {
- this.resourceType = ResourceType.byValue(this.resourceType) || ResourceType.values.find(rt => rt.value === this.resourceType) || this.resourceType;
- }
-
- if (!this.resourceType) {
- this.specificPreferences = null;
+ if (!this.resource_type) {
+ this.specific_preferences = null;
return;
}
- if (!this.resourceType.name) {
+ if (!this.resource_type.name) {
return;
}
if (
- this.specificPreferences &&
- this.specificPreferences instanceof BaseModel
+ this.specific_preferences &&
+ this.specific_preferences instanceof BaseModel
) {
return;
}
let rawData =
- this.specificPreferences && typeof this.specificPreferences === "object"
- ? this.specificPreferences
+ this.specific_preferences && typeof this.specific_preferences === "object"
+ ? this.specific_preferences
: null;
+ // unwrap the proto oneof wrapper ({slurm:{...}} / {aws:{...}}).
if (rawData && !(rawData instanceof BaseModel)) {
- if (this.resourceType.name === 'SLURM' && 'slurm' in rawData) {
+ if (this.resource_type.name === "SLURM" && "slurm" in rawData) {
rawData = rawData.slurm;
- } else if (this.resourceType.name === 'AWS') {
- if ('aws' in rawData) {
- rawData = rawData.aws;
- }
+ } else if (this.resource_type.name === "AWS" && "aws" in rawData) {
+ rawData = rawData.aws;
}
}
- const PreferenceModel = PREFERENCE_MODEL_MAP[this.resourceType.name];
+ const PreferenceModel = PREFERENCE_MODEL_MAP[this.resource_type.name];
if (PreferenceModel) {
const newPref = rawData
? new PreferenceModel(rawData)
: new PreferenceModel();
- this.specificPreferences = newPref;
+ this.specific_preferences = newPref;
} else {
- this.specificPreferences = rawData;
+ this.specific_preferences = rawData;
}
}
resetSpecificPreferences(data = null) {
- if (!this.resourceType) {
- this.specificPreferences = null;
+ if (!this.resource_type) {
+ this.specific_preferences = null;
return;
}
if (data && typeof data === "object") {
- this.specificPreferences = data;
+ this.specific_preferences = data;
} else {
- this.specificPreferences = null;
+ this.specific_preferences = null;
}
this._coerceSpecificPreferences();
}
isResourceType(resourceTypeName) {
- return (
- !!this.resourceType && this.resourceType.name === resourceTypeName
- );
+ return !!this.resource_type && this.resource_type.name === resourceTypeName;
}
_ensureSpecificPreferences() {
- if (!this.specificPreferences) {
+ if (!this.specific_preferences) {
this._coerceSpecificPreferences();
}
}
+ // SLURM-only convenience accessors bridging into the child preference model.
_getSlurmField(fieldName, defaultValue) {
- if (this.isResourceType("SLURM") && this.specificPreferences) {
- return this.specificPreferences[fieldName];
+ if (this.isResourceType("SLURM") && this.specific_preferences) {
+ return this.specific_preferences[fieldName];
}
return defaultValue;
}
@@ -190,41 +153,41 @@ export default class GroupComputeResourcePreference extends BaseModel {
return;
}
this._ensureSpecificPreferences();
- if (this.specificPreferences) {
- this.specificPreferences[fieldName] = value;
+ if (this.specific_preferences) {
+ this.specific_preferences[fieldName] = value;
}
}
- get allocationProjectNumber() {
- return this._getSlurmField("allocationProjectNumber");
+ get allocation_project_number() {
+ return this._getSlurmField("allocation_project_number");
}
- set allocationProjectNumber(value) {
- this._setSlurmField("allocationProjectNumber", value);
+ set allocation_project_number(value) {
+ this._setSlurmField("allocation_project_number", value);
}
- get preferredBatchQueue() {
- return this._getSlurmField("preferredBatchQueue");
+ get preferred_batch_queue() {
+ return this._getSlurmField("preferred_batch_queue");
}
- set preferredBatchQueue(value) {
- this._setSlurmField("preferredBatchQueue", value);
+ set preferred_batch_queue(value) {
+ this._setSlurmField("preferred_batch_queue", value);
}
- get qualityOfService() {
- return this._getSlurmField("qualityOfService");
+ get quality_of_service() {
+ return this._getSlurmField("quality_of_service");
}
- set qualityOfService(value) {
- this._setSlurmField("qualityOfService", value);
+ set quality_of_service(value) {
+ this._setSlurmField("quality_of_service", value);
}
- get usageReportingGatewayId() {
- return this._getSlurmField("usageReportingGatewayId");
+ get usage_reporting_gateway_id() {
+ return this._getSlurmField("usage_reporting_gateway_id");
}
- set usageReportingGatewayId(value) {
- this._setSlurmField("usageReportingGatewayId", value);
+ set usage_reporting_gateway_id(value) {
+ this._setSlurmField("usage_reporting_gateway_id", value);
}
get reservations() {
@@ -237,18 +200,18 @@ export default class GroupComputeResourcePreference extends BaseModel {
validate() {
let validationResults = {};
- if (this.isEmpty(this.loginUserName)) {
- validationResults["loginUserName"] = "Please provide a login username.";
+ if (this.isEmpty(this.login_user_name)) {
+ validationResults["login_user_name"] = "Please provide a login username.";
}
- if (this.isEmpty(this.scratchLocation)) {
- validationResults["scratchLocation"] =
+ if (this.isEmpty(this.scratch_location)) {
+ validationResults["scratch_location"] =
"Please provide a scratch location.";
}
- if (!this.resourceType) {
- validationResults["resourceType"] = "Please select a resource type.";
+ if (!this.resource_type) {
+ validationResults["resource_type"] = "Please select a resource type.";
}
- if (this.resourceType && this.specificPreferences) {
- const specificValidation = this.specificPreferences.validate();
+ if (this.resource_type && this.specific_preferences) {
+ const specificValidation = this.specific_preferences.validate();
if (specificValidation && Object.keys(specificValidation).length > 0) {
Object.assign(validationResults, specificValidation);
}
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GroupPermission.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GroupPermission.js
index 14d38aadd..37e389ee4 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GroupPermission.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GroupPermission.js
@@ -10,8 +10,9 @@ export default class GroupPermission extends BaseModel {
name: "group",
type: Group,
},
+ // permission_type arrives as the enum member NAME string.
{
- name: "permissionType",
+ name: "permission_type",
type: ResourcePermissionType,
},
],
diff --git a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GroupResourceProfile.js b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GroupResourceProfile.js
index 4866dce7d..e9299a6ed 100644
--- a/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GroupResourceProfile.js
+++ b/airavata-django-portal/django_airavata/apps/api/static/django_airavata_api/js/models/GroupResourceProfile.js
@@ -4,37 +4,39 @@ import ComputeResourcePolicy from "./ComputeResourcePolicy";
import GroupComputeResourcePreference from "./GroupComputeResourcePreference";
const FIELDS = [
- "gatewayId",
- "groupResourceProfileId",
- "groupResourceProfileName",
+ "gateway_id",
+ "group_resource_profile_id",
+ "group_resource_profile_name",
{
- name: "computePreferences",
+ name: "compute_preferences",
type: GroupComputeResourcePreference,
list: true,
default: BaseModel.defaultNewInstance(Array),
},
{
- name: "computeResourcePolicies",
+ name: "compute_resource_policies",
type: ComputeResourcePolicy,
list: true,
... 18517 lines suppressed ...