diff --git a/.github/workflows/Build-and-deploy-linux.yml b/.github/workflows/Build-and-deploy-linux.yml index 5383c1728d..7856223469 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 jobs: deploy-on-linux: diff --git a/.github/workflows/Build-and-deploy-win.yml b/.github/workflows/Build-and-deploy-win.yml index 86181d1fe1..28297b92cc 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 jobs: deploy-on-windows: diff --git a/CHANGELOG.md b/CHANGELOG.md index 40551b6760..0fbfd5d9b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to SODA will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## v15.3.0 - 2024-12-03 + +## Feature Additions: + +- 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. + ## v15.2.3 - 2024-11-20 ## Bug Fixes: diff --git a/package.json b/package.json index 4612e1c4ff..a450fd44f4 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.0-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..2ce46b352b 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.0-beta")} diff --git a/src/renderer/src/scripts/globals.js b/src/renderer/src/scripts/globals.js index 549f4c096c..39d287c61f 100644 --- a/src/renderer/src/scripts/globals.js +++ b/src/renderer/src/scripts/globals.js @@ -2187,6 +2187,29 @@ 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); + // TODO: Handle error here + } + + // 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..0aa1461f7b 100644 --- a/src/renderer/src/scripts/guided-mode/guided-curate-dataset.js +++ b/src/renderer/src/scripts/guided-mode/guided-curate-dataset.js @@ -423,6 +423,16 @@ document.getElementById("guided-button-has-docs-data").addEventListener("click", }); const checkIfChangesMetadataPageShouldBeShown = async (pennsieveDatasetID) => { + let existingDataset = window.sodaJSONObj?.["starting-point"]?.["type"] === "bf"; + let ineligible = false; + if (existingDataset) { + let role = await api.getDatasetRole(window.sodaJSONObj["bf-dataset-selected"]["dataset-name"]); + if (role === "editor") { + ineligible = true; + } + } + + if (ineligible) return { shouldShow: false }; try { const changesRes = await client.get(`/prepare_metadata/readme_changes_file`, { params: { @@ -693,6 +703,8 @@ const savePageChanges = async (pageBeingLeftID) => { window.defaultBfAccount, selectedPennsieveDataset ); + + console.log("datasetIsLocked", datasetIsLocked); if (datasetIsLocked) { errorArray.push({ type: "swal", @@ -966,6 +978,12 @@ const savePageChanges = async (pageBeingLeftID) => { window.sodaJSONObj["digital-metadata"]["dataset-workspace"] = guidedGetCurrentUserWorkSpace(); guidedSkipPage("guided-pennsieve-intro-tab"); + + // check if user is a guest in the worksapce + let guest = await window.isWorkspaceGuest(); + if (guest) { + guidedSkipPage("guided-designate-permissions-tab"); + } } //Skip this page becausae we should not come back to it @@ -4396,6 +4414,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 +5235,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 +5865,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", }, }); @@ -6285,6 +6316,8 @@ window.openPage = async (targetPageID) => { } if (targetPageID === "guided-designate-permissions-tab") { + console.log("In permissions tab"); + // Get the users that can be granted permissions const usersReq = await client.get( `manage_datasets/ps_get_users?selected_account=${window.defaultBfAccount}` @@ -6955,6 +6988,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); @@ -7930,8 +7964,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, @@ -7946,6 +7983,21 @@ window.guidedResumeProgress = async (datasetNameToResume) => { `); } + // check if the user is an editor + let userDatasetRole = await api.getDatasetRole( + window.sodaJSONObj["digital-metadata"]["name"] + ); + + if (userDatasetRole === "editor") { + guidedSkipPage("guided-banner-image-tab"); + guidedSkipPage("guided-designate-permissions-tab"); + guidedSkipPage("guided-assign-license-tab"); + } else { + guidedUnSkipPage("guided-banner-image-tab"); + guidedUnSkipPage("guided-designate-permissions-tab"); + guidedUnSkipPage("guided-assign-license-tab"); + } + if (Object.keys(datasetResumeJsonObj["previously-uploaded-data"]).length > 0) { await Swal.fire({ icon: "info", @@ -8011,6 +8063,15 @@ window.guidedResumeProgress = async (datasetNameToResume) => { guidedSkipPage(pageID); } + if (hasConnectedAccountWithPennsieve()) { + let guest = await window.isWorkspaceGuest(); + if (!guest) { + guidedUnSkipPage("guided-designate-permissions-tab"); + } else { + guidedSkipPage("guided-designate-permissions-tab"); + } + } + // Skip this page incase it was not skipped in a previous session guidedSkipPage("guided-select-starting-point-tab"); @@ -13422,7 +13483,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", }, } @@ -14026,6 +14088,17 @@ const guidedAddDatasetDescription = async ( dataCollection, dataConclusion ) => { + let existingDataset = window.sodaJSONObj?.["starting-point"]?.["type"] === "bf"; + + let ineligible = false; + if (existingDataset) { + let role = await api.getDatasetRole(window.sodaJSONObj["bf-dataset-selected"]["dataset-name"]); + if (role === "editor") { + ineligible = true; + } + } + + if (ineligible) return; document.getElementById("guided-dataset-description-upload-tr").classList.remove("hidden"); const datasetDescriptionUploadText = document.getElementById( "guided-dataset-description-upload-text" @@ -14105,6 +14178,17 @@ const guidedAddDatasetDescription = async ( }; const uploadValidBannerImage = async (bfAccount, datasetName, bannerImagePath) => { + let existingDataset = window.sodaJSONObj?.["starting-point"]?.["type"] === "bf"; + + let ineligible = false; + if (existingDataset) { + let role = await api.getDatasetRole(window.sodaJSONObj["bf-dataset-selected"]["dataset-name"]); + if (role === "editor") { + ineligible = true; + } + } + + if (ineligible) return; document.getElementById("guided-dataset-banner-image-upload-tr").classList.remove("hidden"); const datasetBannerImageUploadText = document.getElementById( "guided-dataset-banner-image-upload-text" @@ -14211,6 +14295,16 @@ const guidedAddDatasetBannerImage = async (bfAccount, datasetName, bannerImagePa await uploadValidBannerImage(bfAccount, datasetName, bannerImagePath); }; const guidedAddDatasetLicense = async (bfAccount, datasetName, datasetLicense) => { + let existingDataset = window.sodaJSONObj?.["starting-point"]?.["type"] === "bf"; + let ineligible = false; + if (existingDataset) { + let role = await api.getDatasetRole(window.sodaJSONObj["bf-dataset-selected"]["dataset-name"]); + if (role === "editor") { + ineligible = true; + } + } + + if (ineligible) return; document.getElementById("guided-dataset-license-upload-tr").classList.remove("hidden"); const datasetLicenseUploadText = document.getElementById("guided-dataset-license-upload-text"); datasetLicenseUploadText.innerHTML = "Adding dataset license..."; @@ -14286,6 +14380,16 @@ const guidedAddDatasetLicense = async (bfAccount, datasetName, datasetLicense) = }; const guidedAddDatasetTags = async (bfAccount, datasetName, tags) => { + let existingDataset = window.sodaJSONObj?.["starting-point"]?.["type"] === "bf"; + let ineligible = false; + if (existingDataset) { + let role = await api.getDatasetRole(window.sodaJSONObj["bf-dataset-selected"]["dataset-name"]); + if (role === "editor") { + ineligible = true; + } + } + + if (ineligible) return; document.getElementById("guided-dataset-tags-upload-tr").classList.remove("hidden"); const datasetTagsUploadText = document.getElementById("guided-dataset-tags-upload-text"); datasetTagsUploadText.innerHTML = "Adding dataset tags..."; @@ -15466,6 +15570,39 @@ const hideDatasetMetadataGenerationTableRows = (destination) => { } }; +const editPennsieveMetadata = async () => { + let editingExistingDataset = window.sodaJSONObj?.["starting-point"]?.["type"] === "bf"; + let userDatasetRole = undefined; + if (editingExistingDataset) { + userDatasetRole = await api.getDatasetRole( + window.sodaJSONObj["bf-dataset-selected"]["dataset-name"] + ); + } + + if (userDatasetRole === "editor" || userDatasetRole === "viewer") { + return; + } + + const guidedBfAccount = window.defaultBfAccount; + const guidedDatasetName = window.sodaJSONObj["digital-metadata"]["name"]; + const guidedDatasetSubtitle = window.sodaJSONObj["digital-metadata"]["subtitle"]; + const guidedBannerImagePath = window.sodaJSONObj["digital-metadata"]?.["banner-image-path"]; + const guidedLicense = window.sodaJSONObj["digital-metadata"]["license"]; + const guidedTags = window.sodaJSONObj["digital-metadata"]["dataset-tags"]; + + 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); +}; + const guidedPennsieveDatasetUpload = async () => { guidedSetNavLoadingState(true); try { @@ -15510,22 +15647,17 @@ const guidedPennsieveDatasetUpload = async () => { "guided-div-pennsieve-metadata-pennsieve-genration-status-table" ); + await editPennsieveMetadata(); + + let guest = await window.isWorkspaceGuest(); + // 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); + if (!guest) { + await guidedAddUserPermissions(guidedBfAccount, guidedDatasetName, guidedUsers); + await guidedAddTeamPermissions(guidedBfAccount, guidedDatasetName, guidedTeams); + } 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..7a9acfde80 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) @@ -539,7 +539,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; }; diff --git a/src/renderer/src/scripts/others/renderer.js b/src/renderer/src/scripts/others/renderer.js index 88be44000f..d8c5354c66 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;