diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d9c3ee2b..432eb098 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,31 +3,39 @@ First of all thank you very much for your interest in contributing to this project! ## Getting started -1. Make sure that you have installed the project dependencies -2. Build the project as explained in [README.md](README.md) -3. Fork the repository -4. Apply changes in your own branch -5. Create a pull request that we will review -6. Update README.md if necessary + +1. Fork the repository and clone your fork locally +2. Follow the [Local Development](./docs/localDevelopment.md) guide for setting up your local development environment +3. Create a branch and apply the desired changes on it +4. Create a pull request from your fork branch targeting the develop branch of the root repository ## Checklist before creating PR + - Project builds - Lint and format checks pass -- Unit tests pass -- Unit tests for new functionality/fix are added +- Unit and integration tests pass +- Unit and integration tests for new functionality/fix are added +- Documentation is updated (Any new use case added or modified should be documented in the [Use Cases](./docs/useCases.md) section) ## Code of Conduct + We abide by the upstream Code of Conduct at https://github.com/IQSS/dataverse/blob/develop/CODE_OF_CONDUCT.md and in addition ask the following. ### Git + - Branch names are self descriptive - Commit messages are short and concise - Branch is put up to date before creating PR ### Our responsibilities + - To keep the code clean - To provide constructive feedback to other developers - To maintain readable code at all times ## Getting help -Please feel free to reach out in https://chat.dataverse.org or https://groups.google.com/g/dataverse-dev \ No newline at end of file + +Please, do not hesitate to contact us through: + +- Zulip: https://dataverse.zulipchat.com/#narrow/stream/410361-ui-dev +- Google Group: https://groups.google.com/g/dataverse-dev diff --git a/README.md b/README.md index 85e21130..c88d7b79 100644 --- a/README.md +++ b/README.md @@ -1,85 +1,11 @@ -# dataverse-client-javascript +# js-dataverse [![npm](https://img.shields.io/npm/v/js-dataverse.svg)](https://www.npmjs.com/package/js-dataverse) A JavaScript/TypeScript API wrapper for [Dataverse](http://guides.dataverse.org/en/latest/api/). -## NPM - -A stable 1.x version of this package is available as `js-dataverse` at https://www.npmjs.com/package/js-dataverse - -An unstable 2.x version of this package with breaking changes is under development. Until a 2.0 version is officially released, it can be installed from https://github.com/IQSS/dataverse-client-javascript/pkgs/npm/dataverse-client-javascript - -## Getting Started - -This package is built using `node v19`, so it is recommended to use that version. - -Make sure that you install all the project dependencies: - -`npm install` - -## Build project - -In order to build the project, we need to run the following command: - -`npm run build` - -the build generated will be placed in `dist` folder. - -## Tests - -### Run all tests - -`npm run test` - -### Run unit tests - -`npm run test:unit` - -### Run integration tests - -`npm run test:integration` - -#### Configure the integration testing environment - -The integration testing environment is implemented with Test Containers and Docker Compose. The environment uses different environment variables, defined in a .env file, available in the _test/integration/environment_ folder. - -These environment variables can be updated as needed for integration testing. For example, we can specify the Dataverse image registry and tag, to point to the particular Dataverse image to test. - -- To test images generated in Dataverse PRs: Set `ghcr.io` as the image registry (DATAVERSE_IMAGE_REGISTRY) and the source branch name of a particular PR as the image tag (DATAVERSE_IMAGE_TAG). - -- To test the Dataverse develop branch: Set `docker.io` as the image registry (DATAVERSE_IMAGE_REGISTRY) and `unstable` as the image tag (DATAVERSE_IMAGE_TAG). - -### Run test coverage - -`npm run test:coverage` - -## Format and lint - -### Run formatter - -`npm run format` - -### Run linter - -Running a linting check on the code: - -`npm run lint` - -Fix linting checks on the code: - -`npm run lint:fix` - -## Publishing new version - -Automated publishing of versions could be automated when merging to master. Below are the steps that would be required to publish a new version: - -1. Run tests and checks -2. Build the project -3. Commit changes -4. Upgrade npm version -5. Publish, `npm publish` - -## Contributing - -We love contributors! Please see [CONTRIBUTING.md](CONTRIBUTING.md). +- [Installation](./docs/installation.md) +- [Use Cases](./docs/useCases.md) +- [Local Development](./docs/localDevelopment.md) +- [Contributing](./CONTRIBUTING.md) +- [License](./LICENSE) diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 00000000..df3efac0 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,108 @@ +# Installation + +Recommended versions node >=16 and npm >=8. + +## Getting Started with the Stable Version + +A stable 1.x version of this package is available as `js-dataverse` at https://www.npmjs.com/package/js-dataverse + +Install the package stable version using npm: + +```bash +npm install js-dataverse +``` + +## Getting Started with the Development Version + +An unstable 2.x version of this package with breaking changes is under development. + +Until a 2.0 version is officially released, it can be installed from https://github.com/IQSS/dataverse-client-javascript/pkgs/npm/dataverse-client-javascript + + +### Create a `.npmrc` file and add a token + +To install the [@iqss/dataverse-client-javascript](https://github.com/IQSS/dataverse-client-javascript/pkgs/npm/dataverse-client-javascript) +from the GitHub registry, follow these steps to create an `.npmrc` file in the root of your project using your GitHub token. + +1. **Create `.npmrc`** in your project's root directory. + + ```bash + touch .npmrc + ``` + +2. **Replace the Token** + + Open the newly created `.npmrc` file and replace `YOUR_GITHUB_TOKEN` with your actual GitHub token. + + ```plaintext + legacy-peer-deps=true + + //npm.pkg.github.com/:_authToken= + @iqss:registry=https://npm.pkg.github.com/ + ``` + +#### How to Get a GitHub Token + +If you don't have a GitHub token yet, follow these steps: + +1. Go to your GitHub account settings. + +2. Navigate to "Developer settings" -> "Personal access tokens." + +3. Click "Personal access tokens" -> "Tokens (classic)" -> "Generate new token (classic)". + +4. Give the token a name and select the "read:packages" scope. + +5. Copy the generated token. + +6. Replace `YOUR_GITHUB_AUTH_TOKEN` in the `.npmrc` file with the copied token. + +Now, you should be able to install the Dataverse JavaScript client using npm. + +### Install the package + +Install the package development version using npm: + +```bash +npm install @iqss/dataverse-client-javascript +``` + +## Initialization + +In order for the package to connect to the Dataverse API, there is an `APIConfig` object that should be initialized to set the preferred authentication mechanism with the associated credentials for connecting to the Dataverse API. + +Currently, the supported authentication mechanisms are: + +- **API Key**: The recommended authentication mechanism. The API Key should correspond to a particular Dataverse user account. + +- **Session Cookie**: This is an experimental feature primarily designed for Dataverse SPA development. To use this mechanism, you must enable the corresponding feature flag in the Dataverse installation (See https://guides.dataverse.org/en/latest/installation/config.html?#feature-flags). It is recommended not to use this mechanism and instead use API Key authentication. + +It is recommended to globally initialize the `ApiConfig` object from the consuming application, as the configuration will be read on every API call made by the package's use cases. + +For example, in a React application, we can globally initialize the `ApiConfig` object in the `App` file, like this: + +```typescript +ApiConfig.init(, DataverseApiAuthMechanism.API_KEY, ) + +function App() { + /* Yor App code */ +} + +export default App +```` + +The same example but with example values set: + +```typescript +ApiConfig.init('http://localhost:8000/api/v1', DataverseApiAuthMechanism.API_KEY, 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx') + +function App() { + /* Yor App code */ +} + +export default App +```` + +We can initialize the `ApiConfig` object as an unauthenticated user, by setting `undefined` as the API Key value. + +This will allow use cases that do not require authentication to be successfully executed, but those that do require authentication will fail. diff --git a/docs/localDevelopment.md b/docs/localDevelopment.md new file mode 100644 index 00000000..9527a778 --- /dev/null +++ b/docs/localDevelopment.md @@ -0,0 +1,95 @@ +# Local Development + +To set up your local development environment for working on this project, follow these steps: + +## Prerequisites + +### Node.js and npm + +Make sure you have Node.js and npm installed on your machine. + +This package is built using `node v19`, so it is recommended to use that version. + +### Docker and Docker Compose + +We use [Test Containers](https://github.com/testcontainers/testcontainers-node) for running integration tests. + +In our Test Containers setup we use Docker Compose, as our tests involve multiple containers that need to be orchestrated together. + +If you want to run integration tests, you need Docker and Docker Compose installed on your machine. + +## Install Dependencies + +Make sure that you install all the project dependencies: + +```bash +npm install +``` + +## Build + +In order to build the project, we need to run the following command: + +```bash +npm run build +``` + +the build generated will be placed in `dist` folder. + +## Tests + +### Run all tests + +```bash +npm run test +``` + +### Run unit tests + +```bash +npm run test:unit +``` + +### Run integration tests + +```bash +npm run test:integration +``` + +#### Configure the integration testing environment + +The integration testing environment uses different environment variables, defined in a .env file, available in the _test/integration/environment_ folder. + +These environment variables can be updated as needed for integration testing. For example, we can specify the Dataverse image registry and tag, to point to the particular Dataverse image to test. + +- To test images generated in Dataverse PRs: Set `ghcr.io` as the image registry (DATAVERSE_IMAGE_REGISTRY) and the source branch name of a particular PR as the image tag (DATAVERSE_IMAGE_TAG). + +- To test the Dataverse develop branch: Set `docker.io` as the image registry (DATAVERSE_IMAGE_REGISTRY) and `unstable` as the image tag (DATAVERSE_IMAGE_TAG). + +### Run test coverage + +```bash +npm run test:coverage +``` + +## Format and lint + +### Run formatter + +```bash +npm run format +``` + +### Run linter + +Running a linting check on the code: + +```bash +npm run lint +``` + +Fix linting checks on the code: + +```bash +npm run lint:fix +``` \ No newline at end of file diff --git a/docs/useCases.md b/docs/useCases.md new file mode 100644 index 00000000..b9812185 --- /dev/null +++ b/docs/useCases.md @@ -0,0 +1,728 @@ +# Use Cases + +In the context of [Domain-Driven Design (DDD)](https://martinfowler.com/bliki/DomainDrivenDesign.html), a use case is a specific way to describe and capture a user's or system's interaction with the domain to achieve a particular goal. + +This package exposes the functionality in the form of use cases, with the main goal that any package consumer can easily identify the desired functionality. + +The different use cases currently available in the package are classified below, according to the subdomains they target: + +## Table of Contents + +- [Datasets](#Datasets) + - [Datasets read use cases](#datasets-read-use-cases) + - [Get a Dataset](#get-a-dataset) + - [Get Dataset By Private URL Token](#get-dataset-by-private-url-token) + - [Get Dataset Citation Text](#get-dataset-citation-text) + - [Get Dataset Citation Text By Private URL Token](#get-dataset-citation-text-by-private-url-token) + - [Get Dataset Locks](#get-dataset-locks) + - [Get Dataset Summary Field Names](#get-dataset-summary-field-names) + - [Get User Permissions on a Dataset](#get-user-permissions-on-a-dataset) + - [List All Datasets](#list-all-datasets) + - [Datasets write use cases](#datasets-write-use-cases) + - [Create a Dataset](#create-a-dataset) +- [Files](#Files) + - [Files read use cases](#files-read-use-cases) + - [Get a File](#get-a-file) + - [Get File Citation Text](#get-file-citation-text) + - [Get File Counts in a Dataset](#get-file-counts-in-a-dataset) + - [Get File Data Tables](#get-file-data-tables) + - [Get File Download Count](#get-file-download-count) + - [Get the size of Downloading all the files of a Dataset Version](#get-the-size-of-downloading-all-the-files-of-a-dataset-version) + - [Get User Permissions on a File](#get-user-permissions-on-a-file) + - [List Files in a Dataset](#list-files-in-a-dataset) +- [Metadata Blocks](#metadata-blocks) + - [Metadata Blocks read use cases](#metadata-blocks-read-use-cases) + - [Get Metadata Block By Name](#get-metadata-block-by-name) +- [Users](#Users) + - [Users read use cases](#users-read-use-cases) + - [Get Current Authenticated User](#get-current-authenticated-user) +- [Info](#Info) + - [Get Dataverse Backend Version](#get-dataverse-backend-version) + - [Get Maximum Embargo Duration In Months](#get-maximum-embargo-duration-in-months) + - [Get ZIP Download Limit](#get-zip-download-limit) + +## Datasets + +### Datasets Read Use Cases + +#### Get a Dataset + +Returns a [Dataset](../src/datasets/domain/models/Dataset.ts) instance, given the search parameters to identify it. + +##### Example call: + +```typescript +import { getDataset } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const datasetId = 'doi:10.77777/FK2/AAAAAA'; +const datasetVersionId = '1.0'; + +getDataset.execute(datasetId, datasetVersionId).then((dataset: Dataset) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/datasets/domain/useCases/GetDataset.ts)_ definition. + +The `datasetId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers. + +The optional `datasetVersionId` parameter can correspond to a numeric version identifier, as in the previous example, or a [DatasetNotNumberedVersion](../src/datasets/domain/models/DatasetNotNumberedVersion.ts) enum value. If not set, the default value is `DatasetNotNumberedVersion.LATEST`. + +There is an optional third parameter called `includeDeaccessioned`, which indicates whether to consider deaccessioned versions or not in the dataset search. If not set, the default value is `false`. + +#### Get Dataset By Private URL Token + +Returns a [Dataset](../src/datasets/domain/models/Dataset.ts) instance, given an associated Private URL Token. + +```typescript +import { getPrivateUrlDataset } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const token = 'a56444bc-7697-4711-8964-e0577f055fd2'; + +getPrivateUrlDataset.execute(token).then((dataset: Dataset) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/datasets/domain/useCases/GetPrivateUrlDataset.ts)_ definition. + +#### Get Dataset Citation Text + +Returns the Dataset citation text. + +##### Example call: + +```typescript +import { getDatasetCitation } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const datasetId = 2; +const datasetVersionId = '1.0'; + +getDatasetCitation.execute(datasetId, datasetVersionId).then((citationText: string) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/datasets/domain/useCases/GetDatasetCitation.ts) implementation_. + +The `datasetId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers. + +There is an optional third parameter called `includeDeaccessioned`, which indicates whether to consider deaccessioned versions or not in the dataset search. If not set, the default value is `false`. + +#### Get Dataset Citation Text By Private URL Token + +Returns the Dataset citation text, given an associated Private URL Token. + +##### Example call: + +```typescript +import { getPrivateUrlDatasetCitation } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const token = 'a56444bc-7697-4711-8964-e0577f055fd2'; + +getPrivateUrlDatasetCitation.execute(token).then((citationText: string) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/datasets/domain/useCases/GetPrivateUrlDatasetCitation.ts) implementation_. + +#### Get Dataset Locks + +Returns a [DatasetLock](../src/datasets/domain/models/DatasetLock.ts) array of all locks present in a Dataset. + +##### Example call: + +```typescript +import { getDatasetLocks } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const datasetId = 'doi:10.77777/FK2/AAAAAA'; + +getDatasetLocks.execute(datasetId).then((datasetLocks: DatasetLock[]) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/datasets/domain/useCases/GetDatasetLocks.ts) implementation_. + +The `datasetId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers. + +#### Get Dataset Summary Field Names + +Returns the names of the dataset summary fields configured in the installation. + +##### Example call: + +```typescript +import { getDatasetSummaryFieldNames } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +getDatasetSummaryFieldNames.execute().then((names: string[]) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/datasets/domain/useCases/GetDatasetSummaryFieldNames.ts) implementation_. + +#### Get User Permissions on a Dataset + +Returns an instance of [DatasetUserPermissions](../src/datasets/domain/models/DatasetUserPermissions.ts) that includes the permissions that the calling user has on a particular Dataset. + +##### Example call: + +```typescript +import { getDatasetUserPermissions } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const datasetId = 'doi:10.77777/FK2/AAAAAA'; + +getDatasetUserPermissions.execute(datasetId).then((permissions: DatasetUserPermissions) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/datasets/domain/useCases/GetDatasetUserPermissions.ts) implementation_. + +The `datasetId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers. + +#### List All Datasets + +Returns an instance of [DatasetPreviewSubset](../src/datasets/domain/models/DatasetPreviewSubset.ts) that contains reduced information for each dataset that the calling user can access in the installation. + +##### Example call: + +```typescript +import { getAllDatasetPreviews } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const limit = 10; +const offset = 20; + +getAllDatasetPreviews.execute(limit, offset).then((subset: DatasetPreviewSubset) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/datasets/domain/useCases/GetAllDatasetPreviews.ts) implementation_. + +Note that `limit` and `offset` are optional parameters for pagination. + +The `DatasetPreviewSubset`returned instance contains a property called `totalDatasetCount` which is necessary for pagination. + +### Datasets Write Use Cases + +#### Create a Dataset + +Creates a new Dataset in a collection, given a [NewDatasetDTO](../src/datasets/domain/dtos/NewDatasetDTO.ts) object and an optional collection identifier, which defaults to `root`. + +This use case validates the submitted fields of each metadata block and can return errors of type [ResourceValidationError](../src/core/domain/useCases/validators/errors/ResourceValidationError.ts), which include sufficient information to determine which field value is invalid and why. + +##### Example call: + +```typescript +import { createDataset } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const newDatasetDTO: NewDatasetDTO = { + metadataBlockValues: [ + { + name: 'citation', + fields: { + title: 'New Dataset', + author: [ + { + authorName: 'John Doe', + authorAffiliation: 'Dataverse', + }, + { + authorName: 'John Lee', + authorAffiliation: 'Dataverse', + }, + ], + datasetContact: [ + { + datasetContactEmail: 'johndoe@dataverse.com', + datasetContactName: 'John', + }, + ], + dsDescription: [ + { + dsDescriptionValue: 'This is the description of our new dataset', + }, + ], + subject: 'Earth and Environmental Sciences', + + /* Rest of field values... */ + + }, + }, + ], +}; + +createDataset.execute(newDatasetDTO).then((newDatasetIds: CreatedDatasetIdentifiers) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/datasets/domain/useCases/CreateDataset.ts) implementation_. + +The above example creates the new dataset in the `root` collection since no collection identifier is specified. If you want to create the dataset in a different collection, you must add the collection identifier as a second parameter in the use case call. + +The use case returns a [CreatedDatasetIdentifiers](../src/datasets/domain/models/CreatedDatasetIdentifiers.ts) object, which includes the persistent and numeric identifiers of the created dataset. + +## Files + +### Files read use cases + +#### Get a File + +Returns a [File](../src/files/domain/models/File.ts) instance, given the search parameters to identify it. + +##### Example call: + +```typescript +import { getFile } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const fileId = 2; +const datasetVersionId = '1.0'; + +getFile.execute(fileId, datasetVersionId).then((file: File) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/files/domain/useCases/GetFile.ts)_ definition. + +The `fileId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers. + +The optional `datasetVersionId` parameter can correspond to a numeric version identifier, as in the previous example, or a [DatasetNotNumberedVersion](../src/datasets/domain/models/DatasetNotNumberedVersion.ts) enum value. If not set, the default value is `DatasetNotNumberedVersion.LATEST`. + +#### Get File Citation Text + +Returns the File citation text. + +##### Example call: + +```typescript +import { getFileCitation } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const fileId = 3; +const datasetVersionId = '1.0'; + +getFileCitation.execute(fileId, datasetVersionId).then((citationText: string) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/files/domain/useCases/GetFileCitation.ts) implementation_. + +The `fileId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers. + +There is an optional third parameter called `includeDeaccessioned`, which indicates whether to consider deaccessioned versions or not in the file search. If not set, the default value is `false`. + +#### Get File Counts in a Dataset + +Returns an instance of [FileCounts](../src/files/domain/models/FileCounts.ts), containing the requested Dataset total file count, as well as file counts for the following file properties: + +- **Per content type** +- **Per category name** +- **Per tabular tag name** +- **Per access status** (Possible values: _Public_, _Restricted_, _EmbargoedThenRestricted_, _EmbargoedThenPublic_) + +##### Example call: + +```typescript +import { getDatasetFileCounts } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const datasetId = 2; +const datasetVersionId = '1.0'; + +getDatasetFileCounts.execute(datasetId, datasetVersionId).then((fileCounts: FileCounts) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/files/domain/useCases/GetDatasetFileCounts.ts) implementation_. + +The `datasetId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers. +The optional `datasetVersionId` parameter can correspond to a numeric version identifier, as in the previous example, or a [DatasetNotNumberedVersion](../src/datasets/domain/models/DatasetNotNumberedVersion.ts) enum value. If not set, the default value is `DatasetNotNumberedVersion.LATEST`. +There is an optional third parameter called `includeDeaccessioned`, which indicates whether to consider deaccessioned versions or not in the dataset search. If not set, the default value is `false`. + +An optional fourth parameter `fileSearchCriteria` receives a [FileSearchCriteria](../src/files/domain/models/FileCriteria.ts) object to retrieve counts only for files that match the specified criteria. + +##### Example call using optional parameters: + +```typescript +import { getDatasetFileCounts } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const datasetId: number = 2; +const datasetVersionId: string = '1.0'; +const includeDeaccessioned: boolean = true; +const searchCriteria: FileSearchCriteria = { + categoryName: 'physics', +}; + +getDatasetFileCounts + .execute(datasetId, datasetVersionId, includeDeaccessioned, searchCriteria) + .then((fileCounts: FileCounts) => { + /* ... */ + }); + +/* ... */ +``` + +#### Get File Data Tables + +This use case is oriented toward tabular files and provides an array of [FileDataTable](../src/files/domain/models/FileDataTable.ts) objects for an existing tabular file. + +##### Example call: + +```typescript +import { getFileDataTables } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const fileId = 2; + +getFileDataTables.execute(fileId).then((dataTables: FileDataTable[]) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/files/domain/useCases/GetFileDataTables.ts) implementation_. + +The `fileId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers. + +#### Get File Download Count + +Provides the download count for a particular File. + +##### Example call: + +```typescript +import { getFileDownloadCount } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const fileId: number = 2; + +getFileDownloadCount.execute(fileId).then((count: number) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/files/domain/useCases/GetFileDownloadCount.ts) implementation_. + +The `fileId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers. + +#### Get the size of Downloading all the files of a Dataset Version + +Returns the combined size in bytes of all the files available for download from a particular Dataset. + +##### Example call: + +```typescript +import { getDatasetFilesTotalDownloadSize } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const datasetId: number = 2; +const datasetVersionId: string = '1.0'; + +getDatasetFilesTotalDownloadSize.execute(datasetId, datasetVersionId).then((size: number) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/files/domain/useCases/GetDatasetFilesTotalDownloadSize.ts) implementation_. + +The `datasetId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers. +The optional `datasetVersionId` parameter can correspond to a numeric version identifier, as in the previous example, or a [DatasetNotNumberedVersion](../src/datasets/domain/models/DatasetNotNumberedVersion.ts) enum value. If not set, the default value is `DatasetNotNumberedVersion.LATEST`. +There is a third optional parameter called `fileDownloadSizeMode` which receives an enum type of [FileDownloadSizeMode](../src/files/domain/models/FileDownloadSizeMode.ts), and applies a filter criteria to the operation. This parameter supports the following values: + +- `FileDownloadSizeMode.ALL` (Default): Includes both archival and original sizes for tabular files +- `FileDownloadSizeMode.ARCHIVAL`: Includes only the archival size for tabular files +- `FileDownloadSizeMode.ORIGINAL`: Includes only the original size for tabular files + +An optional fourth parameter called `fileSearchCriteria` receives a [FileSearchCriteria](../src/files/domain/models/FileCriteria.ts) object to only consider files that match the specified criteria. + +An optional fifth parameter called `includeDeaccessioned` indicates whether to consider deaccessioned versions or not in the dataset search. If not set, the default value is `false`. + +##### Example call using optional parameters: + +```typescript +import { getDatasetFilesTotalDownloadSize } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const datasetId: number = 2; +const datasetVersionId: string = '1.0'; +const mode: FileDownloadSizeMode = FileDownloadSizeMode.ARCHIVAL; +const searchCriteria: FileDownloadSizeMode = { + categoryName: 'physics', +}; +const includeDeaccessioned: boolean = true; + +getDatasetFilesTotalDownloadSize + .execute(datasetId, datasetVersionId, mode, searchCriteria, includeDeaccessioned) + .then((size: number) => { + /* ... */ + }); + +/* ... */ +``` + +#### Get User Permissions on a File + +This use case returns a [FileUserPermissions](../src/files/domain/models/FileUserPermissions.ts) object, which includes the permissions that the calling user has on a particular File. + +The returned _FileUserPermissions_ object contains the following permissions, as booleans: + +- Can download the file (_canDownloadFile_) +- Can manage the file permissions (_canManageFilePermissions_) +- Can edit the file owner dataset (_canEditOwnerDataset_) + +##### Example call: + +```typescript +import { getFileUserPermissions } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const fileId: number = 2; + +getFileUserPermissions.execute(fileId).then((permissions: FileUserPermissions) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/files/domain/useCases/GetFileUserPermissions.ts) implementation_. + +The `fileId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers. + +#### List Files in a Dataset + +Returns an instance of [FilesSubset](../src/files/domain/models/FilesSubset.ts), which contains the files from the requested Dataset and page (if pagination parameters are set). + +##### Example call: + +```typescript +import { getDatasetFiles } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const datasetId = 2; +const datasetVersionId = '1.0'; + +getDatasetFiles.execute(datasetId, datasetVersionId).then((subset: FilesSubset) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/files/domain/useCases/GetDatasetFiles.ts) implementation_. + +The `datasetId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers. +The optional `datasetVersionId` parameter can correspond to a numeric version identifier, as in the previous example, or a [DatasetNotNumberedVersion](../src/datasets/domain/models/DatasetNotNumberedVersion.ts) enum value. If not set, the default value is `DatasetNotNumberedVersion.LATEST`. +This use case supports the following optional parameters depending on the search goals: + +- **includeDeaccessioned**: (boolean) Indicates whether to consider deaccessioned versions or not in the dataset search. If not set, the default value is `false`. +- **limit**: (number) Limit for pagination. +- **offset**: (number) Offset for pagination. +- **fileSearchCriteria**: ([FileSearchCriteria](../src/files/domain/models/FileCriteria.ts)) Supports filtering the files by different file properties. +- **fileOrderCriteria**: ([FileOrderCriteria](../src/files/domain/models/FileCriteria.ts)) Supports ordering the results according to different criteria. If not set, the defalt value is `FileOrderCriteria.NAME_AZ`. + +##### Example call using optional parameters: + +```typescript +import { getDatasetFiles } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const datasetId: number = 2; +const datasetVersionId: string = '1.0'; +const includeDeaccessioned: boolean = true; +const limit: number = 10; +const offset: number = 20; +const searchCriteria: FileSearchCriteria = { + searchText: 'file title', +}; +const orderCriteria: FileOrderCriteria = FileOrderCriteria.NEWEST; + +getDatasetFiles + .execute(datasetId, datasetVersionId, includeDeaccessioned, limit, offset, searchCriteria, orderCriteria) + .then((subset: FilesSubset) => { + /* ... */ + }); + +/* ... */ +``` + +## Metadata Blocks + +### Metadata Blocks read use cases + +#### Get Metadata Block By Name + +Returns a [MetadataBlock](../src/metadataBlocks/domain/models/MetadataBlock.ts) instance, given its name. + +##### Example call: + +```typescript +import { getMetadataBlockByName } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +const name = 'citation'; + +getMetadataBlockByName.execute(name).then((metadataBlock: MetadataBlock) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/metadataBlocks/domain/useCases/GetMetadataBlockByName.ts) implementation_. + +## Users + +### Users read use cases + +#### Get Current Authenticated User + +Returns the current [AuthenticatedUser](../src/users/domain/models/AuthenticatedUser.ts) corresponding to the authentication mechanism provided through `ApiConfig`. + +##### Example call: + +```typescript +import { getCurrentAuthenticatedUser } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +getCurrentAuthenticatedUser.execute().then((user: AuthenticatedUser) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/users/domain/useCases/GetCurrentAuthenticatedUser.ts) implementation_. + +## Info + +#### Get Dataverse Backend Version + +Returns a [DataverseVersion](../src/info/domain/models/DataverseVersion.ts) object, which contains version information for the Dataverse backend installation. + +##### Example call: + +```typescript +import { getDataverseVersion } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +getDataverseVersion.execute().then((version: DataverseVersion) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/info/domain/useCases/GetDataverseVersion.ts) implementation_. + +#### Get Maximum Embargo Duration In Months + +Returns a number indicating the configured maximum embargo duration in months. For information on the possible values +that can be returned, please refer to the `MaxEmbargoDurationInMonths` property in the Dataverse documentation: +[MaxEmbargoDurationInMonths](https://guides.dataverse.org/en/latest/installation/config.html#maxembargodurationinmonths). + +##### Example call: + +```typescript +import { getMaxEmbargoDurationInMonths } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +getMaxEmbargoDurationInMonths.execute().then((months: number) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/info/domain/useCases/GetMaxEmbargoDurationInMonths.ts) implementation_. + +#### Get ZIP Download Limit + +Returns a number indicating the configured ZIP download limit in bytes. + +##### Example call: + +```typescript +import { getZipDownloadLimit } from '@iqss/dataverse-client-javascript'; + +/* ... */ + +getZipDownloadLimit.execute().then((downloadLimit: number) => { + /* ... */ +}); + +/* ... */ +``` + +_See [use case](../src/info/domain/useCases/GetZipDownloadLimit.ts) implementation_. diff --git a/package-lock.json b/package-lock.json index d54b28f2..fed65deb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@types/node": "^18.15.11", "@types/turndown": "^5.0.1", "axios": "^1.3.4", + "node-html-markdown": "^1.3.0", "turndown": "^7.1.2", "typescript": "^4.9.5" }, @@ -2027,6 +2028,11 @@ "readable-stream": "^3.4.0" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2419,6 +2425,32 @@ "node": ">= 8" } }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -2581,11 +2613,62 @@ "node": ">=6.0.0" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, "node_modules/domino": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/domino/-/domino-2.1.6.tgz", "integrity": "sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ==" }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.394", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.394.tgz", @@ -2619,6 +2702,17 @@ "once": "^1.4.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -3274,6 +3368,14 @@ "node": ">=8" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -4547,6 +4649,26 @@ } } }, + "node_modules/node-html-markdown": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/node-html-markdown/-/node-html-markdown-1.3.0.tgz", + "integrity": "sha512-OeFi3QwC/cPjvVKZ114tzzu+YoR+v9UXW5RwSXGUqGb0qCl0DvP406tzdL7SFn8pZrMyzXoisfG2zcuF9+zw4g==", + "dependencies": { + "node-html-parser": "^6.1.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/node-html-parser": { + "version": "6.1.12", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.12.tgz", + "integrity": "sha512-/bT/Ncmv+fbMGX96XG9g05vFt43m/+SYKIs9oAemQVYyVcZmDAI2Xq/SbNcpOA35eF0Zk2av3Ksf+Xk8Vt8abA==", + "dependencies": { + "css-select": "^5.1.0", + "he": "1.2.0" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -4580,6 +4702,17 @@ "node": ">=8" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", diff --git a/package.json b/package.json index 3a9330ba..d02075f2 100644 --- a/package.json +++ b/package.json @@ -31,25 +31,26 @@ }, "homepage": "https://github.com/IQSS/dataverse-client-javascript#readme", "devDependencies": { + "@types/chai": "^4.3.4", "@types/jest": "^29.4.0", "@types/sinon": "^10.0.13", - "@types/chai": "^4.3.4", "@typescript-eslint/eslint-plugin": "^5.54.0", "@typescript-eslint/parser": "^5.52.0", + "chai": "^4.3.7", "eslint": "^8.35.0", "eslint-plugin-jest": "^27.2.1", "jest": "^29.4.3", - "chai": "^4.3.7", "prettier": "^2.8.4", - "ts-jest": "^29.0.5", "sinon": "^15.0.3", - "testcontainers": "^9.9.1" + "testcontainers": "^9.9.1", + "ts-jest": "^29.0.5" }, "dependencies": { "@types/node": "^18.15.11", "@types/turndown": "^5.0.1", "axios": "^1.3.4", - "typescript": "^4.9.5", - "turndown": "^7.1.2" + "node-html-markdown": "^1.3.0", + "turndown": "^7.1.2", + "typescript": "^4.9.5" } } diff --git a/src/datasets/domain/useCases/CreateDataset.ts b/src/datasets/domain/useCases/CreateDataset.ts index ca352d82..4b71167f 100644 --- a/src/datasets/domain/useCases/CreateDataset.ts +++ b/src/datasets/domain/useCases/CreateDataset.ts @@ -21,6 +21,16 @@ export class CreateDataset implements UseCase { this.newDatasetValidator = newDatasetValidator; } + /** + * Creates a new Dataset in a collection, given a NewDatasetDTO object and an optional collection identifier, which defaults to root. + * + * @param {NewDatasetDTO} [newDataset] - NewDatasetDTO object including the new dataset metadata field values for each metadata block. + * @param {string} [collectionId] - Specifies the collection identifier where the new dataset should be created (optional, defaults to root). + * @returns {Promise} + * @throws {ResourceValidationError} - If there are validation errors related to the provided information. + * @throws {ReadError} - If there are errors while reading data. + * @throws {WriteError} - If there are errors while writing data. + */ async execute(newDataset: NewDatasetDTO, collectionId: string = 'root'): Promise { const metadataBlocks = await this.getNewDatasetMetadataBlocks(newDataset); this.newDatasetValidator.validate(newDataset, metadataBlocks); diff --git a/src/datasets/domain/useCases/GetAllDatasetPreviews.ts b/src/datasets/domain/useCases/GetAllDatasetPreviews.ts index e10cd9c3..baa0c7ea 100644 --- a/src/datasets/domain/useCases/GetAllDatasetPreviews.ts +++ b/src/datasets/domain/useCases/GetAllDatasetPreviews.ts @@ -9,6 +9,13 @@ export class GetAllDatasetPreviews implements UseCase { this.datasetsRepository = datasetsRepository; } + /** + * Returns an instance of DatasetPreviewSubset that contains reduced information for each dataset that the calling user can access in the installation. + * + * @param {number} [limit] - Limit for pagination (optional). + * @param {number} [offset] - Offset for pagination (optional). + * @returns {Promise} + */ async execute(limit?: number, offset?: number): Promise { return await this.datasetsRepository.getAllDatasetPreviews(limit, offset); } diff --git a/src/datasets/domain/useCases/GetDataset.ts b/src/datasets/domain/useCases/GetDataset.ts index 873dd27c..ca3075a6 100644 --- a/src/datasets/domain/useCases/GetDataset.ts +++ b/src/datasets/domain/useCases/GetDataset.ts @@ -10,6 +10,14 @@ export class GetDataset implements UseCase { this.datasetsRepository = datasetsRepository; } + /** + * Returns a Dataset instance, given the search parameters to identify it. + * + * @param {number | string} [datasetId] - The dataset identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers). + * @param {string | DatasetNotNumberedVersion} [datasetVersionId=DatasetNotNumberedVersion.LATEST] - The dataset version identifier, which can be a version-specific numeric string (for example, 1.0) or a DatasetNotNumberedVersion enum value. If this parameter is not set, the default value is: DatasetNotNumberedVersion.LATEST + * @param {boolean} [includeDeaccessioned=false] - Indicates whether to consider deaccessioned versions in the dataset search or not. The default value is false + * @returns {Promise} + */ async execute( datasetId: number | string, datasetVersionId: string | DatasetNotNumberedVersion = DatasetNotNumberedVersion.LATEST, diff --git a/src/datasets/domain/useCases/GetDatasetCitation.ts b/src/datasets/domain/useCases/GetDatasetCitation.ts index f9751387..11dbb089 100644 --- a/src/datasets/domain/useCases/GetDatasetCitation.ts +++ b/src/datasets/domain/useCases/GetDatasetCitation.ts @@ -9,6 +9,14 @@ export class GetDatasetCitation implements UseCase { this.datasetsRepository = datasetsRepository; } + /** + * Returns the Dataset citation text. + * + * @param {number} [datasetId] - The dataset identifier. + * @param {string | DatasetNotNumberedVersion} [datasetVersionId=DatasetNotNumberedVersion.LATEST] - The dataset version identifier, which can be a version-specific numeric string (for example, 1.0) or a DatasetNotNumberedVersion enum value. If this parameter is not set, the default value is: DatasetNotNumberedVersion.LATEST + * @param {boolean} [includeDeaccessioned=false] - Indicates whether to consider deaccessioned versions in the dataset search or not. The default value is false + * @returns {Promise} + */ async execute( datasetId: number, datasetVersionId: string | DatasetNotNumberedVersion = DatasetNotNumberedVersion.LATEST, diff --git a/src/datasets/domain/useCases/GetDatasetLocks.ts b/src/datasets/domain/useCases/GetDatasetLocks.ts index f44dccda..b4164567 100644 --- a/src/datasets/domain/useCases/GetDatasetLocks.ts +++ b/src/datasets/domain/useCases/GetDatasetLocks.ts @@ -9,6 +9,12 @@ export class GetDatasetLocks implements UseCase { this.datasetsRepository = datasetsRepository; } + /** + * Returns all locks present in a Dataset. + * + * @param {number | string} [datasetId] - The dataset identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers). + * @returns {Promise} + */ async execute(datasetId: number | string): Promise { return await this.datasetsRepository.getDatasetLocks(datasetId); } diff --git a/src/datasets/domain/useCases/GetDatasetSummaryFieldNames.ts b/src/datasets/domain/useCases/GetDatasetSummaryFieldNames.ts index 4041e408..4b67afc3 100644 --- a/src/datasets/domain/useCases/GetDatasetSummaryFieldNames.ts +++ b/src/datasets/domain/useCases/GetDatasetSummaryFieldNames.ts @@ -8,6 +8,11 @@ export class GetDatasetSummaryFieldNames implements UseCase { this.datasetsRepository = datasetsRepository; } + /** + * Returns the names of the dataset summary fields configured in the installation. + * + * @returns {Promise} + */ async execute(): Promise { return await this.datasetsRepository.getDatasetSummaryFieldNames(); } diff --git a/src/datasets/domain/useCases/GetDatasetUserPermissions.ts b/src/datasets/domain/useCases/GetDatasetUserPermissions.ts index 594e0ba6..13055977 100644 --- a/src/datasets/domain/useCases/GetDatasetUserPermissions.ts +++ b/src/datasets/domain/useCases/GetDatasetUserPermissions.ts @@ -9,6 +9,12 @@ export class GetDatasetUserPermissions implements UseCase} + */ async execute(datasetId: number | string): Promise { return await this.datasetsRepository.getDatasetUserPermissions(datasetId); } diff --git a/src/datasets/domain/useCases/GetPrivateUrlDataset.ts b/src/datasets/domain/useCases/GetPrivateUrlDataset.ts index 3580632c..2e05906d 100644 --- a/src/datasets/domain/useCases/GetPrivateUrlDataset.ts +++ b/src/datasets/domain/useCases/GetPrivateUrlDataset.ts @@ -9,6 +9,12 @@ export class GetPrivateUrlDataset implements UseCase { this.datasetsRepository = datasetsRepository; } + /** + * Returns a Dataset instance, given an associated Private URL Token. + * + * @param {string} [token] - A Private URL token. + * @returns {Promise} + */ async execute(token: string): Promise { return await this.datasetsRepository.getPrivateUrlDataset(token); } diff --git a/src/datasets/domain/useCases/GetPrivateUrlDatasetCitation.ts b/src/datasets/domain/useCases/GetPrivateUrlDatasetCitation.ts index 7ff06f47..508376e8 100644 --- a/src/datasets/domain/useCases/GetPrivateUrlDatasetCitation.ts +++ b/src/datasets/domain/useCases/GetPrivateUrlDatasetCitation.ts @@ -8,6 +8,12 @@ export class GetPrivateUrlDatasetCitation implements UseCase { this.datasetsRepository = datasetsRepository; } + /** + * Returns the Dataset citation text, given an associated Private URL Token. + * + * @param {string} [token] - A Private URL token. + * @returns {Promise} + */ async execute(token: string): Promise { return await this.datasetsRepository.getPrivateUrlDatasetCitation(token); } diff --git a/src/datasets/infra/repositories/transformers/datasetTransformers.ts b/src/datasets/infra/repositories/transformers/datasetTransformers.ts index 758e832d..b7e614bd 100644 --- a/src/datasets/infra/repositories/transformers/datasetTransformers.ts +++ b/src/datasets/infra/repositories/transformers/datasetTransformers.ts @@ -8,9 +8,7 @@ import { DatasetMetadataBlocks, } from '../../../domain/models/Dataset'; import { AxiosResponse } from 'axios'; -import TurndownService from 'turndown'; - -const turndownService = new TurndownService(); +import { NodeHtmlMarkdown } from 'node-html-markdown'; export const transformVersionResponseToDataset = (response: AxiosResponse): Dataset => { const versionPayload = response.data.data; @@ -104,5 +102,5 @@ const transformPayloadToDatasetMetadataFieldValue = (metadataFieldValuePayload: }; const transformHtmlToMarkdown = (source: string): string => { - return turndownService.turndown(source); + return NodeHtmlMarkdown.translate(source); }; diff --git a/src/files/domain/models/FileCriteria.ts b/src/files/domain/models/FileCriteria.ts index 3285624a..5ad26aa1 100644 --- a/src/files/domain/models/FileCriteria.ts +++ b/src/files/domain/models/FileCriteria.ts @@ -70,6 +70,6 @@ export enum FileOrderCriteria { export enum FileAccessStatus { PUBLIC = 'Public', RESTRICTED = 'Restricted', - EMBARGOED = 'EmbargoedThenRestricted', - EMBARGOED_RESTRICTED = 'EmbargoedThenPublic', + EMBARGOED = 'EmbargoedThenPublic', + EMBARGOED_RESTRICTED = 'EmbargoedThenRestricted', } diff --git a/src/files/domain/repositories/IFilesRepository.ts b/src/files/domain/repositories/IFilesRepository.ts index efd38b2d..e3f16127 100644 --- a/src/files/domain/repositories/IFilesRepository.ts +++ b/src/files/domain/repositories/IFilesRepository.ts @@ -39,5 +39,6 @@ export interface IFilesRepository { getFileDataTables(fileId: number | string): Promise; getFile(fileId: number | string, datasetVersionId: string): Promise; + getFileCitation(fileId: number | string, datasetVersionId: string, includeDeaccessioned: boolean): Promise; } diff --git a/src/files/domain/useCases/GetDatasetFileCounts.ts b/src/files/domain/useCases/GetDatasetFileCounts.ts index 2154100e..f164dcf9 100644 --- a/src/files/domain/useCases/GetDatasetFileCounts.ts +++ b/src/files/domain/useCases/GetDatasetFileCounts.ts @@ -11,6 +11,15 @@ export class GetDatasetFileCounts implements UseCase { this.filesRepository = filesRepository; } + /** + * Returns an instance of FileCounts, containing the requested Dataset total file count, as well as file counts for different file properties. + * + * @param {number | string} [datasetId] - The dataset identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers). + * @param {string | DatasetNotNumberedVersion} [datasetVersionId=DatasetNotNumberedVersion.LATEST] - The dataset version identifier, which can be a version-specific numeric string (for example, 1.0) or a DatasetNotNumberedVersion enum value. If this parameter is not set, the default value is: DatasetNotNumberedVersion.LATEST + * @param {boolean} [includeDeaccessioned=false] - Indicates whether to consider deaccessioned versions in the dataset search or not. The default value is false. + * @param {FileSearchCriteria} [fileSearchCriteria] - Supports filtering the files by different file properties (optional). + * @returns {Promise} + */ async execute( datasetId: number | string, datasetVersionId: string | DatasetNotNumberedVersion = DatasetNotNumberedVersion.LATEST, diff --git a/src/files/domain/useCases/GetDatasetFiles.ts b/src/files/domain/useCases/GetDatasetFiles.ts index 605ab542..642d7c18 100644 --- a/src/files/domain/useCases/GetDatasetFiles.ts +++ b/src/files/domain/useCases/GetDatasetFiles.ts @@ -11,6 +11,18 @@ export class GetDatasetFiles implements UseCase { this.filesRepository = filesRepository; } + /** + * Returns an instance of FilesSubset, which contains the files from the requested Dataset and page (if pagination parameters are set). + * + * @param {number | string} [datasetId] - The dataset identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers). + * @param {string | DatasetNotNumberedVersion} [datasetVersionId=DatasetNotNumberedVersion.LATEST] - The dataset version identifier, which can be a version-specific numeric string (for example, 1.0) or a DatasetNotNumberedVersion enum value. If this parameter is not set, the default value is: DatasetNotNumberedVersion.LATEST + * @param {boolean} [includeDeaccessioned=false] - Indicates whether to consider deaccessioned versions in the dataset search or not. The default value is false. + * @param {number} [limit] - Limit for pagination (optional). + * @param {number} [offset] - Offset for pagination (optional). + * @param {FileSearchCriteria} [fileSearchCriteria] - Supports filtering the files by different file properties (optional). + * @param {FileOrderCriteria} [fileOrderCriteria=FileOrderCriteria.NAME_AZ] - Supports ordering the results according to different criteria. If not set, the defalt value is FileOrderCriteria.NAME_AZ. + * @returns {Promise} + */ async execute( datasetId: number | string, datasetVersionId: string | DatasetNotNumberedVersion = DatasetNotNumberedVersion.LATEST, diff --git a/src/files/domain/useCases/GetDatasetFilesTotalDownloadSize.ts b/src/files/domain/useCases/GetDatasetFilesTotalDownloadSize.ts index b582b551..53fdb25e 100644 --- a/src/files/domain/useCases/GetDatasetFilesTotalDownloadSize.ts +++ b/src/files/domain/useCases/GetDatasetFilesTotalDownloadSize.ts @@ -11,6 +11,16 @@ export class GetDatasetFilesTotalDownloadSize implements UseCase { this.filesRepository = filesRepository; } + /** + * Returns the combined size in bytes of all the files available for download from a particular Dataset. + * + * @param {number | string} [datasetId] - The dataset identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers). + * @param {string | DatasetNotNumberedVersion} [datasetVersionId=DatasetNotNumberedVersion.LATEST] - The dataset version identifier, which can be a version-specific numeric string (for example, 1.0) or a DatasetNotNumberedVersion enum value. If this parameter is not set, the default value is: DatasetNotNumberedVersion.LATEST + * @param {FileDownloadSizeMode} [fileDownloadSizeMode=FileDownloadSizeMode.ALL] - Applies a filter mode to the operation to consider only archival sizes, original or both (all). The default value is FileDownloadSizeMode.ALL. + * @param {FileSearchCriteria} [fileSearchCriteria] - Supports filtering the files to obtain their combined size by different file properties (optional). + * @param {boolean} [includeDeaccessioned=false] - Indicates whether to consider deaccessioned versions in the dataset search or not. The default value is false. + * @returns {Promise} + */ async execute( datasetId: number | string, datasetVersionId: string | DatasetNotNumberedVersion = DatasetNotNumberedVersion.LATEST, diff --git a/src/files/domain/useCases/GetFile.ts b/src/files/domain/useCases/GetFile.ts index 64f30052..6eb65991 100644 --- a/src/files/domain/useCases/GetFile.ts +++ b/src/files/domain/useCases/GetFile.ts @@ -5,6 +5,13 @@ import { DatasetNotNumberedVersion } from '../../../datasets'; export class GetFile { constructor(private readonly filesRepository: IFilesRepository) {} + /** + * Returns a File instance, given the search parameters to identify it. + * + * @param {number | string} [fileId] - The File identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers). + * @param {string | DatasetNotNumberedVersion} [datasetVersionId=DatasetNotNumberedVersion.LATEST] - The dataset version identifier, which can be a version-specific numeric string (for example, 1.0) or a DatasetNotNumberedVersion enum value. If this parameter is not set, the default value is: DatasetNotNumberedVersion.LATEST + * @returns {Promise} + */ async execute( fileId: number | string, datasetVersionId: string | DatasetNotNumberedVersion = DatasetNotNumberedVersion.LATEST, diff --git a/src/files/domain/useCases/GetFileCitation.ts b/src/files/domain/useCases/GetFileCitation.ts index 2daccc1d..196968f0 100644 --- a/src/files/domain/useCases/GetFileCitation.ts +++ b/src/files/domain/useCases/GetFileCitation.ts @@ -9,6 +9,14 @@ export class GetFileCitation implements UseCase { this.filesRepository = filesRepository; } + /** + * Returns the File citation text. + * + * @param {number | string} [fileId] - The File identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers). + * @param {string | DatasetNotNumberedVersion} [datasetVersionId=DatasetNotNumberedVersion.LATEST] - The dataset version identifier, which can be a version-specific numeric string (for example, 1.0) or a DatasetNotNumberedVersion enum value. If this parameter is not set, the default value is: DatasetNotNumberedVersion.LATEST + * @param {boolean} [includeDeaccessioned=false] - Indicates whether to consider deaccessioned versions in the dataset search or not. The default value is false + * @returns {Promise} + */ async execute( fileId: number, datasetVersionId: string | DatasetNotNumberedVersion = DatasetNotNumberedVersion.LATEST, diff --git a/src/files/domain/useCases/GetFileDataTables.ts b/src/files/domain/useCases/GetFileDataTables.ts index d8a65891..07ffdeda 100644 --- a/src/files/domain/useCases/GetFileDataTables.ts +++ b/src/files/domain/useCases/GetFileDataTables.ts @@ -9,6 +9,12 @@ export class GetFileDataTables implements UseCase { this.filesRepository = filesRepository; } + /** + * This use case is oriented toward tabular files and provides an array of FileDataTable objects for an existing tabular file. + * + * @param {number | string} [fileId] - The file identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers). + * @returns {Promise} + */ async execute(fileId: number | string): Promise { return await this.filesRepository.getFileDataTables(fileId); } diff --git a/src/files/domain/useCases/GetFileDownloadCount.ts b/src/files/domain/useCases/GetFileDownloadCount.ts index 4d2b41eb..e527e1ef 100644 --- a/src/files/domain/useCases/GetFileDownloadCount.ts +++ b/src/files/domain/useCases/GetFileDownloadCount.ts @@ -8,6 +8,12 @@ export class GetFileDownloadCount implements UseCase { this.filesRepository = filesRepository; } + /** + * Provides the download count for a particular File. + * + * @param {number | string} [fileId] - The file identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers). + * @returns {Promise} + */ async execute(fileId: number | string): Promise { return await this.filesRepository.getFileDownloadCount(fileId); } diff --git a/src/files/domain/useCases/GetFileUserPermissions.ts b/src/files/domain/useCases/GetFileUserPermissions.ts index 454984ef..ed2ee266 100644 --- a/src/files/domain/useCases/GetFileUserPermissions.ts +++ b/src/files/domain/useCases/GetFileUserPermissions.ts @@ -9,6 +9,12 @@ export class GetFileUserPermissions implements UseCase { this.filesRepository = filesRepository; } + /** + * Returns a FileUserPermissions object, which includes the permissions that the calling user has on a particular File. + * + * @param {number | string} [fileId] - The file identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers). + * @returns {Promise} + */ async execute(fileId: number | string): Promise { return await this.filesRepository.getFileUserPermissions(fileId); } diff --git a/src/info/domain/useCases/GetDataverseVersion.ts b/src/info/domain/useCases/GetDataverseVersion.ts index 4937b9d1..51455549 100644 --- a/src/info/domain/useCases/GetDataverseVersion.ts +++ b/src/info/domain/useCases/GetDataverseVersion.ts @@ -9,6 +9,11 @@ export class GetDataverseVersion implements UseCase { this.dataverseInfoRepository = dataverseInfoRepository; } + /** + * Returns a DataverseVersion object, which contains version information for the Dataverse backend installation. + * + * @returns {Promise} + */ async execute(): Promise { return await this.dataverseInfoRepository.getDataverseVersion(); } diff --git a/src/info/domain/useCases/GetMaxEmbargoDurationInMonths.ts b/src/info/domain/useCases/GetMaxEmbargoDurationInMonths.ts index b10c4d1e..3c3b62be 100644 --- a/src/info/domain/useCases/GetMaxEmbargoDurationInMonths.ts +++ b/src/info/domain/useCases/GetMaxEmbargoDurationInMonths.ts @@ -8,6 +8,11 @@ export class GetMaxEmbargoDurationInMonths implements UseCase { this.dataverseInfoRepository = dataverseInfoRepository; } + /** + * Returns a number indicating the configured maximum embargo duration in months. + * + * @returns {Promise} + */ async execute(): Promise { return await this.dataverseInfoRepository.getMaxEmbargoDurationInMonths(); } diff --git a/src/info/domain/useCases/GetZipDownloadLimit.ts b/src/info/domain/useCases/GetZipDownloadLimit.ts index 84e8af4b..aa93bb6b 100644 --- a/src/info/domain/useCases/GetZipDownloadLimit.ts +++ b/src/info/domain/useCases/GetZipDownloadLimit.ts @@ -8,6 +8,11 @@ export class GetZipDownloadLimit implements UseCase { this.dataverseInfoRepository = dataverseInfoRepository; } + /** + * Returns a number indicating the configured ZIP download limit in bytes. + * + * @returns {Promise} + */ async execute(): Promise { return await this.dataverseInfoRepository.getZipDownloadLimit(); } diff --git a/src/metadataBlocks/domain/useCases/GetMetadataBlockByName.ts b/src/metadataBlocks/domain/useCases/GetMetadataBlockByName.ts index dc09c1c4..a34953e3 100644 --- a/src/metadataBlocks/domain/useCases/GetMetadataBlockByName.ts +++ b/src/metadataBlocks/domain/useCases/GetMetadataBlockByName.ts @@ -9,6 +9,12 @@ export class GetMetadataBlockByName implements UseCase { this.metadataBlocksRepository = metadataBlocksRepository; } + /** + * Returns a MetadataBlock instance, given its name. + * + * @param {string} [metadataBlockName] - The requested metadata block name. + * @returns {Promise} + */ async execute(metadataBlockName: string): Promise { return await this.metadataBlocksRepository.getMetadataBlockByName(metadataBlockName); } diff --git a/src/users/domain/useCases/GetCurrentAuthenticatedUser.ts b/src/users/domain/useCases/GetCurrentAuthenticatedUser.ts index 1b9acb85..6724b518 100644 --- a/src/users/domain/useCases/GetCurrentAuthenticatedUser.ts +++ b/src/users/domain/useCases/GetCurrentAuthenticatedUser.ts @@ -9,6 +9,11 @@ export class GetCurrentAuthenticatedUser implements UseCase { this.usersRepository = usersRepository; } + /** + * Returns the current AuthenticatedUser corresponding to the authentication mechanism provided through ApiConfig. + * + * @returns {Promise} + */ async execute(): Promise { return await this.usersRepository.getCurrentAuthenticatedUser(); } diff --git a/test/testHelpers/datasets/datasetHelper.ts b/test/testHelpers/datasets/datasetHelper.ts index b257a0b8..8415fce6 100644 --- a/test/testHelpers/datasets/datasetHelper.ts +++ b/test/testHelpers/datasets/datasetHelper.ts @@ -1,10 +1,8 @@ import { Dataset, DatasetVersionState, DatasetLicense } from '../../../src/datasets/domain/models/Dataset'; -import TurndownService from 'turndown'; +import { NodeHtmlMarkdown } from 'node-html-markdown'; import axios, { AxiosResponse } from 'axios'; import { TestConstants } from '../TestConstants'; -const turndownService = new TurndownService(); - const DATASET_CREATE_TIME_STR = '2023-05-15T08:21:01Z'; const DATASET_UPDATE_TIME_STR = '2023-05-15T08:21:03Z'; const DATASET_RELEASE_TIME_STR = '2023-05-15T08:21:03Z'; @@ -50,7 +48,7 @@ export const createDatasetModel = (license?: DatasetLicense): Dataset => { subject: ['Subject1', 'Subject2'], dsDescription: [ { - dsDescriptionValue: turndownService.turndown(DATASET_HTML_DESCRIPTION), + dsDescriptionValue: NodeHtmlMarkdown.translate(DATASET_HTML_DESCRIPTION), }, ], datasetContact: [ @@ -185,7 +183,7 @@ export const createDatasetVersionPayload = (license?: DatasetLicense): any => { return datasetPayload; }; -export const createDatasetLicenseModel = (withIconUri: boolean = true): DatasetLicense => { +export const createDatasetLicenseModel = (withIconUri = true): DatasetLicense => { const datasetLicense: DatasetLicense = { name: 'CC0 1.0', uri: 'https://creativecommons.org/publicdomain/zero/1.0/',