Skip to content

Commit

Permalink
feat(lib): disallow creating threads in deleted messages
Browse files Browse the repository at this point in the history
  • Loading branch information
piotr-suwala committed Dec 12, 2023
1 parent 8851d71 commit 4805f74
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 2 deletions.
3 changes: 3 additions & 0 deletions lib/src/entities/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,9 @@ export class Chat {
if (message.channelId.startsWith(MESSAGE_THREAD_ID_PREFIX)) {
throw "Only one level of thread nesting is allowed"
}
if (message.deleted) {
throw "You cannot create threads on deleted messages"
}

const threadChannelId = this.getThreadId(message.channelId, message.timetoken)

Expand Down
26 changes: 26 additions & 0 deletions lib/tests/message.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,32 @@ describe("Send message test", () => {
expect(logSpy).toHaveBeenCalledWith("This message has not been deleted")
})

test("should throw an error if you try to create a thread on a deleted message", async () => {
await channel.sendText("Test message")
await sleep(150) // history calls have around 130ms of cache time

const historyBeforeDelete = await channel.getHistory()
const messagesBeforeDelete = historyBeforeDelete.messages
const sentMessage = messagesBeforeDelete[messagesBeforeDelete.length - 1]

await sentMessage.delete({ soft: true })
await sleep(150) // history calls have around 130ms of cache time

const historyAfterDelete = await channel.getHistory()
const messagesAfterDelete = historyAfterDelete.messages

const deletedMessage = messagesAfterDelete.find(
(message: Message) => message.timetoken === sentMessage.timetoken
)
let thrownExceptionString = ""

await deletedMessage.createThread().catch((e) => {
thrownExceptionString = e
})

expect(thrownExceptionString).toBe("You cannot create threads on deleted messages")
})

test("should edit the message", async () => {
await channel.sendText("Test message")
await sleep(150) // history calls have around 130ms of cache time
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export function useActionsMenu({
Copy message
</Button>
<Gap value={16} />
{!removeThreadReply ? (
{!removeThreadReply && !currentlyFocusedMessage?.originalPnMessage.deleted ? (
<>
<Button
size="md"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export function ChatScreen({}: StackScreenProps<HomeStackParamList, "Chat">) {

const handleDeleteMessage = useCallback(async (message: Message) => {
if (message.deleted) {
const restoredMessage = await message.restore()
await message.restore()
} else {
await message.delete({ soft: true })
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export function ThreadReply({ route }: StackScreenProps<HomeStackParamList, "Thr
const [suggestedData, setSuggestedData] = useState<User[] | Channel[]>([])
const [showSuggestedData, setShowSuggestedData] = useState(false)
const [lastAffectedNameOccurrenceIndex, setLastAffectedNameOccurrenceIndex] = useState(-1)
const [showTextLinkBox, setShowTextLinkBox] = useState(false)

const { renderFooter, renderMessageText, renderChatFooter } = useCommonChatRenderers({
typingData,
Expand All @@ -41,6 +42,9 @@ export function ThreadReply({ route }: StackScreenProps<HomeStackParamList, "Thr
giftedChatMappedMessages,
giftedChatRef,
lastAffectedNameOccurrenceIndex,
showTextLinkBox,
setShowTextLinkBox,
image: "",
})

const handleQuote = useCallback(
Expand All @@ -67,10 +71,39 @@ export function ThreadReply({ route }: StackScreenProps<HomeStackParamList, "Thr
[chat]
)

const handleEmoji = useCallback(
(message: Message) => {
const copiedMessages = [...giftedChatMappedMessages]

const index = copiedMessages.findIndex(
(msg) => msg.originalPnMessage.timetoken === message.timetoken
)

if (index === -1) {
return
}

copiedMessages[index].originalPnMessage = message

setGiftedChatMappedMessages(copiedMessages)
},
[giftedChatMappedMessages]
)

const handleDeleteMessage = useCallback(async (message: Message) => {
if (message.deleted) {
await message.restore()
} else {
await message.delete({ soft: true })
}
}, [])

const { ActionsMenuComponent, handlePresentModalPress } = useActionsMenu({
onQuote: handleQuote,
removeThreadReply: true,
onPinMessage: handlePin,
onDeleteMessage: handleDeleteMessage,
onToggleEmoji: handleEmoji,
})

useEffect(() => {
Expand Down

0 comments on commit 4805f74

Please sign in to comment.