diff --git a/dandiapi/api/tests/test_dandiset.py b/dandiapi/api/tests/test_dandiset.py index 7a64181c9..570333953 100644 --- a/dandiapi/api/tests/test_dandiset.py +++ b/dandiapi/api/tests/test_dandiset.py @@ -241,6 +241,21 @@ def test_dandiset_rest_retrieve(api_client, dandiset): } +@pytest.mark.django_db +def test_dandiset_rest_retrieve_embargoed(api_client, dandiset_factory, user): + dandiset: Dandiset = dandiset_factory(embargo_status=Dandiset.EmbargoStatus.EMBARGOED) + resp = api_client.get(f'/api/dandisets/{dandiset.identifier}/') + assert resp.status_code == 401 + + api_client.force_authenticate(user=user) + resp = api_client.get(f'/api/dandisets/{dandiset.identifier}/') + assert resp.status_code == 403 + + dandiset.set_owners([user]) + resp = api_client.get(f'/api/dandisets/{dandiset.identifier}/') + assert resp.status_code == 200 + + @pytest.mark.parametrize( ('embargo_status'), [choice[0] for choice in Dandiset.EmbargoStatus.choices], diff --git a/web/src/views/DandisetLandingView/DandisetLandingView.vue b/web/src/views/DandisetLandingView/DandisetLandingView.vue index 315df8d52..3f86b3b85 100644 --- a/web/src/views/DandisetLandingView/DandisetLandingView.vue +++ b/web/src/views/DandisetLandingView/DandisetLandingView.vue @@ -9,8 +9,30 @@ :total-visible="0" /> + +
+ + + mdi-alert-circle + + This Dandiset is Embargoed + +

+ + If you are an owner of this Dandiset, please log in to enable access. + +
+ + If you are a member of this project, contact the Dandiset owners to enable access. + +

+ + For further assistance, please contact help@dandiarchive.org. + +
+
@@ -92,6 +114,7 @@ import { import type { Ref } from 'vue'; import { onBeforeRouteLeave, useRoute, useRouter } from 'vue-router/composables'; import type { NavigationGuardNext, RawLocation, Route } from 'vue-router'; +import axios from 'axios'; import DandisetSearchField from '@/components/DandisetSearchField.vue'; import Meditor from '@/components/Meditor/Meditor.vue'; @@ -121,7 +144,7 @@ const props = defineProps({ onBeforeRouteLeave((to: Route, from: Route, next: NavigationGuardNext) => { // Prompt user if they try to leave the DLP with unsaved changes in the meditor if (!editorInterface.value?.transactionTracker?.isModified() - // eslint-disable-next-line no-alert + // eslint-disable-next-line no-alert || window.confirm('You have unsaved changes, are you sure you want to leave?')) { next(); return true; @@ -139,6 +162,10 @@ const loading = ref(false); // If loading is finished and currentDandiset is still null, the dandiset doesn't exist. const dandisetDoesNotExist = computed(() => !loading.value && !currentDandiset.value); +// This is set if the request to retrieve the dandiset fails +// due to it being embargoed, or the user being unauthenticated +const embargoedOrUnauthenticated = ref(false); + const schema = computed(() => store.schema); const userCanModifyDandiset = computed(() => store.userCanModifyDandiset); @@ -161,11 +188,27 @@ function navigateToVersion(versionToNavigateTo: string) { // https://stackoverflow.com/a/59127059 watch(() => props.identifier, async () => { const { identifier, version } = props; - if (identifier) { - loading.value = true; + if (!identifier) { + return; + } + + // Set default values + embargoedOrUnauthenticated.value = false; + loading.value = true; + + // Catch error to check if response is 401, for embargoed dandisets + try { await store.initializeDandisets({ identifier, version }); - loading.value = false; + + } catch (e) { + if (axios.isAxiosError(e) && (e.response?.status === 401 || e.response?.status === 403)) { + embargoedOrUnauthenticated.value = true + } else { + throw e + } } + + loading.value = false; }, { immediate: true }); watch([() => props.identifier, () => props.version], async () => { @@ -194,7 +237,7 @@ watch([() => props.identifier, () => props.version], async () => { const page = ref(Number(route.query.pos) || 1); const pages = ref(1); -const nextDandiset : Ref = ref([]); +const nextDandiset: Ref = ref([]); async function fetchNextPage() { const sortOption = Number(route.query.sortOption) || 0;