From 849df996476c68b575aeabe8162825fb9249cb66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Wed, 30 Apr 2025 15:05:28 -0300 Subject: [PATCH 1/6] feat: add use case --- .../repositories/IDataverseInfoRepository.ts | 1 + .../useCases/GetApplicationTermsOfUse.ts | 19 +++++++++++++++++++ src/info/index.ts | 9 ++++++++- .../repositories/DataverseInfoRepository.ts | 16 ++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/info/domain/useCases/GetApplicationTermsOfUse.ts diff --git a/src/info/domain/repositories/IDataverseInfoRepository.ts b/src/info/domain/repositories/IDataverseInfoRepository.ts index 2adbb89a..0ec6c747 100644 --- a/src/info/domain/repositories/IDataverseInfoRepository.ts +++ b/src/info/domain/repositories/IDataverseInfoRepository.ts @@ -4,4 +4,5 @@ export interface IDataverseInfoRepository { getDataverseVersion(): Promise getZipDownloadLimit(): Promise getMaxEmbargoDurationInMonths(): Promise + getApplicationTermsOfUse(lang?: string): Promise } diff --git a/src/info/domain/useCases/GetApplicationTermsOfUse.ts b/src/info/domain/useCases/GetApplicationTermsOfUse.ts new file mode 100644 index 00000000..a3d47bdf --- /dev/null +++ b/src/info/domain/useCases/GetApplicationTermsOfUse.ts @@ -0,0 +1,19 @@ +import { UseCase } from '../../../core/domain/useCases/UseCase' +import { IDataverseInfoRepository } from '../repositories/IDataverseInfoRepository' + +export class GetApplicationTermsOfUse implements UseCase { + private dataverseInfoRepository: IDataverseInfoRepository + + constructor(dataverseInfoRepository: IDataverseInfoRepository) { + this.dataverseInfoRepository = dataverseInfoRepository + } + + /** + * Returns a string containing the application terms of use. + * + * @returns {Promise} + */ + async execute(lang?: string): Promise { + return await this.dataverseInfoRepository.getApplicationTermsOfUse(lang) + } +} diff --git a/src/info/index.ts b/src/info/index.ts index 32513ad1..049cc48d 100644 --- a/src/info/index.ts +++ b/src/info/index.ts @@ -2,11 +2,18 @@ import { DataverseInfoRepository } from './infra/repositories/DataverseInfoRepos import { GetDataverseVersion } from './domain/useCases/GetDataverseVersion' import { GetZipDownloadLimit } from './domain/useCases/GetZipDownloadLimit' import { GetMaxEmbargoDurationInMonths } from './domain/useCases/GetMaxEmbargoDurationInMonths' +import { GetApplicationTermsOfUse } from './domain/useCases/GetApplicationTermsOfUse' const dataverseInfoRepository = new DataverseInfoRepository() const getDataverseVersion = new GetDataverseVersion(dataverseInfoRepository) const getZipDownloadLimit = new GetZipDownloadLimit(dataverseInfoRepository) const getMaxEmbargoDurationInMonths = new GetMaxEmbargoDurationInMonths(dataverseInfoRepository) +const getApplicationTermsOfUse = new GetApplicationTermsOfUse(dataverseInfoRepository) -export { getDataverseVersion, getZipDownloadLimit, getMaxEmbargoDurationInMonths } +export { + getDataverseVersion, + getZipDownloadLimit, + getMaxEmbargoDurationInMonths, + getApplicationTermsOfUse +} diff --git a/src/info/infra/repositories/DataverseInfoRepository.ts b/src/info/infra/repositories/DataverseInfoRepository.ts index 71ba653b..c4de4a22 100644 --- a/src/info/infra/repositories/DataverseInfoRepository.ts +++ b/src/info/infra/repositories/DataverseInfoRepository.ts @@ -39,4 +39,20 @@ export class DataverseInfoRepository extends ApiRepository implements IDataverse build: responseData.build } } + + public async getApplicationTermsOfUse(lang?: string): Promise { + return this.doGet( + this.buildApiEndpoint(this.infoResourceName, `applicationTermsOfUse`), + false, + { + ...(lang ? { lang } : {}) + } + ) + .then((response: AxiosResponse<{ data: { message: string } }>) => { + return response.data.data.message + }) + .catch((error) => { + throw error + }) + } } From df33a12128f72b4f7b4192a764c91907749e8d27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Wed, 30 Apr 2025 15:05:42 -0300 Subject: [PATCH 2/6] docs --- docs/useCases.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/useCases.md b/docs/useCases.md index e8d7be92..2cc3a229 100644 --- a/docs/useCases.md +++ b/docs/useCases.md @@ -75,6 +75,7 @@ The different use cases currently available in the package are classified below, - [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) + - [Get Application Terms of Use](#get-application-terms-of-use) - [Contact](#Contact) - [Send Feedback to Object Contacts](#send-feedback-to-object-contacts) @@ -1781,6 +1782,26 @@ getZipDownloadLimit.execute().then((downloadLimit: number) => { _See [use case](../src/info/domain/useCases/GetZipDownloadLimit.ts) implementation_. +#### Get Application Terms of Use + +Returns the Application Terms of Use. If you have enabled Internationalization you can pass a two-character language code (e.g. “en”) as the lang parameter. + +##### Example call: + +```typescript +import { getApplicationTermsOfUse } from '@iqss/dataverse-client-javascript' + +/* ... */ + +getApplicationTermsOfUse.execute().then((termsOfUse: string) => { + /* ... */ +}) + +/* ... */ +``` + +_See [use case](../src/info/domain/useCases/GetApplicationTermsOfUse.ts) implementation_. + ## Contact #### Send Feedback to Object Contacts From 92dd2762edb432175beec5a5ed8a63dc0c074607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Wed, 30 Apr 2025 15:06:34 -0300 Subject: [PATCH 3/6] test: add unit and integration tests --- .../info/DataverseInfoRepository.test.ts | 25 ++++++- test/testHelpers/info/infoHelper.ts | 16 +++++ .../unit/info/DataverseInfoRepository.test.ts | 65 +++++++++++++++++++ .../info/GetApplicationTermsOfUse.test.ts | 29 +++++++++ 4 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 test/unit/info/GetApplicationTermsOfUse.test.ts diff --git a/test/integration/info/DataverseInfoRepository.test.ts b/test/integration/info/DataverseInfoRepository.test.ts index ed3e5d98..7cc42a48 100644 --- a/test/integration/info/DataverseInfoRepository.test.ts +++ b/test/integration/info/DataverseInfoRepository.test.ts @@ -4,7 +4,11 @@ import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig' import { TestConstants } from '../../testHelpers/TestConstants' -import { setMaxEmbargoDurationInMonthsViaApi } from '../../testHelpers/info/infoHelper' +import { + deleteApplicationTermsOfUseViaApi, + setApplicationTermsOfUseViaApi, + setMaxEmbargoDurationInMonthsViaApi +} from '../../testHelpers/info/infoHelper' import { ReadError } from '../../../src/core/domain/repositories/ReadError' describe('DataverseInfoRepository', () => { @@ -49,4 +53,23 @@ describe('DataverseInfoRepository', () => { expect(actual).toBe(testMaxEmbargoDurationInMonths) }) }) + + describe('getApplicationTermsOfUse', () => { + test('should return no terms message when terms are not set', async () => { + const defaultNoTermsOfUseMessage = + 'There are no Terms of Use for this Dataverse installation.' + const actual = await sut.getApplicationTermsOfUse() + + expect(actual).toBe(defaultNoTermsOfUseMessage) + }) + test('should return terms when terms are set', async () => { + const testTermsOfUse = 'Be excellent to each other.' + await setApplicationTermsOfUseViaApi(testTermsOfUse) + const actual = await sut.getApplicationTermsOfUse() + + expect(actual).toBe(testTermsOfUse) + + await deleteApplicationTermsOfUseViaApi() + }) + }) }) diff --git a/test/testHelpers/info/infoHelper.ts b/test/testHelpers/info/infoHelper.ts index eacfa6d4..121e9489 100644 --- a/test/testHelpers/info/infoHelper.ts +++ b/test/testHelpers/info/infoHelper.ts @@ -12,3 +12,19 @@ export const setMaxEmbargoDurationInMonthsViaApi = async ( } ) } + +export const setApplicationTermsOfUseViaApi = async ( + applicationTermsOfUse: string +): Promise => { + return await axios.put( + `${TestConstants.TEST_API_URL}/admin/settings/:ApplicationTermsOfUse`, + applicationTermsOfUse, + { + headers: { 'Content-Type': 'text/plain' } + } + ) +} + +export const deleteApplicationTermsOfUseViaApi = async (): Promise => { + return await axios.delete(`${TestConstants.TEST_API_URL}/admin/settings/:ApplicationTermsOfUse`) +} diff --git a/test/unit/info/DataverseInfoRepository.test.ts b/test/unit/info/DataverseInfoRepository.test.ts index 3ab062f5..fd6dd138 100644 --- a/test/unit/info/DataverseInfoRepository.test.ts +++ b/test/unit/info/DataverseInfoRepository.test.ts @@ -123,4 +123,69 @@ describe('DataverseInfoRepository', () => { expect(error).toBeInstanceOf(Error) }) }) + + describe('getApplicationTermsOfUse', () => { + test('should return terms of use on successful response', async () => { + const testTermsOfUse = 'Be excellent to each other.' + const testSuccessfulResponse = { + data: { + status: 'OK', + data: { + message: testTermsOfUse + } + } + } + jest.spyOn(axios, 'get').mockResolvedValue(testSuccessfulResponse) + + const actual = await sut.getApplicationTermsOfUse() + + expect(axios.get).toHaveBeenCalledWith( + `${TestConstants.TEST_API_URL}/info/applicationTermsOfUse`, + TestConstants.TEST_EXPECTED_UNAUTHENTICATED_REQUEST_CONFIG + ) + expect(actual).toMatch(testTermsOfUse) + }) + + test('should return terms of use on successful response with lang', async () => { + const testLang = 'en' + const testTermsOfUse = 'Be excellent to each other.' + const testSuccessfulResponse = { + data: { + status: 'OK', + data: { + message: testTermsOfUse + } + } + } + jest.spyOn(axios, 'get').mockResolvedValue(testSuccessfulResponse) + + const actual = await sut.getApplicationTermsOfUse(testLang) + + expect(axios.get).toHaveBeenCalledWith( + `${TestConstants.TEST_API_URL}/info/applicationTermsOfUse`, + { + params: { + lang: testLang + }, + headers: { + 'Content-Type': 'application/json' + } + } + ) + expect(actual).toMatch(testTermsOfUse) + }) + + test('should return error result on error response', async () => { + jest.spyOn(axios, 'get').mockRejectedValue(TestConstants.TEST_ERROR_RESPONSE) + + let error: ReadError | undefined + await sut.getApplicationTermsOfUse().catch((e) => (error = e)) + + expect(axios.get).toHaveBeenCalledWith( + `${TestConstants.TEST_API_URL}/info/applicationTermsOfUse`, + TestConstants.TEST_EXPECTED_UNAUTHENTICATED_REQUEST_CONFIG + ) + expect(error).toBeInstanceOf(Error) + }) + }) }) diff --git a/test/unit/info/GetApplicationTermsOfUse.test.ts b/test/unit/info/GetApplicationTermsOfUse.test.ts new file mode 100644 index 00000000..6be53131 --- /dev/null +++ b/test/unit/info/GetApplicationTermsOfUse.test.ts @@ -0,0 +1,29 @@ +import { ReadError } from '../../../src/core/domain/repositories/ReadError' +import { IDataverseInfoRepository } from '../../../src/info/domain/repositories/IDataverseInfoRepository' +import { GetApplicationTermsOfUse } from '../../../src/info/domain/useCases/GetApplicationTermsOfUse' + +describe('execute', () => { + test('should return successful result with terms of use on repository success', async () => { + const testTermsOfUse = 'Be excellent to each other.' + const dataverseInfoRepositoryStub: IDataverseInfoRepository = {} as IDataverseInfoRepository + dataverseInfoRepositoryStub.getApplicationTermsOfUse = jest + .fn() + .mockResolvedValue(testTermsOfUse) + const sut = new GetApplicationTermsOfUse(dataverseInfoRepositoryStub) + + const actual = await sut.execute() + + expect(actual).toBe(testTermsOfUse) + }) + + test('should return error result on repository error', async () => { + const dataverseInfoRepositoryStub: IDataverseInfoRepository = {} as IDataverseInfoRepository + const testReadError = new ReadError() + dataverseInfoRepositoryStub.getApplicationTermsOfUse = jest + .fn() + .mockRejectedValue(testReadError) + const sut = new GetApplicationTermsOfUse(dataverseInfoRepositoryStub) + + await expect(sut.execute()).rejects.toThrow(ReadError) + }) +}) From fa41668bf154ff4690ca53c798d436c972931917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Wed, 30 Apr 2025 15:17:27 -0300 Subject: [PATCH 4/6] test: use ghcr image --- test/environment/.env | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/environment/.env b/test/environment/.env index 0c691d9b..8ad7370e 100644 --- a/test/environment/.env +++ b/test/environment/.env @@ -1,6 +1,6 @@ POSTGRES_VERSION=13 DATAVERSE_DB_USER=dataverse SOLR_VERSION=9.8.0 -DATAVERSE_IMAGE_REGISTRY=docker.io -DATAVERSE_IMAGE_TAG=unstable +DATAVERSE_IMAGE_REGISTRY=ghcr.io +DATAVERSE_IMAGE_TAG=11415-app-tou DATAVERSE_BOOTSTRAP_TIMEOUT=5m From 0160da871dce7e509c92e942caa5389baf15daf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Fri, 2 May 2025 09:27:59 -0300 Subject: [PATCH 5/6] chore: back to unstable image for tests --- test/environment/.env | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/environment/.env b/test/environment/.env index 8ad7370e..0c691d9b 100644 --- a/test/environment/.env +++ b/test/environment/.env @@ -1,6 +1,6 @@ POSTGRES_VERSION=13 DATAVERSE_DB_USER=dataverse SOLR_VERSION=9.8.0 -DATAVERSE_IMAGE_REGISTRY=ghcr.io -DATAVERSE_IMAGE_TAG=11415-app-tou +DATAVERSE_IMAGE_REGISTRY=docker.io +DATAVERSE_IMAGE_TAG=unstable DATAVERSE_BOOTSTRAP_TIMEOUT=5m From b6ed17dc3d489748a722218c18c6918e92820a20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Mon, 5 May 2025 13:53:04 -0300 Subject: [PATCH 6/6] code review tweaks --- src/info/domain/useCases/GetApplicationTermsOfUse.ts | 1 + test/integration/info/DataverseInfoRepository.test.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/info/domain/useCases/GetApplicationTermsOfUse.ts b/src/info/domain/useCases/GetApplicationTermsOfUse.ts index a3d47bdf..85821fe7 100644 --- a/src/info/domain/useCases/GetApplicationTermsOfUse.ts +++ b/src/info/domain/useCases/GetApplicationTermsOfUse.ts @@ -11,6 +11,7 @@ export class GetApplicationTermsOfUse implements UseCase { /** * Returns a string containing the application terms of use. * + * @param {string} [lang] - Optional language parameter to specify the language of the terms of use. * @returns {Promise} */ async execute(lang?: string): Promise { diff --git a/test/integration/info/DataverseInfoRepository.test.ts b/test/integration/info/DataverseInfoRepository.test.ts index 7cc42a48..4fec4669 100644 --- a/test/integration/info/DataverseInfoRepository.test.ts +++ b/test/integration/info/DataverseInfoRepository.test.ts @@ -62,6 +62,7 @@ describe('DataverseInfoRepository', () => { expect(actual).toBe(defaultNoTermsOfUseMessage) }) + test('should return terms when terms are set', async () => { const testTermsOfUse = 'Be excellent to each other.' await setApplicationTermsOfUseViaApi(testTermsOfUse)