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

-- |
-- Module      : Groups
-- Description : Queries about and updates to groups
-- Copyright   : (c) Rob Stewart, Heriot-Watt University, 2019
-- License     : BSD3
-- Maintainer  : robstewart57@gmail.com
-- Stability   : stable
module GitLab.API.Groups 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.API.Members
import GitLab.API.Users
import GitLab.Types
import GitLab.WebRequests.GitLabWebCalls
import Network.HTTP.Client
import Network.HTTP.Types.URI

-- | gets groups with the given group name or path.
--
-- > projectsWithNameOrPath "group1"
groupsWithNameOrPath ::
  -- | group name being searched for.
  Text ->
  GitLab (Either (Response BSL.ByteString) [Group])
groupsWithNameOrPath :: Text -> GitLab (Either (Response ByteString) [Group])
groupsWithNameOrPath Text
groupName = do
  Either (Response ByteString) [Group]
result <- Text
-> [GitLabParam] -> GitLab (Either (Response ByteString) [Group])
forall a.
FromJSON a =>
Text -> [GitLabParam] -> GitLab (Either (Response ByteString) [a])
gitlabGetMany Text
"/groups" [(ByteString
"search", ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (Text -> ByteString
T.encodeUtf8 Text
groupName))]
  case Either (Response ByteString) [Group]
result of
    Left {} -> Either (Response ByteString) [Group]
-> GitLab (Either (Response ByteString) [Group])
forall (m :: * -> *) a. Monad m => a -> m a
return Either (Response ByteString) [Group]
result
    Right [Group]
groups ->
      Either (Response ByteString) [Group]
-> GitLab (Either (Response ByteString) [Group])
forall (m :: * -> *) a. Monad m => a -> m a
return
        ( [Group] -> Either (Response ByteString) [Group]
forall a b. b -> Either a b
Right
            ([Group] -> Either (Response ByteString) [Group])
-> [Group] -> Either (Response ByteString) [Group]
forall a b. (a -> b) -> a -> b
$(Group -> Bool) -> [Group] -> [Group]
forall a. (a -> Bool) -> [a] -> [a]
filter
            ( \Group
group ->
                Text
groupName Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Group -> Text
group_name Group
group
                  Bool -> Bool -> Bool
|| Text
groupName Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Group -> Text
group_path Group
group
            )
            [Group]
groups
        )

-- | adds all registered users to a group.
addAllUsersToGroup ::
  -- | group name
  Text ->
  -- | level of access granted
  AccessLevel ->
  GitLab [Either (Response BSL.ByteString) (Maybe Member)]
addAllUsersToGroup :: Text
-> AccessLevel
-> GitLab [Either (Response ByteString) (Maybe Member)]
addAllUsersToGroup Text
groupName AccessLevel
access = do
  [User]
allRegisteredUsers <- GitLab [User]
allUsers
  let allUserIds :: [Text]
allUserIds = (User -> Text) -> [User] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map User -> Text
user_username [User]
allRegisteredUsers
  Text
-> AccessLevel
-> [Text]
-> GitLab [Either (Response ByteString) (Maybe Member)]
addUsersToGroup' Text
groupName AccessLevel
access [Text]
allUserIds

-- | adds a user to a group.
addUserToGroup ::
  -- | group name
  Text ->
  -- | level of access granted
  AccessLevel ->
  -- | the user
  User ->
  GitLab (Either (Response BSL.ByteString) (Maybe Member))
addUserToGroup :: Text
-> AccessLevel
-> User
-> GitLab (Either (Response ByteString) (Maybe Member))
addUserToGroup Text
groupName AccessLevel
access User
usr =
  Text
-> AccessLevel
-> Int
-> GitLab (Either (Response ByteString) (Maybe Member))
addUserToGroup' Text
groupName AccessLevel
access (User -> Int
user_id User
usr)

-- | adds a user with a given user ID to a group.
addUserToGroup' ::
  -- | group name
  Text ->
  -- | level of access granted
  AccessLevel ->
  -- | user ID
  Int ->
  GitLab (Either (Response BSL.ByteString) (Maybe Member))
addUserToGroup' :: Text
-> AccessLevel
-> Int
-> GitLab (Either (Response ByteString) (Maybe Member))
addUserToGroup' Text
groupName AccessLevel
access Int
usrId = do
  Either (Response ByteString) [Group]
attempt <- Text -> GitLab (Either (Response ByteString) [Group])
groupsWithNameOrPath Text
groupName
  case Either (Response ByteString) [Group]
attempt of
    Left Response ByteString
resp -> Either (Response ByteString) (Maybe Member)
-> GitLab (Either (Response ByteString) (Maybe Member))
forall (m :: * -> *) a. Monad m => a -> m a
return (Response ByteString -> Either (Response ByteString) (Maybe Member)
forall a b. a -> Either a b
Left Response ByteString
resp)
    Right [] ->
      -- TODO crreate response
      [Char] -> GitLab (Either (Response ByteString) (Maybe Member))
forall a. HasCallStack => [Char] -> a
error [Char]
"foo"
    -- return (Left (mk (Response BSL.ByteString) 404 (T.encodeUtf8 (T.pack "cannot find group"))))
    -- return (Left (mk (Response (T.encodeUtf8 (T.pack "cannot find group"))))
    Right [Group
grp] ->
      Text
-> [GitLabParam]
-> GitLab (Either (Response ByteString) (Maybe Member))
forall a.
FromJSON a =>
Text
-> [GitLabParam] -> GitLab (Either (Response ByteString) (Maybe a))
gitlabPost Text
addr [GitLabParam]
params
      where
        params :: [GitLabParam]
        params :: [GitLabParam]
params =
          [ (ByteString
"user_id", ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (Text -> ByteString
T.encodeUtf8 ([Char] -> Text
T.pack (Int -> [Char]
forall a. Show a => a -> [Char]
show Int
usrId)))),
            (ByteString
"access_level", ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (Text -> ByteString
T.encodeUtf8 ([Char] -> Text
T.pack (AccessLevel -> [Char]
forall a. Show a => a -> [Char]
show AccessLevel
access))))
          ]
        addr :: Text
addr =
          Text
"/groups/"
            Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ByteString -> Text
T.decodeUtf8 (Bool -> ByteString -> ByteString
urlEncode Bool
False (Text -> ByteString
T.encodeUtf8 ([Char] -> Text
T.pack (Int -> [Char]
forall a. Show a => a -> [Char]
show (Group -> Int
group_id Group
grp)))))
            Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/members"
    Right (Group
_ : [Group]
_) ->
      -- return (Left (Response (T.encodeUtf8 (T.pack "too many groups found"))))
      -- TODO crreate response
      [Char] -> GitLab (Either (Response ByteString) (Maybe Member))
forall a. HasCallStack => [Char] -> a
error [Char]
"foo"

-- return (Left (mk (Response BSL.ByteString) 404 (T.encodeUtf8 (T.pack "too many groups found"))))

-- | adds a list of users to a group.
addUsersToGroup ::
  -- | group name
  Text ->
  -- | level of access granted
  AccessLevel ->
  -- | list of usernames to be added to the group
  [User] ->
  GitLab [Either (Response BSL.ByteString) (Maybe Member)]
addUsersToGroup :: Text
-> AccessLevel
-> [User]
-> GitLab [Either (Response ByteString) (Maybe Member)]
addUsersToGroup Text
groupName AccessLevel
access =
  (User -> GitLab (Either (Response ByteString) (Maybe Member)))
-> [User] -> GitLab [Either (Response ByteString) (Maybe Member)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Text
-> AccessLevel
-> User
-> GitLab (Either (Response ByteString) (Maybe Member))
addUserToGroup Text
groupName AccessLevel
access)

-- | adds a list of users to a group.
addUsersToGroup' ::
  -- | group name
  Text ->
  -- | level of access granted
  AccessLevel ->
  -- | list of usernames to be added to the group
  [Text] ->
  GitLab [Either (Response BSL.ByteString) (Maybe Member)]
addUsersToGroup' :: Text
-> AccessLevel
-> [Text]
-> GitLab [Either (Response ByteString) (Maybe Member)]
addUsersToGroup' Text
groupName AccessLevel
access [Text]
usernames = do
  [User]
users <- [Maybe User] -> [User]
forall a. [Maybe a] -> [a]
catMaybes ([Maybe User] -> [User])
-> ReaderT GitLabState IO [Maybe User] -> GitLab [User]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Text -> ReaderT GitLabState IO (Maybe User))
-> [Text] -> ReaderT GitLabState IO [Maybe User]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Text -> ReaderT GitLabState IO (Maybe User)
searchUser [Text]
usernames
  (User -> GitLab (Either (Response ByteString) (Maybe Member)))
-> [User] -> GitLab [Either (Response ByteString) (Maybe Member)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Text
-> AccessLevel
-> Int
-> GitLab (Either (Response ByteString) (Maybe Member))
addUserToGroup' Text
groupName AccessLevel
access (Int -> GitLab (Either (Response ByteString) (Maybe Member)))
-> (User -> Int)
-> User
-> GitLab (Either (Response ByteString) (Maybe Member))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. User -> Int
user_id) [User]
users

groupProjects ::
  -- | group
  Group ->
  GitLab (Either (Response BSL.ByteString) [Project])
groupProjects :: Group -> GitLab (Either (Response ByteString) [Project])
groupProjects Group
group = do
  Int -> GitLab (Either (Response ByteString) [Project])
groupProjects' (Group -> Int
group_id Group
group)

groupProjects' ::
  -- | group ID
  Int ->
  GitLab (Either (Response BSL.ByteString) [Project])
groupProjects' :: Int -> GitLab (Either (Response ByteString) [Project])
groupProjects' Int
groupID = do
  let urlPath :: Text
urlPath =
        [Char] -> Text
T.pack ([Char] -> Text) -> [Char] -> Text
forall a b. (a -> b) -> a -> b
$
          [Char]
"/groups/"
            [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> Int -> [Char]
forall a. Show a => a -> [Char]
show Int
groupID
            [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
"/projects"
  Text
-> [GitLabParam] -> GitLab (Either (Response ByteString) [Project])
forall a.
FromJSON a =>
Text -> [GitLabParam] -> GitLab (Either (Response ByteString) [a])
gitlabGetMany Text
urlPath []