packages feed

gitlab-haskell-1.0.0.0: src/GitLab/API/Discussions.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}

-- |
-- Module      : Discussions
-- Description : Queries about discussions, which are a set of related notes on snippets, issues, epics, merge requests and commits.
-- Copyright   : (c) Rob Stewart, Heriot-Watt University, 2021
-- License     : BSD3
-- Maintainer  : robstewart57@gmail.com
-- Stability   : stable
module GitLab.API.Discussions
  ( -- * Issues

    -- ** List project issue discussion items
    projectIssueDiscussions,

    -- ** Get single issue discussion item
    issueDiscussion,

    -- ** Create new issue thread
    createIssueThread,

    -- ** Add note to existing issue thread
    addNoteToIssueThread,

    -- ** Modify existing issue thread note
    modifyThreadNoteIssue,

    -- ** Delete an issue thread note
    deleteIssueThreadNote,

    -- * Snippets

    -- ** List project snippet discussion items
    snippetDiscussionItems,

    -- ** Get single snippet discussion item
    snippetDiscussionItem,

    -- ** Create new snippet thread
    createSnippetThread,

    -- ** Add note to existing snippet thread
    addNoteToSnippetThread,

    -- ** Modify existing snippet thread note
    modifySnippetThreadNote,

    -- ** Delete a snippet thread note
    deleteSnippetThreadNote,
    -- -- * Epics

    -- -- ** List group epic discussion items

    -- -- ** Get single epic discussion item

    -- -- ** Create new epic thread

    -- -- ** Add note to existing epic thread

    -- -- ** Modify existing epic thread note

    -- -- ** Delete an epic thread note

    -- * Merge requests

    -- ** List project merge request discussion items
    projectMergeRequestDiscussionItems,

    -- ** Get single merge request discussion item
    mergeRequestDiscussionItems,

    -- ** Create new merge request thread
    createMergeRequestThread,
    -- -- ** Create a new thread on the overview page

    -- -- ** Create a new thread in the merge request diff

    -- -- ** Parameters for multiline comments

    -- * Line code

    -- ** Resolve a merge request thread
    resolveMergeRequestThread,

    -- ** Add note to existing merge request thread
    addNoteToMergeRequestThread,

    -- ** Modify an existing merge request thread note
    modifyMergeRequestThreadNote,

    -- ** Delete a merge request thread note
    deleteMergeRequestThreadNote,

    -- * Commits

    -- ** List project commit discussion items
    projectCommitDiscussionItems,

    -- ** Get single commit discussion item
    projectCommitDiscussionItem,

    -- ** Create new commit thread
    createCommitThread,

    -- ** Add note to existing commit thread
    addNoteToCommitThread,

    -- ** Modify an existing commit thread note
    modifyCommityThreadNote,

    -- ** Delete a commit thread note
    deleteCommitThreadNote,

    -- * Types
    PositionReference (..),
  )
where

import qualified Data.ByteString.Lazy as BSL
import Data.Maybe
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import GitLab.Types
import GitLab.WebRequests.GitLabWebCalls
import Network.HTTP.Client

-- | Gets a list of all discussion items for a single issue.
projectIssueDiscussions ::
  -- | project
  Project ->
  -- | The IID of an issue
  Int ->
  GitLab (Either (Response BSL.ByteString) [Discussion])
projectIssueDiscussions prj issueIid = do
  let urlPath =
        T.pack $
          "/projects/"
            <> show (project_id prj)
            <> "/issues/"
            <> show issueIid
            <> "/discussions"
  gitlabGetMany urlPath []

-- | Returns a single discussion item for a specific project issue.
issueDiscussion ::
  -- | project
  Project ->
  -- | The IID of an issue
  Int ->
  -- | The ID of a discussion item
  Int ->
  GitLab (Either (Response BSL.ByteString) (Maybe Discussion))
issueDiscussion prj issueIid discussionId = do
  let urlPath =
        T.pack $
          "/projects/"
            <> show (project_id prj)
            <> "/issues/"
            <> show issueIid
            <> "/discussions/"
            <> show discussionId
  gitlabGetOne urlPath []

-- | Creates a new thread to a single project issue. This is similar
-- to creating a note but other comments (replies) can be added to it
-- later.
createIssueThread ::
  -- | project
  Project ->
  -- | The IID of an issue
  Int ->
  -- | The content of the thread
  Text ->
  GitLab (Either (Response BSL.ByteString) (Maybe Discussion))
createIssueThread prj issueIid threadContent = do
  gitlabPost discussionAddr [("body", Just (T.encodeUtf8 threadContent))]
  where
    discussionAddr :: Text
    discussionAddr =
      "/projects/"
        <> T.pack (show (project_id prj))
        <> "/issues/"
        <> T.pack (show issueIid)
        <> "/discussions"

-- | Adds a new note to the thread. This can also create a thread from
-- a single comment. Notes can be added to other items than comments,
-- such as system notes, making them threads.
addNoteToIssueThread ::
  -- | project
  Project ->
  -- | The IID of an issue
  Int ->
  -- | The ID of a thread
  Int ->
  -- -- | The ID of a thread note
  -- Int ->

  -- | The content of the note/reply
  Text ->
  GitLab (Either (Response BSL.ByteString) (Maybe Discussion))
addNoteToIssueThread prj issueIid discussionId content = do
  gitlabPost discussionAddr [("body", Just (T.encodeUtf8 content))]
  where
    discussionAddr :: Text
    discussionAddr =
      "/projects/"
        <> T.pack (show (project_id prj))
        <> "/issues/"
        <> T.pack (show issueIid)
        <> "/discussions/"
        <> T.pack (show discussionId)
        <> "/notes"

-- <> "/notes/"
-- <> T.pack (show noteId)

-- | Modify existing thread note of an issue.
modifyThreadNoteIssue ::
  -- | project
  Project ->
  -- | The IID of an issue
  Int ->
  -- | The ID of a thread
  Int ->
  -- | The ID of a thread note
  Int ->
  -- | The content of the note/reply
  Text ->
  GitLab (Either (Response BSL.ByteString) (Maybe Discussion))
modifyThreadNoteIssue prj issueIid discussionId noteId content = do
  gitlabPut noteAddr [("body", Just (T.encodeUtf8 content))]
  where
    noteAddr :: Text
    noteAddr =
      "/projects/"
        <> T.pack (show (project_id prj))
        <> "/issues/"
        <> T.pack (show issueIid)
        <> "/discussions/"
        <> T.pack (show discussionId)
        <> "/notes/"
        <> T.pack (show noteId)

-- | Deletes an existing thread note of an issue.
deleteIssueThreadNote ::
  -- | project
  Project ->
  -- | The IID of an issue
  Int ->
  -- | The ID of a discussion
  Int ->
  -- | The ID of a discussion note
  Int ->
  GitLab (Either (Response BSL.ByteString) (Maybe ()))
deleteIssueThreadNote prj issueIid discussionId noteId = do
  gitlabDelete noteAddr []
  where
    noteAddr :: Text
    noteAddr =
      "/projects/"
        <> T.pack (show (project_id prj))
        <> "/issues/"
        <> T.pack (show issueIid)
        <> "/discussions/"
        <> T.pack (show discussionId)
        <> "/notes/"
        <> T.pack (show noteId)

-- | Gets a list of all discussion items for a single snippet.
snippetDiscussionItems ::
  -- | project
  Project ->
  -- | snippet ID
  Int ->
  GitLab (Either (Response BSL.ByteString) [Discussion])
snippetDiscussionItems prj snippetId =
  gitlabGetMany urlPath []
  where
    urlPath =
      T.pack $
        "/projects/"
          <> show (project_id prj)
          <> "/snippets/"
          <> show snippetId
          <> "/discussions"

-- | Returns a single discussion item for a specific project snippet.
snippetDiscussionItem ::
  -- | project
  Project ->
  -- | snippet ID
  Int ->
  -- | discussion ID
  Int ->
  GitLab (Either (Response BSL.ByteString) (Maybe Discussion))
snippetDiscussionItem prj snippetId discussionId =
  gitlabGetOne urlPath []
  where
    urlPath =
      T.pack $
        "/projects/"
          <> show (project_id prj)
          <> "/snippets/"
          <> show snippetId
          <> "/discussions/"
          <> show discussionId

-- | Creates a new thread to a single project snippet. This is similar
-- to creating a note but other comments (replies) can be added to it
-- later.
createSnippetThread ::
  -- | project
  Project ->
  -- | snippet ID
  Int ->
  -- | The content of a discussion
  Text ->
  GitLab (Either (Response BSL.ByteString) (Maybe Discussion))
createSnippetThread prj snippetId content = do
  gitlabPost discussionAddr [("body", Just (T.encodeUtf8 content))]
  where
    discussionAddr :: Text
    discussionAddr =
      "/projects/"
        <> T.pack (show (project_id prj))
        <> "/snippets/"
        <> T.pack (show snippetId)
        <> "/discussions"

-- | Adds a new note to the thread.
addNoteToSnippetThread ::
  -- | project
  Project ->
  -- | snippet ID
  Int ->
  -- | discussion ID
  Int ->
  -- -- | note ID
  -- Int ->

  -- | The content of the note/reply
  Text ->
  GitLab (Either (Response BSL.ByteString) (Maybe Discussion))
addNoteToSnippetThread prj snippetId discussionId content =
  gitlabPost discussionAddr [("body", Just (T.encodeUtf8 content))]
  where
    discussionAddr :: Text
    discussionAddr =
      "/projects/"
        <> T.pack (show (project_id prj))
        <> "/snippets/"
        <> T.pack (show snippetId)
        <> "/discussions/"
        <> T.pack (show discussionId)
        <> "/notes"

-- <> "/notes/"
-- <> T.pack (show noteId)

-- | Modify existing thread note of a snippet.
modifySnippetThreadNote ::
  -- | project
  Project ->
  -- | snippet ID
  Int ->
  -- | discussion ID
  Int ->
  -- | note ID
  Int ->
  -- | The content of the note/reply
  Text ->
  GitLab (Either (Response BSL.ByteString) (Maybe Discussion))
modifySnippetThreadNote prj snippetId discussionId noteId content =
  gitlabPut noteAddr [("body", Just (T.encodeUtf8 content))]
  where
    noteAddr :: Text
    noteAddr =
      "/projects/"
        <> T.pack (show (project_id prj))
        <> "/snippets/"
        <> T.pack (show snippetId)
        <> "/discussions/"
        <> T.pack (show discussionId)
        <> "/notes/"
        <> T.pack (show noteId)

-- | Deletes an existing thread note of an issue.
deleteSnippetThreadNote ::
  -- | Project
  Project ->
  -- | snippet ID
  Int ->
  -- | discussion ID
  Int ->
  -- | note ID
  Int ->
  GitLab (Either (Response BSL.ByteString) (Maybe ()))
deleteSnippetThreadNote prj snippetId discussionId noteId = do
  gitlabDelete noteAddr []
  where
    noteAddr :: Text
    noteAddr =
      "/projects/"
        <> T.pack (show (project_id prj))
        <> "/snippets/"
        <> T.pack (show snippetId)
        <> "/discussions/"
        <> T.pack (show discussionId)
        <> "/notes/"
        <> T.pack (show noteId)

-- | Gets a list of all discussion items for a single merge request.
projectMergeRequestDiscussionItems ::
  -- | project
  Project ->
  -- | Merge request IID
  Int ->
  GitLab (Either (Response BSL.ByteString) [Discussion])
projectMergeRequestDiscussionItems prj mergeRequestIid = do
  gitlabGetMany urlPath []
  where
    urlPath =
      T.pack $
        "/projects/"
          <> show (project_id prj)
          <> "/merge_requests/"
          <> show mergeRequestIid
          <> "/discussions"

-- | Gets a list of all discussion items for a single merge request.
mergeRequestDiscussionItems ::
  -- | project
  Project ->
  -- | Merge request IID
  Int ->
  -- | discussion ID
  Int ->
  GitLab (Either (Response BSL.ByteString) (Maybe Discussion))
mergeRequestDiscussionItems prj mergeRequestIid discussionId = do
  gitlabGetOne urlPath []
  where
    urlPath =
      T.pack $
        "/projects/"
          <> show (project_id prj)
          <> "/merge_requests/"
          <> show mergeRequestIid
          <> "/discussions/"
          <> show discussionId

-- | Position reference for an entry in a discussion.
data PositionReference = TextPos | ImagePos

instance Show PositionReference where
  show TextPos = "text"
  show ImagePos = "image"

-- | Creates a new thread to a single project merge request. This is
-- similar to creating a note but other comments (replies) can be
-- added to it later.  See the GitLab document:
-- https://docs.gitlab.com/ee/api/discussions.html#create-new-merge-request-thread
createMergeRequestThread ::
  -- | project
  Project ->
  -- | merge request ID
  Int ->
  -- | The content of the thread
  Text ->
  -- | Base commit SHA in the source branch
  Text ->
  -- | SHA referencing commit in target branch
  Text ->
  -- | SHA referencing HEAD of this merge request
  Text ->
  -- | Type of the position reference
  PositionReference ->
  -- | File path after change
  Text ->
  -- | File path before change
  Text ->
  GitLab (Either (Response BSL.ByteString) (Maybe Discussion))
createMergeRequestThread prj mergeRequestIid content baseCommitShaSource shaCommitTarget shaHeadMR typePosRef filePathAfter filePathBefore =
  gitlabPost
    discussionAddr
    [ ("body", Just (T.encodeUtf8 content)),
      ("position[base_sha]", Just (T.encodeUtf8 baseCommitShaSource)),
      ("position[start_sha]", Just (T.encodeUtf8 shaCommitTarget)),
      ("position[head_sha]", Just (T.encodeUtf8 shaHeadMR)),
      ("position[position_type]", Just (T.encodeUtf8 (T.pack (show typePosRef)))),
      ("position[new_path]", Just (T.encodeUtf8 filePathAfter)),
      ("position[old_path]", Just (T.encodeUtf8 filePathBefore))
    ]
  where
    discussionAddr :: Text
    discussionAddr =
      "/projects/"
        <> T.pack (show (project_id prj))
        <> "/merge_requests/"
        <> T.pack (show mergeRequestIid)
        <> "/discussions"

-- | Resolve/unresolve whole thread of a merge request.
resolveMergeRequestThread ::
  -- | project
  Project ->
  -- | merge request IID
  Int ->
  -- | discussion ID
  Int ->
  -- | Resolve/unresolve the discussion
  Bool ->
  GitLab (Either (Response BSL.ByteString) (Maybe Discussion))
resolveMergeRequestThread prj mergeRequestIid discussionId resolved =
  gitlabPut noteAddr [("resolved", Just (T.encodeUtf8 (resolvedStr resolved)))]
  where
    noteAddr :: Text
    noteAddr =
      "/projects/"
        <> T.pack (show (project_id prj))
        <> "/merge_requests/"
        <> T.pack (show mergeRequestIid)
        <> "/discussions/"
        <> T.pack (show discussionId)
    resolvedStr True = "true"
    resolvedStr False = "false"

-- | Adds a new note to the thread. This can also create a thread from a single comment.
addNoteToMergeRequestThread ::
  -- | project
  Project ->
  -- | merge request ID
  Int ->
  -- | discussion ID
  Int ->
  -- -- | note ID
  -- Int ->

  -- | The content of the note/reply
  Text ->
  GitLab (Either (Response BSL.ByteString) (Maybe Discussion))
addNoteToMergeRequestThread prj mergeRequestIid discussionId content =
  gitlabPost
    discussionAddr
    [ ("body", Just (T.encodeUtf8 content))
    ]
  where
    discussionAddr :: Text
    discussionAddr =
      "/projects/"
        <> T.pack (show (project_id prj))
        <> "/merge_requests/"
        <> T.pack (show mergeRequestIid)
        <> "/discussions/"
        <> T.pack (show discussionId)
        <> "/notes"

-- | exactly one of body or resolved must be a 'Just' value
modifyMergeRequestThreadNote ::
  -- | project
  Project ->
  -- | merge request IID
  Int ->
  -- | discussion ID
  Int ->
  -- | note ID
  Int ->
  -- | The content of the note/reply
  Maybe Text ->
  -- | Resolve/unresolve the note
  Maybe Bool ->
  GitLab (Either (Response BSL.ByteString) (Maybe Discussion))
modifyMergeRequestThreadNote prj mergeRequestIid discussionId noteId content resolved =
  gitlabPut
    noteAddr
    (catMaybes [contentAttr, resolveAttr])
  where
    contentAttr =
      case content of
        Nothing -> Nothing
        Just x -> Just ("body", Just (T.encodeUtf8 x))
    resolveAttr =
      case resolved of
        Nothing -> Nothing
        Just x ->
          if x
            then Just ("resolved", Just (T.encodeUtf8 "true"))
            else Just ("resolved", Just (T.encodeUtf8 "false"))
    noteAddr :: Text
    noteAddr =
      "/projects/"
        <> T.pack (show (project_id prj))
        <> "/merge_requests/"
        <> T.pack (show mergeRequestIid)
        <> "/discussions/"
        <> T.pack (show discussionId)
        <> "/notes/"
        <> T.pack (show noteId)

-- | Deletes an existing thread note of a merge request.
deleteMergeRequestThreadNote ::
  -- | project
  Project ->
  -- | merge request IID
  Int ->
  -- | discussion ID
  Int ->
  -- | note ID
  Int ->
  GitLab (Either (Response BSL.ByteString) (Maybe ()))
deleteMergeRequestThreadNote prj mergeRequestIid discussionId noteId = do
  gitlabDelete noteAddr []
  where
    noteAddr :: Text
    noteAddr =
      "/projects/"
        <> T.pack (show (project_id prj))
        <> "/merge_requests/"
        <> T.pack (show mergeRequestIid)
        <> "/discussions/"
        <> T.pack (show discussionId)
        <> "/notes/"
        <> T.pack (show noteId)

-- | Gets a list of all discussion items for a single commit.
projectCommitDiscussionItems ::
  -- | project
  Project ->
  -- | commit ID
  Int ->
  GitLab (Either (Response BSL.ByteString) [Discussion])
projectCommitDiscussionItems prj commitId =
  gitlabGetMany urlPath []
  where
    urlPath =
      T.pack $
        "/projects/"
          <> show (project_id prj)
          <> "/commits/"
          <> show commitId
          <> "/discussions"

-- | Returns a single discussion item for a specific project commit.
projectCommitDiscussionItem ::
  -- | project
  Project ->
  -- | commit ID
  Int ->
  -- | discussion ID
  Int ->
  GitLab (Either (Response BSL.ByteString) (Maybe Discussion))
projectCommitDiscussionItem prj commitId discussionId =
  gitlabGetOne urlPath []
  where
    urlPath =
      T.pack $
        "/projects/"
          <> show (project_id prj)
          <> "/commits/"
          <> show commitId
          <> "/discussions/"
          <> show discussionId

-- | Creates a new thread to a single project commit. This is similar
-- to creating a note but other comments (replies) can be added to it
-- later.
createCommitThread ::
  -- | project
  Project ->
  -- | commit ID
  Int ->
  -- | The content of the thread
  Text ->
  -- | SHA of the parent commit
  Text ->
  -- | SHA of the parent commit (bug in GitLab document?)
  Text ->
  -- | The SHA of this commit
  Text ->
  -- | Type of the position reference
  PositionReference ->
  GitLab (Either (Response BSL.ByteString) (Maybe Discussion))
createCommitThread prj commitId content shaParent shaStart shaThisCommit typePosRef =
  gitlabPost
    discussionAddr
    [ ("body", Just (T.encodeUtf8 content)),
      ("position[base_sha]", Just (T.encodeUtf8 shaParent)),
      ("position[start_sha]", Just (T.encodeUtf8 shaStart)),
      ("position[head_sha]", Just (T.encodeUtf8 shaThisCommit)),
      ("position[position_type]", Just (T.encodeUtf8 (T.pack (show typePosRef))))
    ]
  where
    discussionAddr :: Text
    discussionAddr =
      "/projects/"
        <> T.pack (show (project_id prj))
        <> "/commits/"
        <> T.pack (show commitId)
        <> "/discussions"

-- | Adds a new note to the thread.
addNoteToCommitThread ::
  -- | project
  Project ->
  -- | commit ID
  Int ->
  -- | discussion ID
  Int ->
  -- -- | note ID
  -- Int ->

  -- | The content of the note/reply
  Text ->
  GitLab (Either (Response BSL.ByteString) (Maybe Discussion))
addNoteToCommitThread prj commitId discussionId content =
  gitlabPost
    discussionAddr
    [ ("body", Just (T.encodeUtf8 content))
    ]
  where
    discussionAddr :: Text
    discussionAddr =
      "/projects/"
        <> T.pack (show (project_id prj))
        <> "/commits/"
        <> T.pack (show commitId)
        <> "/discussions/"
        <> T.pack (show discussionId)
        <> "/notes"

-- | Adds a new note to the thread.
modifyCommityThreadNote ::
  -- | project
  Project ->
  -- | commit ID
  Int ->
  -- | discussion ID
  Int ->
  -- | note ID
  Int ->
  -- | The content of the note/reply
  Maybe Text ->
  -- | Resolve/unresolve the note
  Maybe Bool ->
  GitLab (Either (Response BSL.ByteString) (Maybe Discussion))
modifyCommityThreadNote prj commitId discussionId noteId content resolved =
  gitlabPut
    noteAddr
    (catMaybes [contentAttr, resolveAttr])
  where
    contentAttr =
      case content of
        Nothing -> Nothing
        Just x -> Just ("body", Just (T.encodeUtf8 x))
    resolveAttr =
      case resolved of
        Nothing -> Nothing
        Just x ->
          if x
            then Just ("resolved", Just (T.encodeUtf8 "true"))
            else Just ("resolved", Just (T.encodeUtf8 "false"))
    noteAddr :: Text
    noteAddr =
      "/projects/"
        <> T.pack (show (project_id prj))
        <> "/commits/"
        <> T.pack (show commitId)
        <> "/discussions/"
        <> T.pack (show discussionId)
        <> "/notes/"
        <> T.pack (show noteId)

-- | Deletes an existing thread note of a commit.
deleteCommitThreadNote ::
  -- | project
  Project ->
  -- | commit ID
  Int ->
  -- | discussion ID
  Int ->
  -- | The ID of a discussion note
  Int ->
  GitLab (Either (Response BSL.ByteString) (Maybe ()))
deleteCommitThreadNote prj commitId discussionId noteId = do
  gitlabDelete noteAddr []
  where
    noteAddr :: Text
    noteAddr =
      "/projects/"
        <> T.pack (show (project_id prj))
        <> "/commits/"
        <> T.pack (show commitId)
        <> "/discussions/"
        <> T.pack (show discussionId)
        <> "/notes/"
        <> T.pack (show noteId)