@@ -11,14 +11,11 @@ import Control.Monad.Except (ExceptT (..), runExceptT)
1111import Crypto.JWT (JWTError )
1212import Data.Aeson (FromJSON (.. ), ToJSON (.. ))
1313import Data.Aeson qualified as Aeson
14- import Data.Aeson.Types ((.=) )
1514import Data.ByteString.Lazy.Char8 qualified as BL
1615import Data.List.Extra qualified as List
1716import Data.Text qualified as Text
1817import Data.Text.Encoding qualified as Text
1918import Data.Time (UTCTime )
20- import Data.Time qualified as Time
21- import Data.Time.Clock.POSIX qualified as POSIX
2219import Ki.Unlifted qualified as Ki
2320import Network.HTTP.Client qualified as HTTPClient
2421import Network.HTTP.Types qualified as HTTP
@@ -28,6 +25,8 @@ import Share.BackgroundJobs.Errors (reportError)
2825import Share.BackgroundJobs.Monad (Background )
2926import Share.BackgroundJobs.Webhooks.Queries qualified as WQ
3027import Share.BackgroundJobs.Workers (newWorker )
28+ import Share.ChatApps (Author (.. ))
29+ import Share.ChatApps qualified as ChatApps
3130import Share.Env qualified as Env
3231import Share.IDs
3332import Share.IDs qualified as IDs
@@ -42,7 +41,7 @@ import Share.Postgres qualified as PG
4241import Share.Postgres.Notifications qualified as Notif
4342import Share.Prelude
4443import Share.Utils.Logging qualified as Logging
45- import Share.Utils.URI (URIParam (.. ), uriToText )
44+ import Share.Utils.URI (URIParam (.. ))
4645import Share.Web.Authorization qualified as AuthZ
4746import Share.Web.Share.DisplayInfo.Queries qualified as DisplayInfoQ
4847import Share.Web.Share.DisplayInfo.Types (UnifiedDisplayInfo )
@@ -207,72 +206,12 @@ tryWebhook event webhookId = UnliftIO.handleAny (\someException -> pure $ Just $
207206 | status >= 400 -> throwError $ ReceiverError event. eventId webhookId httpStatus $ HTTPClient. responseBody resp
208207 | otherwise -> pure ()
209208
210- data ChatProvider
211- = Slack
212- | Discord
213- deriving stock (Show , Eq )
214-
215- -- A type to unify slack and discord message types
216- data MessageContent (provider :: ChatProvider ) = MessageContent
217- { -- Text of the bot message
218- preText :: Text ,
219- -- Title of the attachment
220- title :: Text ,
221- -- Text of the attachment
222- content :: Text ,
223- -- Title link
224- mainLink :: URI ,
225- authorName :: Text ,
226- authorLink :: URI ,
227- authorAvatarUrl :: Maybe URI ,
228- thumbnailUrl :: Maybe URI ,
229- timestamp :: UTCTime
230- }
231- deriving stock (Show , Eq )
232-
233- instance ToJSON (MessageContent 'Slack) where
234- toJSON MessageContent {preText, content, title, mainLink, authorName, authorLink, authorAvatarUrl, thumbnailUrl, timestamp} =
235- Aeson. object
236- [ " text" .= preText,
237- " attachments"
238- .= [ Aeson. object
239- [ " title" .= cutOffText 250 title,
240- " title_link" .= uriToText mainLink,
241- " text" .= content,
242- " author_name" .= authorName,
243- " author_link" .= uriToText authorLink,
244- " author_icon" .= fmap uriToText authorAvatarUrl,
245- " thumb_url" .= fmap uriToText thumbnailUrl,
246- " ts" .= (round (POSIX. utcTimeToPOSIXSeconds timestamp) :: Int64 ),
247- " color" .= (" #36a64f" :: Text )
248- ]
249- ]
250- ]
251-
252- instance ToJSON (MessageContent 'Discord) where
253- toJSON MessageContent {preText, content, title, mainLink, authorName, authorLink, authorAvatarUrl, thumbnailUrl, timestamp} =
254- Aeson. object
255- [ " username" .= (" Share Notifications" :: Text ),
256- " avatar_url" .= Links. unisonLogoImage,
257- " content" .= cutOffText 1950 preText,
258- " embeds"
259- .= [ Aeson. object
260- [ " title" .= cutOffText 250 title,
261- " url" .= uriToText mainLink,
262- " description" .= cutOffText 4000 content,
263- " author" .= Aeson. object [" name" .= cutOffText 250 authorName, " url" .= uriToText authorLink, " icon_url" .= fmap uriToText authorAvatarUrl],
264- " timestamp" .= (Just $ Text. pack $ Time. formatTime Time. defaultTimeLocale " %FT%T%QZ" timestamp),
265- " thumbnail" .= fmap (\ url -> Aeson. object [" url" .= uriToText url]) thumbnailUrl
266- ]
267- ]
268- ]
269-
270209buildWebhookRequest :: NotificationWebhookId -> URI -> NotificationEvent NotificationEventId UnifiedDisplayInfo UTCTime HydratedEventPayload -> WebhookEventPayload JWTParam -> Background (Either WebhookSendFailure HTTPClient. Request )
271210buildWebhookRequest webhookId uri event defaultPayload = do
272211 if
273- | isSlackWebhook uri -> buildChatAppPayload (Proxy @ Slack ) uri
274- | isDiscordWebhook uri -> buildChatAppPayload (Proxy @ Discord ) uri
275- | otherwise -> pure $ buildDefaultPayload
212+ | isSlackWebhook uri -> buildChatAppPayload (Proxy @ ChatApps. Slack ) uri
213+ | isDiscordWebhook uri -> buildChatAppPayload (Proxy @ ChatApps. Discord ) uri
214+ | otherwise -> pure $ buildDefaultPayload
276215 where
277216 isSlackWebhook :: URI -> Bool
278217 isSlackWebhook uri =
@@ -300,28 +239,31 @@ buildWebhookRequest webhookId uri event defaultPayload = do
300239 HTTPClient. requestBody = HTTPClient. RequestBodyLBS $ Aeson. encode defaultPayload
301240 }
302241
303- buildChatAppPayload :: forall provider . (ToJSON (MessageContent provider )) => Proxy provider -> URI -> Background (Either WebhookSendFailure HTTPClient. Request )
242+ buildChatAppPayload :: forall provider . (ToJSON (ChatApps. MessageContent provider )) => Proxy provider -> URI -> Background (Either WebhookSendFailure HTTPClient. Request )
304243 buildChatAppPayload _ uri = do
305244 let actorName = event. eventActor ^. DisplayInfo. name_
306245 actorHandle = " (" <> IDs. toText (PrefixedID @ " @" $ event. eventActor ^. DisplayInfo. handle_) <> " )"
307246 actorAuthor = maybe " " (<> " " ) actorName <> actorHandle
308247 actorAvatarUrl = event. eventActor ^. DisplayInfo. avatarUrl_
309248 actorLink <- Links. userProfilePage (event. eventActor ^. DisplayInfo. handle_)
310- messageContent :: MessageContent provider <- case event. eventData of
249+ messageContent :: ChatApps. MessageContent provider <- case event. eventData of
311250 HydratedProjectBranchUpdatedPayload payload -> do
312251 let pbShorthand = (projectBranchShortHandFromParts payload. projectInfo. projectShortHand payload. branchInfo. branchShortHand)
313252 title = " Branch " <> IDs. toText pbShorthand <> " was just updated."
314253 preText = title
315254 link <- Links. notificationLink event. eventData
316255 pure $
317- MessageContent
256+ ChatApps. MessageContent
318257 { preText = preText,
319258 content = " Branch updated" ,
320259 title = title,
321- mainLink = link,
322- authorName = actorAuthor,
323- authorLink = actorLink,
324- authorAvatarUrl = actorAvatarUrl,
260+ mainLink = Just link,
261+ author =
262+ Author
263+ { authorName = Just actorAuthor,
264+ authorLink = Just actorLink,
265+ authorAvatarUrl = actorAvatarUrl
266+ },
325267 thumbnailUrl = Nothing ,
326268 timestamp = event. eventOccurredAt
327269 }
@@ -332,14 +274,17 @@ buildWebhookRequest webhookId uri event defaultPayload = do
332274 preText = " New Contribution in " <> IDs. toText pbShorthand
333275 link <- Links. notificationLink event. eventData
334276 pure $
335- MessageContent
277+ ChatApps. MessageContent
336278 { preText = preText,
337279 content = description,
338280 title = title,
339- mainLink = link,
340- authorName = actorAuthor,
341- authorLink = actorLink,
342- authorAvatarUrl = actorAvatarUrl,
281+ mainLink = Just link,
282+ author =
283+ Author
284+ { authorName = Just actorAuthor,
285+ authorLink = Just actorLink,
286+ authorAvatarUrl = actorAvatarUrl
287+ },
343288 thumbnailUrl = Nothing ,
344289 timestamp = event. eventOccurredAt
345290 }
@@ -355,13 +300,6 @@ buildWebhookRequest webhookId uri event defaultPayload = do
355300 }
356301 )
357302
358- -- | Nicely cut off text so that it doesn't exceed the max length
359- cutOffText :: Int -> Text -> Text
360- cutOffText maxLength text =
361- if Text. length text > maxLength
362- then Text. take (maxLength - 3 ) text <> " ..."
363- else text
364-
365303attemptWebhookSend ::
366304 AuthZ. AuthZReceipt ->
367305 (NotificationEvent NotificationEventId UnifiedDisplayInfo UTCTime HydratedEventPayload -> NotificationWebhookId -> IO (Maybe WebhookSendFailure )) ->
0 commit comments