mirror of
https://github.com/nowcommunity/nowdatabase.git
synced 2026-10-12 19:13:52 +03:00
Address filtered export review comments
This commit is contained in:
@@ -57,6 +57,39 @@ describe('DwC-A locality export (admin-only)', () => {
|
||||
expect(measurementCsv).toContain('"verbatimMeasurementType"')
|
||||
})
|
||||
|
||||
it('returns a filtered ZIP archive for POST requests', async () => {
|
||||
const loginResult = await send<{ token: string }>('user/login', 'POST', { username: 'testSu', password: 'test' })
|
||||
expect(loginResult.status).toEqual(200)
|
||||
|
||||
const result = await request(app)
|
||||
.post('/locality/export/dwc-archive')
|
||||
.set('authorization', `bearer ${loginResult.body.token}`)
|
||||
.send({ ids: [21050] })
|
||||
.buffer(true)
|
||||
.parse(parseBinary)
|
||||
|
||||
expect(result.status).toEqual(200)
|
||||
expect(result.headers['content-type']).toMatch(/application\/zip/i)
|
||||
|
||||
const zip = await JSZip.loadAsync(result.body as unknown as Buffer)
|
||||
const locationCsv = await zip.file('location.csv')!.async('string')
|
||||
expect(locationCsv).toContain('NOW:LOC:21050')
|
||||
expect(locationCsv).not.toContain('NOW:LOC:24750')
|
||||
})
|
||||
|
||||
it('returns 400 for invalid POST id payloads', async () => {
|
||||
const loginResult = await send<{ token: string }>('user/login', 'POST', { username: 'testSu', password: 'test' })
|
||||
expect(loginResult.status).toEqual(200)
|
||||
|
||||
const result = await request(app)
|
||||
.post('/locality/export/dwc-archive')
|
||||
.set('authorization', `bearer ${loginResult.body.token}`)
|
||||
.send({ ids: ['21050.5'] })
|
||||
|
||||
expect(result.status).toEqual(400)
|
||||
expect(result.body).toEqual({ error: 'ids must contain only integers.' })
|
||||
})
|
||||
|
||||
it('rejects non-admin requests', async () => {
|
||||
const result = await request(app).get('/locality/export/dwc-archive')
|
||||
expect(result.status).toEqual(403)
|
||||
|
||||
@@ -66,6 +66,39 @@ describe('DwC-A species export (admin-only)', () => {
|
||||
expect(metaXml).toContain('<extension')
|
||||
})
|
||||
|
||||
it('returns a filtered ZIP archive for POST requests', async () => {
|
||||
const loginResult = await send<{ token: string }>('user/login', 'POST', { username: 'testSu', password: 'test' })
|
||||
expect(loginResult.status).toEqual(200)
|
||||
|
||||
const result = await request(app)
|
||||
.post('/species/export/dwc-archive')
|
||||
.set('authorization', `bearer ${loginResult.body.token}`)
|
||||
.send({ ids: [85729] })
|
||||
.buffer(true)
|
||||
.parse(parseBinary)
|
||||
|
||||
expect(result.status).toEqual(200)
|
||||
expect(result.headers['content-type']).toMatch(/application\/zip/i)
|
||||
|
||||
const zip = await JSZip.loadAsync(result.body as unknown as Buffer)
|
||||
const taxonCsv = await zip.file('taxon.csv')!.async('string')
|
||||
expect(taxonCsv).toContain('NOW:85729')
|
||||
expect(taxonCsv).not.toContain('NOW:85730')
|
||||
})
|
||||
|
||||
it('returns 400 for invalid POST id payloads', async () => {
|
||||
const loginResult = await send<{ token: string }>('user/login', 'POST', { username: 'testSu', password: 'test' })
|
||||
expect(loginResult.status).toEqual(200)
|
||||
|
||||
const result = await request(app)
|
||||
.post('/species/export/dwc-archive')
|
||||
.set('authorization', `bearer ${loginResult.body.token}`)
|
||||
.send({ ids: ['85729abc'] })
|
||||
|
||||
expect(result.status).toEqual(400)
|
||||
expect(result.body).toEqual({ error: 'ids must contain only integers.' })
|
||||
})
|
||||
|
||||
it('rejects non-admin requests', async () => {
|
||||
const result = await request(app).get('/species/export/dwc-archive')
|
||||
expect(result.status).toEqual(403)
|
||||
|
||||
@@ -34,7 +34,9 @@ router.get('/export/dwc-archive', requireOneOf([Role.Admin]), async (_req, res)
|
||||
|
||||
router.post('/export/dwc-archive', requireOneOf([Role.Admin]), async (req, res) => {
|
||||
try {
|
||||
return await sendDwcArchive(parseNumericIds((req.body as { ids?: unknown }).ids), res)
|
||||
const body = req.body as { ids?: unknown } | undefined
|
||||
if (!body || !('ids' in body)) throw new Error('ids must be an array.')
|
||||
return await sendDwcArchive(parseNumericIds(body.ids), res)
|
||||
} catch (error) {
|
||||
return res.status(400).send({ error: error instanceof Error ? error.message : 'Invalid export filters.' })
|
||||
}
|
||||
|
||||
@@ -33,7 +33,9 @@ router.get('/export/dwc-archive', requireOneOf([Role.Admin]), async (_req, res)
|
||||
|
||||
router.post('/export/dwc-archive', requireOneOf([Role.Admin]), async (req, res) => {
|
||||
try {
|
||||
return await sendDwcArchive(parseNumericIds((req.body as { ids?: unknown }).ids), res)
|
||||
const body = req.body as { ids?: unknown } | undefined
|
||||
if (!body || !('ids' in body)) throw new Error('ids must be an array.')
|
||||
return await sendDwcArchive(parseNumericIds(body.ids), res)
|
||||
} catch (error) {
|
||||
return res.status(400).send({ error: error instanceof Error ? error.message : 'Invalid export filters.' })
|
||||
}
|
||||
|
||||
@@ -956,11 +956,18 @@ const fetchOccurrencesForDwcDataPackageExport = async (
|
||||
}
|
||||
|
||||
export const buildDwcDataPackageZipBuffer = async (occurrenceKeys?: DwcOccurrenceKey[]): Promise<Buffer> => {
|
||||
const { nowDb } = await import('../utils/db')
|
||||
const occurrences = await fetchOccurrencesForDwcDataPackageExport(occurrenceKeys)
|
||||
const localityIds = occurrenceKeys ? [...new Set(occurrences.map(occurrence => occurrence.lid))] : undefined
|
||||
return await buildDwcDataPackageZipBufferFromOccurrences(occurrences, Boolean(occurrenceKeys))
|
||||
}
|
||||
|
||||
const buildDwcDataPackageZipBufferFromOccurrences = async (
|
||||
occurrences: OccurrenceForDwcDpExport[],
|
||||
isFilteredExport: boolean
|
||||
): Promise<Buffer> => {
|
||||
const { nowDb } = await import('../utils/db')
|
||||
const localityIds = isFilteredExport ? [...new Set(occurrences.map(occurrence => occurrence.lid))] : undefined
|
||||
const localities = (await nowDb.now_loc.findMany({
|
||||
where: localityIds ? { lid: { in: localityIds } } : undefined,
|
||||
where: isFilteredExport ? { lid: { in: localityIds } } : undefined,
|
||||
orderBy: { lid: 'asc' },
|
||||
select: localitySelect,
|
||||
})) as unknown as LocalityForDwcDpExport[]
|
||||
@@ -1129,13 +1136,9 @@ export const buildFullDarwinCoreExportZipBufferFromArchives = async ({
|
||||
|
||||
export const buildFullDarwinCoreExportZipBuffer = async (occurrenceKeys?: DwcOccurrenceKey[]): Promise<Buffer> => {
|
||||
const occurrences = occurrenceKeys ? await fetchOccurrencesForDwcDataPackageExport(occurrenceKeys) : undefined
|
||||
const filteredOccurrenceKeys = occurrences?.map(occurrence => ({
|
||||
lid: occurrence.lid,
|
||||
speciesId: occurrence.species_id,
|
||||
}))
|
||||
const speciesIds = occurrences ? [...new Set(occurrences.map(occurrence => occurrence.species_id))] : undefined
|
||||
const [dwcDataPackageZipBuffer, dwcTaxonArchiveZipBuffer] = await Promise.all([
|
||||
buildDwcDataPackageZipBuffer(filteredOccurrenceKeys),
|
||||
occurrences ? buildDwcDataPackageZipBufferFromOccurrences(occurrences, true) : buildDwcDataPackageZipBuffer(),
|
||||
buildDwcArchiveZipBuffer(speciesIds),
|
||||
])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user