Skip to content

Commit 585c419

Browse files
authored
Merge pull request #353 from IQSS/feat/352-external-tool-use-cases
External Tools use cases
2 parents 81a431e + 40ea333 commit 585c419

19 files changed

+835
-0
lines changed

docs/useCases.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ The different use cases currently available in the package are classified below,
102102
- [Mark As Read](#mark-as-read)
103103
- [Search](#Search)
104104
- [Get Search Services](#get-search-services)
105+
- [External Tools](#external-tools)
106+
- [External Tools read use cases](#external-tools-read-use-cases)
107+
- [Get External Tools](#get-external-tools)
108+
- [Get Dataset External Tool Resolved](#get-dataset-external-tool-resolved)
109+
- [Get File External Tool Resolved](#get-file-external-tool-resolved)
105110

106111
## Collections
107112

@@ -2300,3 +2305,81 @@ getSearchServices.execute().then((searchServices: SearchService[]) => {
23002305
```
23012306

23022307
_See [use case](../src/search/domain/useCases/GetSearchServices.ts) implementation_.
2308+
2309+
## External Tools
2310+
2311+
### External Tools Read Use Cases
2312+
2313+
#### Get External Tools
2314+
2315+
Returns an array of [ExternalTool](../src/externalTools/domain/models/ExternalTool.ts) objects, which represent the external tools available in the installation.
2316+
2317+
##### Example call:
2318+
2319+
```typescript
2320+
import { getExternalTools } from '@iqss/dataverse-client-javascript'
2321+
2322+
/* ... */
2323+
2324+
getExternalTools.execute().then((externalTools: ExternalTool[]) => {
2325+
/* ... */
2326+
})
2327+
2328+
/* ... */
2329+
```
2330+
2331+
_See [use case](../src/externalTools/domain/useCases/GetExternalTools.ts) implementation_.
2332+
2333+
#### Get Dataset External Tool Resolved
2334+
2335+
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.
2336+
2337+
##### Example call:
2338+
2339+
```typescript
2340+
import { getDatasetExternalToolResolved } from '@iqss/dataverse-client-javascript'
2341+
2342+
/* ... */
2343+
const toolId = 1
2344+
const datasetId = 2
2345+
const getExternalToolDTO: GetExternalToolDTO = {
2346+
preview: true,
2347+
locale: 'en'
2348+
}
2349+
2350+
getDatasetExternalToolResolved
2351+
.execute(toolId, datasetId, getExternalToolDTO)
2352+
.then((datasetExternalToolResolved: DatasetExternalToolResolved) => {
2353+
/* ... */
2354+
})
2355+
/* ... */
2356+
```
2357+
2358+
_See [use case](../src/externalTools/domain/useCases/GetDatasetExternalToolResolved.ts) implementation_.
2359+
2360+
#### Get File External Tool Resolved
2361+
2362+
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.
2363+
2364+
##### Example call:
2365+
2366+
```typescript
2367+
import { getFileExternalToolResolved } from '@iqss/dataverse-client-javascript'
2368+
2369+
/* ... */
2370+
const toolId = 1
2371+
const fileId = 2
2372+
const getExternalToolDTO: GetExternalToolDTO = {
2373+
preview: true,
2374+
locale: 'en'
2375+
}
2376+
2377+
getFileExternalToolResolved
2378+
.execute(toolId, fileId, getExternalToolDTO)
2379+
.then((fileExternalToolResolved: FileExternalToolResolved) => {
2380+
/* ... */
2381+
})
2382+
/* ... */
2383+
```
2384+
2385+
_See [use case](../src/externalTools/domain/useCases/GetfileExternalToolResolved.ts) implementation_.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* @property {boolean} preview - boolean flag to indicate if the request is for previewing the tool or not.
3+
* @property {string} locale - string specifying the locale for internationalization
4+
*/
5+
6+
export interface GetExternalToolDTO {
7+
preview: boolean
8+
locale: string
9+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
export interface ExternalTool {
2+
id: number
3+
displayName: string
4+
description: string
5+
types: ToolType[]
6+
scope: ToolScope
7+
contentType?: string // Only present when scope is 'file'
8+
toolParameters?: { queryParameters?: Record<string, string>[] }
9+
allowedApiCalls?: { name: string; httpMethod: string; urlTemplate: string; timeOut: number }[]
10+
requirements?: { auxFilesExist: { formatTag: string; formatVersion: string }[] }
11+
}
12+
13+
export enum ToolType {
14+
Explore = 'explore',
15+
Configure = 'configure',
16+
Preview = 'preview',
17+
Query = 'query'
18+
}
19+
20+
export enum ToolScope {
21+
Dataset = 'dataset',
22+
File = 'file'
23+
}
24+
25+
export interface DatasetExternalToolResolved {
26+
toolUrlResolved: string
27+
displayName: string
28+
datasetId: number
29+
preview: boolean
30+
}
31+
32+
export interface FileExternalToolResolved {
33+
toolUrlResolved: string
34+
displayName: string
35+
fileId: number
36+
preview: boolean
37+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { GetExternalToolDTO } from '../dtos/GetExternalToolDTO'
2+
import {
3+
DatasetExternalToolResolved,
4+
ExternalTool,
5+
FileExternalToolResolved
6+
} from '../models/ExternalTool'
7+
8+
export interface IExternalToolsRepository {
9+
getExternalTools(): Promise<ExternalTool[]>
10+
getDatasetExternalToolResolved(
11+
datasetId: number | string,
12+
toolId: number,
13+
getExternalToolDTO: GetExternalToolDTO
14+
): Promise<DatasetExternalToolResolved>
15+
getFileExternalToolResolved(
16+
fileId: number | string,
17+
toolId: number,
18+
getExternalToolDTO: GetExternalToolDTO
19+
): Promise<FileExternalToolResolved>
20+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { UseCase } from '../../../core/domain/useCases/UseCase'
2+
import { GetExternalToolDTO } from '../dtos/GetExternalToolDTO'
3+
import { DatasetExternalToolResolved } from '../models/ExternalTool'
4+
import { IExternalToolsRepository } from '../repositories/IExternalToolsRepository'
5+
6+
export class GetDatasetExternalToolResolved implements UseCase<DatasetExternalToolResolved> {
7+
private externalToolsRepository: IExternalToolsRepository
8+
9+
constructor(externalToolsRepository: IExternalToolsRepository) {
10+
this.externalToolsRepository = externalToolsRepository
11+
}
12+
13+
/**
14+
* Returns a DatasetExternalToolResolved object containing the resolved URL for accessing an external tool that operates at the dataset level.
15+
* The URL includes necessary authentication tokens and parameters based on the user's permissions and the tool's configuration.
16+
* Authentication is required for draft or deaccessioned datasets and the user must have ViewUnpublishedDataset permission.
17+
*
18+
* @param {number | string} [datasetId] - The dataset identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers).
19+
* @param {number} toolId - The identifier of the external tool.
20+
* @param {GetExternalToolDTO} getExternalToolDTO - The GetExternalToolDTO object containing additional parameters for the request.
21+
* @returns {Promise<DatasetExternalToolResolved>}
22+
*/
23+
async execute(
24+
datasetId: number | string,
25+
toolId: number,
26+
getExternalToolDTO: GetExternalToolDTO
27+
): Promise<DatasetExternalToolResolved> {
28+
return await this.externalToolsRepository.getDatasetExternalToolResolved(
29+
datasetId,
30+
toolId,
31+
getExternalToolDTO
32+
)
33+
}
34+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { UseCase } from '../../../core/domain/useCases/UseCase'
2+
import { ExternalTool } from '../models/ExternalTool'
3+
import { IExternalToolsRepository } from '../repositories/IExternalToolsRepository'
4+
5+
export class GetExternalTools implements UseCase<ExternalTool[]> {
6+
private externalToolsRepository: IExternalToolsRepository
7+
8+
constructor(externalToolsRepository: IExternalToolsRepository) {
9+
this.externalToolsRepository = externalToolsRepository
10+
}
11+
12+
/**
13+
* Returns a list containing all the external tools available in the installation.
14+
*
15+
* @returns {Promise<ExternalTool[]>}
16+
*/
17+
async execute(): Promise<ExternalTool[]> {
18+
return await this.externalToolsRepository.getExternalTools()
19+
}
20+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { UseCase } from '../../../core/domain/useCases/UseCase'
2+
import { GetExternalToolDTO } from '../dtos/GetExternalToolDTO'
3+
import { FileExternalToolResolved } from '../models/ExternalTool'
4+
import { IExternalToolsRepository } from '../repositories/IExternalToolsRepository'
5+
6+
export class GetFileExternalToolResolved implements UseCase<FileExternalToolResolved> {
7+
private externalToolsRepository: IExternalToolsRepository
8+
9+
constructor(externalToolsRepository: IExternalToolsRepository) {
10+
this.externalToolsRepository = externalToolsRepository
11+
}
12+
13+
/**
14+
* Returns a FileExternalToolResolved object containing the resolved URL for accessing an external tool that operates at the file level.
15+
* The URL includes necessary authentication tokens and parameters based on the user's permissions and the tool's configuration.
16+
* Authentication is required for draft, restricted, embargoed, or expired (retention period) files, the user must have appropriate permissions.
17+
*
18+
* @param {number | string} [fileId] - The File identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers).
19+
* @param {number} toolId - The identifier of the external tool.
20+
* @param {GetExternalToolDTO} getExternalToolDTO - The GetExternalToolDTO object containing additional parameters for the request.
21+
* @returns {Promise<FileExternalToolResolved>}
22+
*/
23+
async execute(
24+
fileId: number | string,
25+
toolId: number,
26+
getExternalToolDTO: GetExternalToolDTO
27+
): Promise<FileExternalToolResolved> {
28+
return await this.externalToolsRepository.getFileExternalToolResolved(
29+
fileId,
30+
toolId,
31+
getExternalToolDTO
32+
)
33+
}
34+
}

src/externalTools/index.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { GetDatasetExternalToolResolved } from './domain/useCases/GetDatasetExternalToolResolved'
2+
import { GetExternalTools } from './domain/useCases/GetExternalTools'
3+
import { GetFileExternalToolResolved } from './domain/useCases/GetFileExternalToolResolved'
4+
import { ExternalToolsRepository } from './infra/ExternalToolsRepository'
5+
6+
const externalToolsRepository = new ExternalToolsRepository()
7+
8+
const getExternalTools = new GetExternalTools(externalToolsRepository)
9+
const getDatasetExternalToolResolved = new GetDatasetExternalToolResolved(externalToolsRepository)
10+
const getFileExternalToolResolved = new GetFileExternalToolResolved(externalToolsRepository)
11+
12+
export {
13+
getExternalTools,
14+
getDatasetExternalToolResolved,
15+
getFileExternalToolResolved,
16+
externalToolsRepository
17+
}
18+
19+
export {
20+
ExternalTool,
21+
ToolScope,
22+
ToolType,
23+
DatasetExternalToolResolved,
24+
FileExternalToolResolved
25+
} from './domain/models/ExternalTool'
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { IExternalToolsRepository } from '../domain/repositories/IExternalToolsRepository'
2+
import { ApiRepository } from '../../core/infra/repositories/ApiRepository'
3+
import {
4+
DatasetExternalToolResolved,
5+
ExternalTool,
6+
FileExternalToolResolved
7+
} from '../domain/models/ExternalTool'
8+
import { GetExternalToolDTO } from '../domain/dtos/GetExternalToolDTO'
9+
import { datasetExternalToolTransformer } from './transformers/datasetExternalToolTransformer'
10+
import { fileExternalToolTransformer } from './transformers/fileExternalToolTransformer'
11+
import { externalToolsTransformer } from './transformers/externalToolsTransformer'
12+
13+
export class ExternalToolsRepository extends ApiRepository implements IExternalToolsRepository {
14+
private readonly externalToolsResourceName: string = 'externalTools'
15+
16+
public async getExternalTools(): Promise<ExternalTool[]> {
17+
return this.doGet(this.buildApiEndpoint(this.externalToolsResourceName))
18+
.then((response) => externalToolsTransformer(response))
19+
.catch((error) => {
20+
throw error
21+
})
22+
}
23+
24+
public async getDatasetExternalToolResolved(
25+
datasetId: number | string,
26+
toolId: number,
27+
getExternalToolDTO: GetExternalToolDTO
28+
): Promise<DatasetExternalToolResolved> {
29+
return this.doPost(
30+
this.buildApiEndpoint('datasets', `externalTool/${toolId}/toolUrl`, datasetId),
31+
getExternalToolDTO
32+
)
33+
.then((response) => datasetExternalToolTransformer(response))
34+
.catch((error) => {
35+
throw error
36+
})
37+
}
38+
39+
public async getFileExternalToolResolved(
40+
fileId: number | string,
41+
toolId: number,
42+
getExternalToolDTO: GetExternalToolDTO
43+
): Promise<FileExternalToolResolved> {
44+
return this.doPost(
45+
this.buildApiEndpoint('files', `externalTool/${toolId}/toolUrl`, fileId),
46+
getExternalToolDTO
47+
)
48+
.then((response) => fileExternalToolTransformer(response))
49+
.catch((error) => {
50+
throw error
51+
})
52+
}
53+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { ToolScope, ToolType } from '../../domain/models/ExternalTool'
2+
3+
export interface ExternalToolPayload {
4+
id: number
5+
displayName: string
6+
description: string
7+
types: ToolType[]
8+
scope: ToolScope
9+
contentType?: string // Only present when scope is 'file'
10+
toolParameters?: { queryParameters?: Record<string, string>[] }
11+
allowedApiCalls?: { name: string; httpMethod: string; urlTemplate: string; timeOut: number }[]
12+
requirements?: { auxFilesExist: { formatTag: string; formatVersion: string }[] }
13+
}

0 commit comments

Comments
 (0)