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
101 changes: 61 additions & 40 deletions docs/useCases.md
Original file line number Diff line number Diff line change
Expand Up @@ -3018,14 +3018,18 @@ Submits guestbook answers for a datafile and returns a signed URL.
import { submitGuestbookForDatafileDownload } from '@iqss/dataverse-client-javascript'

submitGuestbookForDatafileDownload
.execute(10, {
guestbookResponse: {
answers: [
{ id: 123, value: 'Good' },
{ id: 124, value: ['Multi', 'Line'] }
]
}
})
.execute(
10,
{
guestbookResponse: {
answers: [
{ id: 123, value: 'Good' },
{ id: 124, value: ['Multi', 'Line'] }
]
}
},
'original'
)
.then((signedUrl: string) => {
/* ... */
})
Expand All @@ -3043,15 +3047,19 @@ Submits guestbook answers for multiple files and returns a signed URL.
import { submitGuestbookForDatafilesDownload } from '@iqss/dataverse-client-javascript'

submitGuestbookForDatafilesDownload
.execute([10, 11], {
guestbookResponse: {
answers: [
{ id: 123, value: 'Good' },
{ id: 124, value: ['Multi', 'Line'] },
{ id: 125, value: 'Yellow' }
]
}
})
.execute(
[10, 11],
{
guestbookResponse: {
answers: [
{ id: 123, value: 'Good' },
{ id: 124, value: ['Multi', 'Line'] },
{ id: 125, value: 'Yellow' }
]
}
},
'original'
)
.then((signedUrl: string) => {
/* ... */
})
Expand All @@ -3069,15 +3077,19 @@ Submits guestbook answers for dataset download and returns a signed URL.
import { submitGuestbookForDatasetDownload } from '@iqss/dataverse-client-javascript'

submitGuestbookForDatasetDownload
.execute('doi:10.5072/FK2/XXXXXX', {
guestbookResponse: {
answers: [
{ id: 123, value: 'Good' },
{ id: 124, value: ['Multi', 'Line'] },
{ id: 125, value: 'Yellow' }
]
}
})
.execute(
'doi:10.5072/FK2/XXXXXX',
{
guestbookResponse: {
answers: [
{ id: 123, value: 'Good' },
{ id: 124, value: ['Multi', 'Line'] },
{ id: 125, value: 'Yellow' }
]
}
},
'original'
)
.then((signedUrl: string) => {
/* ... */
})
Expand All @@ -3095,19 +3107,24 @@ Submits guestbook answers for a specific dataset version and returns a signed UR
import { submitGuestbookForDatasetVersionDownload } from '@iqss/dataverse-client-javascript'

submitGuestbookForDatasetVersionDownload
.execute(10, ':latest', {
guestbookResponse: {
name: 'Jane Doe',
email: 'jane@example.org',
institution: 'Example University',
position: 'Researcher',
answers: [
{ id: 123, value: 'Good' },
{ id: 124, value: ['Multi', 'Line'] },
{ id: 125, value: 'Yellow' }
]
}
})
.execute(
10,
':latest',
{
guestbookResponse: {
name: 'Jane Doe',
email: 'jane@example.org',
institution: 'Example University',
position: 'Researcher',
answers: [
{ id: 123, value: 'Good' },
{ id: 124, value: ['Multi', 'Line'] },
{ id: 125, value: 'Yellow' }
]
}
},
'original'
)
.then((signedUrl: string) => {
/* ... */
})
Expand All @@ -3119,4 +3136,8 @@ The `datasetId` parameter can be a string, for persistent identifiers, or a numb

The `versionId` parameter accepts a numbered version such as `'1.0'` or a non-numbered version such as `':latest'`.

The third parameter must match [GuestbookResponseDTO](../src/access/domain/dtos/GuestbookResponseDTO.ts). The resolved value is a signed download URL as a string.
The `guestbookResponse` parameter must match [GuestbookResponseDTO](../src/access/domain/dtos/GuestbookResponseDTO.ts).

The optional `format` parameter is sent as a query parameter on the download endpoint. For example, pass `'original'` to request the original dataset or file format.

The resolved value is a signed download URL as a string.
12 changes: 8 additions & 4 deletions src/access/domain/repositories/IAccessRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,26 @@ import { GuestbookResponseDTO } from '../dtos/GuestbookResponseDTO'
export interface IAccessRepository {
submitGuestbookForDatafileDownload(
fileId: number | string,
guestbookResponse: GuestbookResponseDTO
guestbookResponse: GuestbookResponseDTO,
format?: string
): Promise<string>

submitGuestbookForDatafilesDownload(
fileIds: string | Array<number | string>,
guestbookResponse: GuestbookResponseDTO
guestbookResponse: GuestbookResponseDTO,
format?: string
): Promise<string>

submitGuestbookForDatasetDownload(
datasetId: number | string,
guestbookResponse: GuestbookResponseDTO
guestbookResponse: GuestbookResponseDTO,
format?: string
): Promise<string>

submitGuestbookForDatasetVersionDownload(
datasetId: number | string,
versionId: string,
guestbookResponse: GuestbookResponseDTO
guestbookResponse: GuestbookResponseDTO,
format?: string
): Promise<string>
}
13 changes: 11 additions & 2 deletions src/access/domain/useCases/SubmitGuestbookForDatafileDownload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,18 @@ export class SubmitGuestbookForDatafileDownload implements UseCase<string> {
*
* @param {number | string} fileId - Datafile identifier (numeric id or persistent id).
* @param {GuestbookResponseDTO} guestbookResponse - Guestbook response payload.
* @param {string} [format] - Optional download format passed as a query parameter.
* @returns {Promise<string>} - Signed URL for the download.
*/
async execute(fileId: number | string, guestbookResponse: GuestbookResponseDTO): Promise<string> {
return await this.accessRepository.submitGuestbookForDatafileDownload(fileId, guestbookResponse)
async execute(
fileId: number | string,
guestbookResponse: GuestbookResponseDTO,
format?: string
): Promise<string> {
return await this.accessRepository.submitGuestbookForDatafileDownload(
fileId,
guestbookResponse,
format
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@ export class SubmitGuestbookForDatafilesDownload implements UseCase<string> {
*
* @param {string | Array<number | string>} fileIds - Comma-separated string or array of file ids.
* @param {GuestbookResponseDTO} guestbookResponse - Guestbook response payload.
* @param {string} [format] - Optional download format passed as a query parameter.
* @returns {Promise<string>} - Signed URL for the download.
*/
async execute(
fileIds: string | Array<number | string>,
guestbookResponse: GuestbookResponseDTO
guestbookResponse: GuestbookResponseDTO,
format?: string
): Promise<string> {
return await this.accessRepository.submitGuestbookForDatafilesDownload(
fileIds,
guestbookResponse
guestbookResponse,
format
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@ export class SubmitGuestbookForDatasetDownload implements UseCase<string> {
*
* @param {number | string} datasetId - Dataset identifier (numeric id or persistent id).
* @param {GuestbookResponseDTO} guestbookResponse - Guestbook response payload.
* @param {string} [format] - Optional download format passed as a query parameter.
* @returns {Promise<string>} - Signed URL for the download.
*/
async execute(
datasetId: number | string,
guestbookResponse: GuestbookResponseDTO
guestbookResponse: GuestbookResponseDTO,
format?: string
): Promise<string> {
return await this.accessRepository.submitGuestbookForDatasetDownload(
datasetId,
guestbookResponse
guestbookResponse,
format
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,20 @@ export class SubmitGuestbookForDatasetVersionDownload implements UseCase<string>
* @param {number | string} datasetId - Dataset identifier (numeric id or persistent id).
* @param {string} versionId - Dataset version identifier (for example, ':latest' or '1.0').
* @param {GuestbookResponseDTO} guestbookResponse - Guestbook response payload.
* @param {string} [format] - Optional download format passed as a query parameter.
* @returns {Promise<string>} - Signed URL for the download.
*/
async execute(
datasetId: number | string,
versionId: string,
guestbookResponse: GuestbookResponseDTO
guestbookResponse: GuestbookResponseDTO,
format?: string
): Promise<string> {
return await this.accessRepository.submitGuestbookForDatasetVersionDownload(
datasetId,
versionId,
guestbookResponse
guestbookResponse,
format
)
}
}
28 changes: 20 additions & 8 deletions src/access/infra/repositories/AccessRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ export class AccessRepository extends ApiRepository implements IAccessRepository

public async submitGuestbookForDatafileDownload(
fileId: number | string,
guestbookResponse: GuestbookResponseDTO
guestbookResponse: GuestbookResponseDTO,
format?: string
): Promise<string> {
const endpoint = this.buildApiEndpoint(`${this.accessResourceName}/datafile`, undefined, fileId)
return this.doPost(endpoint, guestbookResponse, { signed: true })
const queryParams = format ? { signed: true, format } : { signed: true }

return this.doPost(endpoint, guestbookResponse, queryParams)
.then((response) => {
const signedUrl = response.data.data.signedUrl
return signedUrl
Expand All @@ -22,15 +25,18 @@ export class AccessRepository extends ApiRepository implements IAccessRepository

public async submitGuestbookForDatafilesDownload(
fileIds: Array<number>,
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fileIds parameter type here is narrower than the interface (IAccessRepository allows string | Array<number | string>). This makes Array.isArray(fileIds) effectively dead-code from a typing perspective and prevents callers using AccessRepository directly from passing a comma-separated string. Update this method signature (and any related typing) to match IAccessRepository and keep the Array.isArray branch meaningful.

Suggested change
fileIds: Array<number>,
fileIds: string | Array<number | string>,

Copilot uses AI. Check for mistakes.
guestbookResponse: GuestbookResponseDTO
guestbookResponse: GuestbookResponseDTO,
format?: string
): Promise<string> {
const queryParams = format ? { signed: true, format } : { signed: true }

return this.doPost(
this.buildApiEndpoint(
this.accessResourceName,
`datafiles/${Array.isArray(fileIds) ? fileIds.join(',') : fileIds}`
),
guestbookResponse,
{ signed: true }
queryParams
)
.then((response) => {
const signedUrl = response.data.data.signedUrl
Expand All @@ -43,14 +49,17 @@ export class AccessRepository extends ApiRepository implements IAccessRepository

public async submitGuestbookForDatasetDownload(
datasetId: number | string,
guestbookResponse: GuestbookResponseDTO
guestbookResponse: GuestbookResponseDTO,
format?: string
): Promise<string> {
const endpoint = this.buildApiEndpoint(
`${this.accessResourceName}/dataset`,
undefined,
datasetId
)
return this.doPost(endpoint, guestbookResponse, { signed: true })
const queryParams = format ? { signed: true, format } : { signed: true }

return this.doPost(endpoint, guestbookResponse, queryParams)
.then((response) => {
const signedUrl = response.data.data.signedUrl
return signedUrl
Expand All @@ -63,14 +72,17 @@ export class AccessRepository extends ApiRepository implements IAccessRepository
public async submitGuestbookForDatasetVersionDownload(
datasetId: number | string,
versionId: string,
guestbookResponse: GuestbookResponseDTO
guestbookResponse: GuestbookResponseDTO,
format?: string
): Promise<string> {
const endpoint = this.buildApiEndpoint(
`${this.accessResourceName}/dataset`,
`versions/${versionId}`,
datasetId
)
return this.doPost(endpoint, guestbookResponse, { signed: true })
const queryParams = format ? { signed: true, format } : { signed: true }

return this.doPost(endpoint, guestbookResponse, queryParams)
.then((response) => {
const signedUrl = response.data.data.signedUrl
return signedUrl
Expand Down
11 changes: 11 additions & 0 deletions test/integration/access/AccessRepository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@ describe('AccessRepository', () => {
expect(() => new URL(actual)).not.toThrow()
})

test('should preserve format=original in signed url for dataset download', async () => {
const actual = await sut.submitGuestbookForDatasetDownload(
testDatasetIds.numericId,
guestbookResponse,
'original'
)
const signedUrl = new URL(actual)

expect(signedUrl.searchParams.get('format')).toEqual('original')
})

test('should return error when dataset does not exist', async () => {
const nonExistentId = 999999999
await expect(
Expand Down
Loading
Loading