Skip to content
Merged
9 changes: 9 additions & 0 deletions gateway/config/settings/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@
# http://whitenoise.evans.io/en/latest/django.html#using-whitenoise-in-development
INSTALLED_APPS: list[str] = ["whitenoise.runserver_nostatic", *INSTALLED_APPS]

# TEMPLATES
# ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/latest/topics/templates/#module-django.template.backends.django
# 'debug': a boolean that turns on/off template debug mode.
# If it is True, the fancy error page will display a detailed report for any exception
# raised during template rendering. This report contains the relevant snippet of the
# template with the appropriate line highlighted.
TEMPLATES[0]["OPTIONS"]["debug"] = True

# DJANGO-DEBUG-TOOLBAR
# ------------------------------------------------------------------------------
Expand All @@ -76,6 +84,7 @@
],
"SHOW_TEMPLATE_CONTEXT": True,
}

# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#internal-ips
INTERNAL_IPS: list[str] = ["127.0.0.1", "10.0.2.2"]
if env("USE_DOCKER") == "yes":
Expand Down
4 changes: 3 additions & 1 deletion gateway/justfile
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ logs-once *args:
[group('service')]
down *args:
@echo "Stopping sds-gateway"
{{ docker_compose }} down {{ args }}
{{ docker_compose }} down --remove-orphans {{ args }}

# runs the pre-commit hooks with dev dependencies
[group('development')]
Expand Down Expand Up @@ -259,6 +259,8 @@ up *args:
echo "Starting sds-gateway in detached mode"
echo "Environment: '{{ env }}'"
echo "Compose file: '{{ compose_file }}'"
echo "Tip: call \`just build\` before \`just up\` to prevent "
echo " Docker from trying to pull a locally built image from the registry"
{{ docker_compose }} up --detach --remove-orphans {{ args }}

# this watcher is not working as intended today, and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@
from sds_gateway.api_methods.models import PermissionLevel
from sds_gateway.api_methods.models import UserSharePermission

READABLE_ISO_DATE_TIME: str = "%Y-%m-%d %H:%M:%S%z"


class DatasetGetSerializer(serializers.ModelSerializer[Dataset]):
authors = serializers.SerializerMethodField()
keywords = serializers.SerializerMethodField()
created_at = serializers.DateTimeField(format="%m/%d/%Y %H:%M:%S", read_only=True)
created_at = serializers.DateTimeField(
format=READABLE_ISO_DATE_TIME, read_only=True
)
is_shared_with_me = serializers.SerializerMethodField()
is_owner = serializers.SerializerMethodField()
status_display = serializers.CharField(source="get_status_display", read_only=True)
Expand Down Expand Up @@ -165,3 +169,80 @@ def get_can_edit(self, obj):
class Meta:
model = Dataset
fields = "__all__"


class DatasetPublicSerializer(serializers.ModelSerializer[Dataset]):
"""
Serializer for public dataset access (unauthenticated or public datasets).

This serializer uses an explicit allowlist of fields to avoid exposing
sensitive internal metadata like shared_with user IDs or owner information.
"""

authors = serializers.SerializerMethodField()
keywords = serializers.SerializerMethodField()
created_at = serializers.DateTimeField(
format=READABLE_ISO_DATE_TIME, read_only=True
)
status_display = serializers.CharField(source="get_status_display", read_only=True)
owner_name = serializers.SerializerMethodField()

def get_authors(self, obj):
"""Return the full authors list using the model's get_authors_display method."""
return obj.get_authors_display()

def get_keywords(self, obj):
"""Return a list of keyword names for the dataset."""
return [kw.name for kw in obj.keywords.filter(is_deleted=False)]

def get_owner_name(self, obj):
"""Get the owner's display name."""
return obj.owner.name if obj.owner else "Owner"

class Meta:
model = Dataset
fields = [
"uuid",
"name",
"status",
"status_display",
"abstract",
"description",
"doi",
"authors",
"license",
"keywords",
"institutions",
"release_date",
"repository",
"version",
"website",
"provenance",
"citation",
"other",
"created_at",
"is_public",
"owner_name",
]


def get_dataset_serializer(dataset: Dataset, *, has_user_access: bool) -> dict: # pyright: ignore[reportMissingTypeArgument]
"""
Get serialized dataset data using the appropriate serializer.

Args:
dataset: The dataset to serialize
has_user_access: Whether the requesting user has authenticated access

Returns:
Serialized dataset data as a dictionary

Notes:
- Uses DatasetGetSerializer for authenticated users with access
(includes sharing info, permissions, etc.)
- Uses DatasetPublicSerializer for unauthenticated/public-only access
(excludes sensitive fields like shared_with user IDs)
"""
if has_user_access:
return DatasetGetSerializer(dataset).data
return DatasetPublicSerializer(dataset).data
2 changes: 1 addition & 1 deletion gateway/sds_gateway/api_methods/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ def notify_shared_users(
if item_type == "dataset":
item_url = f"{settings.SITE_URL}/users/dataset-list/"
elif item_type == "capture":
item_url = f"{settings.SITE_URL}/users/file-list/"
item_url = f"{settings.SITE_URL}/users/capture-list/"
else:
item_url = settings.SITE_URL

Expand Down
80 changes: 52 additions & 28 deletions gateway/sds_gateway/static/css/file-manager.css
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,6 @@
--z-index-sticky: 10;
}

/* Base Styles */
/* Apply Google Sans font only to file manager content */
.files-page-container {
font-family: var(--font-family);
}

/* Accessibility */
/* Focus styles for keyboard navigation */
.file-card:focus-visible,
Expand Down Expand Up @@ -70,8 +64,10 @@
display: flex;
flex-direction: column;
height: auto;
min-height: 200px; /* Minimum height to prevent empty state from looking too small */
max-height: calc(100vh - 250px); /* Maximum height based on viewport */
min-height: 200px;
/* Minimum height to prevent empty state from looking too small */
max-height: calc(100vh - 250px);
/* Maximum height based on viewport */
overflow: auto;
}

Expand All @@ -84,8 +80,10 @@
border: 1px solid var(--color-border);
border-radius: 8px;
margin: 0 16px;
height: auto; /* Let it grow based on content */
min-height: 100px; /* Minimum height for empty state */
height: auto;
/* Let it grow based on content */
min-height: 100px;
/* Minimum height for empty state */
}

/* Individual file card */
Expand Down Expand Up @@ -163,13 +161,15 @@
.file-card:hover .file-name,
.file-card:hover .folder-icon,
.file-card:hover .file-icon {
color: #005a9c; /* SpectrumX blue */
color: #005a9c;
/* SpectrumX blue */
}

/* No hover effects for H5 files */
.file-card[data-type="file"]:not([data-h5-file="true"]):hover .file-name,
.file-card[data-type="file"]:not([data-h5-file="true"]):hover .file-icon {
color: #005a9c; /* SpectrumX blue */
color: #005a9c;
/* SpectrumX blue */
}

/* Directory hover should also use the same blue */
Expand All @@ -182,13 +182,16 @@
color: var(--color-text-secondary);
white-space: nowrap;
flex-shrink: 0;
min-width: 150px; /* Increased width for modified date */
text-align: center; /* Center align the modified date */
min-width: 150px;
/* Increased width for modified date */
text-align: center;
/* Center align the modified date */
display: flex;
align-items: center;
justify-content: center;
position: relative;
padding-right: 24px; /* reserve space for right-aligned shared icon */
padding-right: 24px;
/* reserve space for right-aligned shared icon */
}

/* Keep the shared-with icon from shifting the centered date */
Expand All @@ -198,9 +201,12 @@
color: var(--color-text-secondary);
white-space: nowrap;
flex-shrink: 0;
min-width: 120px; /* Fixed width for shared by column */
text-align: center; /* Center align shared by */
margin-left: 0; /* Remove offset that pushes content */
min-width: 120px;
/* Fixed width for shared by column */
text-align: center;
/* Center align shared by */
margin-left: 0;
/* Remove offset that pushes content */
display: flex;
align-items: center;
justify-content: center;
Expand All @@ -210,8 +216,10 @@
font-size: 0.8125rem;
white-space: nowrap;
flex-shrink: 0;
min-width: 80px; /* Fixed width for actions column */
text-align: center; /* Center align actions */
min-width: 80px;
/* Fixed width for actions column */
text-align: center;
/* Center align actions */
display: flex;
align-items: center;
justify-content: center;
Expand Down Expand Up @@ -268,7 +276,8 @@
font-size: 0.875rem;
height: var(--breadcrumb-height);
font-family: var(--font-family);
font-weight: 400; /* Add normal font weight */
font-weight: 400;
/* Add normal font weight */
}

.breadcrumb-item {
Expand All @@ -281,7 +290,8 @@
padding: 0 4px;
border-radius: 4px;
font-family: var(--font-family);
font-weight: 400; /* Add normal font weight */
font-weight: 400;
/* Add normal font weight */
}

.breadcrumb-item:hover {
Expand All @@ -293,7 +303,8 @@
text-decoration: none;
padding: 0 4px;
font-family: var(--font-family);
font-weight: 400; /* Add normal font weight */
font-weight: 400;
/* Add normal font weight */
}

.breadcrumb-item:hover a {
Expand Down Expand Up @@ -383,7 +394,8 @@
list-style: none;
padding: 0;
margin: 0;
max-height: var(--file-list-max-height); /* taller list for large folder previews */
max-height: var(--file-list-max-height);
/* taller list for large folder previews */
overflow-y: auto;
border: 1px solid #dee2e6;
border-radius: 4px;
Expand Down Expand Up @@ -771,9 +783,11 @@

/* Actions Bar (scoped) */
.files-actions-bar {
margin: 24px 16px; /* Keep the margin */
margin: 24px 16px;
/* Keep the margin */
display: flex;
justify-content: flex-start; /* Align to the left */
justify-content: flex-start;
/* Align to the left */
align-items: center;
}

Expand All @@ -793,8 +807,10 @@
align-items: center;
gap: 8px;
transition: var(--transition-default);
min-width: 100px; /* Give the button a minimum width */
justify-content: center; /* Center the button content */
min-width: 100px;
/* Give the button a minimum width */
justify-content: center;
/* Center the button content */
}

.new-button:hover {
Expand Down Expand Up @@ -860,6 +876,7 @@
.files-actions-bar {
margin: 16px 8px;
}

.files-grid {
margin: 0 8px;
}
Expand All @@ -869,6 +886,7 @@
padding: 8px 12px;
gap: 8px;
}

.file-name {
padding-right: 0;
}
Expand All @@ -878,6 +896,7 @@
.file-shared {
display: none;
}

.file-card.header .file-meta,
.file-card.header .file-shared {
display: none;
Expand All @@ -887,9 +906,11 @@
.upload-zone {
padding: 1rem;
}

.upload-zone-icon {
font-size: 2.4rem;
}

.selected-files-list {
max-height: 220px;
}
Expand All @@ -900,6 +921,7 @@
height: auto;
row-gap: 4px;
}

.breadcrumb-item {
height: auto;
}
Expand All @@ -911,9 +933,11 @@
.modal-footer {
padding: 12px 16px;
}

.modal-body {
padding: 16px;
}

.modal-dialog {
margin: 0.5rem;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1095,7 +1095,7 @@ class UserSearchHandler {
if (this.itemType === "dataset") {
refreshUrl = `/users/dataset-list/?page=${currentPage}&sort_by=${sortBy}&sort_order=${sortOrder}`;
} else if (this.itemType === "capture") {
refreshUrl = `/users/file-list/?page=${currentPage}&sort_by=${sortBy}&sort_order=${sortOrder}`;
refreshUrl = `/users/capture-list/?page=${currentPage}&sort_by=${sortBy}&sort_order=${sortOrder}`;
} else {
console.error(`Unknown item type: ${this.itemType}`);
return;
Expand Down
Loading