Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ Types of changes:
- `Fixed`: for any bug fixes.
- `Security`: in case of vulnerabilities.

## [x.y.z]

- Added new download functions to /api/sedfittingresult, replacing view functions: download_chains, download_modelfit, download_percentiles.
- New download URL: /api/sedfittingresult/{id}/download/{download-type}/
- Fixed download URLs on /api/sedfittingresult using new download functions, rerouted transient download on front-end to these functions. Functionality from front-end is identical.


## [1.12.0]

### Added
Expand Down
53 changes: 52 additions & 1 deletion app/api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from host import models
from rest_framework import serializers
from django.urls import reverse


class CutoutField(serializers.RelatedField):
Expand All @@ -18,7 +19,6 @@ class Meta:
"photometric_class",
"processing_status",
"added_by"
# "host",
]

aliases = serializers.SerializerMethodField()
Expand Down Expand Up @@ -81,11 +81,62 @@ def get_host(self, obj):


class SEDFittingResultSerializer(serializers.ModelSerializer):
chains_file = serializers.SerializerMethodField()
model_file = serializers.SerializerMethodField()
percentiles_file = serializers.SerializerMethodField()
class Meta:
model = models.SEDFittingResult
depth = 1
exclude = ["log_tau_16", "log_tau_50", "log_tau_84", "posterior"]

def to_representation(self, instance):
# """Hardcode download URL"""
ret = super().to_representation(instance)
ret['chains_file'] = self.get_chains_file(instance)
ret['model_file'] = self.get_model_file(instance)
ret['percentiles_file'] = self.get_percentiles_file(instance)

return ret

def get_chains_file(self, obj):
request = self.context["request"]

return request.build_absolute_uri(
reverse(
"sedfittingresult-download",
kwargs={
"pk": obj.pk,
"file_type": "chains",
},
)
)

def get_model_file(self, obj):
request = self.context["request"]

return request.build_absolute_uri(
reverse(
"sedfittingresult-download",
kwargs={
"pk": obj.pk,
"file_type": "model",
},
)
)

def get_percentiles_file(self, obj):
request = self.context["request"]

return request.build_absolute_uri(
reverse(
"sedfittingresult-download",
kwargs={
"pk": obj.pk,
"file_type": "percentiles",
},
)
)


class CutoutSerializer(serializers.ModelSerializer):
class Meta:
Expand Down
26 changes: 25 additions & 1 deletion app/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
from django.shortcuts import render
from django_filters.rest_framework import DjangoFilterBackend
from django.contrib.auth.decorators import login_required, permission_required
from django.shortcuts import get_object_or_404
from rest_framework import status
from rest_framework import viewsets
from rest_framework.decorators import api_view
from rest_framework.decorators import api_view, action
from rest_framework.response import Response
from host.object_store import ObjectStore
from host.models import Aperture
Expand Down Expand Up @@ -48,6 +49,16 @@
from host.log import get_logger
logger = get_logger(__name__)

def stream_download_file(file_path):
# Stream the data file from the S3 bucket
s3 = ObjectStore()
object_key = os.path.join(settings.S3_BASE_PATH, file_path.strip('/'))
filename = os.path.basename(file_path)
obj_stream = s3.stream_object(object_key)
response = StreamingHttpResponse(streaming_content=obj_stream)
response["Content-Disposition"] = f"attachment; filename={filename}"
return response


############################################################
# Filter Sets
Expand Down Expand Up @@ -188,6 +199,19 @@ class SEDFittingResultViewSet(viewsets.ReadOnlyModelViewSet):
filter_backends = (DjangoFilterBackend,)
filterset_class = SEDFittingResultFilter

@action(methods=['get'], detail=True, url_path=r"download/(?P<file_type>[^/.]+)")
def download(self, request, pk=None, file_type=None):
sed_result = self.get_object()
if file_type == 'chains':
file_field = sed_result.chains_file
elif file_type == 'model':
file_field = sed_result.model_file
elif file_type == 'percentiles':
file_field = sed_result.percentiles_file
else:
return Response({'error':"unknown file type"}, status=400)

return stream_download_file(file_field.name)

class TaskRegisterViewSet(viewsets.ReadOnlyModelViewSet):
queryset = TaskRegister.objects.all()
Expand Down
3 changes: 0 additions & 3 deletions app/host/static/robots.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
User-agent: *
Disallow: /transient/
Disallow: /add/
Disallow: /download_chains/
Disallow: /download_modelfit/
Disallow: /download_percentiles/
Disallow: /retrigger_transient/
Disallow: /reprocess_transient/
Disallow: /report_issue/
Expand Down
10 changes: 0 additions & 10 deletions app/host/templates/host/sed_card.html
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,6 @@ <h4>Spectral Energy Distribution</h4>
}
</script>
{% endif %}
<!--
<button style="margin-bottom:5px;" type="button" class="report" onclick="window.open('{% url 'download_modelfit' transient.name 'local' %}','_self')">
<span>Download Best-Fit Model</span>
</button>
-->
</div>
</div>

Expand Down Expand Up @@ -120,11 +115,6 @@ <h4>Spectral Energy Distribution</h4>
}
</script>
{% endif %}
<!--
<button style="margin-bottom:5px;" type="button" class="report" onclick="window.open('{% url 'download_modelfit' transient.name 'global' %}','_self')">
<span>Download Best-Fit Model</span>
</button>
-->
</div>
</div>
</div>
Expand Down
20 changes: 0 additions & 20 deletions app/host/templates/host/sed_inference_card.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,6 @@ <h4>Host SED inference</h4>
<h4>Local parameter details</h4>
<h6><a href="https://blast.readthedocs.io/en/latest/usage/sed_params.html">Documentation</a></h6>
{% if local_sed_results %}
<!--
<div>
<button style="margin-bottom:5px;" type="button" class="report" onclick="window.open('{% url 'download_chains' transient.name 'local' %}','_self')">
<span>Download Chains</span>
</button>
<button style="margin-bottom:5px;" type="button" class="report" onclick="window.open('{% url 'download_percentiles' transient.name 'local' %}','_self')">
<span>Download Percentiles</span>
</button>
</div>
-->

<br>

Expand Down Expand Up @@ -108,16 +98,6 @@ <h5>Binned star formation history</h5>
<h4>Global parameter details</h4>
<h6><a href="https://blast.readthedocs.io/en/latest/usage/sed_params.html">Documentation</a></h6>
{% if global_sed_results %}
<!--
<div>
<button style="margin-bottom:5px;" type="button" class="report" onclick="window.open('{% url 'download_chains' transient.name 'global' %}','_self')">
<span>Download Chains</span>
</button>
<button style="margin-bottom:5px;" type="button" class="report" onclick="window.open('{% url 'download_percentiles' transient.name 'global' %}','_self')">
<span>Download Percentiles</span>
</button>
</div>
-->

<br>

Expand Down
12 changes: 6 additions & 6 deletions app/host/templates/host/transient_actions.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
<a class="dropdown-item" title="Export without files (legacy)" href="/api/transient/get/{{transient.name}}?format=json"><i class="bi bi-filetype-json"></i> Export without files (legacy .json)</a>
{% if local_sed_results %}
<div class="dropdown-divider"></div>
<a class="dropdown-item" title="Local parameter confidence intervals" href="{% url 'download_modelfit' transient.name 'local' %}"><i class="bi bi-graph-up"></i> Local SED best-fit model (.npz)</a>
<a class="dropdown-item" title="Local parameter confidence intervals" href="{% url 'download_percentiles' transient.name 'local' %}"><i class="bi bi-percent"></i> Local parameter confidence intervals (.npz)</a>
<a class="dropdown-item" title="Local parameter estimation chains" href="{% url 'download_chains' transient.name 'local' %}"><i class="bi bi-link"></i> Local parameter estimation chains (.npz)</a>
<a class="dropdown-item" title="Local SED best-fit model" href="{% url 'sedfittingresult-download' transient.id 'model' %}"><i class="bi bi-graph-up"></i> Local SED best-fit model (.npz)</a>
<a class="dropdown-item" title="Local parameter confidence intervals" href="{% url 'sedfittingresult-download' transient.id 'percentiles' %}"><i class="bi bi-percent"></i> Local parameter confidence intervals (.npz)</a>
<a class="dropdown-item" title="Local parameter estimation chains" href="{% url 'sedfittingresult-download' transient.id 'chains' %}"><i class="bi bi-link"></i> Local parameter estimation chains (.npz)</a>
{% endif %}
{% if global_sed_results %}
<div class="dropdown-divider"></div>
<a class="dropdown-item" title="Global parameter confidence intervals" href="{% url 'download_modelfit' transient.name 'global' %}"><i class="bi bi-graph-up"></i> Global SED best-fit model (.npz)</a>
<a class="dropdown-item" title="Global parameter confidence intervals" href="{% url 'download_percentiles' transient.name 'global' %}"><i class="bi bi-percent"></i> Global parameter confidence intervals (.npz)</a>
<a class="dropdown-item" title="Global parameter estimation chains" href="{% url 'download_chains' transient.name 'global' %}"><i class="bi bi-link"></i> Global parameter estimation chains (.npz)</a>
<a class="dropdown-item" title=Global SED best-fit model" href="{% url 'sedfittingresult-download' transient.id 'model' %}"><i class="bi bi-graph-up"></i> Global SED best-fit model (.npz)</a>
<a class="dropdown-item" title="Global parameter confidence intervals" href="{% url 'sedfittingresult-download' transient.id 'percentiles' %}"><i class="bi bi-percent"></i> Global parameter confidence intervals (.npz)</a>
<a class="dropdown-item" title="Global parameter estimation chains" href="{% url 'sedfittingresult-download' transient.id 'chains' %}"><i class="bi bi-link"></i> Global parameter estimation chains (.npz)</a>
{% endif %}
</div>
</li>
Expand Down
17 changes: 1 addition & 16 deletions app/host/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,6 @@
path(f"""{base_path}transients/""", views.transient_list, name="transient_list"),
path(f"""{base_path}add/""", views.add_transient, name="add_transient"),
path(f"""{base_path}transients/<slug:transient_name>/""", views.results, name="results"),
path(
f"""{base_path}download_chains/<slug:slug>/<str:aperture_type>/""",
views.download_chains,
name="download_chains",
),
path(
f"""{base_path}download_modelfit/<slug:slug>/<str:aperture_type>/""",
views.download_modelfit,
name="download_modelfit",
),
path(
f"""{base_path}download_percentiles/<slug:slug>/<str:aperture_type>/""",
views.download_percentiles,
name="download_percentiles",
),
path(f"""{base_path}acknowledgements/""", views.acknowledgements, name="acknowledgements"),
path(f"""{base_path}team/""", views.team, name="team"),
path(f"""{base_path}""", views.home),
Expand Down Expand Up @@ -72,7 +57,7 @@
router.register(r"cutout", api.views.CutoutViewSet)
router.register(r"filter", api.views.FilterViewSet)
router.register(r"aperturephotometry", api.views.AperturePhotometryViewSet)
router.register(r"sedfittingresult", api.views.SEDFittingResultViewSet)
router.register(r"sedfittingresult", api.views.SEDFittingResultViewSet, basename="sedfittingresult")
router.register(r"taskregister", api.views.TaskRegisterViewSet)
router.register(r"task", api.views.TaskViewSet)
router.register(r"host", api.views.HostViewSet)
Expand Down
35 changes: 0 additions & 35 deletions app/host/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -634,41 +634,6 @@ def compile_sed_results(transient, category, scope):
return render(request, "results.html", context)


def stream_sed_output_file(file_path):
# Stream the data file from the S3 bucket
s3 = ObjectStore()
object_key = os.path.join(settings.S3_BASE_PATH, file_path.strip('/'))
filename = os.path.basename(file_path)
obj_stream = s3.stream_object(object_key)
response = StreamingHttpResponse(streaming_content=obj_stream)
response["Content-Disposition"] = f"attachment; filename={filename}"
return response


@log_usage_metric()
def download_chains(request, slug, aperture_type):
sed_result = get_object_or_404(
SEDFittingResult, transient__name=slug, aperture__type=aperture_type
)
return stream_sed_output_file(sed_result.chains_file.name)


@log_usage_metric()
def download_modelfit(request, slug, aperture_type):
sed_result = get_object_or_404(
SEDFittingResult, transient__name=slug, aperture__type=aperture_type
)
return stream_sed_output_file(sed_result.model_file.name)


@log_usage_metric()
def download_percentiles(request, slug, aperture_type):
sed_result = get_object_or_404(
SEDFittingResult, transient__name=slug, aperture__type=aperture_type
)
return stream_sed_output_file(sed_result.percentiles_file.name)


@log_usage_metric()
def acknowledgements(request):
context = {}
Expand Down