Skip to content

Commit 393e745

Browse files
committed
구독 스페이스 새 포스트 알림 (#2749)
1 parent 63b85fa commit 393e745

File tree

5 files changed

+98
-0
lines changed

5 files changed

+98
-0
lines changed

apps/website/src/lib/enums.ts

+1
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ export const UserNotificationCategory = {
238238
COMMENT: 'COMMENT',
239239
DONATE: 'DONATE',
240240
EMOJI_REACTION: 'EMOJI_REACTION',
241+
NEW_POST: 'NEW_POST',
241242
PURCHASE: 'PURCHASE',
242243
REPLY: 'REPLY',
243244
SUBSCRIBE: 'SUBSCRIBE',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { and, eq } from 'drizzle-orm';
2+
import { database, PostRevisions, Posts, Profiles, SpaceFollows, SpaceMembers, Spaces } from '$lib/server/database';
3+
import { createNotification, useFirstRow } from '$lib/server/utils';
4+
import type { NotificationMaker } from './type';
5+
6+
export const SpaceNewPostNotificationMaker: NotificationMaker = async (postId: string) => {
7+
const post = await database
8+
.select({
9+
permalink: Posts.permalink,
10+
title: PostRevisions.title,
11+
userId: Posts.userId,
12+
memberProfileId: SpaceMembers.profileId,
13+
memberProfileName: Profiles.name,
14+
spaceId: Spaces.id,
15+
spaceSlug: Spaces.slug,
16+
spaceName: Spaces.name,
17+
})
18+
.from(Posts)
19+
.innerJoin(Spaces, eq(Posts.spaceId, Spaces.id))
20+
.innerJoin(PostRevisions, eq(Posts.publishedRevisionId, PostRevisions.id))
21+
.innerJoin(
22+
SpaceMembers,
23+
and(
24+
eq(SpaceMembers.spaceId, Posts.spaceId),
25+
eq(SpaceMembers.userId, Posts.userId),
26+
eq(SpaceMembers.state, 'ACTIVE'),
27+
),
28+
)
29+
.innerJoin(Profiles, eq(SpaceMembers.profileId, Profiles.id))
30+
.where(and(eq(Posts.id, postId), eq(Posts.state, 'PUBLISHED'), eq(Posts.visibility, 'PUBLIC')))
31+
.then(useFirstRow);
32+
33+
if (!post) {
34+
return;
35+
}
36+
37+
const followerIds = await database
38+
.select({
39+
userId: SpaceFollows.userId,
40+
})
41+
.from(SpaceFollows)
42+
.where(and(eq(SpaceFollows.spaceId, post.spaceId)))
43+
.then((rows) => rows.map((row) => row.userId));
44+
45+
await Promise.all(
46+
followerIds.map(async (userId) => {
47+
await createNotification({
48+
userId,
49+
category: 'NEW_POST',
50+
actorId: post.memberProfileId,
51+
data: {
52+
postId,
53+
},
54+
pushTitle: post.spaceName,
55+
pushBody: `${post.title} 글이 올라왔어요.`,
56+
pushPath: `/${post.spaceSlug}/${post.permalink}`,
57+
});
58+
}),
59+
);
60+
};

apps/website/src/lib/server/graphql/schemas/notification.ts

+15
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ IUserNotification.implement({
3636
.with('SUBSCRIBE', () => 'SubscribeNotification')
3737
.with('COMMENT', () => 'CommentNotification')
3838
.with('EMOJI_REACTION', () => 'EmojiReactionNotification')
39+
.with('NEW_POST', () => 'NewPostNotification')
3940
.run(),
4041
});
4142

@@ -131,6 +132,20 @@ EmojiReactionNotification.implement({
131132
}),
132133
});
133134

135+
export const NewPostNotification = createObjectRef('NewPostNotification', UserNotifications);
136+
NewPostNotification.implement({
137+
interfaces: [IUserNotification],
138+
fields: (t) => ({
139+
post: t.field({
140+
type: Post,
141+
resolve: async (notification) => {
142+
const data = notification.data as { postId: string };
143+
return data.postId;
144+
},
145+
}),
146+
}),
147+
});
148+
134149
/**
135150
* * Inputs
136151
*/

apps/website/src/lib/server/rest/routes/notification.ts

+13
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,19 @@ notification.get('/notification/:notificationId', async (request) => {
7171

7272
return `/${posts[0].space.slug}/${posts[0].permalink}`;
7373
})
74+
.with({ category: 'NEW_POST' }, async ({ data }) => {
75+
const posts = await database
76+
.select({ permalink: Posts.permalink, space: { slug: Spaces.slug } })
77+
.from(Posts)
78+
.innerJoin(Spaces, eq(Spaces.id, Posts.spaceId))
79+
.where(eq(Posts.id, data.postId));
80+
81+
if (posts.length === 0) {
82+
return `/404`;
83+
}
84+
85+
return `/${posts[0].space.slug}/${posts[0].permalink}`;
86+
})
7487
.exhaustive(),
7588
},
7689
});

apps/website/src/lib/utils/notification.ts

+9
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,20 @@ type EmojiReactionNotification = {
3131
};
3232
};
3333

34+
type NewPostNotification = {
35+
category: 'NEW_POST';
36+
actorId: string;
37+
data: {
38+
postId: string;
39+
};
40+
};
41+
3442
export type Notification = (
3543
| PurchaseNotification
3644
| SubscribeNotification
3745
| CommentNotification
3846
| EmojiReactionNotification
47+
| NewPostNotification
3948
) & {
4049
userId: string;
4150
};

0 commit comments

Comments
 (0)