Skip to content

Commit 35ce917

Browse files
committed
feat: add use case to submit feedback to contacts
1 parent f21affc commit 35ce917

File tree

11 files changed

+326
-0
lines changed

11 files changed

+326
-0
lines changed

docs/useCases.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ The different use cases currently available in the package are classified below,
6363
- [Get Dataverse Backend Version](#get-dataverse-backend-version)
6464
- [Get Maximum Embargo Duration In Months](#get-maximum-embargo-duration-in-months)
6565
- [Get ZIP Download Limit](#get-zip-download-limit)
66+
- [Contact](#Contact)
67+
- [Send Feedback to Object Contacts](#send-feedback-to-object-contacts)
6668

6769
## Collections
6870

@@ -1363,3 +1365,23 @@ getZipDownloadLimit.execute().then((downloadLimit: number) => {
13631365
```
13641366

13651367
_See [use case](../src/info/domain/useCases/GetZipDownloadLimit.ts) implementation_.
1368+
1369+
##Contact
1370+
1371+
#### Send Feedback to Object Contacts
1372+
1373+
Returns a [Contact](../src/contactInfo/domain/models/Contact.ts) object, which contains contact return information, showing toEmail, fromEmail, subject, body.
1374+
1375+
##### Example call:
1376+
1377+
```typescript
1378+
import { submitContactInfo } from '@iqss/dataverse-client-javascript'
1379+
1380+
/* ... */
1381+
1382+
submitContactInfo.execute((contact: ContactDTO)).then( => {
1383+
/* ... */
1384+
})
1385+
1386+
/* ... */
1387+
```
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export interface ContactDTO {
2+
targetId: number
3+
subject: string
4+
body: string
5+
fromEmail: string
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export interface Contact {
2+
fromEmail: string
3+
toEmail: string
4+
body: string
5+
subject: string
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { Contact } from '../models/Contact'
2+
import { ContactDTO } from '../dtos/ContactDTO'
3+
4+
export interface IContactRepository {
5+
submitContactInfo(contactDTO: ContactDTO): Promise<Contact[]>
6+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { UseCase } from '../../../core/domain/useCases/UseCase'
2+
import { ContactDTO } from '../dtos/ContactDTO'
3+
import { Contact } from '../models/Contact'
4+
import { IContactRepository } from '../repositories/IContactRepository'
5+
6+
export class SubmitContactInfo implements UseCase<Contact[]> {
7+
private contactRepository: IContactRepository
8+
9+
constructor(contactRepository: IContactRepository) {
10+
this.contactRepository = contactRepository
11+
}
12+
/**
13+
* Submits contact information and returns a DTO containing the submitted data.
14+
*
15+
* @param {ContactDTO} contactDTO - The contact information to be submitted.
16+
* @returns {Promise<Contact>} A promise resolving to a ContactDTO.
17+
*/
18+
async execute(contactDTO: ContactDTO): Promise<Contact[]> {
19+
try {
20+
return await this.contactRepository.submitContactInfo(contactDTO)
21+
} catch (error) {
22+
throw new Error(`${error.message}`)
23+
}
24+
}
25+
}

src/contactInfo/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { SubmitContactInfo } from './domain/useCases/SubmitContactInfo'
2+
import { ContactRepository } from './infra/repositories/ContactRepository'
3+
4+
const contactRepository = new ContactRepository()
5+
const submitContactInfo = new SubmitContactInfo(contactRepository)
6+
7+
export { submitContactInfo }
8+
export { Contact } from './domain/models/Contact'
9+
export { ContactDTO } from './domain/dtos/ContactDTO'
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { ApiRepository } from '../../../core/infra/repositories/ApiRepository'
2+
import { Contact } from '../../domain/models/Contact'
3+
import { IContactRepository } from '../../domain/repositories/IContactRepository'
4+
import { ContactDTO } from '../../domain/dtos/ContactDTO'
5+
6+
export class ContactRepository extends ApiRepository implements IContactRepository {
7+
public async submitContactInfo(contactDTO: ContactDTO): Promise<Contact[]> {
8+
return this.doPost(`/admin/feedback`, contactDTO)
9+
.then((response) => {
10+
const responseData = response.data
11+
const contact: Contact[] = responseData.data.map((item: Contact) => ({
12+
fromEmail: item.fromEmail,
13+
toEmail: item.toEmail,
14+
subject: item.subject,
15+
body: item.body
16+
}))
17+
18+
return contact
19+
})
20+
.catch((error) => {
21+
throw error
22+
})
23+
}
24+
}

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ export * from './datasets'
66
export * from './collections'
77
export * from './metadataBlocks'
88
export * from './files'
9+
export * from './contactInfo'
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { ApiConfig, submitContactInfo, ContactDTO, WriteError } from '../../../src'
2+
import { TestConstants } from '../../testHelpers/TestConstants'
3+
import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig'
4+
5+
describe('submitContactInfo', () => {
6+
beforeAll(async () => {
7+
ApiConfig.init(
8+
TestConstants.TEST_API_URL,
9+
DataverseApiAuthMechanism.API_KEY,
10+
process.env.TEST_API_KEY
11+
)
12+
})
13+
14+
test('should return success result on repository success', async () => {
15+
const subject = 'Data Question'
16+
const fromEmail = '[email protected]'
17+
const collectionAlias = 'collection-1'
18+
const collectionEmail = '[email protected],[email protected]'
19+
const baseUrl = 'http://localhost:8080/dataverse/'
20+
21+
const contactDTO: ContactDTO = {
22+
targetId: 6,
23+
subject: subject,
24+
body: 'Please help me understand your data. Thank you!',
25+
fromEmail: fromEmail
26+
}
27+
28+
const bodyMessage =
29+
'You have just been sent the following message from ' +
30+
fromEmail +
31+
' via the Root hosted dataverse named "' +
32+
collectionAlias +
33+
'":\n' +
34+
'\n' +
35+
'---\n' +
36+
'\n' +
37+
'Please help me understand your data. Thank you!\n' +
38+
'\n' +
39+
'---\n' +
40+
'\n' +
41+
'Root Support\n' +
42+
'null\n' +
43+
'\n' +
44+
'Go to dataverse ' +
45+
baseUrl +
46+
collectionAlias +
47+
'\n' +
48+
'\n' +
49+
'You received this email because you have been listed as a contact for the dataverse. If you believe this was an error, please contact Root Support at null. To respond directly to the individual who sent the message, simply reply to this email.'
50+
51+
const expectedResponse = [
52+
{
53+
fromEmail: fromEmail,
54+
toEmail: collectionEmail,
55+
subject: 'Root contact: ' + subject,
56+
body: bodyMessage
57+
}
58+
]
59+
60+
let contactInfo
61+
try {
62+
contactInfo = await submitContactInfo.execute(contactDTO)
63+
} catch (error) {
64+
throw new Error('Contact info should be submitted')
65+
} finally {
66+
expect(contactInfo).toEqual(expectedResponse)
67+
}
68+
})
69+
70+
test('should return error if the target id is unexisted', async () => {
71+
const contactDTO: ContactDTO = {
72+
targetId: 0, // non-existent target id
73+
subject: '',
74+
body: '',
75+
fromEmail: '[email protected]'
76+
}
77+
const expectedError = new WriteError(`[400] Feedback target object not found`)
78+
await expect(submitContactInfo.execute(contactDTO)).rejects.toThrow(expectedError)
79+
})
80+
})
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { ContactRepository } from '../../../src/contactInfo/infra/repositories/ContactRepository'
2+
import { ApiConfig, Contact, ContactDTO, WriteError } from '../../../src'
3+
import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig'
4+
import { TestConstants } from '../../testHelpers/TestConstants'
5+
6+
describe('submitContactInfo', () => {
7+
beforeAll(async () => {
8+
ApiConfig.init(
9+
TestConstants.TEST_API_URL,
10+
DataverseApiAuthMechanism.API_KEY,
11+
process.env.TEST_API_KEY
12+
)
13+
})
14+
15+
const testContactDTO: ContactDTO = {
16+
targetId: 6,
17+
subject: 'Data Question',
18+
body: 'Please help me understand your data. Thank you!',
19+
fromEmail: '[email protected]'
20+
}
21+
22+
const sut: ContactRepository = new ContactRepository()
23+
24+
test('should return ContactDTO when contact info is successfully submitted', async () => {
25+
const collectionAlias = 'collection-1'
26+
const collectionEmail = '[email protected],[email protected]'
27+
const baseUrl = 'http://localhost:8080/dataverse/'
28+
const bodyMessage =
29+
'You have just been sent the following message from ' +
30+
testContactDTO.fromEmail +
31+
' via the Root hosted dataverse named "' +
32+
collectionAlias +
33+
'":\n' +
34+
'\n' +
35+
'---\n' +
36+
'\n' +
37+
'Please help me understand your data. Thank you!\n' +
38+
'\n' +
39+
'---\n' +
40+
'\n' +
41+
'Root Support\n' +
42+
'null\n' +
43+
'\n' +
44+
'Go to dataverse ' +
45+
baseUrl +
46+
collectionAlias +
47+
'\n' +
48+
'\n' +
49+
'You received this email because you have been listed as a contact for the dataverse. If you believe this was an error, please contact Root Support at null. To respond directly to the individual who sent the message, simply reply to this email.'
50+
51+
const expectedResponse: Contact[] = [
52+
{
53+
fromEmail: testContactDTO.fromEmail,
54+
toEmail: collectionEmail,
55+
subject: 'Root contact: ' + testContactDTO.subject,
56+
body: bodyMessage
57+
}
58+
]
59+
const actual = await sut.submitContactInfo(testContactDTO)
60+
expect(actual).toEqual(expectedResponse)
61+
})
62+
63+
test('should return error if the target id is unexisted', async () => {
64+
const invalidContactDTO: ContactDTO = {
65+
targetId: 0,
66+
subject: '',
67+
body: '',
68+
fromEmail: ''
69+
}
70+
const expectedError = new WriteError(`[400] Feedback target object not found`)
71+
await expect(sut.submitContactInfo(invalidContactDTO)).rejects.toThrow(expectedError)
72+
})
73+
})

0 commit comments

Comments
 (0)