Skip to content

Commit 74ec1ef

Browse files
authored
Merge pull request #449 from IQSS/448-add-usage-and-response-counts-to-get-guestbooks-use-case
Extend get guestbooks use case with stats and Download responses
2 parents eb0cae7 + 46b12b0 commit 74ec1ef

18 files changed

Lines changed: 1149 additions & 14 deletions

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ This changelog follows the principles of [Keep a Changelog](https://keepachangel
88

99
### Added
1010

11+
- Guestbooks: Added `getGuestbookResponsesByGuestbookId` use case and repository support for retrieving paginated guestbook responses with total count as structured JSON.
12+
- Guestbooks: Added `downloadGuestbookResponsesByCollectionId` and `downloadGuestbookResponsesOfAGuestbook` use cases and repository support for exporting guestbook responses as raw CSV content.
13+
- Guestbooks: Added optional `includeStats` support to `getGuestbooksByCollectionId`, returning `usageCount` and `responseCount` when requested.
1114
- Files: Added `getFileCitationByFormat` use case, repository method, and `FileCitationFormat` enum to support Dataverse file citation exports in `EndNote`, `RIS`, `BibTeX`, `CSL`, and `Internal` formats.
1215
- Collections: Added `allowedDatasetTypes` field to the [Collection](./src/collections/domain/models/Collection.ts) model. This field is optional and only populated the feature is enabled on the installation and configured on the collection.
1316
- Collections: Added theme information when retrieving a collection using `getCollection`.

docs/useCases.md

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ The different use cases currently available in the package are classified below,
138138
- [Guestbooks read use cases](#guestbooks-read-use-cases)
139139
- [Get a Guestbook](#get-a-guestbook)
140140
- [Get Guestbooks By Collection Id](#get-guestbooks-by-collection-id)
141+
- [Get Guestbook Responses By Guestbook Id](#get-guestbook-responses-by-guestbook-id)
142+
- [Download Guestbook Responses By Collection Id](#download-guestbook-responses-by-collection-id)
143+
- [Download Guestbook Responses Of A Guestbook](#download-guestbook-responses-of-a-guestbook)
141144
- [Guestbooks write use cases](#guestbooks-write-use-cases)
142145
- [Create a Guestbook](#create-a-guestbook)
143146
- [Set Guestbook Enabled](#set-guestbook-enabled)
@@ -3168,21 +3171,88 @@ _See [use case](../src/guestbooks/domain/useCases/GetGuestbook.ts) implementatio
31683171
#### Get Guestbooks By Collection Id
31693172

31703173
Returns all [Guestbook](../src/guestbooks/domain/models/Guestbook.ts) entries available for a collection.
3174+
Set `includeStats` to `true` to include `usageCount` and `responseCount` for each guestbook.
31713175

31723176
##### Example call:
31733177

31743178
```typescript
31753179
import { getGuestbooksByCollectionId } from '@iqss/dataverse-client-javascript'
31763180

31773181
const collectionIdOrAlias = 'root'
3182+
const includeStats = true
31783183

3179-
getGuestbooksByCollectionId.execute(collectionIdOrAlias).then((guestbooks: Guestbook[]) => {
3180-
/* ... */
3181-
})
3184+
getGuestbooksByCollectionId
3185+
.execute(collectionIdOrAlias, includeStats)
3186+
.then((guestbooks: Guestbook[]) => {
3187+
/* ... */
3188+
})
31823189
```
31833190

31843191
_See [use case](../src/guestbooks/domain/useCases/GetGuestbooksByCollectionId.ts) implementation_.
31853192

3193+
#### Get Guestbook Responses By Guestbook Id
3194+
3195+
Returns a [GuestbookResponseSubset](../src/guestbooks/domain/models/GuestbookResponse.ts) containing paginated guestbook response entries and the total response count for a guestbook.
3196+
3197+
##### Example call:
3198+
3199+
```typescript
3200+
import { getGuestbookResponsesByGuestbookId } from '@iqss/dataverse-client-javascript'
3201+
3202+
const guestbookId = 123
3203+
const limit = 10
3204+
const offset = 0
3205+
3206+
getGuestbookResponsesByGuestbookId
3207+
.execute(guestbookId, limit, offset)
3208+
.then((guestbookResponseSubset: GuestbookResponseSubset) => {
3209+
/* ... */
3210+
})
3211+
```
3212+
3213+
_See [use case](../src/guestbooks/domain/useCases/GetGuestbookResponsesByGuestbookId.ts) implementation_.
3214+
3215+
#### Download Guestbook Responses By Collection Id
3216+
3217+
Downloads all guestbook responses for a collection and returns the raw response body, typically CSV content.
3218+
3219+
##### Example call:
3220+
3221+
```typescript
3222+
import { downloadGuestbookResponsesByCollectionId } from '@iqss/dataverse-client-javascript'
3223+
3224+
const collectionIdOrAlias = 'root'
3225+
3226+
downloadGuestbookResponsesByCollectionId
3227+
.execute(collectionIdOrAlias)
3228+
.then((csvResponse: string) => {
3229+
/* ... */
3230+
})
3231+
```
3232+
3233+
_See [use case](../src/guestbooks/domain/useCases/DownloadGuestbookResponsesByCollectionId.ts) implementation_.
3234+
3235+
#### Download Guestbook Responses Of A Guestbook
3236+
3237+
Downloads guestbook responses for one guestbook in a collection and returns the raw response body, typically CSV content.
3238+
3239+
##### Example call:
3240+
3241+
```typescript
3242+
import { downloadGuestbookResponsesOfAGuestbook } from '@iqss/dataverse-client-javascript'
3243+
3244+
const collectionIdOrAlias = 'root'
3245+
const guestbookId = 123
3246+
3247+
downloadGuestbookResponsesOfAGuestbook
3248+
.execute(collectionIdOrAlias, guestbookId)
3249+
.then((csvResponse: string) => {
3250+
/* ... */
3251+
})
3252+
```
3253+
3254+
_See [use case](../src/guestbooks/domain/useCases/DownloadGuestbookResponsesOfAGuestbook.ts) implementation_.
3255+
31863256
### Guestbooks Write Use Cases
31873257

31883258
#### Create a Guestbook
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Guestbook } from '../models/Guestbook'
2+
import { GuestbookResponse } from '../models/GuestbookResponse'
3+
4+
export interface GuestbookResponsesDTO {
5+
guestbook: Guestbook
6+
responses: GuestbookResponse[]
7+
pagination?: GuestbookResponsesPaginationDTO
8+
}
9+
10+
export interface GuestbookResponsesPaginationDTO {
11+
next?: string
12+
totalResponses: number
13+
}

src/guestbooks/domain/models/Guestbook.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,6 @@ export interface Guestbook {
2525
customQuestions: GuestbookCustomQuestion[]
2626
createTime: string
2727
dataverseId: number
28+
usageCount?: number
29+
responseCount?: number
2830
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
export interface GuestbookResponse {
2+
id: number
3+
dataset: string
4+
datasetPid: string
5+
date: string
6+
type: EventType
7+
fileName?: string
8+
fileId?: number
9+
filePid?: string
10+
userName: string
11+
email?: string
12+
institution?: string
13+
position?: string
14+
customQuestions?: GuestbookResponseCustomQuestion[]
15+
}
16+
17+
export interface GuestbookResponseCustomQuestion {
18+
question: string
19+
response: string
20+
}
21+
22+
export interface GuestbookResponseSubset {
23+
guestbookResponses: GuestbookResponse[]
24+
totalGuestbookResponseCount: number
25+
}
26+
27+
export enum EventType {
28+
ACCESS_REQUEST = 'AccessRequest',
29+
DOWNLOAD = 'Download',
30+
SUBSET = 'Subset',
31+
EXPLORE = 'Explore'
32+
}

src/guestbooks/domain/repositories/IGuestbooksRepository.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
11
import { CreateGuestbookDTO } from '../dtos/CreateGuestbookDTO'
22
import { Guestbook } from '../models/Guestbook'
3+
import { GuestbookResponseSubset } from '../models/GuestbookResponse'
34

45
export interface IGuestbooksRepository {
56
createGuestbook(
67
collectionIdOrAlias: number | string,
78
guestbook: CreateGuestbookDTO
89
): Promise<number>
910
getGuestbook(guestbookId: number): Promise<Guestbook>
10-
getGuestbooksByCollectionId(collectionIdOrAlias: number | string): Promise<Guestbook[]>
11+
getGuestbooksByCollectionId(
12+
collectionIdOrAlias: number | string,
13+
includeStats?: boolean,
14+
includeInherited?: boolean
15+
): Promise<Guestbook[]>
16+
getGuestbookResponsesByGuestbookId(
17+
guestbookId: number,
18+
limit?: number,
19+
offset?: number
20+
): Promise<GuestbookResponseSubset>
21+
downloadGuestbookResponsesByCollectionId(
22+
collectionIdOrAlias: number | string,
23+
guestbookId?: number
24+
): Promise<string>
1125
setGuestbookEnabled(
1226
collectionIdOrAlias: number | string,
1327
guestbookId: number,
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { UseCase } from '../../../core/domain/useCases/UseCase'
2+
import { IGuestbooksRepository } from '../repositories/IGuestbooksRepository'
3+
4+
export class DownloadGuestbookResponsesByCollectionId implements UseCase<string> {
5+
constructor(private readonly guestbooksRepository: IGuestbooksRepository) {}
6+
7+
/**
8+
* Downloads all guestbook responses for a collection.
9+
*
10+
* @param {number | string} collectionIdOrAlias - Collection alias/identifier or numeric database id.
11+
* @returns {Promise<string>} Raw response body returned by the Dataverse API.
12+
*/
13+
async execute(collectionIdOrAlias: number | string): Promise<string> {
14+
return await this.guestbooksRepository.downloadGuestbookResponsesByCollectionId(
15+
collectionIdOrAlias
16+
)
17+
}
18+
}
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 { IGuestbooksRepository } from '../repositories/IGuestbooksRepository'
3+
4+
export class DownloadGuestbookResponsesOfAGuestbook implements UseCase<string> {
5+
constructor(private readonly guestbooksRepository: IGuestbooksRepository) {}
6+
7+
/**
8+
* Downloads guestbook responses for one guestbook in a collection.
9+
*
10+
* @param {number | string} collectionIdOrAlias - Collection alias/identifier or numeric database id.
11+
* @param {number} guestbookId - Guestbook identifier to restrict the export.
12+
* @returns {Promise<string>} Raw response body returned by the Dataverse API.
13+
*/
14+
async execute(collectionIdOrAlias: number | string, guestbookId: number): Promise<string> {
15+
return await this.guestbooksRepository.downloadGuestbookResponsesByCollectionId(
16+
collectionIdOrAlias,
17+
guestbookId
18+
)
19+
}
20+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { UseCase } from '../../../core/domain/useCases/UseCase'
2+
import { GuestbookResponseSubset } from '../models/GuestbookResponse'
3+
import { IGuestbooksRepository } from '../repositories/IGuestbooksRepository'
4+
5+
export class GetGuestbookResponsesByGuestbookId implements UseCase<GuestbookResponseSubset> {
6+
constructor(private readonly guestbooksRepository: IGuestbooksRepository) {}
7+
8+
/**
9+
* Returns paginated guestbook responses for one guestbook.
10+
*
11+
* @param {number} guestbookId - Guestbook identifier.
12+
* @param {number} limit - Maximum number of responses to return.
13+
* @param {number} offset - Number of responses to skip.
14+
* @returns {Promise<GuestbookResponseSubset>}
15+
*/
16+
async execute(guestbookId: number, limit = 10, offset = 0): Promise<GuestbookResponseSubset> {
17+
return await this.guestbooksRepository.getGuestbookResponsesByGuestbookId(
18+
guestbookId,
19+
limit,
20+
offset
21+
)
22+
}
23+
}

src/guestbooks/domain/useCases/GetGuestbooksByCollectionId.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,23 @@ export class GetGuestbooksByCollectionId implements UseCase<Guestbook[]> {
99
* Returns all guestbooks available for a given collection.
1010
*
1111
* @param {number | string} collectionIdOrAlias - Collection identifier (numeric id or alias).
12+
* @param {boolean} [includeStats=false] - Include usage and response counts for each guestbook.
13+
* @param {boolean} [includeInherited=false] - Include guestbooks inherited from hierarchical owners.
1214
* @returns {Promise<Guestbook[]>}
1315
*/
14-
async execute(collectionIdOrAlias: number | string): Promise<Guestbook[]> {
15-
return await this.guestbooksRepository.getGuestbooksByCollectionId(collectionIdOrAlias)
16+
async execute(
17+
collectionIdOrAlias: number | string,
18+
includeStats = false,
19+
includeInherited = false
20+
): Promise<Guestbook[]> {
21+
if (!includeStats && !includeInherited) {
22+
return await this.guestbooksRepository.getGuestbooksByCollectionId(collectionIdOrAlias)
23+
}
24+
25+
return await this.guestbooksRepository.getGuestbooksByCollectionId(
26+
collectionIdOrAlias,
27+
includeStats,
28+
includeInherited
29+
)
1630
}
1731
}

0 commit comments

Comments
 (0)