This repository has been archived by the owner on Sep 30, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
send notification for comments (closes #6)
- Loading branch information
Showing
15 changed files
with
376 additions
and
21 deletions.
There are no files selected for viewing
155 changes: 155 additions & 0 deletions
155
functions/src/comments/onCreate/__tests__/sendNotification.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
import functions from 'firebase-functions-test'; | ||
import * as admin from 'firebase-admin'; | ||
import { when } from 'jest-when'; | ||
|
||
const testEnv = functions(); | ||
const db = admin.firestore(); | ||
const batch = db.batch(); | ||
|
||
import { onCreateCommentSendNotification } from '../sendNotification'; | ||
|
||
beforeAll(() => { | ||
spyOn(batch, 'commit').and.returnValue('sent'); | ||
}); | ||
|
||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
test('do not send a notification to the post author when they comment their own post', async (done) => { | ||
const comment = { commentId: null, createdById: 'author', postId: 'postId' }; | ||
const post = { createdById: 'author' }; | ||
const snap = { data: () => comment }; | ||
|
||
spyOn(db.doc(''), 'get').and.returnValue({ data: () => post }); | ||
|
||
const wrapped = testEnv.wrap(onCreateCommentSendNotification); | ||
const req = await wrapped(snap); | ||
|
||
expect(req).toEqual('sent'); | ||
expect(db.doc).toHaveBeenCalledWith('posts/postId'); | ||
expect(db.collection).not.toHaveBeenCalled(); | ||
expect(batch.set).not.toHaveBeenCalled(); | ||
done(); | ||
}); | ||
|
||
test('send a notification to the post author', async (done) => { | ||
const comment = { | ||
commentId: null, | ||
createdBy: { name: 'user name' }, | ||
createdById: 'author', | ||
language: 'en', | ||
postId: 'postId', | ||
}; | ||
const post = { createdById: 'other', title: 'post title' }; | ||
const snap = { data: () => comment, id: 'commentId' }; | ||
|
||
spyOn(db.doc(''), 'get').and.returnValue({ data: () => post }); | ||
when(db.collection as any) | ||
.calledWith('users/other/notifications') | ||
.mockReturnValue({ | ||
doc: jest.fn().mockReturnValue('notRef'), | ||
}); | ||
|
||
const wrapped = testEnv.wrap(onCreateCommentSendNotification); | ||
const req = await wrapped(snap); | ||
const notification = { | ||
action: 'created', | ||
activityId: null, | ||
category: 'comments', | ||
itemPath: 'comments/commentId', | ||
language: 'en', | ||
title: 'post title', | ||
type: 'comments', | ||
updatedAt: 'timestamp', | ||
user: { name: 'user name' }, | ||
}; | ||
|
||
expect(req).toEqual('sent'); | ||
expect(db.doc).toHaveBeenCalledWith('posts/postId'); | ||
expect(db.collection).toHaveBeenCalledWith('users/other/notifications'); | ||
expect(db.collection).toHaveBeenCalledTimes(1); | ||
expect(batch.set).toHaveBeenCalledWith('notRef', notification); | ||
expect(batch.set).toHaveBeenCalledTimes(1); | ||
done(); | ||
}); | ||
|
||
test('do not send a notification to the comment author when replying to their own comment', async (done) => { | ||
const comment = { | ||
commentId: 'commentId', | ||
createdById: 'author', | ||
postId: 'postId', | ||
}; | ||
const parent = { createdById: 'author' }; | ||
const post = { createdById: 'author' }; | ||
const snap = { data: () => comment }; | ||
|
||
when(db.doc as any) | ||
.calledWith('posts/postId') | ||
.mockReturnValue({ get: jest.fn().mockReturnValue({ data: () => post }) }); | ||
when(db.doc as any) | ||
.calledWith('comments/commentId') | ||
.mockReturnValue({ | ||
get: jest.fn().mockReturnValue({ data: () => parent }), | ||
}); | ||
|
||
const wrapped = testEnv.wrap(onCreateCommentSendNotification); | ||
const req = await wrapped(snap); | ||
|
||
expect(req).toEqual('sent'); | ||
expect(db.doc).toHaveBeenCalledWith('posts/postId'); | ||
expect(db.doc).toHaveBeenCalledWith('comments/commentId'); | ||
expect(db.collection).not.toHaveBeenCalled(); | ||
expect(batch.set).not.toHaveBeenCalled(); | ||
done(); | ||
}); | ||
|
||
test('send a notification for replies to the comment author', async (done) => { | ||
const comment = { | ||
commentId: 'parent', | ||
createdBy: { name: 'user name' }, | ||
createdById: 'author', | ||
language: 'en', | ||
postId: 'postId', | ||
}; | ||
const post = { createdById: 'author', title: 'post title' }; | ||
const parent = { createdById: 'other' }; | ||
const snap = { data: () => comment, id: 'commentId' }; | ||
|
||
when(db.doc as any) | ||
.calledWith('posts/postId') | ||
.mockReturnValue({ get: jest.fn().mockReturnValue({ data: () => post }) }); | ||
when(db.doc as any) | ||
.calledWith('comments/parent') | ||
.mockReturnValue({ | ||
get: jest.fn().mockReturnValue({ data: () => parent }), | ||
}); | ||
when(db.collection as any) | ||
.calledWith('users/other/notifications') | ||
.mockReturnValue({ | ||
doc: jest.fn().mockReturnValue('notRef'), | ||
}); | ||
|
||
const wrapped = testEnv.wrap(onCreateCommentSendNotification); | ||
const req = await wrapped(snap); | ||
const notification = { | ||
action: 'created', | ||
activityId: null, | ||
category: 'comments', | ||
itemPath: 'comments/commentId', | ||
language: 'en', | ||
title: 'post title', | ||
type: 'comments', | ||
updatedAt: 'timestamp', | ||
user: { name: 'user name' }, | ||
}; | ||
|
||
expect(req).toEqual('sent'); | ||
expect(db.doc).toHaveBeenCalledWith('posts/postId'); | ||
expect(db.doc).toHaveBeenCalledWith('comments/parent'); | ||
expect(db.collection).toHaveBeenCalledWith('users/other/notifications'); | ||
expect(db.collection).toHaveBeenCalledTimes(1); | ||
expect(batch.set).toHaveBeenCalledWith('notRef', notification); | ||
expect(batch.set).toHaveBeenCalledTimes(1); | ||
done(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from './earnXp'; | ||
export * from './sendNotification'; | ||
export * from './updateCommentsCount'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import * as functions from 'firebase-functions'; | ||
import * as admin from 'firebase-admin'; | ||
import { Comment, Notification, Post } from '@zoonk/models'; | ||
|
||
const db = admin.firestore(); | ||
|
||
export const onCreateCommentSendNotification = functions.firestore | ||
.document('comments/{id}') | ||
.onCreate(async (snap) => { | ||
const batch = db.batch(); | ||
const data = snap.data() as Comment.Response; | ||
const post = await db.doc(`posts/${data.postId}`).get(); | ||
const postData = post.data() as Post.Response; | ||
const isAuthor = data.createdById === postData.createdById; | ||
|
||
const notification: Notification.Create = { | ||
action: 'created', | ||
activityId: null, | ||
category: 'comments', | ||
itemPath: `comments/${snap.id}`, | ||
language: data.language, | ||
title: postData.title, | ||
type: 'comments', | ||
updatedAt: admin.firestore.FieldValue.serverTimestamp(), | ||
user: data.createdBy, | ||
}; | ||
|
||
if (!isAuthor) { | ||
const postAuthorRef = db | ||
.collection(`users/${postData.createdById}/notifications`) | ||
.doc(); | ||
batch.set(postAuthorRef, notification); | ||
} | ||
|
||
if (data.commentId) { | ||
const parent = await db.doc(`comments/${data.commentId}`).get(); | ||
const parentData = parent.data() as Comment.Response; | ||
const isCommentAuthor = data.createdById === parentData.createdById; | ||
|
||
if (!isCommentAuthor) { | ||
const commentAuthorRef = db | ||
.collection(`users/${parentData.createdById}/notifications`) | ||
.doc(); | ||
batch.set(commentAuthorRef, notification); | ||
} | ||
} | ||
|
||
return batch.commit(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
c4e7ddd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to following URLs: