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;