From 3c7ebf11402cb4247f38fd564660313540a44ff1 Mon Sep 17 00:00:00 2001 From: Sal Tijerina Date: Tue, 3 Oct 2023 14:17:05 -0500 Subject: [PATCH 1/7] bug/WP-297: Fix site search for public and community data (#870) * fix site search for pub/community data * fix unit tests --------- Co-authored-by: Jake Rosenberg --- server/portal/apps/site_search/api/unit_test.py | 16 +++++++++++----- server/portal/apps/site_search/api/views.py | 11 +++++++---- server/portal/libs/agave/operations.py | 5 +++-- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/server/portal/apps/site_search/api/unit_test.py b/server/portal/apps/site_search/api/unit_test.py index 6f5f09668..b871a3e70 100644 --- a/server/portal/apps/site_search/api/unit_test.py +++ b/server/portal/apps/site_search/api/unit_test.py @@ -20,6 +20,11 @@ def mock_cms_search(mocker): yield mocked_fn +@pytest.fixture +def mock_service_account(mocker): + yield mocker.patch('portal.apps.site_search.api.views.service_account', autospec=True) + + @pytest.fixture def mock_files_search(mocker): mocked_fn = mocker.patch('portal.apps.site_search.api.views.files_search') @@ -76,7 +81,7 @@ def test_search_with_auth(regular_user, client, mock_cms_search, 'include': True}} -def test_search_no_auth(client, mock_cms_search, mock_files_search): +def test_search_no_auth(client, mock_cms_search, mock_files_search, mock_service_account): response = client.get('/api/site-search/?page=0&query_string=test') assert response.json() == { @@ -93,7 +98,7 @@ def test_search_no_auth(client, mock_cms_search, mock_files_search): def test_search_public(client, configure_public, mock_cms_search, - mock_files_search): + mock_files_search, mock_service_account): response = client.get('/api/site-search/?page=0&query_string=test') assert response.json() == { @@ -132,15 +137,16 @@ def test_cms_search_util(mock_dsl_search): 'highlight': {'body': ['highlight 1']}}]) -def test_file_search_util(mock_file_search): +def test_file_search_util(mock_file_search, regular_user): from portal.apps.site_search.api.views import files_search mock_file_search.return_value = {'count': 1, 'listing': [{'name': 'testfile', 'path': '/path/to/testfile'}]} - res = files_search('test_query', 'test_system') + client = regular_user.tapis_oauth.client + res = files_search(client, 'test_query', 'test_system') - mock_file_search.assert_called_with(None, 'test_system', '/', + mock_file_search.assert_called_with(client, 'test_system', '/', query_string='test_query', filter=None, offset=0, diff --git a/server/portal/apps/site_search/api/views.py b/server/portal/apps/site_search/api/views.py index 061e71db4..7203e15e2 100644 --- a/server/portal/apps/site_search/api/views.py +++ b/server/portal/apps/site_search/api/views.py @@ -3,6 +3,7 @@ from portal.libs.agave.operations import search as search_operation from portal.views.base import BaseApiView from django.conf import settings +from portal.libs.agave.utils import service_account import logging logger = logging.getLogger(__name__) @@ -35,8 +36,8 @@ def cms_search(query_string, offset=0, limit=10): return total, results -def files_search(query_string, system, filter=None, offset=0, limit=10): - res = search_operation(None, system, '/', offset=offset, limit=limit, +def files_search(client, query_string, system, filter=None, offset=0, limit=10): + res = search_operation(client, system, '/', offset=offset, limit=limit, query_string=query_string, filter=filter) return (res['count'], res['listing']) @@ -62,8 +63,9 @@ def get(self, request, *args, **kwargs): in settings.PORTAL_DATAFILES_STORAGE_SYSTEMS if conf['scheme'] == 'public' and ('siteSearchPriority' in conf and conf['siteSearchPriority'] is not None)) + client = request.user.tapis_oauth.client if (request.user.is_authenticated and request.user.profile.setup_complete) else service_account() (public_total, public_results) = \ - files_search(qs, public_conf['system'], filter=filter, + files_search(client, qs, public_conf['system'], filter=filter, offset=offset, limit=limit) response['public'] = {'count': public_total, 'listing': public_results, @@ -80,8 +82,9 @@ def get(self, request, *args, **kwargs): in settings.PORTAL_DATAFILES_STORAGE_SYSTEMS if conf['scheme'] == 'community' and ('siteSearchPriority' in conf and conf['siteSearchPriority'] is not None)) + client = request.user.tapis_oauth.client (community_total, community_results) = \ - files_search(qs, community_conf['system'], filter=filter, + files_search(client, qs, community_conf['system'], filter=filter, offset=offset, limit=limit) response['community'] = {'count': community_total, diff --git a/server/portal/libs/agave/operations.py b/server/portal/libs/agave/operations.py index 78e730cff..0131dcef8 100644 --- a/server/portal/libs/agave/operations.py +++ b/server/portal/libs/agave/operations.py @@ -20,7 +20,7 @@ def listing(client, system, path, offset=0, limit=100, *args, **kwargs): Params ------ - client: agavepy.agave.Agave + client: tapipy.tapis.Tapis Tapis client to use for the listing. system: str Tapis system ID. @@ -92,7 +92,8 @@ def search(client, system, path='', offset=0, limit=100, query_string='', filter Params ------ - client: NoneType + client: tapipy.tapis.Tapis + Tapis client to use for the listing. system: str Tapis system ID to filter on. path: NoneType From 67f4e757df7287a993bb7e6024e9a09f71336bbe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 14:46:12 -0500 Subject: [PATCH 2/7] build(deps): bump urllib3 from 1.26.13 to 1.26.17 in /server (#869) Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.26.13 to 1.26.17. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/1.26.13...1.26.17) --- updated-dependencies: - dependency-name: urllib3 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- server/poetry.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/poetry.lock b/server/poetry.lock index 49bc25825..3e25cce44 100644 --- a/server/poetry.lock +++ b/server/poetry.lock @@ -2619,17 +2619,17 @@ files = [ [[package]] name = "urllib3" -version = "1.26.13" +version = "1.26.17" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "urllib3-1.26.13-py2.py3-none-any.whl", hash = "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc"}, - {file = "urllib3-1.26.13.tar.gz", hash = "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"}, + {file = "urllib3-1.26.17-py2.py3-none-any.whl", hash = "sha256:94a757d178c9be92ef5539b8840d48dc9cf1b2709c9d6b588232a055c524458b"}, + {file = "urllib3-1.26.17.tar.gz", hash = "sha256:24d6a242c28d29af46c3fae832c36db3bbebcc533dd1bb549172cd739c82df21"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] From 7abd8ad9271f0e98fb4b06a35ded2c84bee7ea7b Mon Sep 17 00:00:00 2001 From: Chandra Y Date: Thu, 5 Oct 2023 11:04:04 -0500 Subject: [PATCH 3/7] Bug/WP-306: If input file target path is empty, do not send it to tapis (#871) * Adjustments to targetpath * Prettier fix --- .../Applications/AppForm/AppForm.jsx | 11 +++++---- .../Applications/AppForm/AppFormUtils.js | 23 +++++++++++++++---- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/client/src/components/Applications/AppForm/AppForm.jsx b/client/src/components/Applications/AppForm/AppForm.jsx index b2b7ed793..787dcf255 100644 --- a/client/src/components/Applications/AppForm/AppForm.jsx +++ b/client/src/components/Applications/AppForm/AppForm.jsx @@ -19,7 +19,7 @@ import { Link } from 'react-router-dom'; import { getSystemName } from 'utils/systems'; import FormSchema from './AppFormSchema'; import { - checkAndSetDefaultTargetPath, + isTargetPathEmpty, isTargetPathField, getInputFieldFromTargetPathField, getQueueMaxMinutes, @@ -501,9 +501,12 @@ export const AppSchemaForm = ({ app }) => { .flat() .filter((fileInput) => fileInput.sourceUrl) // filter out any empty values .map((fileInput) => { - fileInput.targetPath = checkAndSetDefaultTargetPath( - fileInput.targetPath - ); + if (isTargetPathEmpty(fileInput.targetPath)) { + return { + name: fileInput.name, + sourceUrl: fileInput.sourceUrl, + }; + } return fileInput; }); diff --git a/client/src/components/Applications/AppForm/AppFormUtils.js b/client/src/components/Applications/AppForm/AppFormUtils.js index 1b5b30c7e..fcaa7910c 100644 --- a/client/src/components/Applications/AppForm/AppFormUtils.js +++ b/client/src/components/Applications/AppForm/AppFormUtils.js @@ -202,20 +202,35 @@ export const getInputFieldFromTargetPathField = (targetPathFieldName) => { }; /** - * Sets the default value if target path is not set. + * Check if targetPath is empty on input field * * @function * @param {String} targetPathFieldValue - * @returns {String} target path value + * @returns {boolean} if target path is empty */ -export const checkAndSetDefaultTargetPath = (targetPathFieldValue) => { +export const isTargetPathEmpty = (targetPathFieldValue) => { if (targetPathFieldValue === null || targetPathFieldValue === undefined) { - return '*'; + return true; } targetPathFieldValue = targetPathFieldValue.trim(); if (targetPathFieldValue.trim() === '') { + return true; + } + + return false; +}; + +/** + * Sets the default value if target path is not set. + * + * @function + * @param {String} targetPathFieldValue + * @returns {String} target path value + */ +export const checkAndSetDefaultTargetPath = (targetPathFieldValue) => { + if (isTargetPathEmpty(targetPathFieldValue)) { return '*'; } From a0ade9217356a346655a463d6c54de03f6725172 Mon Sep 17 00:00:00 2001 From: Chandra Y Date: Thu, 5 Oct 2023 12:09:35 -0500 Subject: [PATCH 4/7] Update Changelog for 3.2.1 --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd0153581..847a88e80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [3.2.1] - 2023-10-05: Search and Target Path fixes + +### Fixed +WP-297: Fix site search for public and community data (#870) +WP-306: Fix target path regression (#871) + ## [3.2.0] - 2023-10-02: V3 integration improvements; bug fixes ### Added @@ -953,7 +959,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.0.0] - 2020-02-28 v1.0.0 Production release as of Feb 28, 2020. -[unreleased]: https://github.com/TACC/Core-Portal/compare/v3.1.2...HEAD +[unreleased]: https://github.com/TACC/Core-Portal/compare/v3.2.1...HEAD +[3.2.1]: https://github.com/TACC/Core-Portal/releases/tag/v3.2.1 [3.2.0]: https://github.com/TACC/Core-Portal/releases/tag/v3.2.0 [3.1.2]: https://github.com/TACC/Core-Portal/releases/tag/v3.1.2 [3.1.1]: https://github.com/TACC/Core-Portal/releases/tag/v3.1.1 From b31a09d03e992cf95782c0a2ed73ae72618d35a8 Mon Sep 17 00:00:00 2001 From: Asim Regmi <54924215+asimregmi@users.noreply.github.com> Date: Mon, 9 Oct 2023 13:38:08 -0500 Subject: [PATCH 5/7] Task/WP-66: Refactored some variables and props to include proptypes (#876) * Refactored some variables and props to include proptypes * fixed linting errors --- .../DataFilesProjectMembers.jsx | 1 + .../DataFilesSidebar/DataFilesSidebar.jsx | 4 ++-- .../DataFiles/DataFilesStatus/DataFilesStatus.jsx | 15 ++++++++------- .../DataFilesSystemSelector.jsx | 15 ++++++++------- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/client/src/components/DataFiles/DataFilesProjectMembers/DataFilesProjectMembers.jsx b/client/src/components/DataFiles/DataFilesProjectMembers/DataFilesProjectMembers.jsx index 7433e0fa3..b8bad0f9e 100644 --- a/client/src/components/DataFiles/DataFilesProjectMembers/DataFilesProjectMembers.jsx +++ b/client/src/components/DataFiles/DataFilesProjectMembers/DataFilesProjectMembers.jsx @@ -286,6 +286,7 @@ const DataFilesProjectMembers = ({ }; DataFilesProjectMembers.propTypes = { + projectId: PropTypes.string, members: PropTypes.arrayOf( PropTypes.shape({ username: PropTypes.string, diff --git a/client/src/components/DataFiles/DataFilesSidebar/DataFilesSidebar.jsx b/client/src/components/DataFiles/DataFilesSidebar/DataFilesSidebar.jsx index aba95d175..6ac81f652 100644 --- a/client/src/components/DataFiles/DataFilesSidebar/DataFilesSidebar.jsx +++ b/client/src/components/DataFiles/DataFilesSidebar/DataFilesSidebar.jsx @@ -27,7 +27,7 @@ const DataFilesAddButton = ({ readOnly }) => { payload: { operation: 'upload', props: {} }, }); }; - const err = useSelector((state) => state.files.error.FilesListing); + const hasError = useSelector((state) => state.files.error.FilesListing); const { api, scheme } = useSelector( (state) => state.files.params.FilesListing ); @@ -60,7 +60,7 @@ const DataFilesAddButton = ({ readOnly }) => { const disabled = readOnly || - err !== false || + hasError !== false || api !== 'tapis' || (scheme !== 'private' && scheme !== 'projects'); diff --git a/client/src/components/DataFiles/DataFilesStatus/DataFilesStatus.jsx b/client/src/components/DataFiles/DataFilesStatus/DataFilesStatus.jsx index f7756c7bf..5a747c3e0 100644 --- a/client/src/components/DataFiles/DataFilesStatus/DataFilesStatus.jsx +++ b/client/src/components/DataFiles/DataFilesStatus/DataFilesStatus.jsx @@ -38,17 +38,18 @@ const OPERATION_MAP = { case 'upload': case 'move': case 'copy': { - const destPath = response.path.split('/').slice(0, -1).join('/'); - const projectName = findProjectTitle(projectList, response.systemId); + const { path, systemId, source } = response; + const destPath = path.split('/').slice(0, -1).join('/'); + const projectName = findProjectTitle(projectList, systemId); let op = mappedOp; if (mappedOp === 'copied') { const srcSystem = - response.source.split('/')[0] === 'https:' - ? response.source.split('/')[7] - : response.source.split('/')[2]; - const destSystem = response.systemId; + source.split('/')[0] === 'https:' + ? source.split('/')[7] + : source.split('/')[2]; + const destSystem = systemId; if (srcSystem !== destSystem) { op = 'started copying'; } @@ -62,7 +63,7 @@ const OPERATION_MAP = { } else { dest = destPath === '/' || destPath === '' - ? `${findSystemDisplayName(systemList, response.systemId)}/` + ? `${findSystemDisplayName(systemList, systemId)}/` : destPath; } diff --git a/client/src/components/DataFiles/DataFilesSystemSelector/DataFilesSystemSelector.jsx b/client/src/components/DataFiles/DataFilesSystemSelector/DataFilesSystemSelector.jsx index 4c1fc721a..55a477207 100644 --- a/client/src/components/DataFiles/DataFilesSystemSelector/DataFilesSystemSelector.jsx +++ b/client/src/components/DataFiles/DataFilesSystemSelector/DataFilesSystemSelector.jsx @@ -5,7 +5,7 @@ import { DropdownSelector } from '_common'; import styles from './DataFilesSystemSelector.module.scss'; const DataFilesSystemSelector = ({ - systemId, + systemAndHomeDirId, section, disabled, operation, @@ -17,11 +17,12 @@ const DataFilesSystemSelector = ({ (state) => state.systems.storage.configuration ); const modalProps = useSelector((state) => state.files.modalProps[operation]); - const findSystem = (id) => + const findSystem = (systemAndHomeDirPath) => systemList.find( - (system) => `${system.system}${system.homeDir || ''}` === id + (system) => + `${system.system}${system.homeDir || ''}` === systemAndHomeDirPath ); - const [selectedSystem, setSelectedSystem] = useState(systemId); + const [selectedSystem, setSelectedSystem] = useState(systemAndHomeDirId); const openSystem = useCallback( (event) => { @@ -69,7 +70,7 @@ const DataFilesSystemSelector = ({ }; useEffect(() => { - setSelectedSystem(systemId); + setSelectedSystem(systemAndHomeDirId); }, []); const dropdownSystems = systemList.filter( @@ -111,7 +112,7 @@ const DataFilesSystemSelector = ({ }; DataFilesSystemSelector.propTypes = { - systemId: PropTypes.string, + systemAndHomeDirId: PropTypes.string, section: PropTypes.string.isRequired, disabled: PropTypes.bool, operation: PropTypes.string.isRequired, @@ -120,7 +121,7 @@ DataFilesSystemSelector.propTypes = { }; DataFilesSystemSelector.defaultProps = { - systemId: '', + systemAndHomeDirId: '', disabled: false, showProjects: false, excludedSystems: [], From 982c7d690d1b1d01e3b4edd131fb036e290a793d Mon Sep 17 00:00:00 2001 From: Asim Regmi <54924215+asimregmi@users.noreply.github.com> Date: Mon, 9 Oct 2023 14:31:40 -0500 Subject: [PATCH 6/7] WP-299: Add Data Files button dropdown needs minor adjustment in alignment (#878) * small UI change to align dropdown * linting issues fixed --------- Co-authored-by: Chandra Y --- .../DataFiles/DataFilesSidebar/DataFilesSidebar.scss | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/client/src/components/DataFiles/DataFilesSidebar/DataFilesSidebar.scss b/client/src/components/DataFiles/DataFilesSidebar/DataFilesSidebar.scss index 9f4fac877..3b5cd538b 100644 --- a/client/src/components/DataFiles/DataFilesSidebar/DataFilesSidebar.scss +++ b/client/src/components/DataFiles/DataFilesSidebar/DataFilesSidebar.scss @@ -24,15 +24,14 @@ .dropdown-menu { border-color: var(--global-color-accent--normal); border-radius: 0; - margin-top: 11px; - padding: 0; + margin: 11px 3px 0; width: 200px; vertical-align: top; } .dropdown-menu::before { position: absolute; top: -10px; - left: 65px; + left: 67px; border-right: 10px solid transparent; border-bottom: 10px solid var(--global-color-accent--normal); border-left: 10px solid transparent; @@ -42,7 +41,7 @@ .dropdown-menu::after { position: absolute; top: -9px; - left: 66px; + left: 68px; border-right: 9px solid transparent; border-bottom: 9px solid #ffffff; border-left: 9px solid transparent; From 4cacf3253c3415efdaf530ee73de993de7ae6535 Mon Sep 17 00:00:00 2001 From: Sal Tijerina Date: Mon, 9 Oct 2023 15:44:52 -0500 Subject: [PATCH 7/7] handle interactive session messages (#877) --- .../Jobs/JobsSessionModal/JobsSessionModal.jsx | 8 +++++++- client/src/components/Jobs/JobsStatus/JobsStatus.jsx | 3 +++ .../shared_workspace_migration.py | 12 ++++++++++-- server/portal/apps/webhooks/views.py | 4 ++++ 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/client/src/components/Jobs/JobsSessionModal/JobsSessionModal.jsx b/client/src/components/Jobs/JobsSessionModal/JobsSessionModal.jsx index bb0827877..9fbd2e06f 100644 --- a/client/src/components/Jobs/JobsSessionModal/JobsSessionModal.jsx +++ b/client/src/components/Jobs/JobsSessionModal/JobsSessionModal.jsx @@ -4,7 +4,12 @@ import { bool, func, string } from 'prop-types'; import './JobsSessionModal.global.scss'; import styles from './JobsSessionModal.module.scss'; -const JobsSessionModal = ({ isOpen, toggle, interactiveSessionLink }) => { +const JobsSessionModal = ({ + isOpen, + toggle, + interactiveSessionLink, + message, +}) => { return ( { Click the button below to connect to the interactive session. + {message && {message}} To end the job, quit the application within the session. Files may take some time to appear in the output location after the diff --git a/client/src/components/Jobs/JobsStatus/JobsStatus.jsx b/client/src/components/Jobs/JobsStatus/JobsStatus.jsx index e162a3a77..4f5ec2291 100644 --- a/client/src/components/Jobs/JobsStatus/JobsStatus.jsx +++ b/client/src/components/Jobs/JobsStatus/JobsStatus.jsx @@ -72,6 +72,7 @@ function JobsStatus({ status, fancy, jobUuid }) { const notifs = useSelector((state) => state.notifications.list.notifs); let interactiveSessionLink; + let message; const jobConcluded = isTerminalState(status) || status === 'ARCHIVING'; @@ -85,6 +86,7 @@ function JobsStatus({ status, fancy, jobUuid }) { ); const notif = interactiveNotifs.find((n) => n.extra.uuid === jobUuid); interactiveSessionLink = notif ? notif.action_link : null; + message = notif ? notif.message : null; } return ( @@ -109,6 +111,7 @@ function JobsStatus({ status, fancy, jobUuid }) { toggle={toggleModal} isOpen={modal} interactiveSessionLink={interactiveSessionLink} + message={message} /> )} diff --git a/server/portal/apps/projects/workspace_operations/shared_workspace_migration.py b/server/portal/apps/projects/workspace_operations/shared_workspace_migration.py index 6bf6d4ec8..58cd57e3f 100644 --- a/server/portal/apps/projects/workspace_operations/shared_workspace_migration.py +++ b/server/portal/apps/projects/workspace_operations/shared_workspace_migration.py @@ -62,7 +62,11 @@ def migrate_project(project_id): for co_pi in v2_project.co_pis.all(): v2_role = get_role(project_id, co_pi.username) - v3_role = ROLE_MAP[v2_role] + try: + v3_role = ROLE_MAP[v2_role] + except KeyError: + print(f'ERROR: No role found for: {v2_role}') + v3_role = "reader" try: add_user_to_workspace(client, project_id, co_pi.username, v3_role) except NotFoundError: @@ -71,7 +75,11 @@ def migrate_project(project_id): for team_member in v2_project.team_members.all(): v2_role = get_role(project_id, team_member.username) - v3_role = ROLE_MAP[v2_role] + try: + v3_role = ROLE_MAP[v2_role] + except KeyError: + print(f'ERROR: No role found for: {v2_role}') + v3_role = "reader" try: add_user_to_workspace(client, project_id, team_member.username, v3_role) except NotFoundError: diff --git a/server/portal/apps/webhooks/views.py b/server/portal/apps/webhooks/views.py index 54544b23d..f38430c1b 100644 --- a/server/portal/apps/webhooks/views.py +++ b/server/portal/apps/webhooks/views.py @@ -161,6 +161,7 @@ def post(self, request, *args, **kwargs): job_uuid = request.POST.get('job_uuid', None) job_owner = request.POST.get('owner', None) address = request.POST.get('address', None) + message = request.POST.get('message', None) if not address: msg = "Missing required interactive webhook parameter: address" @@ -174,6 +175,9 @@ def post(self, request, *args, **kwargs): Notification.ACTION_LINK: address } + if message: + event_data[Notification.MESSAGE] = message + # confirm that there is a corresponding running tapis job before sending notification try: valid_state = validate_tapis_job(job_uuid, job_owner, TERMINAL_JOB_STATES)