diff --git a/README.md b/README.md index 6b777d5..28a22e9 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,8 @@ We provide separate libraries for authentication (`ms-auth`), Graph (`ms-graph-a ## Examples -* OAuth flow : see `ms-graph-api-test/app/Main.hs` +* OAuth flow : see `ms-graph-api-test/app/Main.hs` +* Azure bot service : see `ms-azure-api-test/app/Main.hs` ## Status diff --git a/ms-azure-api-test/app/Main.hs b/ms-azure-api-test/app/Main.hs index b044e2d..d1b6b1c 100644 --- a/ms-azure-api-test/app/Main.hs +++ b/ms-azure-api-test/app/Main.hs @@ -8,6 +8,9 @@ module Main (main) where import Control.Monad.IO.Class (MonadIO(..)) -- aeson import Data.Aeson (eitherDecode) +import Data.Aeson.Encode.Pretty (encodePretty) +-- bytestring +import qualified Data.ByteString.Lazy.Char8 as LBS8 (pack, unpack, putStrLn) -- dotenv-micro import DotEnv.Micro (loadDotEnv) -- hoauth2 @@ -46,13 +49,13 @@ server :: MonadIO m => m () server = do loadDotEnv Nothing ip <- idpApp - withTLS $ \httpcfg mgr -> do + withTLS $ \hc mgr -> do tv <- tokenUpdateLoop ip mgr let runR r = runReaderT r tv scottyT 3000 runR $ do middleware logStdoutDev - pong tv httpcfg "/pong" + pong tv hc "/pong" pong :: (MonadIO m) => @@ -64,9 +67,11 @@ pong tv hc pth = post pth $ do case m of Nothing -> raise "readToken: found Nothing" Just atok -> do - ei <- run hc $ sendReply acti "It worked!" [] atok + ei <- run hc $ sendReply acti "It works!" [] atok case ei of - Right _ -> status status200 + Right _ -> do + liftIO $ LBS8.putStrLn $ encodePretty acti + status status200 Left e -> raise $ TL.pack (show e) diff --git a/ms-azure-api/ms-azure-api.cabal b/ms-azure-api/ms-azure-api.cabal index 90ae571..18b10f6 100644 --- a/ms-azure-api/ms-azure-api.cabal +++ b/ms-azure-api/ms-azure-api.cabal @@ -1,5 +1,5 @@ name: ms-azure-api -version: 0.6.0.0 +version: 0.6.0.1 synopsis: Microsoft Azure API description: Bindings to the Microsoft Azure API homepage: https://github.com/unfoldml/ms-graph-api diff --git a/ms-azure-api/src/MSAzureAPI/BotService.hs b/ms-azure-api/src/MSAzureAPI/BotService.hs index 67ffd76..2721ac6 100644 --- a/ms-azure-api/src/MSAzureAPI/BotService.hs +++ b/ms-azure-api/src/MSAzureAPI/BotService.hs @@ -1,3 +1,4 @@ +{-# options_ghc -Wno-unused-imports #-} -- | Azure Bot Framework -- -- https://learn.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-connector-quickstart?view=azure-bot-service-4.0 @@ -15,7 +16,7 @@ module MSAzureAPI.BotService ( , TextBlock(..) , ColumnSet(..) , Column(..) - ) where + ) where import Data.Char (toLower) import GHC.Exts (IsString(..)) @@ -31,7 +32,7 @@ import Network.HTTP.Req (HttpException, runReq, HttpConfig, defaultHttpConfig, R -- text import Data.Text (Text, pack, unpack) -import MSAzureAPI.Internal.Common (run, APIPlane(..), Location(..), locationDisplayName, (==:), get, getBs, post, postRaw, getLbs, put, tryReq, aesonOptions) +import MSAzureAPI.Internal.Common (run, APIPlane(..), Location(..), locationDisplayName, (==:), get, getBs, post, postRaw, getLbs, put, tryReq, aesonOptions, say) -- * Send and receive messages with the Bot Framework : https://learn.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-connector-send-and-receive-messages?view=azure-bot-service-4.0 @@ -45,7 +46,8 @@ sendReply :: Activity -- ^ data from the user -> AccessToken -> Req () sendReply acti txt atts atok = case aReplyToId acti of - Nothing -> pure () + Nothing -> do + say "sendReply: replyToId is null" Just aid -> postRaw urib ["v3", "conversations", cid, "activities", aid] mempty actO atok where urib = aServiceUrl acti @@ -68,9 +70,9 @@ mkReplyActivity actI = Activity ATMessage Nothing Nothing conO froO recO surl re -- -- https://learn.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-connector-send-and-receive-messages?view=azure-bot-service-4.0#send-a-non-reply-message sendMessage :: (A.FromJSON b) => - Text - -> Text - -> Activity + Text -- ^ base URI, taken from the @serviceUrl@ property in the incoming 'Activity' object + -> Text -- ^ conversation ID + -> Activity -- ^ message payload -> AccessToken -> Req b sendMessage urib cid = postRaw urib ["v3", "conversations", cid, "activities"] mempty @@ -83,12 +85,12 @@ data Activity = Activity { , aId :: Maybe Text , aChannelId :: Maybe Text , aConversation :: ConversationAccount - , aFrom :: ChannelAccount - , aRecipient :: ChannelAccount + , aFrom :: ChannelAccount -- ^ sender + , aRecipient :: ChannelAccount -- ^ recipient , aServiceUrl :: Text -- ^ URL that specifies the channel's service endpoint. Set by the channel. , aReplyToId :: Maybe Text - , aText :: Text - , aAttachments :: [Attachment] + , aText :: Text -- ^ message text + , aAttachments :: [Attachment] -- ^ message attachments } deriving (Show, Generic) instance A.FromJSON Activity where parseJSON = A.genericParseJSON (aesonOptions "a") diff --git a/ms-azure-api/src/MSAzureAPI/Internal/Common.hs b/ms-azure-api/src/MSAzureAPI/Internal/Common.hs index f74f57f..4ac50df 100644 --- a/ms-azure-api/src/MSAzureAPI/Internal/Common.hs +++ b/ms-azure-api/src/MSAzureAPI/Internal/Common.hs @@ -34,6 +34,8 @@ module MSAzureAPI.Internal.Common ( , locationDisplayName -- ** JSON co\/dec , aesonOptions + -- ** misc + , say ) where import Control.Monad.IO.Class (MonadIO(..)) @@ -293,3 +295,6 @@ recordName pf str = case uncons $ dropPrefix pf str of -- > dropPrefix "Mr. " "Dr. Men" == "Dr. Men" dropPrefix :: Eq a => [a] -> [a] -> [a] dropPrefix a b = fromMaybe b $ stripPrefix a b + +say :: MonadIO m => String -> m () +say = liftIO . putStrLn