diff --git a/website/src/components/SequenceDetailsPage/SequencesDataTable.astro b/website/src/components/SequenceDetailsPage/SequencesDataTable.astro
index d48b46468c..9d3f692d93 100644
--- a/website/src/components/SequenceDetailsPage/SequencesDataTable.astro
+++ b/website/src/components/SequenceDetailsPage/SequencesDataTable.astro
@@ -2,6 +2,7 @@
import { SequencesContainer } from './SequencesContainer';
import { type TableDataEntry } from './getTableData';
import { getReferenceGenomes, getRuntimeConfig } from '../../config';
+import { routes } from '../../routes.ts';
interface Props {
tableData: TableDataEntry[];
@@ -33,6 +34,14 @@ const nucleotideSegmentNames = referenceGenomes.nucleotideSequences.map((s) => s
+
{
+export const GET: APIRoute = async ({ params, redirect, request }) => {
const accessionVersion = params.accessionVersion!;
const organism = params.organism!;
- const result = await getSequenceDetailsUnalignedFasta(accessionVersion, organism);
+ const isDownload = new URL(request.url).searchParams.has('download');
+
+ const result = await getSequenceDetailsUnalignedFasta(accessionVersion, organism, isDownload);
if (!result.isOk()) {
return new Response(undefined, {
status: 404,
@@ -23,10 +25,16 @@ export const GET: APIRoute = async ({ params, redirect }) => {
return redirect(result.value.redirectUrl);
}
+ const headers: Record = {
+ 'Content-Type': 'text/x-fasta',
+ };
+ if (isDownload) {
+ const filename = `${accessionVersion}.fa`;
+ headers['Content-Disposition'] = `attachment; filename="${filename}"`;
+ }
+
return new Response(result.value.fasta, {
- headers: {
- 'Content-Type': 'text/x-fasta',
- },
+ headers,
});
};
@@ -48,6 +56,7 @@ type Redirect = {
const getSequenceDetailsUnalignedFasta = async (
accessionVersion: string,
organism: string,
+ isDownload: boolean,
): Promise> => {
const { accession, version } = parseAccessionVersionFromString(accessionVersion);
@@ -57,7 +66,7 @@ const getSequenceDetailsUnalignedFasta = async (
const latestVersionResult = await lapisClient.getLatestAccessionVersion(accession);
return latestVersionResult.map((latestVersion) => ({
type: ResultType.REDIRECT,
- redirectUrl: routes.sequencesFastaPage(organism, latestVersion),
+ redirectUrl: routes.sequencesFastaPage(organism, latestVersion, isDownload),
}));
}
diff --git a/website/src/routes.ts b/website/src/routes.ts
index f6ff7dcf7b..d35e0aff7d 100644
--- a/website/src/routes.ts
+++ b/website/src/routes.ts
@@ -24,8 +24,13 @@ export const routes = {
`/${organism}/seq/${getAccessionVersionString(accessionVersion)}`,
sequencesVersionsPage: (organism: string, accessionVersion: AccessionVersion | string) =>
`/${organism}/seq/${getAccessionVersionString(accessionVersion)}/versions`,
- sequencesFastaPage: (organism: string, accessionVersion: AccessionVersion | string) =>
- `${routes.sequencesDetailsPage(organism, accessionVersion)}.fa`,
+ sequencesFastaPage: (organism: string, accessionVersion: AccessionVersion | string, download = false) => {
+ let url = `${routes.sequencesDetailsPage(organism, accessionVersion)}.fa`;
+ if (download) {
+ url += '?download';
+ }
+ return url;
+ },
submitPage: (organism: string) => withOrganism(organism, '/submit'),
revisePage: (organism: string) => withOrganism(organism, '/revise'),
editPage: (organism: string, accessionVersion: AccessionVersion) =>
diff --git a/website/tests/pages/sequences/accession.fa.spec.ts b/website/tests/pages/sequences/accession.fa.spec.ts
index 525f7bc04b..9f35f49c0f 100644
--- a/website/tests/pages/sequences/accession.fa.spec.ts
+++ b/website/tests/pages/sequences/accession.fa.spec.ts
@@ -4,7 +4,18 @@ import { baseUrl, dummyOrganism, expect, test, testSequenceEntry } from '../../e
test.describe('The sequence.fa page', () => {
test('can load and show fasta file', async () => {
const url = `${baseUrl}${routes.sequencesFastaPage(dummyOrganism.key, testSequenceEntry)}`;
- const content = await (await fetch(url)).text();
+ const response = await fetch(url);
+ const content = await response.text();
expect(content).toBe(`>${testSequenceEntry.name}\n${testSequenceEntry.unaligned}\n`);
});
+
+ test('can download fasta file', async () => {
+ const downloadUrl = `${baseUrl}${routes.sequencesFastaPage(dummyOrganism.key, testSequenceEntry, true)}`;
+ const response = await fetch(downloadUrl);
+ const contentDisposition = response.headers.get('Content-Disposition');
+
+ expect(contentDisposition).not.toBeNull();
+ expect(contentDisposition).toContain('attachment');
+ expect(contentDisposition).toContain(testSequenceEntry.name);
+ });
});