diff --git a/.github/workflows/Build-and-deploy-linux.yml b/.github/workflows/Build-and-deploy-linux.yml index 5383c1728d..b735777f43 100644 --- a/.github/workflows/Build-and-deploy-linux.yml +++ b/.github/workflows/Build-and-deploy-linux.yml @@ -7,7 +7,7 @@ on: - main - staging - pre-staging - - folder-build + - guest-contributor-fixes-ui-update jobs: deploy-on-linux: diff --git a/.github/workflows/Build-and-deploy-mac.yml b/.github/workflows/Build-and-deploy-mac.yml index a1f56eeecd..0698984018 100644 --- a/.github/workflows/Build-and-deploy-mac.yml +++ b/.github/workflows/Build-and-deploy-mac.yml @@ -7,7 +7,7 @@ on: - main - staging - pre-staging - - folder-build + - guest-contributor-fixes-ui-update jobs: deploy-on-mac: diff --git a/.github/workflows/Build-and-deploy-win.yml b/.github/workflows/Build-and-deploy-win.yml index 86181d1fe1..1a4b54eafb 100644 --- a/.github/workflows/Build-and-deploy-win.yml +++ b/.github/workflows/Build-and-deploy-win.yml @@ -7,7 +7,7 @@ on: - main - staging - pre-staging - - folder-build + - guest-contributor-fixes-ui-update jobs: deploy-on-windows: diff --git a/CHANGELOG.md b/CHANGELOG.md index d0f9460da2..75470c93d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,10 +9,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## Feature Additions: -- SODA notifies the client when a firewall may be blocking access to Pennsieve. - Pennsieve guest users can use the Prepare Datset Step-by-Step to edit their Pennsieve datasets. -- Prepare Dataset Step-by-Step progress can now be resumed when temporary data files on the user machine are saved, and when saved files have been moved. - SODA's server starts faster on Mac computers. +- SODA will notify users if it is determined that a network setting may be preventing communication to the Pennsieve platform. +- The `Prepare Dataset Step-by-Step` feature allows users to resume curating a dataset even when that dataset saved files that have since been deleted from the computer. + ## Bug Fixes: diff --git a/package-lock.json b/package-lock.json index 9a9e81bfbb..3b34b8662c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "soda-for-sparc", - "version": "15.2.4-beta", + "version": "15.3.9-beta", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "soda-for-sparc", - "version": "15.2.4-beta", + "version": "15.3.9-beta", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 4612e1c4ff..49cdec05d5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "soda-for-sparc", "procductName": "SODA for SPARC", - "version": "15.2.4-beta", + "version": "15.3.9-beta", "description": "Keep Calm and Curate", "main": "./out/main/index.js", "author": "SODA Team", diff --git a/src/pyflask/manageDatasets/manage_datasets.py b/src/pyflask/manageDatasets/manage_datasets.py index eb88ae6a59..45ddca589e 100644 --- a/src/pyflask/manageDatasets/manage_datasets.py +++ b/src/pyflask/manageDatasets/manage_datasets.py @@ -337,7 +337,8 @@ def filter_dataset(datasets_list, store=None): r = requests.get(f"{PENNSIEVE_URL}/datasets/{str(selected_dataset_id)}/role", headers=create_request_headers(get_access_token())) r.raise_for_status() user_role = r.json()["role"] - if user_role not in ["viewer", "editor"]: + namespace_logger.info(f"User role: {user_role}") + if user_role not in ["viewer"]: store.append( {"id": selected_dataset_id, "name": dataset['name'], "role": user_role, "intId": dataset["intId"]} ) @@ -358,6 +359,7 @@ def filter_dataset(datasets_list, store=None): [t.join() for t in threads] sorted_bf_datasets = sorted(store, key=lambda k: k["name"].upper()) + namespace_logger.info(f"Sorted datasets: {sorted_bf_datasets}") return {"datasets": sorted_bf_datasets} def get_username(accountname): diff --git a/src/pyflask/organizeDatasets/organize_datasets.py b/src/pyflask/organizeDatasets/organize_datasets.py index 454cf2d939..24655365e6 100644 --- a/src/pyflask/organizeDatasets/organize_datasets.py +++ b/src/pyflask/organizeDatasets/organize_datasets.py @@ -1157,13 +1157,16 @@ def createFolderStructure(subfolder_json, manifest): # START start = timer() - # check that the Pennsieve dataset is valid - try: - bf_dataset_name = soda_json_structure["bf-dataset-selected"]["dataset-name"] - except Exception as e: - raise e + if "digital-metadata" in soda_json_structure and "pennsieve-dataset-id" in soda_json_structure["digital-metadata"]: + selected_dataset_id = soda_json_structure["digital-metadata"]["pennsieve-dataset-id"] + else: + # check that the Pennsieve dataset is valid + try: + bf_dataset_name = soda_json_structure["bf-dataset-selected"]["dataset-name"] + except Exception as e: + raise e - selected_dataset_id = get_dataset_id(bf_dataset_name) + selected_dataset_id = get_dataset_id(bf_dataset_name) # check that the user has permission to edit this dataset try: diff --git a/src/pyflask/permissions/permissions.py b/src/pyflask/permissions/permissions.py index 66fb63f249..eaaf1dde53 100644 --- a/src/pyflask/permissions/permissions.py +++ b/src/pyflask/permissions/permissions.py @@ -29,4 +29,4 @@ def has_edit_permissions(ps_or_token, selected_dataset_id): except Exception as e: abort(500, "Could not get permissions for this dataset.") - return role in ["owner", "manager"] + return role in ["owner", "manager", "editor"] diff --git a/src/pyflask/startup/minimumApiVersion.py b/src/pyflask/startup/minimumApiVersion.py index ff271d0e4f..9e8f847f77 100644 --- a/src/pyflask/startup/minimumApiVersion.py +++ b/src/pyflask/startup/minimumApiVersion.py @@ -8,7 +8,7 @@ def get_api_version(): """ - return {'version': os.getenv('API_VERSION', "15.2.4-beta")} + return {'version': os.getenv('API_VERSION', "15.3.9-beta")} diff --git a/src/renderer/src/components/utils/ui/DropDownNote/index.jsx b/src/renderer/src/components/utils/ui/DropDownNote/index.jsx index a67f597686..52d0ac7b85 100644 --- a/src/renderer/src/components/utils/ui/DropDownNote/index.jsx +++ b/src/renderer/src/components/utils/ui/DropDownNote/index.jsx @@ -16,7 +16,7 @@ const DropDownNote = ({ dropDownIcon, dropDownButtonText, dropDownNote }) => { {dropDownIcon && dropDownIcons[dropDownIcon]} { }, }); } - - // check if the user is the dataset owner let role; try { - role = await api.getDatasetRole(currentDataset); + // check if the user is the dataset owner + const { userRole, userCanModifyPennsieveMetadata } = + await api.getDatasetAccessDetails(currentDataset); + role = userRole; } catch (error) { // tell the user something went wrong getting access to their dataset permissions await Swal.fire({ diff --git a/src/renderer/src/scripts/globals.js b/src/renderer/src/scripts/globals.js index 549f4c096c..5e2ac7237e 100644 --- a/src/renderer/src/scripts/globals.js +++ b/src/renderer/src/scripts/globals.js @@ -2187,6 +2187,30 @@ const get_api_key = (login, password, key_name) => { }); }; +window.isWorkspaceGuest = async () => { + let userInfo = await api.getUserInformation(); + let currentWorkspace = userInfo["preferredOrganization"]; + + let orgResponse; + try { + orgResponse = await client.get(`user/organizations`, { + params: { + selected_account: window.defaultBfAccount, + }, + }); + } catch (error) { + clientError(error); + console.error("Error fetching organizations", error); + // TODO: Handle error here + } + console.log("currentWorkspace", currentWorkspace); + // get the current workspace by matching the id + let currentWorkspaceObj = orgResponse.data.organizations.filter( + (org) => org.organization.id === currentWorkspace + )[0]; + return currentWorkspaceObj.isGuest; +}; + export { currentConTable, showHideDropdownButtons, diff --git a/src/renderer/src/scripts/guided-mode/guided-curate-dataset.js b/src/renderer/src/scripts/guided-mode/guided-curate-dataset.js index 8fe01a9a4a..40668b6838 100644 --- a/src/renderer/src/scripts/guided-mode/guided-curate-dataset.js +++ b/src/renderer/src/scripts/guided-mode/guided-curate-dataset.js @@ -424,6 +424,13 @@ document.getElementById("guided-button-has-docs-data").addEventListener("click", const checkIfChangesMetadataPageShouldBeShown = async (pennsieveDatasetID) => { try { + // Check and make sure the user has permissions to modify the Pennsieve dataset metadata + const { userRole, userCanModifyPennsieveMetadata } = + await api.getDatasetAccessDetails(pennsieveDatasetID); + + if (!userCanModifyPennsieveMetadata) { + return { shouldShow: false }; + } const changesRes = await client.get(`/prepare_metadata/readme_changes_file`, { params: { file_type: "CHANGES", @@ -434,6 +441,7 @@ const checkIfChangesMetadataPageShouldBeShown = async (pennsieveDatasetID) => { const changes_text = changesRes.data.text; return { shouldShow: true, changesMetadata: changes_text }; } catch (error) { + console.error(error); const emessage = userErrorMessage(error); const datasetInfo = await api.getDatasetInformation( @@ -693,6 +701,8 @@ const savePageChanges = async (pageBeingLeftID) => { window.defaultBfAccount, selectedPennsieveDataset ); + + console.log("datasetIsLocked", datasetIsLocked); if (datasetIsLocked) { errorArray.push({ type: "swal", @@ -929,7 +939,7 @@ const savePageChanges = async (pageBeingLeftID) => { await Swal.fire({ icon: "info", - title: "Begining Pennsieve Dataset edit session", + title: "Beginning Pennsieve Dataset edit session", html: ` Note: it is imperative that you do not manually make any changes to your dataset folders and files directly on Pennsieve while working on this dataset on SODA. @@ -961,11 +971,6 @@ const savePageChanges = async (pageBeingLeftID) => { window.sodaJSONObj["dataset-metadata"]["CHANGES"] = ""; guidedSkipPage("guided-create-changes-metadata-tab"); } - - // Skip the page where they confirm their log in and workspace because we should already have it - window.sodaJSONObj["digital-metadata"]["dataset-workspace"] = - guidedGetCurrentUserWorkSpace(); - guidedSkipPage("guided-pennsieve-intro-tab"); } //Skip this page becausae we should not come back to it @@ -1802,23 +1807,23 @@ const savePageChanges = async (pageBeingLeftID) => { } if (pageBeingLeftID === "guided-pennsieve-intro-tab") { - const confirmAccountbutton = document.getElementById( + const confirmAccountButton = document.getElementById( "guided-confirm-pennsieve-account-button" ); - if (!confirmAccountbutton.classList.contains("selected")) { + if (!confirmAccountButton.classList.contains("selected")) { if (!window.defaultBfAccount) { - // If the user has not logged in, throw an error errorArray.push({ type: "notyf", message: "Please sign in to Pennsieve before continuing", }); + log.error("User attempted to proceed without signing into Pennsieve."); throw errorArray; } else { - // If the user has not confirmed their account, throw an error errorArray.push({ type: "notyf", message: "Please confirm your account before continuing", }); + log.error("User attempted to proceed without confirming their Pennsieve account."); throw errorArray; } } @@ -1829,37 +1834,78 @@ const savePageChanges = async (pageBeingLeftID) => { const userSelectedWorkSpace = guidedGetCurrentUserWorkSpace(); if (!userSelectedWorkSpace) { - // If the user has not selected an organization, throw an error errorArray.push({ type: "notyf", message: "Please select an organization before continuing", }); + log.error("User attempted to proceed without selecting an organization."); throw errorArray; } else { window.sodaJSONObj["digital-metadata"]["dataset-workspace"] = userSelectedWorkSpace; } if (!confirmOrganizationButton.classList.contains("selected")) { - // If the user has not confirmed their organization, throw an error errorArray.push({ type: "notyf", message: "Please confirm your organization before continuing", }); + log.error("User attempted to proceed without confirming their organization."); throw errorArray; } const pennsieveAgentChecksPassed = await window.getPennsieveAgentStatus(); if (!pennsieveAgentChecksPassed) { - window.unHideAndSmoothScrollToElement("guided-mode-post-log-in-pennsieve-agent-check"); errorArray.push({ type: "notyf", message: "The Pennsieve Agent must be installed and running to continue.", }); + log.error("Pennsieve Agent is not installed or running."); + window.unHideAndSmoothScrollToElement("guided-mode-post-log-in-pennsieve-agent-check"); throw errorArray; } window.sodaJSONObj["last-confirmed-bf-account-details"] = window.defaultBfAccount; window.sodaJSONObj["last-confirmed-pennsieve-workspace-details"] = userSelectedWorkSpace; + + const loggedInUserIsWorkspaceGuest = await window.isWorkspaceGuest(); + window.sodaJSONObj["last-confirmed-organization-guest-status"] = loggedInUserIsWorkspaceGuest; + + let userRole = null; + let userCanModifyPennsieveMetadata = true; + + if (window.sodaJSONObj?.["starting-point"]?.["type"] === "bf") { + try { + ({ userRole, userCanModifyPennsieveMetadata } = await api.getDatasetAccessDetails( + window.sodaJSONObj["digital-metadata"]["pennsieve-dataset-id"] + )); + console.log("userRole", userRole); + console.log("userCanModifyPennsieveMetadata", userCanModifyPennsieveMetadata); + window.sodaJSONObj["last-confirmed-dataset-role"] = userRole; + } catch (error) { + errorArray.push({ + type: "notyf", + message: + "SODA was not able to determine if you have the correct permissions to edit this dataset. If you get stuck here, please contact us on the home page.", + }); + log.error("Error determining user dataset role.", error); + throw errorArray; + } + } + + // If the user is a workspace or guest, skip the permissions tab since they do not have permissions to modify them on Pennsieve + if (loggedInUserIsWorkspaceGuest || !userCanModifyPennsieveMetadata) { + guidedSkipPage("guided-designate-permissions-tab"); + } else { + guidedUnSkipPage("guided-designate-permissions-tab"); + } + + if (!userCanModifyPennsieveMetadata) { + guidedSkipPage("guided-banner-image-tab"); + guidedSkipPage("guided-assign-license-tab"); + } else { + guidedUnSkipPage("guided-banner-image-tab"); + guidedUnSkipPage("guided-assign-license-tab"); + } } if (pageBeingLeftID === "guided-assign-license-tab") { @@ -4396,6 +4442,7 @@ const guidedUnSkipPage = (pageId) => { const subPagesCapsule = `${pageId}-capsule`; document.getElementById(subPagesCapsule).classList.remove("hidden"); } + // remove the page from window.sodaJSONObj array if it is there if (window.sodaJSONObj["skipped-pages"].includes(pageId)) { window.sodaJSONObj["skipped-pages"].splice( @@ -5216,7 +5263,19 @@ window.openPage = async (targetPageID) => { if (pageNeedsUpdateFromPennsieve("guided-name-subtitle-tab")) { // Show the loading page while the page's data is being fetched from Pennsieve setPageLoadingState(true); + try { + // get the dataset name from Pennsieve + const datasetResponse = await api.getDatasetInformation( + window.defaultBfAccount, + window.sodaJSONObj["digital-metadata"]["pennsieve-dataset-id"] + ); + console.log(datasetResponse); + let datasetName = datasetResponse["content"]["name"]; + // Save the dataset name to the JSON and add it to the input + window.sodaJSONObj["digital-metadata"]["name"] = datasetName; + setGuidedDatasetName(datasetName); + //Try to get the dataset name from Pennsieve //If the request fails, the subtitle input will remain blank const datasetSubtitle = await api.getDatasetSubtitle( @@ -5834,7 +5893,7 @@ window.openPage = async (targetPageID) => { let metadata_import = await client.get(`/prepare_metadata/import_metadata_file`, { params: { selected_account: window.defaultBfAccount, - selected_dataset: window.sodaJSONObj["bf-dataset-selected"]["dataset-name"], + selected_dataset: window.sodaJSONObj["digital-metadata"]["pennsieve-dataset-id"], file_type: "dataset_description.xlsx", }, }); @@ -6955,6 +7014,7 @@ window.openPage = async (targetPageID) => { // Set the last opened page and save it window.sodaJSONObj["page-before-exit"] = targetPageID; + console.log("About to save progress"); await guidedSaveProgress(); } catch (error) { const eMessage = userErrorMessage(error); @@ -7649,32 +7709,76 @@ const newEmptyFolderObj = () => { }; }; -const guidedCheckIfUserNeedsToReconfirmAccountDetails = () => { +const guidedCheckIfUserNeedsToReconfirmAccountDetails = async () => { if (!window.sodaJSONObj["completed-tabs"].includes("guided-pennsieve-intro-tab")) { return false; } - // If the user has changed their Pennsieve account, they need to confirm their new Pennsieve account and workspace - if (window.sodaJSONObj?.["last-confirmed-bf-account-details"] !== window.defaultBfAccount) { - if (window.sodaJSONObj["button-config"]?.["pennsieve-account-has-been-confirmed"]) { - delete window.sodaJSONObj["button-config"]["pennsieve-account-has-been-confirmed"]; + try { + // If the user has changed their Pennsieve account, they need to confirm their new Pennsieve account and workspace + if (window.sodaJSONObj?.["last-confirmed-bf-account-details"] !== window.defaultBfAccount) { + if (window.sodaJSONObj["button-config"]?.["pennsieve-account-has-been-confirmed"]) { + delete window.sodaJSONObj["button-config"]["pennsieve-account-has-been-confirmed"]; + } + if (window.sodaJSONObj["button-config"]?.["organization-has-been-confirmed"]) { + delete window.sodaJSONObj["button-config"]["organization-has-been-confirmed"]; + } + await swalShowInfo( + "Your Pennsieve account has changed", + "You will be taken back to the account details page" + ); + return true; } - if (window.sodaJSONObj["button-config"]?.["organization-has-been-confirmed"]) { - delete window.sodaJSONObj["button-config"]["organization-has-been-confirmed"]; + // If the user has changed their Pennsieve workspace, they need to confirm their new workspace + if ( + guidedGetCurrentUserWorkSpace() != + window.sodaJSONObj?.["last-confirmed-pennsieve-workspace-details"] + ) { + if (window.sodaJSONObj["button-config"]?.["organization-has-been-confirmed"]) { + delete window.sodaJSONObj["button-config"]["organization-has-been-confirmed"]; + } + await swalShowInfo( + "Your Pennsieve workspace has changed", + "You will be taken back to the account details page" + ); + return true; } - return true; - } - // If the user has changed their Pennsieve workspace, they need to confirm their new workspace - if ( - guidedGetCurrentUserWorkSpace() != - window.sodaJSONObj?.["last-confirmed-pennsieve-workspace-details"] - ) { - if (window.sodaJSONObj["button-config"]?.["organization-has-been-confirmed"]) { - delete window.sodaJSONObj["button-config"]["organization-has-been-confirmed"]; + + const currentGuestStatus = await window.isWorkspaceGuest(); + + // If the guest status was set and the user's guest status has changed, they need to reconfirm their account details + if ( + window.sodaJSONObj?.["last-confirmed-organization-guest-status"] && + currentGuestStatus !== window.sodaJSONObj?.["last-confirmed-organization-guest-status"] + ) { + log.info( + "The user's guest status has changed so we are returning to the account details page" + ); + await swalShowInfo( + "Your guest status in the workspace has changed", + "You will be taken back to the account details page" + ); + return true; } + if (window.sodaJSONObj?.["starting-point"]?.["type"] === "bf") { + if (window.sodaJSONObj["last-confirmed-dataset-role"]) { + const { userRole, userCanModifyPennsieveMetadata } = + await api.getDatasetAccessDetails(currentDataset); + if (userRole !== window.sodaJSONObj["last-confirmed-dataset-role"]) { + await swalShowInfo( + "Your role in the dataset has changed", + "You will be taken back to the account details page" + ); + return true; + } + } + } + + return false; + } catch (error) { + log.error("Error checking if user needs to reconfirm account details", error); + log.info("Returning true to reconfirm account details"); return true; } - // Return false if the user does not need to reconfirm their account details - return false; }; const guidedGetPageToReturnTo = async (sodaJSONObj) => { @@ -7701,7 +7805,7 @@ const guidedGetPageToReturnTo = async (sodaJSONObj) => { return firstPageID; } - if (guidedCheckIfUserNeedsToReconfirmAccountDetails() === true) { + if ((await guidedCheckIfUserNeedsToReconfirmAccountDetails()) === true) { return "guided-pennsieve-intro-tab"; } @@ -7829,12 +7933,11 @@ const patchPreviousGuidedModeVersions = async () => { } } - if (window.sodaJSONObj?.["starting-point"]?.["type"] === "bf") { - if (!window.sodaJSONObj?.["digital-metadata"]?.["dataset-workspace"]) { - // Skip the log in page since we no longer need it - guidedSkipPage("guided-pennsieve-intro-tab"); - window.sodaJSONObj["digital-metadata"]["dataset-workspace"] = guidedGetCurrentUserWorkSpace(); - } + // No longer skip pennsieve log in tab (even when starting from Pennsieve) + if (window.sodaJSONObj["skipped-pages"].includes("guided-pennsieve-intro-tab")) { + window.sodaJSONObj["skipped-pages"] = window.sodaJSONObj["skipped-pages"].filter( + (page) => page !== "guided-pennsieve-intro-tab" + ); } // No longer skip validation page for non-sparc datasts ("page should always be unskipped") @@ -7884,6 +7987,9 @@ const patchPreviousGuidedModeVersions = async () => { //Loads UI when continue curation button is pressed window.guidedResumeProgress = async (datasetNameToResume) => { + let userResumingProgressIsAGuest = false; + let userResumingProgressIsAnEditor = false; + const loadingSwal = Swal.fire({ title: "Resuming where you last left off", html: ` @@ -7930,8 +8036,11 @@ window.guidedResumeProgress = async (datasetNameToResume) => { } if (!datasetHasAlreadyBeenSuccessfullyUploaded) { + console.log("DOing this resume logic"); // If the dataset is being edited on Pensieve, check to make sure the folders and files are still the same. if (datasetResumeJsonObj["starting-point"]?.["type"] === "bf") { + console.log("DOing this resume logic inner"); + // Check to make sure the dataset is not locked const datasetIsLocked = await api.isDatasetLocked( window.defaultBfAccount, @@ -7992,6 +8101,8 @@ window.guidedResumeProgress = async (datasetNameToResume) => { } } } + + console.log("here"); window.sodaJSONObj = datasetResumeJsonObj; attachGuidedMethodsToSodaJSONObj(); @@ -13422,7 +13533,8 @@ const handleMultipleSubSectionDisplay = async (controlledSectionID) => { { params: { selected_account: window.defaultBfAccount, - selected_dataset: window.sodaJSONObj["bf-dataset-selected"]["dataset-name"], + selected_dataset: + window.sodaJSONObj["bf-dataset-selected"]["pennsieve-dataset-id"], file_type: "dataset_description.xlsx", }, } @@ -15473,7 +15585,6 @@ const guidedPennsieveDatasetUpload = async () => { const guidedDatasetName = window.sodaJSONObj["digital-metadata"]["name"]; const guidedDatasetSubtitle = window.sodaJSONObj["digital-metadata"]["subtitle"]; const guidedUsers = window.sodaJSONObj["digital-metadata"]["user-permissions"]; - //const guidedPIOwner = window.sodaJSONObj["digital-metadata"]["pi-owner"]; const guidedTeams = window.sodaJSONObj["digital-metadata"]["team-permissions"]; const guidedPennsieveStudyPurpose = @@ -15513,19 +15624,57 @@ const guidedPennsieveDatasetUpload = async () => { // Create the dataset on Pennsieve await guidedCreateOrRenameDataset(guidedBfAccount, guidedDatasetName); - await guidedAddDatasetSubtitle(guidedBfAccount, guidedDatasetName, guidedDatasetSubtitle); - await guidedAddDatasetDescription( - guidedBfAccount, - guidedDatasetName, - guidedPennsieveStudyPurpose, - guidedPennsieveDataCollection, - guidedPennsievePrimaryConclusion - ); - await guidedAddDatasetBannerImage(guidedBfAccount, guidedDatasetName, guidedBannerImagePath); - await guidedAddDatasetLicense(guidedBfAccount, guidedDatasetName, guidedLicense); - await guidedAddDatasetTags(guidedBfAccount, guidedDatasetName, guidedTags); - await guidedAddUserPermissions(guidedBfAccount, guidedDatasetName, guidedUsers); - await guidedAddTeamPermissions(guidedBfAccount, guidedDatasetName, guidedTeams); + const editingExistingDataset = window.sodaJSONObj?.["starting-point"]?.["type"] === "bf"; + let userHasPermissionsToModifyPennsieveMetadata = true; + + if (editingExistingDataset) { + const { userCanModifyPennsieveMetadata } = await api.getDatasetAccessDetails( + window.sodaJSONObj["digital-metadata"]["pennsieve-dataset-id"] + ); + if (!userCanModifyPennsieveMetadata) { + log.info( + "Skipping metadata editing because user does not have permission to edit metadata" + ); + userHasPermissionsToModifyPennsieveMetadata = false; + } + } + + if (userHasPermissionsToModifyPennsieveMetadata) { + await guidedAddDatasetSubtitle(guidedBfAccount, guidedDatasetName, guidedDatasetSubtitle); + await guidedAddDatasetDescription( + guidedBfAccount, + guidedDatasetName, + guidedPennsieveStudyPurpose, + guidedPennsieveDataCollection, + guidedPennsievePrimaryConclusion + ); + if (!pageIsSkipped("guided-banner-image-tab")) { + await guidedAddDatasetBannerImage( + guidedBfAccount, + guidedDatasetName, + guidedBannerImagePath + ); + } + if (!pageIsSkipped("guided-assign-license-tab")) { + await guidedAddDatasetLicense(guidedBfAccount, guidedDatasetName, guidedLicense); + } + await guidedAddDatasetTags(guidedBfAccount, guidedDatasetName, guidedTags); + if (!pageIsSkipped("guided-designate-permissions-tab")) { + try { + // Double check if the user is a guest before adding permissions + const guest = await window.isWorkspaceGuest(); + + if (!guest) { + await guidedAddUserPermissions(guidedBfAccount, guidedDatasetName, guidedUsers); + await guidedAddTeamPermissions(guidedBfAccount, guidedDatasetName, guidedTeams); + } + } catch (error) { + const errorMessage = userErrorMessage(error); + log.error("Error checking guest status during dataset upload", errorMessage); + throw new Error(errorMessage); + } + } + } hideDatasetMetadataGenerationTableRows("pennsieve"); diff --git a/src/renderer/src/scripts/meta/announcements.json b/src/renderer/src/scripts/meta/announcements.json index fa389013e1..427a671c8f 100644 --- a/src/renderer/src/scripts/meta/announcements.json +++ b/src/renderer/src/scripts/meta/announcements.json @@ -1,4 +1,13 @@ { + "15.3.0": { + "announcements": { + "bug-fixes": [], + "features": [ + "SODA will notify users if it is determined that a network setting may be preventing communication to the Pennsieve platform.", + "The `Prepare Dataset Step-by-Step` feature allows users to resume curating a dataset even when that dataset saved files that have since been deleted from the computer." + ] + } + }, "15.2.2": { "announcements": { "bug-fixes": [ diff --git a/src/renderer/src/scripts/others/api/api.js b/src/renderer/src/scripts/others/api/api.js index 57e21ed504..6e17138703 100644 --- a/src/renderer/src/scripts/others/api/api.js +++ b/src/renderer/src/scripts/others/api/api.js @@ -53,7 +53,7 @@ const isDatasetLocked = async (account, datasetNameOrId) => { ); teamsInCurrentUsersOrganization = teamsReq.data.teams; } catch (error) { - userErrorMessage(error); + clientError(error); } // Get the team with the name "Publishers" (if it exists) @@ -88,16 +88,22 @@ const isDatasetLocked = async (account, datasetNameOrId) => { } }; -const getDatasetRole = async (datasetNameOrId) => { - if (datasetNameOrId != undefined || datasetNameOrId != "") { +const getDatasetAccessDetails = async (datasetNameOrId) => { + console.log("getDatasetAccessDetails", datasetNameOrId); + if (datasetNameOrId) { window.defaultBfDataset = datasetNameOrId; } - let datasetRoleResponse = await client.get(`/datasets/${window.defaultBfDataset}/role`); + const { + data: { role }, + } = await client.get(`/datasets/${window.defaultBfDataset}/role`); - let { role } = datasetRoleResponse.data; + const userRole = role.toLowerCase(); + const userCanModifyPennsieveMetadata = ["owner", "manager"].includes(userRole); - return role; + console.log("userRole", userRole); + console.log("userCanModifyPennsieveMetadata", userCanModifyPennsieveMetadata); + return { userRole, userCanModifyPennsieveMetadata }; }; const getDatasetInformation = async (account, datasetNameOrId) => { @@ -539,7 +545,6 @@ const getLocalRemoteComparisonResults = async (datasetId, localDatasetPath) => { const response = await client.get( `/datasets/${datasetId}/comparison_results?local_dataset_path=${localDatasetPath}` ); - console.log(response.data); return response.data; }; @@ -555,7 +560,7 @@ const api = { getDataset, getDatasetReadme, getDatasetBannerImageURL, - getDatasetRole, + getDatasetAccessDetails, withdrawDatasetReviewSubmission, getDatasetMetadataFiles, getDatasetPermissions, diff --git a/src/renderer/src/scripts/others/renderer.js b/src/renderer/src/scripts/others/renderer.js index 88be44000f..c3d01025a4 100644 --- a/src/renderer/src/scripts/others/renderer.js +++ b/src/renderer/src/scripts/others/renderer.js @@ -545,7 +545,6 @@ const initializeSODARenderer = async () => { initializeSODARenderer(); const abortPennsieveAgentCheck = (pennsieveAgentStatusDivId) => { - console.log("CHange for build"); setPennsieveAgentCheckSuccessful(false); if (!pennsieveAgentStatusDivId) { return; @@ -4324,7 +4323,7 @@ const replaceProblematicFoldersWithSDSCompliantNames = (datasetStructure) => { // If the folder name is not valid, replace it with a valid name and then recurse through the // renamed folder to check for any other problematic folders if (!folderNameIsValid) { - const newFolderName = folderKey.replace(sparcFolderAndFileRegex, "-"); + const newFolderName = folderKey.replace(invalidSparcFolderAndFileNameRegexReplacer, "-"); const newFolderObj = { ...datasetStructure["folders"][folderKey] }; if (!newFolderObj["action"].includes("renamed")) { newFolderObj["action"].push("renamed"); @@ -4348,7 +4347,7 @@ window.replaceProblematicFilesWithSDSCompliantNames = (datasetStructure) => { "folder-and-file-name-is-valid" ); if (!fileNameIsValid) { - const newFileName = fileKey.replace(sparcFolderAndFileRegex, "-"); + const newFileName = fileKey.replace(invalidSparcFolderAndFileNameRegexReplacer, "-"); const newFileObj = { ...datasetStructure["files"][fileKey] }; if (!newFileObj["action"].includes("renamed")) { newFileObj["action"].push("renamed"); @@ -4390,13 +4389,14 @@ const namesOfForbiddenFiles = { "Thumbs.db": true, }; -const sparcFolderAndFileRegex = /[\+&\%#]/; +const invalidSparcFolderAndFileNameRegexMatcher = /[\+&\%#]/; +const invalidSparcFolderAndFileNameRegexReplacer = /[\+&\%#]/g; const identifierConventionsRegex = /^[a-zA-Z0-9-_]+$/; const forbiddenCharacters = /[@#$%^&*()+=\/\\|"'~;:<>{}\[\]?]/; window.evaluateStringAgainstSdsRequirements = (stringToTest, stringCase) => { const testCases = { - "folder-and-file-name-is-valid": !sparcFolderAndFileRegex.test(stringToTest), // returns true if the string is valid + "folder-and-file-name-is-valid": !invalidSparcFolderAndFileNameRegexMatcher.test(stringToTest), // returns true if the string is valid "file-is-hidden": stringToTest.startsWith("."), // returns true if the string is hidden "file-is-in-forbidden-files-list": namesOfForbiddenFiles?.[stringToTest], // returns true if the string is in the forbidden files list "string-adheres-to-identifier-conventions": identifierConventionsRegex.test(stringToTest), // returns true if the string adheres to the identifier conventions diff --git a/src/renderer/src/sections/guided_mode/guided_curate_dataset.html b/src/renderer/src/sections/guided_mode/guided_curate_dataset.html index 7ddb660208..015863e844 100644 --- a/src/renderer/src/sections/guided_mode/guided_curate_dataset.html +++ b/src/renderer/src/sections/guided_mode/guided_curate_dataset.html @@ -938,7 +938,7 @@

Computational focused

- Click " to begin the experimental dataset + Click "" to begin the experimental dataset curation process.