Skip to content
Merged
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
83 changes: 83 additions & 0 deletions docs/useCases.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ The different use cases currently available in the package are classified below,
- [Mark As Read](#mark-as-read)
- [Search](#Search)
- [Get Search Services](#get-search-services)
- [External Tools](#external-tools)
- [External Tools read use cases](#external-tools-read-use-cases)
- [Get External Tools](#get-external-tools)
- [Get Dataset External Tool Resolved](#get-dataset-external-tool-resolved)
- [Get File External Tool Resolved](#get-file-external-tool-resolved)

## Collections

Expand Down Expand Up @@ -2281,3 +2286,81 @@ getSearchServices.execute().then((searchServices: SearchService[]) => {
```

_See [use case](../src/search/domain/useCases/GetSearchServices.ts) implementation_.

## External Tools

### External Tools Read Use Cases

#### Get External Tools

Returns an array of [ExternalTool](../src/externalTools/domain/models/ExternalTool.ts) objects, which represent the external tools available in the installation.

##### Example call:

```typescript
import { getExternalTools } from '@iqss/dataverse-client-javascript'

/* ... */

getExternalTools.execute().then((externalTools: ExternalTool[]) => {
/* ... */
})

/* ... */
```

_See [use case](../src/externalTools/domain/useCases/GetExternalTools.ts) implementation_.

#### Get Dataset External Tool Resolved

Returns an instance of [DatasetExternalToolResolved](../src/externalTools/domain/models/ExternalTool.ts), which contains the resolved URL for accessing an external tool that operates at the dataset level.

##### Example call:

```typescript
import { getDatasetExternalToolResolved } from '@iqss/dataverse-client-javascript'

/* ... */
const toolId = 1
const datasetId = 2
const getExternalToolDTO: GetExternalToolDTO = {
preview: true,
locale: 'en'
}

getDatasetExternalToolResolved
.execute(toolId, datasetId, getExternalToolDTO)
.then((datasetExternalToolResolved: DatasetExternalToolResolved) => {
/* ... */
})
/* ... */
```

_See [use case](../src/externalTools/domain/useCases/GetDatasetExternalToolResolved.ts) implementation_.

#### Get File External Tool Resolved

Returns an instance of [FileExternalToolResolved](../src/externalTools/domain/models/ExternalTool.ts), which contains the resolved URL for accessing an external tool that operates at the file level.

##### Example call:

```typescript
import { getFileExternalToolResolved } from '@iqss/dataverse-client-javascript'

/* ... */
const toolId = 1
const fileId = 2
const getExternalToolDTO: GetExternalToolDTO = {
preview: true,
locale: 'en'
}

getFileExternalToolResolved
.execute(toolId, fileId, getExternalToolDTO)
.then((fileExternalToolResolved: FileExternalToolResolved) => {
/* ... */
})
/* ... */
```

_See [use case](../src/externalTools/domain/useCases/GetfileExternalToolResolved.ts) implementation_.
9 changes: 9 additions & 0 deletions src/externalTools/domain/dtos/GetExternalToolDTO.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* @property {boolean} preview - boolean flag to indicate if the request is for previewing the tool or not.
* @property {string} locale - string specifying the locale for internationalization
*/

export interface GetExternalToolDTO {
preview: boolean
locale: string
}
37 changes: 37 additions & 0 deletions src/externalTools/domain/models/ExternalTool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
export interface ExternalTool {
id: number
displayName: string
description: string
types: ToolType[]
scope: ToolScope
contentType?: string // Only present when scope is 'file'
toolParameters?: { queryParameters?: Record<string, string>[] }
allowedApiCalls?: { name: string; httpMethod: string; urlTemplate: string; timeOut: number }[]
requirements?: { auxFilesExist: { formatTag: string; formatVersion: string }[] }
}

export enum ToolType {
Explore = 'explore',
Configure = 'configure',
Preview = 'preview',
Query = 'query'
}

export enum ToolScope {
Dataset = 'dataset',
File = 'file'
}

export interface DatasetExternalToolResolved {
toolUrlResolved: string
displayName: string
datasetId: number
preview: boolean
}

export interface FileExternalToolResolved {
toolUrlResolved: string
displayName: string
fileId: number
preview: boolean
}
20 changes: 20 additions & 0 deletions src/externalTools/domain/repositories/IExternalToolsRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { GetExternalToolDTO } from '../dtos/GetExternalToolDTO'
import {
DatasetExternalToolResolved,
ExternalTool,
FileExternalToolResolved
} from '../models/ExternalTool'

export interface IExternalToolsRepository {
getExternalTools(): Promise<ExternalTool[]>
getDatasetExternalToolResolved(
datasetId: number | string,
toolId: number,
getExternalToolDTO: GetExternalToolDTO
): Promise<DatasetExternalToolResolved>
getFileExternalToolResolved(
fileId: number | string,
toolId: number,
getExternalToolDTO: GetExternalToolDTO
): Promise<FileExternalToolResolved>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { UseCase } from '../../../core/domain/useCases/UseCase'
import { GetExternalToolDTO } from '../dtos/GetExternalToolDTO'
import { DatasetExternalToolResolved } from '../models/ExternalTool'
import { IExternalToolsRepository } from '../repositories/IExternalToolsRepository'

export class GetDatasetExternalToolResolved implements UseCase<DatasetExternalToolResolved> {
private externalToolsRepository: IExternalToolsRepository

constructor(externalToolsRepository: IExternalToolsRepository) {
this.externalToolsRepository = externalToolsRepository
}

/**
* Returns a DatasetExternalToolResolved object containing the resolved URL for accessing an external tool that operates at the dataset level.
* The URL includes necessary authentication tokens and parameters based on the user's permissions and the tool's configuration.
* Authentication is required for draft or deaccessioned datasets and the user must have ViewUnpublishedDataset permission.
*
* @param {number | string} [datasetId] - The dataset identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers).
* @param {number} toolId - The identifier of the external tool.
* @param {GetExternalToolDTO} getExternalToolDTO - The GetExternalToolDTO object containing additional parameters for the request.
* @returns {Promise<DatasetExternalToolResolved>}
*/
async execute(
datasetId: number | string,
toolId: number,
getExternalToolDTO: GetExternalToolDTO
): Promise<DatasetExternalToolResolved> {
return await this.externalToolsRepository.getDatasetExternalToolResolved(
datasetId,
toolId,
getExternalToolDTO
)
}
}
20 changes: 20 additions & 0 deletions src/externalTools/domain/useCases/GetExternalTools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { UseCase } from '../../../core/domain/useCases/UseCase'
import { ExternalTool } from '../models/ExternalTool'
import { IExternalToolsRepository } from '../repositories/IExternalToolsRepository'

export class GetExternalTools implements UseCase<ExternalTool[]> {
private externalToolsRepository: IExternalToolsRepository

constructor(externalToolsRepository: IExternalToolsRepository) {
this.externalToolsRepository = externalToolsRepository
}

/**
* Returns a list containing all the external tools available in the installation.
*
* @returns {Promise<ExternalTool[]>}
*/
async execute(): Promise<ExternalTool[]> {
return await this.externalToolsRepository.getExternalTools()
}
}
34 changes: 34 additions & 0 deletions src/externalTools/domain/useCases/GetFileExternalToolResolved.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { UseCase } from '../../../core/domain/useCases/UseCase'
import { GetExternalToolDTO } from '../dtos/GetExternalToolDTO'
import { FileExternalToolResolved } from '../models/ExternalTool'
import { IExternalToolsRepository } from '../repositories/IExternalToolsRepository'

export class GetFileExternalToolResolved implements UseCase<FileExternalToolResolved> {
private externalToolsRepository: IExternalToolsRepository

constructor(externalToolsRepository: IExternalToolsRepository) {
this.externalToolsRepository = externalToolsRepository
}

/**
* Returns a FileExternalToolResolved object containing the resolved URL for accessing an external tool that operates at the file level.
* The URL includes necessary authentication tokens and parameters based on the user's permissions and the tool's configuration.
* Authentication is required for draft, restricted, embargoed, or expired (retention period) files, the user must have appropriate permissions.
*
* @param {number | string} [fileId] - The File identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers).
* @param {number} toolId - The identifier of the external tool.
* @param {GetExternalToolDTO} getExternalToolDTO - The GetExternalToolDTO object containing additional parameters for the request.
* @returns {Promise<FileExternalToolResolved>}
*/
async execute(
fileId: number | string,
toolId: number,
getExternalToolDTO: GetExternalToolDTO
): Promise<FileExternalToolResolved> {
return await this.externalToolsRepository.getFileExternalToolResolved(
fileId,
toolId,
getExternalToolDTO
)
}
}
25 changes: 25 additions & 0 deletions src/externalTools/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { GetDatasetExternalToolResolved } from './domain/useCases/GetDatasetExternalToolResolved'
import { GetExternalTools } from './domain/useCases/GetExternalTools'
import { GetFileExternalToolResolved } from './domain/useCases/GetFileExternalToolResolved'
import { ExternalToolsRepository } from './infra/ExternalToolsRepository'

const externalToolsRepository = new ExternalToolsRepository()

const getExternalTools = new GetExternalTools(externalToolsRepository)
const getDatasetExternalToolResolved = new GetDatasetExternalToolResolved(externalToolsRepository)
const getFileExternalToolResolved = new GetFileExternalToolResolved(externalToolsRepository)

export {
getExternalTools,
getDatasetExternalToolResolved,
getFileExternalToolResolved,
externalToolsRepository
}

export {
ExternalTool,
ToolScope,
ToolType,
DatasetExternalToolResolved,
FileExternalToolResolved
} from './domain/models/ExternalTool'
53 changes: 53 additions & 0 deletions src/externalTools/infra/ExternalToolsRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { IExternalToolsRepository } from '../domain/repositories/IExternalToolsRepository'
import { ApiRepository } from '../../core/infra/repositories/ApiRepository'
import {
DatasetExternalToolResolved,
ExternalTool,
FileExternalToolResolved
} from '../domain/models/ExternalTool'
import { GetExternalToolDTO } from '../domain/dtos/GetExternalToolDTO'
import { datasetExternalToolTransformer } from './transformers/datasetExternalToolTransformer'
import { fileExternalToolTransformer } from './transformers/fileExternalToolTransformer'
import { externalToolsTransformer } from './transformers/externalToolsTransformer'

export class ExternalToolsRepository extends ApiRepository implements IExternalToolsRepository {
private readonly externalToolsResourceName: string = 'externalTools'

public async getExternalTools(): Promise<ExternalTool[]> {
return this.doGet(this.buildApiEndpoint(this.externalToolsResourceName))
.then((response) => externalToolsTransformer(response))
.catch((error) => {
throw error
})
}

public async getDatasetExternalToolResolved(
datasetId: number | string,
toolId: number,
getExternalToolDTO: GetExternalToolDTO
): Promise<DatasetExternalToolResolved> {
return this.doPost(
this.buildApiEndpoint('datasets', `externalTool/${toolId}/toolUrl`, datasetId),
getExternalToolDTO
)
.then((response) => datasetExternalToolTransformer(response))
.catch((error) => {
throw error
})
}

public async getFileExternalToolResolved(
fileId: number | string,
toolId: number,
getExternalToolDTO: GetExternalToolDTO
): Promise<FileExternalToolResolved> {
return this.doPost(
this.buildApiEndpoint('files', `externalTool/${toolId}/toolUrl`, fileId),
getExternalToolDTO
)
.then((response) => fileExternalToolTransformer(response))
.catch((error) => {
throw error
})
}
}
13 changes: 13 additions & 0 deletions src/externalTools/infra/transformers/ExternalToolPayload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ToolScope, ToolType } from '../../domain/models/ExternalTool'

export interface ExternalToolPayload {
id: number
displayName: string
description: string
types: ToolType[]
scope: ToolScope
contentType?: string // Only present when scope is 'file'
toolParameters?: { queryParameters?: Record<string, string>[] }
allowedApiCalls?: { name: string; httpMethod: string; urlTemplate: string; timeOut: number }[]
requirements?: { auxFilesExist: { formatTag: string; formatVersion: string }[] }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { AxiosResponse } from 'axios'
import { DatasetExternalToolResolved } from '../../domain/models/ExternalTool'

export const datasetExternalToolTransformer = (
response: AxiosResponse<{
data: { toolUrl: string; displayName: string; datasetId: number; preview: boolean }
}>
): DatasetExternalToolResolved => {
const datasetExtTool = response.data.data

return {
toolUrlResolved: datasetExtTool.toolUrl,
displayName: datasetExtTool.displayName,
datasetId: datasetExtTool.datasetId,
preview: datasetExtTool.preview
}
}
23 changes: 23 additions & 0 deletions src/externalTools/infra/transformers/externalToolsTransformer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { AxiosResponse } from 'axios'
import { ExternalTool } from '../../domain/models/ExternalTool'
import { ExternalToolPayload } from './ExternalToolPayload'

export const externalToolsTransformer = (
response: AxiosResponse<{
data: ExternalToolPayload[]
}>
): ExternalTool[] => {
const tools = response.data.data

return tools.map((tool) => ({
id: tool.id,
displayName: tool.displayName,
description: tool.description,
types: tool.types,
scope: tool.scope,
contentType: tool.contentType,
toolParameters: tool.toolParameters,
allowedApiCalls: tool.allowedApiCalls,
requirements: tool.requirements
}))
}
Loading
Loading