Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce chat.update bindings #112

Merged
merged 3 commits into from
Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/nix-checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ jobs:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- name: Run all nix checks
run: |
nix build --keep-going ".#checks.x86_64-linux.all"
nix build --print-build-logs --keep-going ".#checks.x86_64-linux.all"
3 changes: 3 additions & 0 deletions slack-web.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ extra-source-files:
tests/golden/Conversation/*.golden
tests/golden/UsersConversationsResponse/*.json
tests/golden/UsersConversationsResponse/*.golden
tests/golden/UpdateRsp/*.json
tests/golden/UpdateRsp/*.golden

category: Web

Expand Down Expand Up @@ -174,6 +176,7 @@ test-suite tests
Web.Slack.PagerSpec
Web.Slack.MessageParserSpec
Web.Slack.ConversationSpec
Web.Slack.ChatSpec
Web.Slack.UsersConversationsSpec
Web.Slack.Experimental.RequestVerificationSpec
Web.Slack.Experimental.Events.TypesSpec
Expand Down
22 changes: 22 additions & 0 deletions src/Web/Slack.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module Web.Slack
apiTest,
authTest,
chatPostMessage,
chatUpdate,
conversationsList,
conversationsListAll,
conversationsHistory,
Expand Down Expand Up @@ -85,6 +86,10 @@ type Api =
:> AuthProtect "token"
:> ReqBody '[FormUrlEncoded] Chat.PostMsgReq
:> Post '[JSON] (ResponseJSON Chat.PostMsgRsp)
:<|> "chat.update"
:> AuthProtect "token"
:> ReqBody '[FormUrlEncoded] Chat.UpdateReq
:> Post '[JSON] (ResponseJSON Chat.UpdateRsp)
:<|> "users.list"
:> AuthProtect "token"
:> Post '[JSON] (ResponseJSON User.ListRsp)
Expand Down Expand Up @@ -213,6 +218,22 @@ chatPostMessage_ ::
Chat.PostMsgReq ->
ClientM (ResponseJSON Chat.PostMsgRsp)

-- | Updates a message.
--
-- <https://api.slack.com/methods/chat.update>
chatUpdate ::
SlackConfig ->
Chat.UpdateReq ->
IO (Response Chat.UpdateRsp)
chatUpdate = flip $ \updateReq -> do
authR <- mkSlackAuthenticateReq
run (chatUpdate_ authR updateReq) . slackConfigManager

chatUpdate_ ::

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like I've asked this before about this file, but where are all these "underscored" functions defined?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

slack-web/src/Web/Slack.hs

Lines 296 to 304 in ffeccec

apiTest_
:<|> authTest_
:<|> conversationsList_
:<|> conversationsHistory_
:<|> conversationsReplies_
:<|> chatPostMessage_
:<|> usersList_
:<|> userLookupByEmail_ =
client (Proxy :: Proxy Api)

AuthenticatedRequest (AuthProtect "token") ->
Chat.UpdateReq ->
ClientM (ResponseJSON Chat.UpdateRsp)

-- |
--
-- This method returns a list of all users in the team.
Expand Down Expand Up @@ -299,6 +320,7 @@ apiTest_
:<|> conversationsHistory_
:<|> conversationsReplies_
:<|> chatPostMessage_
:<|> chatUpdate_
:<|> usersList_
:<|> userLookupByEmail_ =
client (Proxy :: Proxy Api)
Expand Down
86 changes: 59 additions & 27 deletions src/Web/Slack/Chat.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,21 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}

----------------------------------------------------------------------

----------------------------------------------------------------------

-- |
-- Module: Web.Slack.Chat
-- Description:
module Web.Slack.Chat
( PostMsg (..),
PostMsgReq (..),
mkPostMsgReq,
PostMsgRsp (..),
UpdateReq (..),
mkUpdateReq,
UpdateRsp (..),
)
where

-- FIXME: Web.Slack.Prelude

-- aeson

-- base

-- deepseq
import Control.DeepSeq (NFData)
import Data.Aeson.TH
-- http-api-data

-- slack-web

-- text
import Data.Text (Text)
import GHC.Generics (Generic)
import Web.FormUrlEncoded
import Web.Slack.Conversation (ConversationId)
import Web.Slack.Prelude
import Web.Slack.Util
import Prelude

data PostMsg = PostMsg
{ postMsgText :: Text
Expand All @@ -59,7 +40,9 @@ $(deriveJSON (jsonOpts "postMsg") ''PostMsg)

data PostMsgReq = PostMsgReq
{ postMsgReqChannel :: Text
, postMsgReqText :: Text
, postMsgReqText :: Maybe Text
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually Maybe in the API since you can have a message with blocks and no text.

-- ^ One of 'postMsgReqText', 'postMsgReqAttachments', or 'postMsgReqBlocks'
-- is required.
, postMsgReqParse :: Maybe Text
, postMsgReqLinkNames :: Maybe Bool
, postMsgReqAttachments :: Maybe Text
Expand Down Expand Up @@ -90,7 +73,7 @@ mkPostMsgReq ::
mkPostMsgReq channel text =
PostMsgReq
{ postMsgReqChannel = channel
, postMsgReqText = text
, postMsgReqText = Just text
, postMsgReqParse = Nothing
, postMsgReqLinkNames = Nothing
, postMsgReqAttachments = Nothing
Expand All @@ -106,11 +89,60 @@ mkPostMsgReq channel text =
}

data PostMsgRsp = PostMsgRsp
{ postMsgRspTs :: String
{ postMsgRspTs :: Text
Comment on lines -109 to +92
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking change, but it is silly that this was a String to begin with.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will you be bumping the version number?

Copy link
Contributor Author

@lf- lf- Nov 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am going to write a changelog Soon and release 1.5 (current version is 0.5), but not in this PR.

, postMsgRspMessage :: PostMsg
}
deriving stock (Eq, Generic, Show)

instance NFData PostMsgRsp

$(deriveFromJSON (jsonOpts "postMsgRsp") ''PostMsgRsp)

-- | <https://api.slack.com/methods/chat.update>
data UpdateReq = UpdateReq
{ updateReqChannel :: ConversationId
, updateReqTs :: Text

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, that's strange. do all messages in a channel have a unique timestamp?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, lmao. They are the primary key of messages, which is an Interesting design decision on the part of Slack, but I guess, there are many of those.

-- ^ \"Timestamp of the message to be updated.\"
, updateReqAsUser :: Maybe Bool
-- ^ \"Pass true to update the message as the authed user. Bot users in this context are considered authed users.\"
, updateReqAttachments :: Maybe Text
-- ^ \"A JSON-based array of structured attachments, presented as a URL-encoded string. This field is required when not presenting text. If you don't include this field, the message's previous attachments will be retained. To remove previous attachments, include an empty array for this field.\"
, updateReqLinkNames :: Maybe Bool
, updateReqMetadata :: Maybe Text
, updateReqParse :: Maybe Text
, updateReqReplyBroadcast :: Maybe Bool
-- ^ \"Broadcast an existing thread reply to make it visible to everyone in the channel or conversation.\"
, updateReqText :: Maybe Text
-- ^ \"New text for the message, using the default formatting rules. It's not required when presenting blocks or attachments.\"
}
deriving stock (Eq, Generic, Show)

instance ToForm UpdateReq where
toForm = genericToForm (formOpts "updateReq")

mkUpdateReq :: ConversationId -> Text -> UpdateReq
mkUpdateReq channel ts =
UpdateReq
{ updateReqChannel = channel
, updateReqTs = ts
, updateReqAsUser = Nothing
, updateReqAttachments = Nothing
, updateReqLinkNames = Nothing
, updateReqMetadata = Nothing
, updateReqParse = Nothing
, updateReqReplyBroadcast = Nothing
, updateReqText = Nothing
}

data UpdateRsp = UpdateRsp
{ updateRspChannel :: ConversationId
, updateRspTs :: Text
, updateRspText :: Text
-- FIXME(jadel): this does look suspiciously like the same schema as
-- MessageEvent based on the example I received, but Slack hasn't documented
-- what it actually is, so let's not try to parse it for now.
-- , message :: MessageEvent
}
deriving stock (Eq, Generic, Show)

$(deriveFromJSON (jsonOpts "updateRsp") ''UpdateRsp)
11 changes: 11 additions & 0 deletions tests/Web/Slack/ChatSpec.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Web.Slack.ChatSpec (spec) where

import JSONGolden
import TestImport
import Web.Slack.Chat (UpdateRsp)

spec :: Spec
spec = describe "Chat methods" do
describe "chat.update" do
describe "Response FromJSON" do
mapM_ (oneGoldenTest @UpdateRsp) ["sample", "actual"]
78 changes: 78 additions & 0 deletions tests/golden/SlackWebhookEvent/shared_message_no_content.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
{
"token": "aaaa",
"team_id": "T043DB835ML",
"api_app_id": "A0442TUPHGR",
"event": {
"type": "message",
"text": "",
"user": "U043H11ES4V",
"ts": "1668537593.598469",
"team": "T043DB835ML",
"attachments": [
{
"from_url": "https://jadeapptesting.slack.com/archives/C043KSKGJUB/p1665615886364019",
"ts": "1665615886.364019",
"author_id": "U043H11ES4V",
"channel_id": "C043KSKGJUB",
"channel_team": "T043DB835ML",
"channel_name": "testing-slack-app",
"is_msg_unfurl": true,
"message_blocks": [
{
"team": "T043DB835ML",
"channel": "C043KSKGJUB",
"ts": "1665615886.364019",
"message": {
"blocks": [
{
"type": "rich_text",
"block_id": "TNHa4",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": "blahblahblahblahblah"
}
]
}
]
}
]
}
}
],
"color": "D0D0D0",
"is_share": true,
"fallback": "[October 12th, 2022 4:04 PM] jadel: blahblahblahblahblah",
"text": "blahblahblahblahblah",
"author_name": "jadel",
"author_link": "https://jadeapptesting.slack.com/team/U043H11ES4V",
"author_icon": "https://secure.gravatar.com/avatar/dcd5bc53dcfaca62ddc3f5726d07ba13.jpg?s=48&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0019-48.png",
"author_subname": "jadel",
"mrkdwn_in": [
"text"
],
"footer": "Posted in #testing-slack-app"
}
],
"channel": "C043YJGBY49",
"event_ts": "1668537593.598469",
"channel_type": "channel"
},
"type": "event_callback",
"event_id": "Ev04BEN3QMSM",
"event_time": 1668537593,
"authorizations": [
{
"enterprise_id": null,
"team_id": "T043DB835ML",
"user_id": "U0442US8QGH",
"is_bot": true,
"is_enterprise_install": false
}
],
"is_ext_shared_channel": false,
"event_context": "aaaa"
}
6 changes: 6 additions & 0 deletions tests/golden/UpdateRsp/actual.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
UpdateRsp
{ updateRspChannel = ConversationId
{ unConversationId = "D0442US94JD" }
, updateRspTs = "1668717810.728689"
, updateRspText = "blahblahblah"
}
48 changes: 48 additions & 0 deletions tests/golden/UpdateRsp/actual.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"ok": true,
"channel": "D0442US94JD",
"ts": "1668717810.728689",
"text": "blahblahblah",
"message": {
"bot_id": "B0439P161B9",
"type": "message",
"text": "blahblahblah",
"user": "U0442US8QGH",
"app_id": "A0442TUPHGR",
"blocks": [
{
"type": "rich_text",
"block_id": "j1Bvn",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": "blahblahblah"
}
]
}
]
}
],
"team": "T043DB835ML",
"bot_profile": {
"id": "B0439P161B9",
"app_id": "A0442TUPHGR",
"name": "Slacklinker dev",
"icons": {
"image_36": "https://a.slack-edge.com/80588/img/plugins/app/bot_36.png",
"image_48": "https://a.slack-edge.com/80588/img/plugins/app/bot_48.png",
"image_72": "https://a.slack-edge.com/80588/img/plugins/app/service_72.png"
},
"deleted": false,
"updated": 1663960005,
"team_id": "T043DB835ML"
},
"edited": {
"user": "B0439P161B9",
"ts": "1668721589.000000"
}
}
}
6 changes: 6 additions & 0 deletions tests/golden/UpdateRsp/sample.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
UpdateRsp
{ updateRspChannel = ConversationId
{ unConversationId = "C024BE91L" }
, updateRspTs = "1401383885.000061"
, updateRspText = "Updated text you carefully authored"
}
10 changes: 10 additions & 0 deletions tests/golden/UpdateRsp/sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"ok": true,
"channel": "C024BE91L",
"ts": "1401383885.000061",
"text": "Updated text you carefully authored",
"message": {
"text": "Updated text you carefully authored",
"user": "U34567890"
}
}