diff --git a/ms-graph-api.cabal b/ms-graph-api.cabal index da54222..7d1e385 100644 --- a/ms-graph-api.cabal +++ b/ms-graph-api.cabal @@ -20,8 +20,10 @@ library hs-source-dirs: src exposed-modules: MSGraphAPI.User + MSGraphAPI.Users.User + MSGraphAPI.Users.Group MSGraphAPI.Drive - MSGraphAPI.Files.DriveItems + MSGraphAPI.Files.DriveItem Network.OAuth2.Provider.AzureAD Network.OAuth2.Session MSGraphAPI.Internal.Common diff --git a/src/MSGraphAPI/Files/DriveItems.hs b/src/MSGraphAPI/Files/DriveItem.hs similarity index 78% rename from src/MSGraphAPI/Files/DriveItems.hs rename to src/MSGraphAPI/Files/DriveItem.hs index 299d109..1c48894 100644 --- a/src/MSGraphAPI/Files/DriveItems.hs +++ b/src/MSGraphAPI/Files/DriveItem.hs @@ -1,4 +1,4 @@ -module MSGraphAPI.Files.DriveItems where +module MSGraphAPI.Files.DriveItem where import GHC.Generics (Generic(..)) @@ -12,9 +12,20 @@ import Network.OAuth.OAuth2.Internal (AccessToken(..)) import Network.HTTP.Req (Req) -- text import Data.Text (Text, pack, unpack) +-- time +import Data.Time (LocalTime) import qualified MSGraphAPI.Internal.Common as MSG (get, getLbs, post, Collection, aesonOptions) +data DriveItem = DriveItem { + diId :: Text + , diName :: Text + , diLastModifiedDateTime :: LocalTime + } deriving (Eq, Ord, Show, Generic) +instance A.FromJSON DriveItem where + parseJSON = A.genericParseJSON (MSG.aesonOptions "di") + + -- | download a complete file from user's directory -- -- @GET \/me\/drive\/items\/{item-id}\/content@ diff --git a/src/MSGraphAPI/User.hs b/src/MSGraphAPI/User.hs index 2a66c82..f29e78e 100644 --- a/src/MSGraphAPI/User.hs +++ b/src/MSGraphAPI/User.hs @@ -1,57 +1,35 @@ module MSGraphAPI.User where -import GHC.Generics (Generic(..)) - -import Data.List (sort, sortBy, stripPrefix, uncons) -import Data.Maybe (listToMaybe, fromMaybe) --- import Data.Ord (comparing) -import Data.Char (toLower) -import Data.String (IsString(..)) -import Data.Word (Word) - --- aeson -import qualified Data.Aeson as A (ToJSON(..), FromJSON(..), genericParseJSON, defaultOptions, Options(..), withObject, withText, (.:), (.:?), object, (.=), Key, Value, camelTo2) -import qualified Data.Aeson.Types as A (Parser, Object) --- import qualified Data.Aeson.KeyMap as AKV (KeyMap, lookup) --- containers --- import qualified Data.Map as M (Map, empty, insert, lookup) --- hoauth -import Network.OAuth.OAuth2.Internal (AccessToken(..)) --- req -import Network.HTTP.Req (Req) --- text -import Data.Text (Text, pack, unpack) --- time -import Data.Time.LocalTime (ZonedTime, zonedTimeToLocalTime) - -import qualified MSGraphAPI.Internal.Common as MSG (get, post, aesonOptions) - --- | Get user information --- --- @GET \/users\/{user-id}@ --- --- https://learn.microsoft.com/en-us/graph/api/user-get?view=graph-rest-1.0&tabs=http#request -get :: Text -- ^ user id - -> AccessToken -> Req User -get uid = MSG.get ["users", uid] mempty - --- | Get information on signed-in user --- --- Calling the \/me endpoint requires a signed-in user and therefore a delegated permission. Application permissions are not supported when using the \/me endpoint. --- --- @GET \/me@ --- --- https://learn.microsoft.com/en-us/graph/api/user-get?view=graph-rest-1.0&tabs=http#request-1 -getMe :: AccessToken -> Req User -getMe = MSG.get ["me"] mempty - - -data User = User { - uId :: Text - , uUserPrincipalName :: Text - , uDisplayName :: Text - } deriving (Eq, Ord, Show, Generic) -instance A.FromJSON User where - parseJSON = A.genericParseJSON (MSG.aesonOptions "u") + + +-- import Data.List (sort, sortBy, stripPrefix, uncons) +-- import Data.Maybe (listToMaybe, fromMaybe) +-- -- import Data.Ord (comparing) +-- import Data.Char (toLower) +-- import Data.String (IsString(..)) +-- import Data.Word (Word) + +-- -- aeson +-- import qualified Data.Aeson as A (ToJSON(..), FromJSON(..), genericParseJSON, defaultOptions, Options(..), withObject, withText, (.:), (.:?), object, (.=), Key, Value, camelTo2) +-- import qualified Data.Aeson.Types as A (Parser, Object) +-- -- import qualified Data.Aeson.KeyMap as AKV (KeyMap, lookup) +-- -- containers +-- -- import qualified Data.Map as M (Map, empty, insert, lookup) +-- -- hoauth +-- import Network.OAuth.OAuth2.Internal (AccessToken(..)) +-- -- req +-- import Network.HTTP.Req (Req) +-- -- text +-- import Data.Text (Text, pack, unpack) +-- -- time +-- import Data.Time.LocalTime (ZonedTime, zonedTimeToLocalTime) + +-- import qualified MSGraphAPI.Internal.Common as MSG (get, post, aesonOptions) +-- -- import MSGraphAPI.Users.User (User) + + + + + diff --git a/src/MSGraphAPI/Users/Group.hs b/src/MSGraphAPI/Users/Group.hs new file mode 100644 index 0000000..3098006 --- /dev/null +++ b/src/MSGraphAPI/Users/Group.hs @@ -0,0 +1,55 @@ +-- | User +module MSGraphAPI.Users.Group where + +import GHC.Generics (Generic(..)) + +-- aeson +import qualified Data.Aeson as A (ToJSON(..), FromJSON(..), eitherDecode, genericParseJSON, defaultOptions, Options(..), withObject, withText, (.:), (.:?), object, (.=)) +-- hoauth +import Network.OAuth.OAuth2.Internal (AccessToken(..)) +-- req +import Network.HTTP.Req (Req) +-- text +import Data.Text (Text, pack, unpack) + +import qualified MSGraphAPI.Internal.Common as MSG (Collection(..), get, post, aesonOptions) +import MSGraphAPI.Files.DriveItem (DriveItem) + +-- | Groups are collections of principals with shared access to resources in Microsoft services or in your app. Different principals such as users, other groups, devices, and applications can be part of groups. +-- +-- httpstea://learn.microsoft.com/en-us/graph/api/resources/groups-overview?view=graph-rest-1.0&tabs=http +data Group = Group { + gId :: Text + , gDisplayName :: Text + , gDescription :: Text + } deriving (Eq, Ord, Show, Generic) +instance A.FromJSON Group where + parseJSON = A.genericParseJSON (MSG.aesonOptions "g") + +-- | Get the teams in Microsoft Teams that the 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 + -> AccessToken -> Req (MSG.Collection Group) +getUserJoinedTeams uid = MSG.get ["users", uid, "joinedTeams"] mempty + +-- | Get the 'DriveItem's in the 'Group' storage, starting from the root item +-- +-- @GET \/groups\/{group-id}\/drive\/root\/children@ +-- +-- https://learn.microsoft.com/en-us/graph/api/driveitem-list-children?view=graph-rest-1.0&tabs=http +getGroupsDriveItems :: Text -- ^ Group ID + -> AccessToken -> Req (MSG.Collection DriveItem) +getGroupsDriveItems gid = MSG.get ["groups", gid, "drive", "root", "children"] mempty + + +-- data X = X { xName :: Text } deriving (Eq, Ord, Show, Generic) +-- instance A.FromJSON X where +-- parseJSON = A.genericParseJSON (MSG.aesonOptions "x") + +-- pt0 :: Either String (MSG.Collection DriveItem) +-- pt0 = A.eitherDecode t0 +-- where +-- t0 = "{\r\n \"value\": [\r\n {\"name\": \"myfile.jpg\" },\r\n {\"name\": \"Documents\" },\r\n {\"name\": \"Photos\" },\r\n {\"name\": \"my sheet(1).xlsx\"}\r\n ]\r\n}" diff --git a/src/MSGraphAPI/Users/User.hs b/src/MSGraphAPI/Users/User.hs new file mode 100644 index 0000000..4518895 --- /dev/null +++ b/src/MSGraphAPI/Users/User.hs @@ -0,0 +1,44 @@ +-- | User +module MSGraphAPI.Users.User where + +import GHC.Generics (Generic(..)) + +-- aeson +import qualified Data.Aeson as A (ToJSON(..), FromJSON(..), genericParseJSON, defaultOptions, Options(..), withObject, withText, (.:), (.:?), object, (.=)) +-- hoauth +import Network.OAuth.OAuth2.Internal (AccessToken(..)) +-- req +import Network.HTTP.Req (Req) +-- text +import Data.Text (Text, pack, unpack) + +import qualified MSGraphAPI.Internal.Common as MSG (get, post, aesonOptions) + + +data User = User { + uId :: Text + , uUserPrincipalName :: Text + , uDisplayName :: Text + } deriving (Eq, Ord, Show, Generic) +instance A.FromJSON User where + parseJSON = A.genericParseJSON (MSG.aesonOptions "u") + + +-- | Get user information +-- +-- @GET \/users\/{user-id}@ +-- +-- https://learn.microsoft.com/en-us/graph/api/user-get?view=graph-rest-1.0&tabs=http#request +get :: Text -- ^ user id + -> AccessToken -> Req User +get uid = MSG.get ["users", uid] mempty + +-- | Get information on signed-in user +-- +-- Calling the \/me endpoint requires a signed-in user and therefore a delegated permission. Application permissions are not supported when using the \/me endpoint. +-- +-- @GET \/me@ +-- +-- https://learn.microsoft.com/en-us/graph/api/user-get?view=graph-rest-1.0&tabs=http#request-1 +getMe :: AccessToken -> Req User +getMe = MSG.get ["me"] mempty diff --git a/src/Network/OAuth2/Provider/AzureAD.hs b/src/Network/OAuth2/Provider/AzureAD.hs index e436726..b629272 100644 --- a/src/Network/OAuth2/Provider/AzureAD.hs +++ b/src/Network/OAuth2/Provider/AzureAD.hs @@ -45,6 +45,8 @@ data OAuthCfg = OAuthCfg { } -- | NB : scopes @openid@ and @offline_access@ are ALWAYS requested since the library assumes we have access to refresh tokens and ID tokens +-- +-- Reference on Microsoft Graph permissions : https://learn.microsoft.com/en-us/graph/permissions-reference azureADApp :: OAuthCfg -- ^ OAuth configuration -> IdpApplication 'AuthorizationCode AzureAD azureADApp (OAuthCfg appname clid sec scopes authstate reduri) = defaultAzureADApp{