mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 21:05:19 +00:00
feat(server): support read all notifications (#13083)
close AF-2719 #### PR Dependency Tree * **PR #13083** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added the ability to mark all notifications as read with a single action. * **Bug Fixes** * Ensured notifications marked as read are no longer shown as unread. * **Tests** * Introduced new tests to verify the functionality of marking all notifications as read. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
notificationCountQuery,
|
||||
NotificationObjectType,
|
||||
NotificationType,
|
||||
readAllNotificationsMutation,
|
||||
readNotificationMutation,
|
||||
} from '@affine/graphql';
|
||||
|
||||
@@ -677,3 +678,41 @@ e2e('should list and count notifications', async t => {
|
||||
t.is(result3.currentUser!.notifications.edges.length, 0);
|
||||
}
|
||||
});
|
||||
|
||||
e2e('should mark all notifications as read', async t => {
|
||||
const { member, owner, workspace } = await init();
|
||||
await app.login(owner);
|
||||
|
||||
await app.gql({
|
||||
query: mentionUserMutation,
|
||||
variables: {
|
||||
input: {
|
||||
userId: member.id,
|
||||
workspaceId: workspace.id,
|
||||
doc: {
|
||||
id: 'doc-id-1',
|
||||
title: 'doc-title-1',
|
||||
blockId: 'block-id-1',
|
||||
mode: DocMode.page,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await app.login(member);
|
||||
|
||||
await app.gql({
|
||||
query: readAllNotificationsMutation,
|
||||
});
|
||||
|
||||
const result = await app.gql({
|
||||
query: listNotificationsQuery,
|
||||
variables: {
|
||||
pagination: {
|
||||
first: 10,
|
||||
offset: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
t.is(result.currentUser!.notifications.totalCount, 0);
|
||||
});
|
||||
|
||||
@@ -100,6 +100,14 @@ export class UserNotificationResolver {
|
||||
await this.service.markAsRead(me.id, notificationId);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Mutation(() => Boolean, {
|
||||
description: 'mark all notifications as read',
|
||||
})
|
||||
async readAllNotifications(@CurrentUser() me: UserType) {
|
||||
await this.service.markAllAsRead(me.id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Resolver(() => NotificationObjectType)
|
||||
|
||||
@@ -399,6 +399,10 @@ export class NotificationService {
|
||||
}
|
||||
}
|
||||
|
||||
async markAllAsRead(userId: string) {
|
||||
await this.models.notification.markAllAsRead(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find notifications by user id, order by createdAt desc
|
||||
*/
|
||||
|
||||
@@ -430,3 +430,32 @@ test('should create a comment mention notification', async t => {
|
||||
t.is(notification.body.commentId, commentId);
|
||||
t.is(notification.body.replyId, replyId);
|
||||
});
|
||||
|
||||
test('should mark all notifications as read', async t => {
|
||||
await models.notification.createMention({
|
||||
userId: user.id,
|
||||
body: {
|
||||
workspaceId: workspace.id,
|
||||
doc: {
|
||||
id: docId,
|
||||
title: 'doc-title',
|
||||
blockId: 'blockId',
|
||||
mode: DocMode.page,
|
||||
},
|
||||
createdByUserId: createdBy.id,
|
||||
},
|
||||
});
|
||||
await models.notification.createInvitation({
|
||||
userId: user.id,
|
||||
body: {
|
||||
workspaceId: workspace.id,
|
||||
createdByUserId: createdBy.id,
|
||||
inviteId: randomUUID(),
|
||||
},
|
||||
});
|
||||
|
||||
await models.notification.markAllAsRead(user.id);
|
||||
|
||||
const notifications = await models.notification.findManyByUserId(user.id);
|
||||
t.is(notifications.length, 0);
|
||||
});
|
||||
|
||||
@@ -261,6 +261,18 @@ export class NotificationModel extends BaseModel {
|
||||
});
|
||||
}
|
||||
|
||||
async markAllAsRead(userId: string) {
|
||||
const { count } = await this.db.notification.updateMany({
|
||||
where: { userId },
|
||||
data: {
|
||||
read: true,
|
||||
},
|
||||
});
|
||||
this.logger.log(
|
||||
`Marked all notifications as read for user ${userId}, count: ${count}`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find many notifications by user id, exclude read notifications by default
|
||||
*/
|
||||
|
||||
@@ -1236,6 +1236,9 @@ type Mutation {
|
||||
"""queue workspace doc embedding"""
|
||||
queueWorkspaceEmbedding(docId: [String!]!, workspaceId: String!): Boolean!
|
||||
|
||||
"""mark all notifications as read"""
|
||||
readAllNotifications: Boolean!
|
||||
|
||||
"""mark notification as read"""
|
||||
readNotification(id: String!): Boolean!
|
||||
recoverDoc(guid: String!, timestamp: DateTime!, workspaceId: String!): DateTime!
|
||||
|
||||
@@ -1989,6 +1989,14 @@ export const quotaQuery = {
|
||||
deprecations: ["'storageQuota' is deprecated: use `UserQuotaType['usedStorageQuota']` instead"],
|
||||
};
|
||||
|
||||
export const readAllNotificationsMutation = {
|
||||
id: 'readAllNotificationsMutation' as const,
|
||||
op: 'readAllNotifications',
|
||||
query: `mutation readAllNotifications {
|
||||
readAllNotifications
|
||||
}`,
|
||||
};
|
||||
|
||||
export const readNotificationMutation = {
|
||||
id: 'readNotificationMutation' as const,
|
||||
op: 'readNotification',
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
mutation readAllNotifications {
|
||||
readAllNotifications
|
||||
}
|
||||
@@ -1371,6 +1371,8 @@ export interface Mutation {
|
||||
publishPage: DocType;
|
||||
/** queue workspace doc embedding */
|
||||
queueWorkspaceEmbedding: Scalars['Boolean']['output'];
|
||||
/** mark all notifications as read */
|
||||
readAllNotifications: Scalars['Boolean']['output'];
|
||||
/** mark notification as read */
|
||||
readNotification: Scalars['Boolean']['output'];
|
||||
recoverDoc: Scalars['DateTime']['output'];
|
||||
@@ -5218,6 +5220,15 @@ export type QuotaQuery = {
|
||||
} | null;
|
||||
};
|
||||
|
||||
export type ReadAllNotificationsMutationVariables = Exact<{
|
||||
[key: string]: never;
|
||||
}>;
|
||||
|
||||
export type ReadAllNotificationsMutation = {
|
||||
__typename?: 'Mutation';
|
||||
readAllNotifications: boolean;
|
||||
};
|
||||
|
||||
export type ReadNotificationMutationVariables = Exact<{
|
||||
id: Scalars['String']['input'];
|
||||
}>;
|
||||
@@ -6352,6 +6363,11 @@ export type Mutations =
|
||||
variables: PublishPageMutationVariables;
|
||||
response: PublishPageMutation;
|
||||
}
|
||||
| {
|
||||
name: 'readAllNotificationsMutation';
|
||||
variables: ReadAllNotificationsMutationVariables;
|
||||
response: ReadAllNotificationsMutation;
|
||||
}
|
||||
| {
|
||||
name: 'readNotificationMutation';
|
||||
variables: ReadNotificationMutationVariables;
|
||||
|
||||
Reference in New Issue
Block a user