Эх сурвалжийг харах

Merge pull request #23673 from overleaf/em-reviewer-role-delete-replies

Let reviewers delete their own comments

GitOrigin-RevId: bd5341a917a3e886dc573d7e42d12343da6700cd
Eric Mc Sween 1 жил өмнө
parent
commit
79bb2e3d40

+ 11 - 0
services/chat/app/js/Features/Messages/MessageHttpController.js

@@ -74,6 +74,10 @@ export async function deleteMessage(context) {
   return await callMessageHttpController(context, _deleteMessage)
 }
 
+export async function deleteUserMessage(context) {
+  return await callMessageHttpController(context, _deleteUserMessage)
+}
+
 export async function getResolvedThreadIds(context) {
   return await callMessageHttpController(context, _getResolvedThreadIds)
 }
@@ -190,6 +194,13 @@ const _deleteMessage = async (req, res) => {
   res.status(204)
 }
 
+const _deleteUserMessage = async (req, res) => {
+  const { projectId, threadId, userId, messageId } = req.params
+  const room = await ThreadManager.findOrCreateThread(projectId, threadId)
+  await MessageManager.deleteUserMessage(userId, room._id, messageId)
+  res.status(204)
+}
+
 const _getResolvedThreadIds = async (req, res) => {
   const { projectId } = req.params
   const resolvedThreadIds = await ThreadManager.getResolvedThreadIds(projectId)

+ 8 - 0
services/chat/app/js/Features/Messages/MessageManager.js

@@ -77,6 +77,14 @@ export async function deleteMessage(roomId, messageId) {
   await db.messages.deleteOne(query)
 }
 
+export async function deleteUserMessage(userId, roomId, messageId) {
+  await db.messages.deleteOne({
+    _id: new ObjectId(messageId),
+    user_id: new ObjectId(userId),
+    room_id: new ObjectId(roomId),
+  })
+}
+
 function _ensureIdsAreObjectIds(query) {
   if (query.user_id && !(query.user_id instanceof ObjectId)) {
     query.user_id = new ObjectId(query.user_id)

+ 28 - 0
services/chat/chat.yaml

@@ -177,6 +177,34 @@ paths:
         '204':
           description: No Content
       description: 'Delete message with Message ID provided, from the Thread with ThreadID and ProjectID provided'
+  '/project/{projectId}/thread/{threadId}/user/{userId}/messages/{messageId}':
+    parameters:
+      - schema:
+          type: string
+        name: projectId
+        in: path
+        required: true
+      - schema:
+          type: string
+        name: threadId
+        in: path
+        required: true
+      - schema:
+          type: string
+        name: userId
+        in: path
+        required: true
+      - schema:
+          type: string
+        name: messageId
+        in: path
+        required: true
+    delete:
+      summary: Delete message written by a given user
+      operationId: deleteUserMessage
+      responses:
+        '204':
+          description: No Content
   '/project/{projectId}/thread/{threadId}/resolve':
     parameters:
       - schema:

+ 11 - 0
services/web/app/src/Features/Chat/ChatApiHandler.js

@@ -90,6 +90,15 @@ async function deleteMessage(projectId, threadId, messageId) {
   )
 }
 
+async function deleteUserMessage(projectId, threadId, userId, messageId) {
+  await fetchNothing(
+    chatApiUrl(
+      `/project/${projectId}/thread/${threadId}/user/${userId}/messages/${messageId}`
+    ),
+    { method: 'DELETE' }
+  )
+}
+
 async function getResolvedThreadIds(projectId) {
   const body = await fetchJson(
     chatApiUrl(`/project/${projectId}/resolved-thread-ids`)
@@ -134,6 +143,7 @@ module.exports = {
   deleteThread: callbackify(deleteThread),
   editMessage: callbackify(editMessage),
   deleteMessage: callbackify(deleteMessage),
+  deleteUserMessage: callbackify(deleteUserMessage),
   getResolvedThreadIds: callbackify(getResolvedThreadIds),
   duplicateCommentThreads: callbackify(duplicateCommentThreads),
   generateThreadData: callbackify(generateThreadData),
@@ -148,6 +158,7 @@ module.exports = {
     deleteThread,
     editMessage,
     deleteMessage,
+    deleteUserMessage,
     getResolvedThreadIds,
     duplicateCommentThreads,
     generateThreadData,

+ 18 - 2
services/web/frontend/js/features/review-panel-new/components/review-panel-comment.tsx

@@ -12,6 +12,7 @@ import {
   ThreadId,
 } from '../../../../../types/review-panel/review-panel'
 import { useModalsContext } from '@/features/ide-react/context/modals-context'
+import { usePermissionsContext } from '@/features/ide-react/context/permissions-context'
 import { useTranslation } from 'react-i18next'
 import { debugConsole } from '@/utils/debugging'
 
@@ -29,11 +30,13 @@ export const ReviewPanelComment = memo<{
     resolveThread,
     editMessage,
     deleteMessage,
+    deleteOwnMessage,
     deleteThread,
     addMessage,
   } = useThreadsActionsContext()
   const { showGenericMessageModal } = useModalsContext()
   const { t } = useTranslation()
+  const permissions = usePermissionsContext()
 
   const [processing, setProcessing] = useState(false)
 
@@ -74,7 +77,13 @@ export const ReviewPanelComment = memo<{
     async (commentId: CommentId) => {
       setProcessing(true)
       try {
-        await deleteMessage(comment.op.t, commentId)
+        if (permissions.write) {
+          // Owners and editors can delete any message
+          await deleteMessage(comment.op.t, commentId)
+        } else {
+          // Reviewers can only delete their own messages
+          await deleteOwnMessage(comment.op.t, commentId)
+        }
       } catch (err) {
         debugConsole.error(err)
         showGenericMessageModal(
@@ -85,7 +94,14 @@ export const ReviewPanelComment = memo<{
         setProcessing(false)
       }
     },
-    [comment.op.t, deleteMessage, showGenericMessageModal, t]
+    [
+      comment.op.t,
+      deleteMessage,
+      deleteOwnMessage,
+      showGenericMessageModal,
+      t,
+      permissions.write,
+    ]
   )
 
   const handleDeleteThread = useCallback(

+ 6 - 0
services/web/frontend/js/features/review-panel-new/context/threads-context.tsx

@@ -38,6 +38,7 @@ type ThreadsActions = {
     content: string
   ) => Promise<void>
   deleteMessage: (threadId: ThreadId, commentId: CommentId) => Promise<void>
+  deleteOwnMessage: (threadId: ThreadId, commentId: CommentId) => Promise<void>
 }
 
 const ThreadsActionsContext = createContext<ThreadsActions | undefined>(
@@ -288,6 +289,11 @@ export const ThreadsProvider: FC = ({ children }) => {
           `/project/${projectId}/thread/${threadId}/messages/${commentId}`
         )
       },
+      async deleteOwnMessage(threadId: ThreadId, commentId: CommentId) {
+        await deleteJSON(
+          `/project/${projectId}/thread/${threadId}/own-messages/${commentId}`
+        )
+      },
     }),
     [currentDocument, projectId]
   )