From 7530d2b4bf10ec9b5f8fe325ac42f1fce679b5ac Mon Sep 17 00:00:00 2001 From: Marco Zocca Date: Wed, 5 Jul 2023 18:45:44 +0200 Subject: [PATCH] graph add teams chat stuff --- ms-graph-api-test/app/Main.hs | 8 +- ms-graph-api/CHANGELOG.md | 19 +++- ms-graph-api/ms-graph-api.cabal | 2 +- ms-graph-api/src/MSGraphAPI/Users/Group.hs | 122 +++++++++++++++++++-- 4 files changed, 131 insertions(+), 20 deletions(-) diff --git a/ms-graph-api-test/app/Main.hs b/ms-graph-api-test/app/Main.hs index 8613f72..203681a 100644 --- a/ms-graph-api-test/app/Main.hs +++ b/ms-graph-api-test/app/Main.hs @@ -38,7 +38,7 @@ import Network.Wai.Middleware.RequestLogger (logStdoutDev) import qualified MSGraphAPI as MSG (Collection(..), run, withTLS) import qualified MSGraphAPI.Files.Drive as MSD (Drive(..), listDrivesGroup) import qualified MSGraphAPI.Files.DriveItem as MSDI (listRootChildrenMe) -import qualified MSGraphAPI.Users.Group as MSGU (Group(..), getMeJoinedTeams, getGroupsDriveItems) +import qualified MSGraphAPI.Users.Group as MSGU (Group(..), listMeJoinedTeams, listGroupsDriveItems) import qualified MSGraphAPI.Users.User as MSG (getMe, User(..)) import Network.OAuth2.Provider.AzureAD (OAuthCfg(..), azureOAuthADApp, AzureAD) import MSAuth (applyDotEnv, Tokens, newTokens, tokensToList, withAADUser, loginEndpoint, replyEndpoint, UserSub, Scotty, Action) @@ -67,8 +67,8 @@ server = do groupDriveItems t = do - gs <- MSG.cValue <$> MSGU.getMeJoinedTeams t - traverse (\g -> MSGU.getGroupsDriveItems (MSGU.gId g) t ) gs + gs <- MSG.cValue <$> MSGU.listMeJoinedTeams t + traverse (\g -> MSGU.listGroupsDriveItems (MSGU.gId g) t ) gs meGroupDrivesEndpoint :: (MonadIO m) => Tokens a OAuth2Token @@ -99,7 +99,7 @@ meTeamsEndpoint ts hc pth = get pth $ do f (_, oat) = do let t = accessToken oat - item <- runReq hc $ MSGU.getMeJoinedTeams t + item <- runReq hc $ MSGU.listMeJoinedTeams t let js = A.encodePretty item pure js diff --git a/ms-graph-api/CHANGELOG.md b/ms-graph-api/CHANGELOG.md index 238c49c..0490f0e 100644 --- a/ms-graph-api/CHANGELOG.md +++ b/ms-graph-api/CHANGELOG.md @@ -8,15 +8,24 @@ and this project adheres to the ## Unreleased +## 0.11.0.0 + +.Users.Group +- add listTeamChannels +- add listChannelMessages, listMessageReplies + +*Breaking changes* +Functions in .Users.Group are now called 'list..' rather than 'get..' to correspond with the REST API + ## 0.10.0.0 *Breaking changes* -- MSGraphAPI.ChangeNotifications.Subscription : Subscription has fewer fields (the ID and TLS version fields are optional) +- .ChangeNotifications.Subscription : Subscription has fewer fields (the ID and TLS version fields are optional) ## 0.9.0.0 -MSGraphAPI.Files.Drive +.Files.Drive *Breaking changes* - withTLS changed signature: the inner continuation has an additional Manager parameter @@ -24,7 +33,7 @@ MSGraphAPI.Files.Drive ## 0.8.0.0 -MSGraphAPI.Files.DriveItem : +.Files.DriveItem : - custom FromJSON instance using a sum type for the various types of drive item. Makes it convenient for users to pattern match on type. So far only File, Folder and Package drive item types are parsed further. New MSGraphAPI module to re-expose internals @@ -32,7 +41,7 @@ New MSGraphAPI module to re-expose internals ## 0.7.0.0 -MSGraphAPI.ChangeNotifications.Subscription: +.ChangeNotifications.Subscription: - add createSubscription *Breaking changes* @@ -40,7 +49,7 @@ MSGraphAPI.ChangeNotifications.Subscription: ## 0.6.0.0 -MSGraphAPI.Users.Group : +.Users.Group : - Group - getUserJoinedTeams - getGroupsDriveItems diff --git a/ms-graph-api/ms-graph-api.cabal b/ms-graph-api/ms-graph-api.cabal index f7e6704..9187d0d 100644 --- a/ms-graph-api/ms-graph-api.cabal +++ b/ms-graph-api/ms-graph-api.cabal @@ -1,5 +1,5 @@ name: ms-graph-api -version: 0.10.0.0 +version: 0.11.0.0 synopsis: Microsoft Graph API description: Bindings to the Microsoft Graph API homepage: https://github.com/unfoldml/ms-graph-api diff --git a/ms-graph-api/src/MSGraphAPI/Users/Group.hs b/ms-graph-api/src/MSGraphAPI/Users/Group.hs index d8f00f1..e983157 100644 --- a/ms-graph-api/src/MSGraphAPI/Users/Group.hs +++ b/ms-graph-api/src/MSGraphAPI/Users/Group.hs @@ -1,12 +1,25 @@ -- | Users.Group module MSGraphAPI.Users.Group ( -- * Teams - getUserJoinedTeams - , getMeJoinedTeams + -- ** Joined teams + listUserJoinedTeams + , listMeJoinedTeams + -- ** Associated teams + , listUserAssociatedTeams + , listMeAssociatedTeams + -- * Team channels + , listTeamChannels + -- ** Channel messages + , listChannelMessages + , listMessageReplies -- * Drive items - , getGroupsDriveItems + , listGroupsDriveItems -- * types , Group(..) + , Channel(..) + -- ** Chat messages + , ChatMessage(..) + , ChatMessageBody(..) )where import GHC.Generics (Generic(..)) @@ -18,7 +31,9 @@ import Network.OAuth.OAuth2.Internal (AccessToken(..)) -- req import Network.HTTP.Req (Req) -- text -import Data.Text (Text) +import Data.Text (Text, unpack) +-- time +import Data.Time (ZonedTime) import qualified MSGraphAPI.Internal.Common as MSG (Collection(..), get, aesonOptions) import MSGraphAPI.Files.DriveItem (DriveItem) @@ -35,22 +50,109 @@ instance A.FromJSON Group where parseJSON = A.genericParseJSON (MSG.aesonOptions "g") instance A.ToJSON Group +-- | Teams are made up of channels, which are the conversations you have with your teammates. Each channel is dedicated to a specific topic, department, or project. Channels are where the work actually gets done - where text, audio, and video conversations open to the whole team happen, where files are shared, and where tabs are added. +-- +-- https://learn.microsoft.com/en-us/graph/api/resources/channel?view=graph-rest-1.0 +data Channel = Channel { + chId :: Text + , chDisplayName :: Text + , chDescription :: Text + } deriving (Eq, Ord, Show, Generic) +instance A.FromJSON Channel where + parseJSON = A.genericParseJSON (MSG.aesonOptions "ch") +instance A.ToJSON Channel + +-- | Get the list of channels either in this team or shared with this team (incoming channels). +-- +-- @GET \/teams\/{team-id}\/allChannels@ +listTeamChannels :: Text -- ^ team ID + -> AccessToken -> Req (MSG.Collection Channel) +listTeamChannels tid = MSG.get ["teams", tid, "allChannels"] mempty + + + +-- | Retrieve the list of messages (without the replies) in a channel of a team. +-- +-- To get the replies for a message, call the 'listMessageReplies' or the get message reply API. +-- +-- @GET \/teams\/{team-id}\/channels\/{channel-id}\/messages@ +listChannelMessages :: + Text -- ^ team ID + -> Text -- ^ channel ID + -> AccessToken -> Req (MSG.Collection ChatMessage) +listChannelMessages tid chid = + MSG.get ["teams", tid, "channels", chid, "messages"] mempty + +-- | List all the replies to a message in a channel of a team. +-- +-- This method lists only the replies of the specified message, if any. To get the message itself, simply call get channel message. +-- +-- GET /teams/{team-id}/channels/{channel-id}/messages/{message-id}/replies +listMessageReplies :: + Text -- ^ team ID + -> Text -- ^ channel ID + -> Text -- ^ message ID + -> AccessToken -> Req (MSG.Collection ChatMessage) +listMessageReplies tid chid mid = + MSG.get ["teams", tid, "channels", chid, "messages", mid, "replies"] mempty + + +-- | An individual chat message within a channel or chat. The message can be a root message or part of a thread +-- +-- https://learn.microsoft.com/en-us/graph/api/resources/chatmessage?view=graph-rest-1.0 +data ChatMessage = ChatMessage { + chamBody :: ChatMessageBody + , chamId :: Text + , chamCreatedDateTime :: ZonedTime + , chamDeletedDateTime :: Maybe ZonedTime + } deriving (Show, Generic) +instance A.FromJSON ChatMessage where + parseJSON = A.genericParseJSON (MSG.aesonOptions "cham") +instance A.ToJSON ChatMessage + +data ChatMessageBody = ChatMessageBody { + chambId :: Text + } deriving (Eq, Ord, Generic) +instance Show ChatMessageBody where + show = unpack . chambId +instance A.FromJSON ChatMessageBody where + parseJSON = A.genericParseJSON (MSG.aesonOptions "chamb") +instance A.ToJSON ChatMessageBody + + + +-- | Get the list of teams in Microsoft Teams that a user is associated with. +-- +-- @GET \/users\/{user-id}\/teamwork\/associatedTeams@ +-- +-- Currently, a user can be associated with a team in two different ways: +-- +-- * A user can be a direct member of a team. +-- * A user can be a member of a shared channel that is hosted inside a team. +listUserAssociatedTeams :: Text -- ^ User ID + -> AccessToken -> Req (MSG.Collection Group) +listUserAssociatedTeams uid = MSG.get ["users", uid, "teamwork", "associatedTeams"] mempty + +-- | Get the teams in Microsoft Teams that the current user is associated with (see 'getUserAssociatedTeams'). +listMeAssociatedTeams :: AccessToken -> Req (MSG.Collection Group) +listMeAssociatedTeams = MSG.get ["me", "teamwork", "associatedTeams"] mempty + -- | Get the teams in Microsoft Teams that the given user is a direct member of. -- -- @GET \/users\/{id | user-principal-name}\/joinedTeams@ -- -- https://learn.microsoft.com/en-us/graph/api/user-list-joinedteams?view=graph-rest-1.0&tabs=http -getUserJoinedTeams :: Text -- ^ User ID +listUserJoinedTeams :: Text -- ^ User ID -> AccessToken -> Req (MSG.Collection Group) -getUserJoinedTeams uid = MSG.get ["users", uid, "joinedTeams"] mempty +listUserJoinedTeams uid = MSG.get ["users", uid, "joinedTeams"] mempty -- | Get the teams in Microsoft Teams that the current user is a direct member of. -- -- @GET \/me\/joinedTeams@ -- -- https://learn.microsoft.com/en-us/graph/api/user-list-joinedteams?view=graph-rest-1.0&tabs=http -getMeJoinedTeams :: AccessToken -> Req (MSG.Collection Group) -getMeJoinedTeams = MSG.get ["me", "joinedTeams"] mempty +listMeJoinedTeams :: AccessToken -> Req (MSG.Collection Group) +listMeJoinedTeams = MSG.get ["me", "joinedTeams"] mempty -- | Get the 'DriveItem's in the 'Group' storage, starting from the root item -- @@ -59,9 +161,9 @@ getMeJoinedTeams = MSG.get ["me", "joinedTeams"] mempty -- https://learn.microsoft.com/en-us/graph/api/driveitem-list-children?view=graph-rest-1.0&tabs=http -- -- NB : requires @Files.Read.All@, since it tries to access all files a user has access to. -getGroupsDriveItems :: Text -- ^ Group ID +listGroupsDriveItems :: Text -- ^ Group ID -> AccessToken -> Req (MSG.Collection DriveItem) -getGroupsDriveItems gid = MSG.get ["groups", gid, "drive", "root", "children"] mempty +listGroupsDriveItems gid = MSG.get ["groups", gid, "drive", "root", "children"] mempty -- data X = X { xName :: Text } deriving (Eq, Ord, Show, Generic)