line-bot-sdk 0.1.0.0 → 0.2.0.0
raw patch · 9 files changed
+412/−338 lines, 9 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Line.Bot.Client: Action :: Maybe URL -> Action -> QuickReplyButton
- Line.Bot.Client: ActionCamera :: Text -> Action
- Line.Bot.Client: ActionCameraRoll :: Text -> Action
- Line.Bot.Client: ActionLocation :: Text -> Action
- Line.Bot.Client: ActionMessage :: Text -> Text -> Action
- Line.Bot.Client: ActionPostback :: Text -> Text -> Text -> Action
- Line.Bot.Client: ActionURI :: Text -> Text -> Action
- Line.Bot.Client: Audio :: URL -> Int -> Maybe QuickReply -> Message
- Line.Bot.Client: ChannelToken :: Text -> ChannelToken
- Line.Bot.Client: Group :: ChatType
- Line.Bot.Client: Image :: URL -> URL -> Maybe QuickReply -> Message
- Line.Bot.Client: Location :: Text -> Text -> Double -> Double -> Maybe QuickReply -> Message
- Line.Bot.Client: MulticastMessageBody :: [Id User] -> [Message] -> MulticastMessageBody
- Line.Bot.Client: Profile :: Text -> Id User -> URL -> Maybe Text -> Profile
- Line.Bot.Client: PushMessageBody :: Id a -> [Message] -> PushMessageBody
- Line.Bot.Client: QuickReply :: [QuickReplyButton] -> QuickReply
- Line.Bot.Client: ReplyMessageBody :: ReplyToken -> [Message] -> ReplyMessageBody
- Line.Bot.Client: ReplyToken :: Text -> ReplyToken
- Line.Bot.Client: Room :: ChatType
- Line.Bot.Client: Sticker :: Text -> Text -> Maybe QuickReply -> Message
- Line.Bot.Client: Text :: Text -> Maybe QuickReply -> Message
- Line.Bot.Client: URL :: Text -> URL
- Line.Bot.Client: User :: ChatType
- Line.Bot.Client: Video :: URL -> URL -> Maybe QuickReply -> Message
- Line.Bot.Client: [$sel:action:Action] :: QuickReplyButton -> Action
- Line.Bot.Client: [$sel:address:Text] :: Message -> Text
- Line.Bot.Client: [$sel:displayName:Profile] :: Profile -> Text
- Line.Bot.Client: [$sel:displayText:ActionPostback] :: Action -> Text
- Line.Bot.Client: [$sel:duration:Text] :: Message -> Int
- Line.Bot.Client: [$sel:imageUrl:Action] :: QuickReplyButton -> Maybe URL
- Line.Bot.Client: [$sel:items:QuickReply] :: QuickReply -> [QuickReplyButton]
- Line.Bot.Client: [$sel:label:ActionPostback] :: Action -> Text
- Line.Bot.Client: [$sel:latitude:Text] :: Message -> Double
- Line.Bot.Client: [$sel:longitude:Text] :: Message -> Double
- Line.Bot.Client: [$sel:originalContentUrl:Text] :: Message -> URL
- Line.Bot.Client: [$sel:packageId:Text] :: Message -> Text
- Line.Bot.Client: [$sel:pictureUrl:Profile] :: Profile -> URL
- Line.Bot.Client: [$sel:postbackData:ActionPostback] :: Action -> Text
- Line.Bot.Client: [$sel:previewImageUrl:Text] :: Message -> URL
- Line.Bot.Client: [$sel:quickReply:Text] :: Message -> Maybe QuickReply
- Line.Bot.Client: [$sel:statusMessage:Profile] :: Profile -> Maybe Text
- Line.Bot.Client: [$sel:stickerId:Text] :: Message -> Text
- Line.Bot.Client: [$sel:text:ActionPostback] :: Action -> Text
- Line.Bot.Client: [$sel:text:Text] :: Message -> Text
- Line.Bot.Client: [$sel:title:Text] :: Message -> Text
- Line.Bot.Client: [$sel:uri:ActionPostback] :: Action -> Text
- Line.Bot.Client: [$sel:userId:Profile] :: Profile -> Id User
- Line.Bot.Client: [GroupId] :: Text -> Id Group
- Line.Bot.Client: [RoomId] :: Text -> Id Room
- Line.Bot.Client: [UserId] :: Text -> Id User
- Line.Bot.Client: data Action
- Line.Bot.Client: data ChatType
- Line.Bot.Client: data Id :: ChatType -> *
- Line.Bot.Client: data Message
- Line.Bot.Client: data MulticastMessageBody
- Line.Bot.Client: data Profile
- Line.Bot.Client: data PushMessageBody
- Line.Bot.Client: data QuickReply
- Line.Bot.Client: data QuickReplyButton
- Line.Bot.Client: data ReplyMessageBody
- Line.Bot.Client: instance Data.String.IsString Line.Bot.Client.ChannelToken
- Line.Bot.Client: instance GHC.Classes.Eq Line.Bot.Client.ChannelToken
- Line.Bot.Client: instance Web.Internal.HttpApiData.ToHttpApiData Line.Bot.Client.ChannelToken
- Line.Bot.Client: newtype ChannelToken
- Line.Bot.Client: newtype ReplyToken
- Line.Bot.Client: newtype URL
- Line.Bot.Webhook: AccountLink :: Text -> AccountLinkResult -> AccountLink
- Line.Bot.Webhook: Audio :: Text -> Int -> ContentProvider -> Message
- Line.Bot.Webhook: Banner :: BeaconEvent
- Line.Bot.Webhook: Beacon :: Text -> BeaconEvent -> Maybe Text -> Beacon
- Line.Bot.Webhook: ChannelSecret :: ByteString -> ChannelSecret
- Line.Bot.Webhook: Enter :: BeaconEvent
- Line.Bot.Webhook: EpochMilli :: UTCTime -> EpochMilli
- Line.Bot.Webhook: EventAccountLink :: ReplyToken -> Source -> EpochMilli -> AccountLink -> Event
- Line.Bot.Webhook: EventBeacon :: ReplyToken -> Source -> EpochMilli -> Beacon -> Event
- Line.Bot.Webhook: EventFollow :: ReplyToken -> Source -> EpochMilli -> Event
- Line.Bot.Webhook: EventJoin :: ReplyToken -> Source -> EpochMilli -> Event
- Line.Bot.Webhook: EventLeave :: Source -> EpochMilli -> Event
- Line.Bot.Webhook: EventMemberJoined :: ReplyToken -> Source -> EpochMilli -> Members -> Event
- Line.Bot.Webhook: EventMemberLeft :: Source -> EpochMilli -> Members -> Event
- Line.Bot.Webhook: EventMessage :: ReplyToken -> Message -> Source -> EpochMilli -> Event
- Line.Bot.Webhook: EventPostback :: ReplyToken -> Source -> EpochMilli -> Postback -> Event
- Line.Bot.Webhook: EventThings :: ReplyToken -> Source -> EpochMilli -> Things -> Event
- Line.Bot.Webhook: EventUnfollow :: Source -> EpochMilli -> Event
- Line.Bot.Webhook: Events :: Id User -> [Event] -> Events
- Line.Bot.Webhook: Failed :: AccountLinkResult
- Line.Bot.Webhook: File :: Text -> Int -> Text -> Message
- Line.Bot.Webhook: Image :: Text -> ContentProvider -> Message
- Line.Bot.Webhook: Leave :: BeaconEvent
- Line.Bot.Webhook: Link :: ThingsEvent
- Line.Bot.Webhook: Location :: Text -> Text -> Text -> Double -> Double -> Message
- Line.Bot.Webhook: Members :: [Source] -> Members
- Line.Bot.Webhook: Ok :: AccountLinkResult
- Line.Bot.Webhook: Postback :: Text -> PostbackDateTime -> Postback
- Line.Bot.Webhook: SourceGroup :: Id Group -> Maybe (Id User) -> Source
- Line.Bot.Webhook: SourceRoom :: Id Room -> Maybe (Id User) -> Source
- Line.Bot.Webhook: SourceUser :: Id User -> Source
- Line.Bot.Webhook: Sticker :: Text -> Text -> Text -> Message
- Line.Bot.Webhook: Text :: Text -> Text -> Message
- Line.Bot.Webhook: Things :: Text -> ThingsEvent -> Things
- Line.Bot.Webhook: Unlink :: ThingsEvent
- Line.Bot.Webhook: Video :: Text -> Int -> ContentProvider -> Message
- Line.Bot.Webhook: [$sel:address:Text] :: Message -> Text
- Line.Bot.Webhook: [$sel:beacon:EventMessage] :: Event -> Beacon
- Line.Bot.Webhook: [$sel:contentProvider:Text] :: Message -> ContentProvider
- Line.Bot.Webhook: [$sel:destination:Events] :: Events -> Id User
- Line.Bot.Webhook: [$sel:deviceId:Things] :: Things -> Text
- Line.Bot.Webhook: [$sel:dm:Beacon] :: Beacon -> Maybe Text
- Line.Bot.Webhook: [$sel:duration:Text] :: Message -> Int
- Line.Bot.Webhook: [$sel:eventType:Beacon] :: Beacon -> BeaconEvent
- Line.Bot.Webhook: [$sel:eventType:Things] :: Things -> ThingsEvent
- Line.Bot.Webhook: [$sel:events:Events] :: Events -> [Event]
- Line.Bot.Webhook: [$sel:fileName:Text] :: Message -> Text
- Line.Bot.Webhook: [$sel:fileSize:Text] :: Message -> Int
- Line.Bot.Webhook: [$sel:fromEpochMilli:EpochMilli] :: EpochMilli -> UTCTime
- Line.Bot.Webhook: [$sel:hwid:Beacon] :: Beacon -> Text
- Line.Bot.Webhook: [$sel:joined:EventMessage] :: Event -> Members
- Line.Bot.Webhook: [$sel:latitude:Text] :: Message -> Double
- Line.Bot.Webhook: [$sel:left:EventMessage] :: Event -> Members
- Line.Bot.Webhook: [$sel:link:EventMessage] :: Event -> AccountLink
- Line.Bot.Webhook: [$sel:longitude:Text] :: Message -> Double
- Line.Bot.Webhook: [$sel:members:Members] :: Members -> [Source]
- Line.Bot.Webhook: [$sel:message:EventMessage] :: Event -> Message
- Line.Bot.Webhook: [$sel:messageId:Text] :: Message -> Text
- Line.Bot.Webhook: [$sel:nonce:AccountLink] :: AccountLink -> Text
- Line.Bot.Webhook: [$sel:packageId:Text] :: Message -> Text
- Line.Bot.Webhook: [$sel:postback:EventMessage] :: Event -> Postback
- Line.Bot.Webhook: [$sel:replyToken:EventMessage] :: Event -> ReplyToken
- Line.Bot.Webhook: [$sel:result:AccountLink] :: AccountLink -> AccountLinkResult
- Line.Bot.Webhook: [$sel:source:EventMessage] :: Event -> Source
- Line.Bot.Webhook: [$sel:stickerId:Text] :: Message -> Text
- Line.Bot.Webhook: [$sel:text:Text] :: Message -> Text
- Line.Bot.Webhook: [$sel:things:EventMessage] :: Event -> Things
- Line.Bot.Webhook: [$sel:timestamp:EventMessage] :: Event -> EpochMilli
- Line.Bot.Webhook: [$sel:title:Text] :: Message -> Text
- Line.Bot.Webhook: [$sel:unChannelSecret:ChannelSecret] :: ChannelSecret -> ByteString
- Line.Bot.Webhook: data AccountLink
- Line.Bot.Webhook: data AccountLinkResult
- Line.Bot.Webhook: data Beacon
- Line.Bot.Webhook: data BeaconEvent
- Line.Bot.Webhook: data Event
- Line.Bot.Webhook: data Events
- Line.Bot.Webhook: data Members
- Line.Bot.Webhook: data Message
- Line.Bot.Webhook: data Postback
- Line.Bot.Webhook: data Source
- Line.Bot.Webhook: data Things
- Line.Bot.Webhook: data ThingsEvent
- Line.Bot.Webhook: instance (Servant.API.ContentTypes.AllCTUnrender list a, Servant.Server.Internal.HasServer api context, Servant.Server.Internal.Context.HasContextEntry context Line.Bot.Webhook.Types.ChannelSecret) => Servant.Server.Internal.HasServer (Line.Bot.Webhook.LineReqBody list a Servant.API.Sub.:> api) context
- Line.Bot.Webhook: newtype ChannelSecret
- Line.Bot.Webhook: newtype EpochMilli
+ Line.Bot.Client: getContent :: String -> Line ByteString
+ Line.Bot.Client: issueLinkToken :: Id User -> Line LinkToken
+ Line.Bot.Client: runLineWith :: (ClientM a -> IO (Either ServantError a)) -> Line a -> ChannelToken -> IO (Either ServantError a)
+ Line.Bot.Types: Action :: Maybe URL -> Action -> QuickReplyButton
+ Line.Bot.Types: ActionCamera :: Text -> Action
+ Line.Bot.Types: ActionCameraRoll :: Text -> Action
+ Line.Bot.Types: ActionLocation :: Text -> Action
+ Line.Bot.Types: ActionMessage :: Text -> Text -> Action
+ Line.Bot.Types: ActionPostback :: Text -> Text -> Text -> Action
+ Line.Bot.Types: ActionURI :: Text -> Text -> Action
+ Line.Bot.Types: Audio :: URL -> Int -> Maybe QuickReply -> Message
+ Line.Bot.Types: ChannelSecret :: ByteString -> ChannelSecret
+ Line.Bot.Types: ChannelToken :: Text -> ChannelToken
+ Line.Bot.Types: Group :: ChatType
+ Line.Bot.Types: Image :: URL -> URL -> Maybe QuickReply -> Message
+ Line.Bot.Types: LinkToken :: Text -> LinkToken
+ Line.Bot.Types: Location :: Text -> Text -> Double -> Double -> Maybe QuickReply -> Message
+ Line.Bot.Types: MulticastMessageBody :: [Id User] -> [Message] -> MulticastMessageBody
+ Line.Bot.Types: Profile :: Text -> Id User -> URL -> Maybe Text -> Profile
+ Line.Bot.Types: PushMessageBody :: Id a -> [Message] -> PushMessageBody
+ Line.Bot.Types: QuickReply :: [QuickReplyButton] -> QuickReply
+ Line.Bot.Types: ReplyMessageBody :: ReplyToken -> [Message] -> ReplyMessageBody
+ Line.Bot.Types: ReplyToken :: Text -> ReplyToken
+ Line.Bot.Types: Room :: ChatType
+ Line.Bot.Types: Sticker :: Text -> Text -> Maybe QuickReply -> Message
+ Line.Bot.Types: Text :: Text -> Maybe QuickReply -> Message
+ Line.Bot.Types: URL :: Text -> URL
+ Line.Bot.Types: User :: ChatType
+ Line.Bot.Types: Video :: URL -> URL -> Maybe QuickReply -> Message
+ Line.Bot.Types: [$sel:action:Action] :: QuickReplyButton -> Action
+ Line.Bot.Types: [$sel:address:Text] :: Message -> Text
+ Line.Bot.Types: [$sel:displayName:Profile] :: Profile -> Text
+ Line.Bot.Types: [$sel:displayText:ActionPostback] :: Action -> Text
+ Line.Bot.Types: [$sel:duration:Text] :: Message -> Int
+ Line.Bot.Types: [$sel:imageUrl:Action] :: QuickReplyButton -> Maybe URL
+ Line.Bot.Types: [$sel:items:QuickReply] :: QuickReply -> [QuickReplyButton]
+ Line.Bot.Types: [$sel:label:ActionPostback] :: Action -> Text
+ Line.Bot.Types: [$sel:latitude:Text] :: Message -> Double
+ Line.Bot.Types: [$sel:linkToken:LinkToken] :: LinkToken -> Text
+ Line.Bot.Types: [$sel:longitude:Text] :: Message -> Double
+ Line.Bot.Types: [$sel:originalContentUrl:Text] :: Message -> URL
+ Line.Bot.Types: [$sel:packageId:Text] :: Message -> Text
+ Line.Bot.Types: [$sel:pictureUrl:Profile] :: Profile -> URL
+ Line.Bot.Types: [$sel:postbackData:ActionPostback] :: Action -> Text
+ Line.Bot.Types: [$sel:previewImageUrl:Text] :: Message -> URL
+ Line.Bot.Types: [$sel:quickReply:Text] :: Message -> Maybe QuickReply
+ Line.Bot.Types: [$sel:statusMessage:Profile] :: Profile -> Maybe Text
+ Line.Bot.Types: [$sel:stickerId:Text] :: Message -> Text
+ Line.Bot.Types: [$sel:text:ActionPostback] :: Action -> Text
+ Line.Bot.Types: [$sel:text:Text] :: Message -> Text
+ Line.Bot.Types: [$sel:title:Text] :: Message -> Text
+ Line.Bot.Types: [$sel:unChannelSecret:ChannelSecret] :: ChannelSecret -> ByteString
+ Line.Bot.Types: [$sel:uri:ActionPostback] :: Action -> Text
+ Line.Bot.Types: [$sel:userId:Profile] :: Profile -> Id User
+ Line.Bot.Types: [GroupId] :: Text -> Id Group
+ Line.Bot.Types: [RoomId] :: Text -> Id Room
+ Line.Bot.Types: [UserId] :: Text -> Id User
+ Line.Bot.Types: data Action
+ Line.Bot.Types: data ChatType
+ Line.Bot.Types: data Id :: ChatType -> *
+ Line.Bot.Types: data LinkToken
+ Line.Bot.Types: data Message
+ Line.Bot.Types: data MulticastMessageBody
+ Line.Bot.Types: data Profile
+ Line.Bot.Types: data PushMessageBody
+ Line.Bot.Types: data QuickReply
+ Line.Bot.Types: data QuickReplyButton
+ Line.Bot.Types: data ReplyMessageBody
+ Line.Bot.Types: instance Data.Aeson.Types.FromJSON.FromJSON (Line.Bot.Types.Id 'Line.Bot.Types.Group)
+ Line.Bot.Types: instance Data.Aeson.Types.FromJSON.FromJSON (Line.Bot.Types.Id 'Line.Bot.Types.Room)
+ Line.Bot.Types: instance Data.Aeson.Types.FromJSON.FromJSON (Line.Bot.Types.Id 'Line.Bot.Types.User)
+ Line.Bot.Types: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Types.LinkToken
+ Line.Bot.Types: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Types.Profile
+ Line.Bot.Types: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Types.ReplyToken
+ Line.Bot.Types: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Types.URL
+ Line.Bot.Types: instance Data.Aeson.Types.ToJSON.ToJSON (Line.Bot.Types.Id a)
+ Line.Bot.Types: instance Data.Aeson.Types.ToJSON.ToJSON Line.Bot.Types.Action
+ Line.Bot.Types: instance Data.Aeson.Types.ToJSON.ToJSON Line.Bot.Types.Message
+ Line.Bot.Types: instance Data.Aeson.Types.ToJSON.ToJSON Line.Bot.Types.MulticastMessageBody
+ Line.Bot.Types: instance Data.Aeson.Types.ToJSON.ToJSON Line.Bot.Types.PushMessageBody
+ Line.Bot.Types: instance Data.Aeson.Types.ToJSON.ToJSON Line.Bot.Types.QuickReply
+ Line.Bot.Types: instance Data.Aeson.Types.ToJSON.ToJSON Line.Bot.Types.QuickReplyButton
+ Line.Bot.Types: instance Data.Aeson.Types.ToJSON.ToJSON Line.Bot.Types.ReplyMessageBody
+ Line.Bot.Types: instance Data.Aeson.Types.ToJSON.ToJSON Line.Bot.Types.ReplyToken
+ Line.Bot.Types: instance Data.Aeson.Types.ToJSON.ToJSON Line.Bot.Types.URL
+ Line.Bot.Types: instance Data.String.IsString Line.Bot.Types.ChannelSecret
+ Line.Bot.Types: instance Data.String.IsString Line.Bot.Types.ChannelToken
+ Line.Bot.Types: instance GHC.Classes.Eq (Line.Bot.Types.Id a)
+ Line.Bot.Types: instance GHC.Classes.Eq Line.Bot.Types.Action
+ Line.Bot.Types: instance GHC.Classes.Eq Line.Bot.Types.ChannelToken
+ Line.Bot.Types: instance GHC.Classes.Eq Line.Bot.Types.LinkToken
+ Line.Bot.Types: instance GHC.Classes.Eq Line.Bot.Types.Message
+ Line.Bot.Types: instance GHC.Classes.Eq Line.Bot.Types.QuickReply
+ Line.Bot.Types: instance GHC.Classes.Eq Line.Bot.Types.QuickReplyButton
+ Line.Bot.Types: instance GHC.Classes.Eq Line.Bot.Types.ReplyToken
+ Line.Bot.Types: instance GHC.Classes.Eq Line.Bot.Types.URL
+ Line.Bot.Types: instance GHC.Generics.Generic Line.Bot.Types.Action
+ Line.Bot.Types: instance GHC.Generics.Generic Line.Bot.Types.LinkToken
+ Line.Bot.Types: instance GHC.Generics.Generic Line.Bot.Types.Message
+ Line.Bot.Types: instance GHC.Generics.Generic Line.Bot.Types.MulticastMessageBody
+ Line.Bot.Types: instance GHC.Generics.Generic Line.Bot.Types.Profile
+ Line.Bot.Types: instance GHC.Generics.Generic Line.Bot.Types.QuickReply
+ Line.Bot.Types: instance GHC.Generics.Generic Line.Bot.Types.QuickReplyButton
+ Line.Bot.Types: instance GHC.Generics.Generic Line.Bot.Types.ReplyMessageBody
+ Line.Bot.Types: instance GHC.Generics.Generic Line.Bot.Types.ReplyToken
+ Line.Bot.Types: instance GHC.Generics.Generic Line.Bot.Types.URL
+ Line.Bot.Types: instance GHC.Show.Show (Line.Bot.Types.Id a)
+ Line.Bot.Types: instance GHC.Show.Show Line.Bot.Types.Action
+ Line.Bot.Types: instance GHC.Show.Show Line.Bot.Types.LinkToken
+ Line.Bot.Types: instance GHC.Show.Show Line.Bot.Types.Message
+ Line.Bot.Types: instance GHC.Show.Show Line.Bot.Types.MulticastMessageBody
+ Line.Bot.Types: instance GHC.Show.Show Line.Bot.Types.Profile
+ Line.Bot.Types: instance GHC.Show.Show Line.Bot.Types.PushMessageBody
+ Line.Bot.Types: instance GHC.Show.Show Line.Bot.Types.QuickReply
+ Line.Bot.Types: instance GHC.Show.Show Line.Bot.Types.QuickReplyButton
+ Line.Bot.Types: instance GHC.Show.Show Line.Bot.Types.ReplyMessageBody
+ Line.Bot.Types: instance GHC.Show.Show Line.Bot.Types.ReplyToken
+ Line.Bot.Types: instance GHC.Show.Show Line.Bot.Types.URL
+ Line.Bot.Types: instance Web.Internal.HttpApiData.ToHttpApiData (Line.Bot.Types.Id a)
+ Line.Bot.Types: instance Web.Internal.HttpApiData.ToHttpApiData Line.Bot.Types.ChannelToken
+ Line.Bot.Types: newtype ChannelSecret
+ Line.Bot.Types: newtype ChannelToken
+ Line.Bot.Types: newtype ReplyToken
+ Line.Bot.Types: newtype URL
+ Line.Bot.Webhook: instance (Servant.API.ContentTypes.AllCTUnrender list a, Servant.Server.Internal.HasServer api context, Servant.Server.Internal.Context.HasContextEntry context Line.Bot.Types.ChannelSecret) => Servant.Server.Internal.HasServer (Line.Bot.Webhook.LineReqBody list a Servant.API.Sub.:> api) context
+ Line.Bot.Webhook.Events: AccountLink :: Text -> AccountLinkResult -> AccountLink
+ Line.Bot.Webhook.Events: Audio :: Text -> Int -> ContentProvider -> Message
+ Line.Bot.Webhook.Events: Banner :: BeaconEvent
+ Line.Bot.Webhook.Events: Beacon :: Text -> BeaconEvent -> Maybe Text -> Beacon
+ Line.Bot.Webhook.Events: Enter :: BeaconEvent
+ Line.Bot.Webhook.Events: EpochMilli :: UTCTime -> EpochMilli
+ Line.Bot.Webhook.Events: EventAccountLink :: ReplyToken -> Source -> EpochMilli -> AccountLink -> Event
+ Line.Bot.Webhook.Events: EventBeacon :: ReplyToken -> Source -> EpochMilli -> Beacon -> Event
+ Line.Bot.Webhook.Events: EventFollow :: ReplyToken -> Source -> EpochMilli -> Event
+ Line.Bot.Webhook.Events: EventJoin :: ReplyToken -> Source -> EpochMilli -> Event
+ Line.Bot.Webhook.Events: EventLeave :: Source -> EpochMilli -> Event
+ Line.Bot.Webhook.Events: EventMemberJoined :: ReplyToken -> Source -> EpochMilli -> Members -> Event
+ Line.Bot.Webhook.Events: EventMemberLeft :: Source -> EpochMilli -> Members -> Event
+ Line.Bot.Webhook.Events: EventMessage :: ReplyToken -> Message -> Source -> EpochMilli -> Event
+ Line.Bot.Webhook.Events: EventPostback :: ReplyToken -> Source -> EpochMilli -> Postback -> Event
+ Line.Bot.Webhook.Events: EventThings :: ReplyToken -> Source -> EpochMilli -> Things -> Event
+ Line.Bot.Webhook.Events: EventUnfollow :: Source -> EpochMilli -> Event
+ Line.Bot.Webhook.Events: Events :: Id User -> [Event] -> Events
+ Line.Bot.Webhook.Events: Failed :: AccountLinkResult
+ Line.Bot.Webhook.Events: File :: Text -> Int -> Text -> Message
+ Line.Bot.Webhook.Events: Image :: Text -> ContentProvider -> Message
+ Line.Bot.Webhook.Events: Leave :: BeaconEvent
+ Line.Bot.Webhook.Events: Link :: ThingsEvent
+ Line.Bot.Webhook.Events: Location :: Text -> Text -> Text -> Double -> Double -> Message
+ Line.Bot.Webhook.Events: Members :: [Source] -> Members
+ Line.Bot.Webhook.Events: Ok :: AccountLinkResult
+ Line.Bot.Webhook.Events: Postback :: Text -> PostbackDateTime -> Postback
+ Line.Bot.Webhook.Events: SourceGroup :: Id Group -> Maybe (Id User) -> Source
+ Line.Bot.Webhook.Events: SourceRoom :: Id Room -> Maybe (Id User) -> Source
+ Line.Bot.Webhook.Events: SourceUser :: Id User -> Source
+ Line.Bot.Webhook.Events: Sticker :: Text -> Text -> Text -> Message
+ Line.Bot.Webhook.Events: Text :: Text -> Text -> Message
+ Line.Bot.Webhook.Events: Things :: Text -> ThingsEvent -> Things
+ Line.Bot.Webhook.Events: Unlink :: ThingsEvent
+ Line.Bot.Webhook.Events: Video :: Text -> Int -> ContentProvider -> Message
+ Line.Bot.Webhook.Events: [$sel:address:Text] :: Message -> Text
+ Line.Bot.Webhook.Events: [$sel:beacon:EventMessage] :: Event -> Beacon
+ Line.Bot.Webhook.Events: [$sel:contentProvider:Text] :: Message -> ContentProvider
+ Line.Bot.Webhook.Events: [$sel:destination:Events] :: Events -> Id User
+ Line.Bot.Webhook.Events: [$sel:deviceId:Things] :: Things -> Text
+ Line.Bot.Webhook.Events: [$sel:dm:Beacon] :: Beacon -> Maybe Text
+ Line.Bot.Webhook.Events: [$sel:duration:Text] :: Message -> Int
+ Line.Bot.Webhook.Events: [$sel:eventType:Beacon] :: Beacon -> BeaconEvent
+ Line.Bot.Webhook.Events: [$sel:eventType:Things] :: Things -> ThingsEvent
+ Line.Bot.Webhook.Events: [$sel:events:Events] :: Events -> [Event]
+ Line.Bot.Webhook.Events: [$sel:fileName:Text] :: Message -> Text
+ Line.Bot.Webhook.Events: [$sel:fileSize:Text] :: Message -> Int
+ Line.Bot.Webhook.Events: [$sel:fromEpochMilli:EpochMilli] :: EpochMilli -> UTCTime
+ Line.Bot.Webhook.Events: [$sel:hwid:Beacon] :: Beacon -> Text
+ Line.Bot.Webhook.Events: [$sel:joined:EventMessage] :: Event -> Members
+ Line.Bot.Webhook.Events: [$sel:latitude:Text] :: Message -> Double
+ Line.Bot.Webhook.Events: [$sel:left:EventMessage] :: Event -> Members
+ Line.Bot.Webhook.Events: [$sel:link:EventMessage] :: Event -> AccountLink
+ Line.Bot.Webhook.Events: [$sel:longitude:Text] :: Message -> Double
+ Line.Bot.Webhook.Events: [$sel:members:Members] :: Members -> [Source]
+ Line.Bot.Webhook.Events: [$sel:message:EventMessage] :: Event -> Message
+ Line.Bot.Webhook.Events: [$sel:messageId:Text] :: Message -> Text
+ Line.Bot.Webhook.Events: [$sel:nonce:AccountLink] :: AccountLink -> Text
+ Line.Bot.Webhook.Events: [$sel:packageId:Text] :: Message -> Text
+ Line.Bot.Webhook.Events: [$sel:postback:EventMessage] :: Event -> Postback
+ Line.Bot.Webhook.Events: [$sel:replyToken:EventMessage] :: Event -> ReplyToken
+ Line.Bot.Webhook.Events: [$sel:result:AccountLink] :: AccountLink -> AccountLinkResult
+ Line.Bot.Webhook.Events: [$sel:source:EventMessage] :: Event -> Source
+ Line.Bot.Webhook.Events: [$sel:stickerId:Text] :: Message -> Text
+ Line.Bot.Webhook.Events: [$sel:text:Text] :: Message -> Text
+ Line.Bot.Webhook.Events: [$sel:things:EventMessage] :: Event -> Things
+ Line.Bot.Webhook.Events: [$sel:timestamp:EventMessage] :: Event -> EpochMilli
+ Line.Bot.Webhook.Events: [$sel:title:Text] :: Message -> Text
+ Line.Bot.Webhook.Events: data AccountLink
+ Line.Bot.Webhook.Events: data AccountLinkResult
+ Line.Bot.Webhook.Events: data Beacon
+ Line.Bot.Webhook.Events: data BeaconEvent
+ Line.Bot.Webhook.Events: data Event
+ Line.Bot.Webhook.Events: data Events
+ Line.Bot.Webhook.Events: data Members
+ Line.Bot.Webhook.Events: data Message
+ Line.Bot.Webhook.Events: data Postback
+ Line.Bot.Webhook.Events: data Source
+ Line.Bot.Webhook.Events: data Things
+ Line.Bot.Webhook.Events: data ThingsEvent
+ Line.Bot.Webhook.Events: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Webhook.Events.AccountLink
+ Line.Bot.Webhook.Events: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Webhook.Events.AccountLinkResult
+ Line.Bot.Webhook.Events: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Webhook.Events.Beacon
+ Line.Bot.Webhook.Events: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Webhook.Events.BeaconEvent
+ Line.Bot.Webhook.Events: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Webhook.Events.ContentProvider
+ Line.Bot.Webhook.Events: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Webhook.Events.EpochMilli
+ Line.Bot.Webhook.Events: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Webhook.Events.Event
+ Line.Bot.Webhook.Events: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Webhook.Events.Events
+ Line.Bot.Webhook.Events: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Webhook.Events.Members
+ Line.Bot.Webhook.Events: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Webhook.Events.Message
+ Line.Bot.Webhook.Events: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Webhook.Events.Postback
+ Line.Bot.Webhook.Events: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Webhook.Events.PostbackDateTime
+ Line.Bot.Webhook.Events: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Webhook.Events.Source
+ Line.Bot.Webhook.Events: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Webhook.Events.Things
+ Line.Bot.Webhook.Events: instance Data.Aeson.Types.FromJSON.FromJSON Line.Bot.Webhook.Events.ThingsEvent
+ Line.Bot.Webhook.Events: instance Data.Time.Format.FormatTime Line.Bot.Webhook.Events.EpochMilli
+ Line.Bot.Webhook.Events: instance GHC.Classes.Eq Line.Bot.Webhook.Events.AccountLink
+ Line.Bot.Webhook.Events: instance GHC.Classes.Eq Line.Bot.Webhook.Events.AccountLinkResult
+ Line.Bot.Webhook.Events: instance GHC.Classes.Eq Line.Bot.Webhook.Events.Beacon
+ Line.Bot.Webhook.Events: instance GHC.Classes.Eq Line.Bot.Webhook.Events.BeaconEvent
+ Line.Bot.Webhook.Events: instance GHC.Classes.Eq Line.Bot.Webhook.Events.ContentProvider
+ Line.Bot.Webhook.Events: instance GHC.Classes.Eq Line.Bot.Webhook.Events.EpochMilli
+ Line.Bot.Webhook.Events: instance GHC.Classes.Eq Line.Bot.Webhook.Events.Event
+ Line.Bot.Webhook.Events: instance GHC.Classes.Eq Line.Bot.Webhook.Events.Events
+ Line.Bot.Webhook.Events: instance GHC.Classes.Eq Line.Bot.Webhook.Events.Members
+ Line.Bot.Webhook.Events: instance GHC.Classes.Eq Line.Bot.Webhook.Events.Message
+ Line.Bot.Webhook.Events: instance GHC.Classes.Eq Line.Bot.Webhook.Events.Postback
+ Line.Bot.Webhook.Events: instance GHC.Classes.Eq Line.Bot.Webhook.Events.PostbackDateTime
+ Line.Bot.Webhook.Events: instance GHC.Classes.Eq Line.Bot.Webhook.Events.Source
+ Line.Bot.Webhook.Events: instance GHC.Classes.Eq Line.Bot.Webhook.Events.Things
+ Line.Bot.Webhook.Events: instance GHC.Classes.Eq Line.Bot.Webhook.Events.ThingsEvent
+ Line.Bot.Webhook.Events: instance GHC.Classes.Ord Line.Bot.Webhook.Events.BeaconEvent
+ Line.Bot.Webhook.Events: instance GHC.Classes.Ord Line.Bot.Webhook.Events.EpochMilli
+ Line.Bot.Webhook.Events: instance GHC.Classes.Ord Line.Bot.Webhook.Events.ThingsEvent
+ Line.Bot.Webhook.Events: instance GHC.Generics.Generic Line.Bot.Webhook.Events.AccountLink
+ Line.Bot.Webhook.Events: instance GHC.Generics.Generic Line.Bot.Webhook.Events.AccountLinkResult
+ Line.Bot.Webhook.Events: instance GHC.Generics.Generic Line.Bot.Webhook.Events.Beacon
+ Line.Bot.Webhook.Events: instance GHC.Generics.Generic Line.Bot.Webhook.Events.BeaconEvent
+ Line.Bot.Webhook.Events: instance GHC.Generics.Generic Line.Bot.Webhook.Events.ContentProvider
+ Line.Bot.Webhook.Events: instance GHC.Generics.Generic Line.Bot.Webhook.Events.Event
+ Line.Bot.Webhook.Events: instance GHC.Generics.Generic Line.Bot.Webhook.Events.Events
+ Line.Bot.Webhook.Events: instance GHC.Generics.Generic Line.Bot.Webhook.Events.Members
+ Line.Bot.Webhook.Events: instance GHC.Generics.Generic Line.Bot.Webhook.Events.Message
+ Line.Bot.Webhook.Events: instance GHC.Generics.Generic Line.Bot.Webhook.Events.Things
+ Line.Bot.Webhook.Events: instance GHC.Generics.Generic Line.Bot.Webhook.Events.ThingsEvent
+ Line.Bot.Webhook.Events: instance GHC.Read.Read Line.Bot.Webhook.Events.BeaconEvent
+ Line.Bot.Webhook.Events: instance GHC.Read.Read Line.Bot.Webhook.Events.EpochMilli
+ Line.Bot.Webhook.Events: instance GHC.Read.Read Line.Bot.Webhook.Events.ThingsEvent
+ Line.Bot.Webhook.Events: instance GHC.Show.Show Line.Bot.Webhook.Events.AccountLink
+ Line.Bot.Webhook.Events: instance GHC.Show.Show Line.Bot.Webhook.Events.AccountLinkResult
+ Line.Bot.Webhook.Events: instance GHC.Show.Show Line.Bot.Webhook.Events.Beacon
+ Line.Bot.Webhook.Events: instance GHC.Show.Show Line.Bot.Webhook.Events.BeaconEvent
+ Line.Bot.Webhook.Events: instance GHC.Show.Show Line.Bot.Webhook.Events.ContentProvider
+ Line.Bot.Webhook.Events: instance GHC.Show.Show Line.Bot.Webhook.Events.EpochMilli
+ Line.Bot.Webhook.Events: instance GHC.Show.Show Line.Bot.Webhook.Events.Event
+ Line.Bot.Webhook.Events: instance GHC.Show.Show Line.Bot.Webhook.Events.Events
+ Line.Bot.Webhook.Events: instance GHC.Show.Show Line.Bot.Webhook.Events.Members
+ Line.Bot.Webhook.Events: instance GHC.Show.Show Line.Bot.Webhook.Events.Message
+ Line.Bot.Webhook.Events: instance GHC.Show.Show Line.Bot.Webhook.Events.Postback
+ Line.Bot.Webhook.Events: instance GHC.Show.Show Line.Bot.Webhook.Events.PostbackDateTime
+ Line.Bot.Webhook.Events: instance GHC.Show.Show Line.Bot.Webhook.Events.Source
+ Line.Bot.Webhook.Events: instance GHC.Show.Show Line.Bot.Webhook.Events.Things
+ Line.Bot.Webhook.Events: instance GHC.Show.Show Line.Bot.Webhook.Events.ThingsEvent
+ Line.Bot.Webhook.Events: newtype EpochMilli
- Line.Bot.Client: runLine :: ChannelToken -> Line a -> IO (Either ServantError a)
+ Line.Bot.Client: runLine :: Line a -> ChannelToken -> IO (Either ServantError a)
Files
- LICENSE +1/−1
- examples/Echo.hs +7/−5
- line-bot-sdk.cabal +3/−3
- src/Line/Bot/Client.hs +41/−17
- src/Line/Bot/Endpoints.hs +13/−0
- src/Line/Bot/Types.hs +37/−6
- src/Line/Bot/Webhook.hs +11/−5
- src/Line/Bot/Webhook/Events.hs +299/−0
- src/Line/Bot/Webhook/Types.hs +0/−301
LICENSE view
@@ -1,4 +1,4 @@-Copyright Author name here (c) 2018+Copyright Alexandre Moreno (c) 2018 All rights reserved.
examples/Echo.hs view
@@ -10,7 +10,9 @@ import Control.Monad.IO.Class (liftIO) import Control.Monad.Trans.Reader (ReaderT, ask, runReaderT) import Data.String (fromString)-import Line.Bot.Client as B+import Line.Bot.Client (Line, replyMessage,+ runLine)+import Line.Bot.Types as B import Line.Bot.Webhook as W import Network.Wai.Handler.Warp (run) import Network.Wai.Middleware.RequestLogger (logStdout)@@ -27,14 +29,14 @@ replyMessage replyToken [B.Text text Nothing] echo _ = return NoContent -handleEvents :: Events -> WebM NoContent-handleEvents Events { events } = do+handleEvents :: [Event] -> WebM NoContent+handleEvents events = do token <- ask- _ <- liftIO $ mapM_ (runLine token . echo) events+ _ <- liftIO $ mapM_ (flip runLine token . echo) events return NoContent echoServer :: ServerT API WebM-echoServer = handleEvents+echoServer = handleEvents . events app :: ChannelToken -> ChannelSecret -> Application app token secret = serveWithContext api context server
line-bot-sdk.cabal view
@@ -1,5 +1,5 @@ name: line-bot-sdk-version: 0.1.0.0+version: 0.2.0.0 synopsis: Haskell SDK for LINE Messaging API homepage: https://github.com/moleike/line-bot-sdk#readme bug-reports: https://github.com/moleike/line-bot-sdk/issues@@ -28,11 +28,11 @@ library hs-source-dirs: src exposed-modules: Line.Bot.Webhook+ , Line.Bot.Webhook.Events , Line.Bot.Client+ , Line.Bot.Types other-modules: Line.Bot.Endpoints- , Line.Bot.Types- , Line.Bot.Webhook.Types build-depends: base >= 4.7 && < 5 , aeson >= 1.4.2 && < 1.5
src/Line/Bot/Client.hs view
@@ -7,20 +7,32 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-}+-- |+-- Module : Line.Bot.Client+-- Copyright : (c) Alexandre Moreno, 2019+-- License : BSD3+-- Maintainer : alexmorenocano@gmail.com+-- Stability : experimental module Line.Bot.Client- ( module Line.Bot.Types+ ( Line , runLine- , Line- , ChannelToken(..)+ , runLineWith+ -- ** Profile , getProfile+ -- ** Group , getGroupMemberProfile , leaveGroup+ -- ** Room , getRoomMemberProfile , leaveRoom+ -- ** Message , replyMessage , pushMessage , multicastMessage+ , getContent+ -- ** Account Link+ , issueLinkToken ) where @@ -49,29 +61,31 @@ host :: BaseUrl host = BaseUrl Https "api.line.me" 443 "" -newtype ChannelToken = ChannelToken Text- deriving (Eq)--instance IsString ChannelToken where- fromString s = ChannelToken (fromString s)--instance ToHttpApiData ChannelToken where- toQueryParam (ChannelToken t) = "Bearer " <> t-+-- | @Line@ is the monad in which bot requests run. Contains the+-- OAuth access token for a channel type Line = ReaderT ChannelToken ClientM type Auth = AuthenticatedRequest (AuthProtect ChannelAuth) type instance AuthClientData (AuthProtect ChannelAuth) = ChannelToken -runLine' :: ClientM a -> IO (Either ServantError a)-runLine' comp = do+defaultClient:: ClientM a -> IO (Either ServantError a)+defaultClient comp = do manager <- newManager tlsManagerSettings runClientM comp (mkClientEnv manager host) -runLine :: ChannelToken -> Line a -> IO (Either ServantError a)-runLine token comp = runLine' $ runReaderT comp token+-- | Runs a @Line@ computation with the given channel access token+runLine :: Line a -> ChannelToken -> IO (Either ServantError a)+runLine = runLineWith defaultClient +-- | Runs the monad with a different client evironment+runLineWith+ :: (ClientM a -> IO (Either ServantError a))+ -> Line a+ -> ChannelToken+ -> IO (Either ServantError a)+runLineWith f comp token = f $ runReaderT comp token+ mkAuth :: ChannelToken -> Auth mkAuth token = mkAuthenticatedRequest token addAuthHeader where@@ -96,6 +110,8 @@ getContent' :: Auth -> String -> ClientM ByteString +issueLinkToken' :: Auth -> Id User -> ClientM LinkToken+ getProfile' :<|> getGroupMemberProfile' :<|> leaveGroup'@@ -104,7 +120,8 @@ :<|> replyMessage' :<|> pushMessage' :<|> multicastMessage'- :<|> getContent' = client (Proxy :: Proxy Endpoints)+ :<|> getContent'+ :<|> issueLinkToken' = client (Proxy :: Proxy Endpoints) getProfile :: Id User -> Line Profile getProfile a = ask >>= \token -> lift $ getProfile' (mkAuth token) a@@ -135,3 +152,10 @@ multicastMessage a ms = ask >>= \token -> lift $ multicastMessage' (mkAuth token) body where body = MulticastMessageBody a ms++getContent :: String -> Line ByteString+getContent a = ask >>= \token -> lift $ getContent' (mkAuth token) a++issueLinkToken :: Id User -> Line LinkToken+issueLinkToken a = ask >>= \token -> lift $ issueLinkToken' (mkAuth token) a+
src/Line/Bot/Endpoints.hs view
@@ -7,6 +7,12 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-}+-- |+-- Module : Line.Bot.Endpoints+-- Copyright : (c) Alexandre Moreno, 2019+-- License : BSD3+-- Maintainer : alexmorenocano@gmail.com+-- Stability : experimental module Line.Bot.Endpoints where @@ -72,6 +78,12 @@ :> "content" :> Get '[OctetStream] ByteString +type IssueLinkToken = AuthProtect ChannelAuth+ :> "user"+ :> Capture "userId" (Id User)+ :> "linkToken"+ :> Get '[JSON] LinkToken+ type Endpoints = "v2" :> "bot" :> ( GetProfile :<|> GetGroupMemberProfile@@ -82,4 +94,5 @@ :<|> PushMessage :<|> MulticastMessage :<|> GetContent+ :<|> IssueLinkToken )
src/Line/Bot/Types.hs view
@@ -11,13 +11,22 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE StandaloneDeriving #-}+-- |+-- Module : Line.Bot.Types+-- Copyright : (c) Alexandre Moreno, 2019+-- License : BSD3+-- Maintainer : alexmorenocano@gmail.com+-- Stability : experimental module Line.Bot.Types- ( ChatType(..)+ ( ChannelToken(..)+ , ChannelSecret(..)+ , ChatType(..) , Id(..) , URL(..) , Message(..) , ReplyToken(..)+ , LinkToken(..) , ReplyMessageBody(ReplyMessageBody) , PushMessageBody(PushMessageBody) , MulticastMessageBody(MulticastMessageBody)@@ -30,17 +39,34 @@ import Data.Aeson import Data.Aeson.Types-import Data.Char (toLower)-import Data.List as L (stripPrefix)-import Data.Maybe (fromJust)+import qualified Data.ByteString.Char8 as B+import Data.Char (toLower)+import Data.List as L (stripPrefix)+import Data.Maybe (fromJust) import Data.String-import Data.Text as T hiding (drop, toLower)-import GHC.Generics hiding (to)+import Data.Text as T hiding (drop, toLower)+import GHC.Generics hiding (to) import Servant.API import Text.Show +newtype ChannelToken = ChannelToken Text+ deriving (Eq)++instance IsString ChannelToken where+ fromString s = ChannelToken (fromString s)++instance ToHttpApiData ChannelToken where+ toQueryParam (ChannelToken t) = "Bearer " <> t++newtype ChannelSecret = ChannelSecret+ { unChannelSecret :: B.ByteString }++instance IsString ChannelSecret where+ fromString s = ChannelSecret (B.pack s)+ data ChatType = User | Group | Room +-- | ID of a chat user, group or room data Id :: ChatType -> * where UserId :: Text -> Id User GroupId :: Text -> Id Group@@ -129,6 +155,11 @@ instance ToJSON ReplyToken instance FromJSON ReplyToken++data LinkToken = LinkToken { linkToken :: Text }+ deriving (Eq, Show, Generic)++instance FromJSON LinkToken data ReplyMessageBody = ReplyMessageBody { replyToken :: ReplyToken
src/Line/Bot/Webhook.hs view
@@ -12,14 +12,19 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-}-+-- |+-- Module : Line.Bot.Webhook+-- Copyright : (c) Alexandre Moreno, 2019+-- License : BSD3+-- Maintainer : alexmorenocano@gmail.com+-- Stability : experimental module Line.Bot.Webhook- ( module Line.Bot.Webhook.Types- , Webhook+ ( Webhook , LineReqBody+ , module Events )- where+where import Control.Monad.IO.Class (liftIO) import qualified Crypto.Hash.SHA256 as SHA256@@ -32,7 +37,8 @@ import Data.Proxy import Data.String.Conversions (cs) import Data.Typeable (Typeable)-import Line.Bot.Webhook.Types+import Line.Bot.Types (ChannelSecret (..))+import Line.Bot.Webhook.Events as Events import Network.HTTP.Types (HeaderName, hContentType) import Network.Wai (Request, lazyRequestBody, requestHeaders)
+ src/Line/Bot/Webhook/Events.hs view
@@ -0,0 +1,299 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE ExtendedDefaultRules #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE StandaloneDeriving #-}+-- |+-- Module : Line.Bot.Webhook.Events+-- Copyright : (c) Alexandre Moreno, 2019+-- License : BSD3+-- Maintainer : alexmorenocano@gmail.com+-- Stability : experimental++module Line.Bot.Webhook.Events+ ( Events(..)+ , Event(..)+ , Message(..)+ , EpochMilli(..)+ , Source(..)+ , Members(..)+ , Postback(..)+ , Beacon(..)+ , BeaconEvent(..)+ , Things(..)+ , ThingsEvent(..)+ , AccountLink(..)+ , AccountLinkResult(..)+ )+where++import Data.Aeson+import Data.Aeson.Types+import Data.Char+import Data.Foldable+import Data.List as L (stripPrefix)+import Data.Maybe+import Data.Scientific+import Data.String+import Data.Text as T hiding (drop, stripPrefix, toLower)+import Data.Time (LocalTime, UTCTime)+import Data.Time.Calendar (Day)+import Data.Time.Clock.POSIX+import Data.Time.Format+import Data.Time.LocalTime+import Data.Typeable (Typeable)+import GHC.Generics (Generic)+import Line.Bot.Types hiding (Message, Text)+++data Events = Events+ { destination :: Id User+ , events :: [Event]+ }+ deriving (Eq, Show, Generic)++instance FromJSON Events++data Event =+ EventMessage { replyToken :: ReplyToken+ , message :: Message+ , source :: Source+ , timestamp :: EpochMilli+ }+ | EventFollow { replyToken :: ReplyToken+ , source :: Source+ , timestamp :: EpochMilli+ }+ | EventUnfollow { source :: Source+ , timestamp :: EpochMilli+ }+ | EventJoin { replyToken :: ReplyToken+ , source :: Source+ , timestamp :: EpochMilli+ }+ | EventLeave { source :: Source+ , timestamp :: EpochMilli+ }+ | EventMemberJoined { replyToken :: ReplyToken+ , source :: Source+ , timestamp :: EpochMilli+ , joined :: Members+ }+ | EventMemberLeft { source :: Source+ , timestamp :: EpochMilli+ , left :: Members+ }+ | EventPostback { replyToken :: ReplyToken+ , source :: Source+ , timestamp :: EpochMilli+ , postback :: Postback+ }+ | EventBeacon { replyToken :: ReplyToken+ , source :: Source+ , timestamp :: EpochMilli+ , beacon :: Beacon+ }+ | EventAccountLink { replyToken :: ReplyToken+ , source :: Source+ , timestamp :: EpochMilli+ , link :: AccountLink+ }+ | EventThings { replyToken :: ReplyToken+ , source :: Source+ , timestamp :: EpochMilli+ , things :: Things+ }+ deriving (Eq, Show, Generic)++instance FromJSON Event where+ parseJSON = genericParseJSON $+ defaultOptions { sumEncoding = TaggedObject+ { tagFieldName = "type"+ , contentsFieldName = undefined+ }+ , constructorTagModifier = (\(x : xs) -> toLower x : xs) . drop 5+ }++data Message =+ Text { messageId :: Text+ , text :: Text+ }+ | Image { messageId :: Text+ , contentProvider :: ContentProvider+ }+ | Video { messageId :: Text+ , duration :: Int+ , contentProvider :: ContentProvider+ }+ | Audio { messageId :: Text+ , duration :: Int+ , contentProvider :: ContentProvider+ }+ | File { messageId :: Text+ , fileSize :: Int+ , fileName :: Text+ }+ | Location { messageId :: Text+ , title :: Text+ , address :: Text+ , latitude :: Double+ , longitude :: Double+ }+ | Sticker { messageId :: Text+ , packageId :: Text+ , stickerId :: Text+ }+ deriving (Eq, Show, Generic)++messageJSONOptions :: Options+messageJSONOptions = defaultOptions+ { sumEncoding = TaggedObject+ { tagFieldName = "type"+ , contentsFieldName = undefined+ }+ , constructorTagModifier = fmap toLower+ , fieldLabelModifier = \orig ->+ case L.stripPrefix "message" orig of+ Just s -> fmap toLower s+ Nothing -> orig+ , omitNothingFields = True+ }++instance FromJSON Message where+ parseJSON = genericParseJSON messageJSONOptions+++data ContentProvider = ContentProvider+ { originalContentUrl :: Maybe URL+ , previewImageUrl :: Maybe URL+ }+ deriving (Eq, Show, Generic)++instance FromJSON ContentProvider++newtype EpochMilli = EpochMilli {+ fromEpochMilli :: UTCTime+ -- ^ Acquire the underlying value.+} deriving (Eq, Ord, Read, Show, FormatTime)++instance FromJSON EpochMilli where+ parseJSON = withScientific "EpochMilli" $ \t ->+ pure $ millis t+ where+ millis = EpochMilli+ . posixSecondsToUTCTime+ . fromRational+ . toRational+ . (/ 1000)+++data Source =+ SourceUser (Id User)+ | SourceGroup (Id Group) (Maybe (Id User))+ | SourceRoom (Id Room) (Maybe (Id User))+ deriving (Eq, Show)++instance FromJSON Source where+ parseJSON = withObject "Source" $ \o -> do+ messageType <- o .: "type"+ case messageType of+ "user" -> SourceUser <$> o .: "userId"+ "group" -> SourceGroup <$> o .: "groupId" <*> o .:? "userId"+ "room" -> SourceRoom <$> o .: "roomId" <*> o .:? "userId"+ _ -> fail ("unknown source: " ++ messageType)+++data Members = Members { members :: [Source] }+ deriving (Eq, Show, Generic)++instance FromJSON Members++data PostbackDateTime =+ PostbackDay Day+ | PostbackLocalTime LocalTime+ | PostbackTimeOfDay TimeOfDay+ deriving (Eq, Show)++instance FromJSON PostbackDateTime where+ parseJSON = withObject "PostbackDateTime" $ \o -> do+ dateTime <- asum+ [ PostbackDay <$> o .: "date"+ , PostbackLocalTime <$> o .: "datetime"+ , PostbackTimeOfDay <$> o .: "time"+ ]+ return dateTime++data Postback = Postback Text PostbackDateTime+ deriving (Eq, Show)++instance FromJSON Postback where+ parseJSON = withObject "Postback" $ \o -> do+ postbackData <- o .: "data"+ params <- o .: "params"+ return $ Postback postbackData params++data BeaconEvent = Enter | Leave | Banner+ deriving (Show, Read, Eq, Ord, Generic)++instance FromJSON BeaconEvent where+ parseJSON = genericParseJSON $+ defaultOptions { constructorTagModifier = fmap toLower+ , allNullaryToStringTag = True+ }++data Beacon = Beacon+ { hwid :: Text+ , eventType :: BeaconEvent+ , dm :: Maybe Text+ }+ deriving (Eq, Show, Generic)++instance FromJSON Beacon where+ parseJSON = withObject "Beacon" $ \o -> do+ hwid <- o .: "hwid"+ eventType <- o .: "type"+ dm <- o .:? "dm"+ return $ Beacon{..}++data AccountLinkResult = Ok | Failed+ deriving (Eq, Show, Generic)++instance FromJSON AccountLinkResult where+ parseJSON = genericParseJSON $+ defaultOptions { constructorTagModifier = fmap toLower+ , allNullaryToStringTag = True+ }++data AccountLink = AccountLink+ { nonce :: Text+ , result :: AccountLinkResult+ }+ deriving (Eq, Show, Generic)++instance FromJSON AccountLink++data ThingsEvent = Link | Unlink+ deriving (Show, Read, Eq, Ord, Generic)++instance FromJSON ThingsEvent where+ parseJSON = genericParseJSON $+ defaultOptions { constructorTagModifier = fmap toLower+ , allNullaryToStringTag = True+ }++data Things = Things+ { deviceId :: Text+ , eventType :: ThingsEvent+ }+ deriving (Eq, Show, Generic)++instance FromJSON Things where+ parseJSON = withObject "Things" $ \o -> do+ deviceId <- o .: "deviceId"+ eventType <- o .: "type"+ return $ Things{..}
− src/Line/Bot/Webhook/Types.hs
@@ -1,301 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DuplicateRecordFields #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE ExtendedDefaultRules #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE StandaloneDeriving #-}--module Line.Bot.Webhook.Types- ( ChannelSecret(..)- , Events(..)- , Event(..)- , Message(..)- , EpochMilli(..)- , Source(..)- , Members(..)- , Postback(..)- , Beacon(..)- , BeaconEvent(..)- , Things(..)- , ThingsEvent(..)- , AccountLink(..)- , AccountLinkResult(..)- )-where--import Data.Aeson-import Data.Aeson.Types-import qualified Data.ByteString.Char8 as B-import Data.Char-import Data.Foldable-import Data.List as L (stripPrefix)-import Data.Maybe-import Data.Scientific-import Data.String-import Data.Text as T hiding (drop, stripPrefix, toLower)-import Data.Time (LocalTime, UTCTime)-import Data.Time.Calendar (Day)-import Data.Time.Clock.POSIX-import Data.Time.Format-import Data.Time.LocalTime-import Data.Typeable (Typeable)-import GHC.Generics (Generic)-import Line.Bot.Types hiding (Message, Text)---newtype ChannelSecret = ChannelSecret- { unChannelSecret :: B.ByteString }--instance IsString ChannelSecret where- fromString s = ChannelSecret (B.pack s)--data Events = Events- { destination :: Id User- , events :: [Event]- }- deriving (Eq, Show, Generic)--instance FromJSON Events--data Event =- EventMessage { replyToken :: ReplyToken- , message :: Message- , source :: Source- , timestamp :: EpochMilli- }- | EventFollow { replyToken :: ReplyToken- , source :: Source- , timestamp :: EpochMilli- }- | EventUnfollow { source :: Source- , timestamp :: EpochMilli- }- | EventJoin { replyToken :: ReplyToken- , source :: Source- , timestamp :: EpochMilli- }- | EventLeave { source :: Source- , timestamp :: EpochMilli- }- | EventMemberJoined { replyToken :: ReplyToken- , source :: Source- , timestamp :: EpochMilli- , joined :: Members- }- | EventMemberLeft { source :: Source- , timestamp :: EpochMilli- , left :: Members- }- | EventPostback { replyToken :: ReplyToken- , source :: Source- , timestamp :: EpochMilli- , postback :: Postback- }- | EventBeacon { replyToken :: ReplyToken- , source :: Source- , timestamp :: EpochMilli- , beacon :: Beacon- }- | EventAccountLink { replyToken :: ReplyToken- , source :: Source- , timestamp :: EpochMilli- , link :: AccountLink- }- | EventThings { replyToken :: ReplyToken- , source :: Source- , timestamp :: EpochMilli- , things :: Things- }- deriving (Eq, Show, Generic)--instance FromJSON Event where- parseJSON = genericParseJSON $- defaultOptions { sumEncoding = TaggedObject- { tagFieldName = "type"- , contentsFieldName = undefined- }- , constructorTagModifier = (\(x : xs) -> toLower x : xs) . drop 5- }--data Message =- Text { messageId :: Text- , text :: Text- }- | Image { messageId :: Text- , contentProvider :: ContentProvider- }- | Video { messageId :: Text- , duration :: Int- , contentProvider :: ContentProvider- }- | Audio { messageId :: Text- , duration :: Int- , contentProvider :: ContentProvider- }- | File { messageId :: Text- , fileSize :: Int- , fileName :: Text- }- | Location { messageId :: Text- , title :: Text- , address :: Text- , latitude :: Double- , longitude :: Double- }- | Sticker { messageId :: Text- , packageId :: Text- , stickerId :: Text- }- deriving (Eq, Show, Generic)--messageJSONOptions :: Options-messageJSONOptions = defaultOptions- { sumEncoding = TaggedObject- { tagFieldName = "type"- , contentsFieldName = undefined- }- , constructorTagModifier = fmap toLower- , fieldLabelModifier = \orig ->- case L.stripPrefix "message" orig of- Just s -> fmap toLower s- Nothing -> orig- , omitNothingFields = True- }--instance FromJSON Message where- parseJSON = genericParseJSON messageJSONOptions---data ContentProvider = ContentProvider- { originalContentUrl :: Maybe URL- , previewImageUrl :: Maybe URL- }- deriving (Eq, Show, Generic)--instance FromJSON ContentProvider--newtype EpochMilli = EpochMilli {- fromEpochMilli :: UTCTime- -- ^ Acquire the underlying value.-} deriving (Eq, Ord, Read, Show, FormatTime)--instance FromJSON EpochMilli where- parseJSON = withScientific "EpochMilli" $ \t ->- pure $ millis t- where- millis = EpochMilli- . posixSecondsToUTCTime- . fromRational- . toRational- . (/ 1000)---data Source =- SourceUser (Id User)- | SourceGroup (Id Group) (Maybe (Id User))- | SourceRoom (Id Room) (Maybe (Id User))- deriving (Eq, Show)--instance FromJSON Source where- parseJSON = withObject "Source" $ \o -> do- messageType <- o .: "type"- case messageType of- "user" -> SourceUser <$> o .: "userId"- "group" -> SourceGroup <$> o .: "groupId" <*> o .:? "userId"- "room" -> SourceRoom <$> o .: "roomId" <*> o .:? "userId"- _ -> fail ("unknown source: " ++ messageType)---data Members = Members { members :: [Source] }- deriving (Eq, Show, Generic)--instance FromJSON Members--data PostbackDateTime =- PostbackDay Day- | PostbackLocalTime LocalTime- | PostbackTimeOfDay TimeOfDay- deriving (Eq, Show)--instance FromJSON PostbackDateTime where- parseJSON = withObject "PostbackDateTime" $ \o -> do- dateTime <- asum- [ PostbackDay <$> o .: "date"- , PostbackLocalTime <$> o .: "datetime"- , PostbackTimeOfDay <$> o .: "time"- ]- return dateTime--data Postback = Postback Text PostbackDateTime- deriving (Eq, Show)--instance FromJSON Postback where- parseJSON = withObject "Postback" $ \o -> do- postbackData <- o .: "data"- params <- o .: "params"- return $ Postback postbackData params--data BeaconEvent = Enter | Leave | Banner- deriving (Show, Read, Eq, Ord, Generic)--instance FromJSON BeaconEvent where- parseJSON = genericParseJSON $- defaultOptions { constructorTagModifier = fmap toLower- , allNullaryToStringTag = True- }--data Beacon = Beacon- { hwid :: Text- , eventType :: BeaconEvent- , dm :: Maybe Text- }- deriving (Eq, Show, Generic)--instance FromJSON Beacon where- parseJSON = withObject "Beacon" $ \o -> do- hwid <- o .: "hwid"- eventType <- o .: "type"- dm <- o .:? "dm"- return $ Beacon{..}--data AccountLinkResult = Ok | Failed- deriving (Eq, Show, Generic)--instance FromJSON AccountLinkResult where- parseJSON = genericParseJSON $- defaultOptions { constructorTagModifier = fmap toLower- , allNullaryToStringTag = True- }--data AccountLink = AccountLink- { nonce :: Text- , result :: AccountLinkResult- }- deriving (Eq, Show, Generic)--instance FromJSON AccountLink--data ThingsEvent = Link | Unlink- deriving (Show, Read, Eq, Ord, Generic)--instance FromJSON ThingsEvent where- parseJSON = genericParseJSON $- defaultOptions { constructorTagModifier = fmap toLower- , allNullaryToStringTag = True- }--data Things = Things- { deviceId :: Text- , eventType :: ThingsEvent- }- deriving (Eq, Show, Generic)--instance FromJSON Things where- parseJSON = withObject "Things" $ \o -> do- deviceId <- o .: "deviceId"- eventType <- o .: "type"- return $ Things{..}