Skip to content

Commit 68fcaa7

Browse files
authored
Merge pull request #335 from IQSS/334-create-use-cases-for-get-notifications-and-delete-notifications
Use Cases for Get Notifications and Delete Notifications
2 parents bfb640a + b61f8cf commit 68fcaa7

18 files changed

+755
-0
lines changed

docs/useCases.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ The different use cases currently available in the package are classified below,
9191
- [Get Application Terms of Use](#get-application-terms-of-use)
9292
- [Contact](#Contact)
9393
- [Send Feedback to Object Contacts](#send-feedback-to-object-contacts)
94+
- [Notifications](#Notifications)
95+
- [Get All Notifications by User](#get-all-notifications-by-user)
96+
- [Delete Notification](#delete-notification)
97+
- [Get Unread Count](#get-unread-count)
98+
- [Mark As Read](#mark-as-read)
9499
- [Search](#Search)
95100
- [Get Search Services](#get-search-services)
96101

@@ -2121,6 +2126,92 @@ In ContactDTO, it takes the following information:
21212126
- **body**: the email body to send.
21222127
- **fromEmail**: the email to list in the reply-to field.
21232128

2129+
## Notifications
2130+
2131+
#### Get All Notifications by User
2132+
2133+
Returns a [Notification](../src/notifications/domain/models/Notification.ts) array containing all notifications for the current authenticated user.
2134+
2135+
##### Example call:
2136+
2137+
```typescript
2138+
import { getAllNotificationsByUser } from '@iqss/dataverse-client-javascript'
2139+
2140+
/* ... */
2141+
2142+
getAllNotificationsByUser.execute().then((notifications: Notification[]) => {
2143+
/* ... */
2144+
})
2145+
2146+
/* ... */
2147+
```
2148+
2149+
_See [use case](../src/notifications/domain/useCases/GetAllNotificationsByUser.ts) implementation_.
2150+
2151+
#### Delete Notification
2152+
2153+
Deletes a specific notification for the current authenticated user by its ID.
2154+
2155+
##### Example call:
2156+
2157+
```typescript
2158+
import { deleteNotification } from '@iqss/dataverse-client-javascript'
2159+
2160+
/* ... */
2161+
2162+
const notificationId = 123
2163+
2164+
deleteNotification.execute(notificationId: number).then(() => {
2165+
/* ... */
2166+
})
2167+
2168+
/* ... */
2169+
```
2170+
2171+
_See [use case](../src/notifications/domain/useCases/DeleteNotification.ts) implementation_.
2172+
2173+
#### Get Unread Count
2174+
2175+
Returns the number of unread notifications for the current authenticated user.
2176+
2177+
##### Example call:
2178+
2179+
```typescript
2180+
import { getUnreadNotificationsCount } from '@iqss/dataverse-client-javascript'
2181+
2182+
/* ... */
2183+
2184+
getUnreadNotificationsCount.execute().then((count: number) => {
2185+
console.log(`You have ${count} unread notifications`)
2186+
})
2187+
2188+
/* ... */
2189+
```
2190+
2191+
_See [use case](../src/notifications/domain/useCases/GetUnreadNotificationsCount.ts) implementation_.
2192+
2193+
#### Mark As Read
2194+
2195+
Marks a specific notification as read for the current authenticated user. This operation is idempotent - marking an already-read notification as read will not cause an error.
2196+
2197+
##### Example call:
2198+
2199+
```typescript
2200+
import { markNotificationAsRead } from '@iqss/dataverse-client-javascript'
2201+
2202+
/* ... */
2203+
2204+
const notificationId = 123
2205+
2206+
markNotificationAsRead.execute(notificationId).then(() => {
2207+
console.log('Notification marked as read')
2208+
})
2209+
2210+
/* ... */
2211+
```
2212+
2213+
_See [use case](../src/notifications/domain/useCases/MarkNotificationAsRead.ts) implementation_.
2214+
21242215
## Search
21252216

21262217
#### Get Search Services

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export * from './collections'
88
export * from './metadataBlocks'
99
export * from './files'
1010
export * from './contactInfo'
11+
export * from './notifications'
1112
export * from './search'
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
export enum NotificationType {
2+
ASSIGNROLE = 'ASSIGNROLE',
3+
REVOKEROLE = 'REVOKEROLE',
4+
CREATEDV = 'CREATEDV',
5+
CREATEDS = 'CREATEDS',
6+
CREATEACC = 'CREATEACC',
7+
SUBMITTEDDS = 'SUBMITTEDDS',
8+
RETURNEDDS = 'RETURNEDDS',
9+
PUBLISHEDDS = 'PUBLISHEDDS',
10+
REQUESTFILEACCESS = 'REQUESTFILEACCESS',
11+
GRANTFILEACCESS = 'GRANTFILEACCESS',
12+
REJECTFILEACCESS = 'REJECTFILEACCESS',
13+
FILESYSTEMIMPORT = 'FILESYSTEMIMPORT',
14+
CHECKSUMIMPORT = 'CHECKSUMIMPORT',
15+
CHECKSUMFAIL = 'CHECKSUMFAIL',
16+
CONFIRMEMAIL = 'CONFIRMEMAIL',
17+
APIGENERATED = 'APIGENERATED',
18+
INGESTCOMPLETED = 'INGESTCOMPLETED',
19+
INGESTCOMPLETEDWITHERRORS = 'INGESTCOMPLETEDWITHERRORS',
20+
PUBLISHFAILED_PIDREG = 'PUBLISHFAILED_PIDREG',
21+
WORKFLOW_SUCCESS = 'WORKFLOW_SUCCESS',
22+
WORKFLOW_FAILURE = 'WORKFLOW_FAILURE',
23+
STATUSUPDATED = 'STATUSUPDATED',
24+
DATASETCREATED = 'DATASETCREATED',
25+
DATASETMENTIONED = 'DATASETMENTIONED',
26+
GLOBUSUPLOADCOMPLETED = 'GLOBUSUPLOADCOMPLETED',
27+
GLOBUSUPLOADCOMPLETEDWITHERRORS = 'GLOBUSUPLOADCOMPLETEDWITHERRORS',
28+
GLOBUSDOWNLOADCOMPLETED = 'GLOBUSDOWNLOADCOMPLETED',
29+
GLOBUSDOWNLOADCOMPLETEDWITHERRORS = 'GLOBUSDOWNLOADCOMPLETEDWITHERRORS',
30+
REQUESTEDFILEACCESS = 'REQUESTEDFILEACCESS',
31+
GLOBUSUPLOADREMOTEFAILURE = 'GLOBUSUPLOADREMOTEFAILURE',
32+
GLOBUSUPLOADLOCALFAILURE = 'GLOBUSUPLOADLOCALFAILURE',
33+
PIDRECONCILED = 'PIDRECONCILED'
34+
}
35+
36+
export interface RoleAssignment {
37+
id: number
38+
assignee: string
39+
definitionPointId: number
40+
roleId: number
41+
roleName: string
42+
_roleAlias: string
43+
}
44+
45+
export interface Notification {
46+
id: number
47+
type: NotificationType
48+
subjectText?: string
49+
messageText?: string
50+
sentTimestamp: string
51+
displayAsRead: boolean
52+
installationBrandName?: string
53+
userGuidesBaseUrl?: string
54+
userGuidesVersion?: string
55+
userGuidesSectionPath?: string
56+
roleAssignments?: RoleAssignment[]
57+
collectionAlias?: string
58+
collectionDisplayName?: string
59+
datasetPersistentIdentifier?: string
60+
datasetDisplayName?: string
61+
ownerPersistentIdentifier?: string
62+
ownerAlias?: string
63+
ownerDisplayName?: string
64+
requestorFirstName?: string
65+
requestorLastName?: string
66+
requestorEmail?: string
67+
dataFileId?: number
68+
dataFileDisplayName?: string
69+
currentCurationStatus?: string
70+
additionalInfo?: string
71+
objectDeleted?: boolean
72+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { Notification } from '../models/Notification'
2+
3+
export interface INotificationsRepository {
4+
getAllNotificationsByUser(inAppNotificationFormat?: boolean): Promise<Notification[]>
5+
deleteNotification(notificationId: number): Promise<void>
6+
getUnreadNotificationsCount(): Promise<number>
7+
markNotificationAsRead(notificationId: number): Promise<void>
8+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { UseCase } from '../../../core/domain/useCases/UseCase'
2+
import { INotificationsRepository } from '../repositories/INotificationsRepository'
3+
4+
/**
5+
* Use case for deleting a specific notification for the current user.
6+
*
7+
* @param notificationId - The ID of the notification to delete.
8+
* @returns {Promise<void>} - A promise that resolves when the notification is deleted.
9+
*/
10+
export class DeleteNotification implements UseCase<void> {
11+
constructor(private readonly notificationsRepository: INotificationsRepository) {}
12+
13+
async execute(notificationId: number): Promise<void> {
14+
return this.notificationsRepository.deleteNotification(notificationId)
15+
}
16+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { UseCase } from '../../../core/domain/useCases/UseCase'
2+
import { Notification } from '../models/Notification'
3+
import { INotificationsRepository } from '../repositories/INotificationsRepository'
4+
5+
export class GetAllNotificationsByUser implements UseCase<Notification[]> {
6+
constructor(private readonly notificationsRepository: INotificationsRepository) {}
7+
8+
/**
9+
* Use case for retrieving all notifications for the current user.
10+
*
11+
* @param inAppNotificationFormat - Optional parameter to retrieve fields needed for in-app notifications
12+
* @returns {Promise<Notification[]>} - A promise that resolves to an array of Notification instances.
13+
*/
14+
async execute(inAppNotificationFormat?: boolean): Promise<Notification[]> {
15+
return (await this.notificationsRepository.getAllNotificationsByUser(
16+
inAppNotificationFormat
17+
)) as Notification[]
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { UseCase } from '../../../core/domain/useCases/UseCase'
2+
import { INotificationsRepository } from '../repositories/INotificationsRepository'
3+
4+
export class GetUnreadNotificationsCount implements UseCase<number> {
5+
private notificationsRepository: INotificationsRepository
6+
7+
constructor(notificationsRepository: INotificationsRepository) {
8+
this.notificationsRepository = notificationsRepository
9+
}
10+
11+
/**
12+
* Use case for retrieving the number of unread notifications for the current user.
13+
*
14+
* @returns {Promise<number>} - A promise that resolves to the number of unread notifications.
15+
*/
16+
async execute(): Promise<number> {
17+
return await this.notificationsRepository.getUnreadNotificationsCount()
18+
}
19+
}
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 { INotificationsRepository } from '../repositories/INotificationsRepository'
3+
4+
export class MarkNotificationAsRead implements UseCase<void> {
5+
private notificationsRepository: INotificationsRepository
6+
7+
constructor(notificationsRepository: INotificationsRepository) {
8+
this.notificationsRepository = notificationsRepository
9+
}
10+
11+
/**
12+
* Use case for marking a notification as read.
13+
*
14+
* @param notificationId - The ID of the notification to mark as read.
15+
* @returns {Promise<void>} - A promise that resolves when the notification is marked as read.
16+
*/
17+
async execute(notificationId: number): Promise<void> {
18+
return await this.notificationsRepository.markNotificationAsRead(notificationId)
19+
}
20+
}

src/notifications/index.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { NotificationsRepository } from './infra/repositories/NotificationsRepository'
2+
import { GetAllNotificationsByUser } from './domain/useCases/GetAllNotificationsByUser'
3+
import { DeleteNotification } from './domain/useCases/DeleteNotification'
4+
import { GetUnreadNotificationsCount } from './domain/useCases/GetUnreadNotificationsCount'
5+
import { MarkNotificationAsRead } from './domain/useCases/MarkNotificationAsRead'
6+
7+
const notificationsRepository = new NotificationsRepository()
8+
9+
const getAllNotificationsByUser = new GetAllNotificationsByUser(notificationsRepository)
10+
const deleteNotification = new DeleteNotification(notificationsRepository)
11+
const getUnreadNotificationsCount = new GetUnreadNotificationsCount(notificationsRepository)
12+
const markNotificationAsRead = new MarkNotificationAsRead(notificationsRepository)
13+
14+
export {
15+
getAllNotificationsByUser,
16+
deleteNotification,
17+
getUnreadNotificationsCount,
18+
markNotificationAsRead
19+
}
20+
21+
export { Notification, NotificationType, RoleAssignment } from './domain/models/Notification'
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { ApiRepository } from '../../../core/infra/repositories/ApiRepository'
2+
import { INotificationsRepository } from '../../domain/repositories/INotificationsRepository'
3+
import { Notification } from '../../domain/models/Notification'
4+
import { NotificationPayload } from '../transformers/NotificationPayload'
5+
6+
export class NotificationsRepository extends ApiRepository implements INotificationsRepository {
7+
private readonly notificationsResourceName: string = 'notifications'
8+
9+
public async getAllNotificationsByUser(
10+
inAppNotificationFormat?: boolean
11+
): Promise<Notification[]> {
12+
const queryParams = inAppNotificationFormat ? { inAppNotificationFormat: 'true' } : undefined
13+
return this.doGet(
14+
this.buildApiEndpoint(this.notificationsResourceName, 'all'),
15+
true,
16+
queryParams
17+
)
18+
.then((response) => {
19+
const notifications = response.data.data.notifications
20+
return notifications.map((notification: NotificationPayload) => {
21+
const { dataverseDisplayName, dataverseAlias, ...restNotification } = notification
22+
return {
23+
...restNotification,
24+
...(dataverseDisplayName && { collectionDisplayName: dataverseDisplayName }),
25+
...(dataverseAlias && { collectionAlias: dataverseAlias })
26+
}
27+
}) as Notification[]
28+
})
29+
.catch((error) => {
30+
throw error
31+
})
32+
}
33+
34+
public async deleteNotification(notificationId: number): Promise<void> {
35+
return this.doDelete(
36+
this.buildApiEndpoint(this.notificationsResourceName, notificationId.toString())
37+
)
38+
.then(() => undefined)
39+
.catch((error) => {
40+
throw error
41+
})
42+
}
43+
44+
public async getUnreadNotificationsCount(): Promise<number> {
45+
return this.doGet(
46+
this.buildApiEndpoint(this.notificationsResourceName, 'unreadCount'),
47+
true
48+
).then((response) => response.data.data.unreadCount as number)
49+
}
50+
51+
public async markNotificationAsRead(notificationId: number): Promise<void> {
52+
return this.doPut(
53+
this.buildApiEndpoint(this.notificationsResourceName, 'markAsRead', notificationId),
54+
{}
55+
).then(() => undefined)
56+
}
57+
}

0 commit comments

Comments
 (0)