Skip to content

Commit 3f64a6f

Browse files
authored
Merge pull request #64 from unisoncomputing/cp/hydrate-hub-notifications
Hydrate hub notifications
2 parents f0453c9 + f8c5234 commit 3f64a6f

47 files changed

Lines changed: 889 additions & 528 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

share-api.cabal

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ library
3737
Share.BackgroundJobs.SerializedEntitiesMigration.Queries
3838
Share.BackgroundJobs.SerializedEntitiesMigration.Worker
3939
Share.BackgroundJobs.Webhooks.Queries
40-
Share.BackgroundJobs.Webhooks.Types
4140
Share.BackgroundJobs.Webhooks.Worker
4241
Share.BackgroundJobs.Workers
4342
Share.Branch
@@ -64,6 +63,7 @@ library
6463
Share.Postgres.Causal.Queries
6564
Share.Postgres.Causal.Types
6665
Share.Postgres.Comments.Queries
66+
Share.Postgres.Contributions.Ops
6767
Share.Postgres.Contributions.Queries
6868
Share.Postgres.Cursors
6969
Share.Postgres.Definitions.Queries
@@ -148,7 +148,8 @@ library
148148
Share.Web.Share.DefinitionSearch
149149
Share.Web.Share.Diffs.Impl
150150
Share.Web.Share.Diffs.Types
151-
Share.Web.Share.DisplayInfo
151+
Share.Web.Share.DisplayInfo.Queries
152+
Share.Web.Share.DisplayInfo.Types
152153
Share.Web.Share.Impl
153154
Share.Web.Share.Orgs.API
154155
Share.Web.Share.Orgs.Impl

sql/2025-05-07_event-actor.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
ALTER TABLE notification_events
2+
ADD COLUMN actor_user_id UUID NULL REFERENCES users(id) ON DELETE SET NULL
3+
;
Lines changed: 2 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
1+
{-# LANGUAGE ApplicativeDo #-}
2+
13
-- | This module contains queries related to sending notification webhooks.
24
module Share.BackgroundJobs.Webhooks.Queries
35
( queueWebhook,
46
getUnsentWebhook,
57
recordFailedDeliveryAttempt,
68
markWebhookAsDelivered,
7-
hydrateEventData,
89
)
910
where
1011

11-
import Share.BackgroundJobs.Webhooks.Types
12-
import Share.Contribution (Contribution (..))
1312
import Share.IDs
14-
import Share.Notifications.Types
1513
import Share.Postgres
16-
import Share.Postgres.Contributions.Queries qualified as ContributionQ
1714
import Share.Postgres.Notifications qualified as Notif
18-
import Share.Postgres.Users.Queries qualified as UsersQ
1915

2016
queueWebhook :: (QueryM m) => NotificationEventId -> NotificationWebhookId -> m ()
2117
queueWebhook eventId webhookId = do
@@ -57,77 +53,3 @@ markWebhookAsDelivered eventId webhookId = do
5753
SET delivered = TRUE
5854
WHERE event_id = #{eventId} AND webhook_id = #{webhookId}
5955
|]
60-
61-
hydrateEventData :: forall m. (QueryM m) => NotificationEventData -> m WebhookPayloadData
62-
hydrateEventData = \case
63-
ProjectBranchUpdatedData
64-
(ProjectBranchData {projectId, branchId}) -> do
65-
ProjectBranchUpdatedPayload <$> hydrateProjectBranchPayload projectId branchId
66-
ProjectContributionCreatedData
67-
(ProjectContributionData {projectId, contributionId, fromBranchId, toBranchId, contributorUserId}) -> do
68-
ProjectContributionCreatedPayload <$> hydrateContributionInfo contributionId projectId fromBranchId toBranchId contributorUserId
69-
where
70-
hydrateContributionInfo :: ContributionId -> ProjectId -> BranchId -> BranchId -> UserId -> m ProjectContributionPayload
71-
hydrateContributionInfo contributionId projectId fromBranchId toBranchId authorUserId = do
72-
author <- UsersQ.userDisplayInfoOf id authorUserId
73-
projectInfo <- hydrateProjectPayload projectId
74-
mergeTargetBranch <- hydrateBranchPayload fromBranchId
75-
mergeSourceBranch <- hydrateBranchPayload toBranchId
76-
Contribution {title, description, status} <- ContributionQ.contributionById contributionId
77-
pure $
78-
ProjectContributionPayload
79-
{ projectInfo,
80-
mergeSourceBranch,
81-
mergeTargetBranch,
82-
author,
83-
title,
84-
description,
85-
contributionId,
86-
status
87-
}
88-
hydrateProjectBranchPayload projectId branchId = do
89-
branchInfo <- hydrateBranchPayload branchId
90-
projectInfo <- hydrateProjectPayload projectId
91-
pure $ ProjectBranchPayload {projectInfo, branchInfo}
92-
hydrateBranchPayload branchId = do
93-
( branchName,
94-
branchContributorUserId,
95-
branchContributorHandle
96-
) <-
97-
queryExpect1Row
98-
[sql|
99-
SELECT b.name, contributor.id, contributor.handle
100-
FROM project_branches b
101-
LEFT JOIN users contributor ON b.contributor_id = contributor.id
102-
WHERE b.id = #{branchId}
103-
|]
104-
let branchShortHand = BranchShortHand {contributorHandle = branchContributorHandle, branchName}
105-
pure $
106-
BranchPayload
107-
{ branchId,
108-
branchName,
109-
branchShortHand,
110-
branchContributorUserId,
111-
branchContributorHandle
112-
}
113-
hydrateProjectPayload projectId = do
114-
( projectSlug,
115-
projectOwnerHandle,
116-
projectOwnerUserId
117-
) <-
118-
queryExpect1Row
119-
[sql|
120-
SELECT p.slug, owner.handle, p.owner_user_id
121-
FROM projects p
122-
JOIN users owner ON p.owner_user_id = owner.id
123-
WHERE p.id = #{projectId}
124-
|]
125-
let projectShortHand = ProjectShortHand {userHandle = projectOwnerHandle, projectSlug}
126-
pure $
127-
ProjectPayload
128-
{ projectId,
129-
projectSlug,
130-
projectShortHand,
131-
projectOwnerHandle,
132-
projectOwnerUserId
133-
}

src/Share/BackgroundJobs/Webhooks/Types.hs

Lines changed: 0 additions & 154 deletions
This file was deleted.

src/Share/BackgroundJobs/Webhooks/Worker.hs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,14 @@ import Network.HTTP.Types qualified as HTTP
1818
import Share.BackgroundJobs.Errors (reportError)
1919
import Share.BackgroundJobs.Monad (Background)
2020
import Share.BackgroundJobs.Webhooks.Queries qualified as WQ
21-
import Share.BackgroundJobs.Webhooks.Queries qualified as WebhookQ
22-
import Share.BackgroundJobs.Webhooks.Types (WebhookPayloadData)
2321
import Share.BackgroundJobs.Workers (newWorker)
2422
import Share.Env qualified as Env
2523
import Share.IDs (NotificationEventId, NotificationWebhookId)
2624
import Share.JWT (JWTParam (..))
2725
import Share.JWT qualified as JWT
2826
import Share.Metrics qualified as Metrics
2927
import Share.Notifications.Queries qualified as NQ
30-
import Share.Notifications.Types (NotificationEvent (..), NotificationTopic, eventTopic)
28+
import Share.Notifications.Types (HydratedEventPayload, NotificationEvent (..), NotificationTopic, eventData_, eventUserInfo_, hydratedEventTopic)
3129
import Share.Notifications.Webhooks.Secrets (WebhookConfig (..), WebhookSecretError)
3230
import Share.Notifications.Webhooks.Secrets qualified as Webhooks
3331
import Share.Postgres qualified as PG
@@ -36,6 +34,8 @@ import Share.Prelude
3634
import Share.Utils.Logging qualified as Logging
3735
import Share.Utils.URI (URIParam (..))
3836
import Share.Web.Authorization qualified as AuthZ
37+
import Share.Web.Share.DisplayInfo.Queries qualified as DisplayInfoQ
38+
import Share.Web.Share.DisplayInfo.Types (UnifiedDisplayInfo)
3939
import UnliftIO qualified
4040

4141
data WebhookSendFailure
@@ -90,7 +90,7 @@ worker scope = do
9090
processWebhooks authZReceipt = do
9191
toIO <- UnliftIO.askRunInIO
9292
-- Need to unlift so we can use this in transactions
93-
let tryWebhookIO eventId eventData webhookId = toIO $ tryWebhook eventId eventData webhookId
93+
let tryWebhookIO eventData webhookId = toIO $ tryWebhook eventData webhookId
9494
mayResult <- Metrics.recordWebhookSendingDuration $ PG.runTransaction $ runMaybeT $ do
9595
webhookInfo@(eventId, webhookId) <- MaybeT WQ.getUnsentWebhook
9696
mayErr <- lift $ attemptWebhookSend authZReceipt tryWebhookIO eventId webhookId
@@ -127,7 +127,7 @@ data WebhookEventPayload jwt = WebhookEventPayload
127127
-- | The topic of the notification event.
128128
topic :: NotificationTopic,
129129
-- | The data associated with the notification event.
130-
data_ :: WebhookPayloadData,
130+
data_ :: HydratedEventPayload,
131131
-- | A signed token containing all of the same data.
132132
jwt :: jwt
133133
}
@@ -164,11 +164,10 @@ instance FromJSON (WebhookEventPayload ()) where
164164
<*> pure ()
165165

166166
tryWebhook ::
167-
NotificationEvent NotificationEventId UTCTime ->
168-
WebhookPayloadData ->
167+
NotificationEvent NotificationEventId UnifiedDisplayInfo UTCTime HydratedEventPayload ->
169168
NotificationWebhookId ->
170169
Background (Maybe WebhookSendFailure)
171-
tryWebhook event eventData webhookId = UnliftIO.handleAny (\someException -> pure $ Just $ InvalidRequest event.eventId webhookId someException) do
170+
tryWebhook event webhookId = UnliftIO.handleAny (\someException -> pure $ Just $ InvalidRequest event.eventId webhookId someException) do
172171
fmap (either Just (const Nothing)) $ runExceptT do
173172
proxiedHTTPManager <- asks Env.proxiedHttpClient
174173
WebhookConfig {uri = URIParam uri} <-
@@ -180,8 +179,8 @@ tryWebhook event eventData webhookId = UnliftIO.handleAny (\someException -> pur
180179
WebhookEventPayload
181180
{ eventId = event.eventId,
182181
occurredAt = event.eventOccurredAt,
183-
topic = eventTopic event.eventData,
184-
data_ = eventData,
182+
topic = hydratedEventTopic event.eventData,
183+
data_ = event.eventData,
185184
jwt = ()
186185
}
187186
payloadJWT <-
@@ -208,14 +207,15 @@ tryWebhook event eventData webhookId = UnliftIO.handleAny (\someException -> pur
208207

209208
attemptWebhookSend ::
210209
AuthZ.AuthZReceipt ->
211-
(NotificationEvent NotificationEventId UTCTime -> WebhookPayloadData -> NotificationWebhookId -> IO (Maybe WebhookSendFailure)) ->
210+
(NotificationEvent NotificationEventId UnifiedDisplayInfo UTCTime HydratedEventPayload -> NotificationWebhookId -> IO (Maybe WebhookSendFailure)) ->
212211
NotificationEventId ->
213212
NotificationWebhookId ->
214213
PG.Transaction e (Maybe WebhookSendFailure)
215214
attemptWebhookSend _authZReceipt tryWebhookIO eventId webhookId = do
216215
event <- NQ.expectEvent eventId
217-
eventData <- WebhookQ.hydrateEventData event.eventData
218-
PG.transactionUnsafeIO (tryWebhookIO event eventData webhookId) >>= \case
216+
hydratedEvent <- forOf eventData_ event NQ.hydrateEventData
217+
populatedEvent <- hydratedEvent & DisplayInfoQ.unifiedDisplayInfoForUserOf eventUserInfo_
218+
PG.transactionUnsafeIO (tryWebhookIO populatedEvent webhookId) >>= \case
219219
Just err -> do
220220
WQ.recordFailedDeliveryAttempt eventId webhookId
221221
pure $ Just err

src/Share/Notifications/API.hs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,11 @@ import Data.Text qualified as Text
3939
import Data.Time (UTCTime)
4040
import Servant
4141
import Share.IDs
42-
import Share.Notifications.Types (DeliveryMethodId, NotificationDeliveryMethod, NotificationHubEntry, NotificationStatus, NotificationSubscription, NotificationTopic, SubscriptionFilter)
42+
import Share.Notifications.Types (DeliveryMethodId, HydratedEventPayload, NotificationDeliveryMethod, NotificationHubEntry, NotificationStatus, NotificationSubscription, NotificationTopic, SubscriptionFilter)
4343
import Share.OAuth.Session (AuthenticatedUserId)
4444
import Share.Prelude
4545
import Share.Utils.URI (URIParam)
46+
import Share.Web.Share.DisplayInfo.Types (UnifiedDisplayInfo)
4647

4748
type API = NamedRoutes Routes
4849

@@ -212,7 +213,7 @@ type GetHubEntriesEndpoint =
212213
:> Get '[JSON] GetHubEntriesResponse
213214

214215
data GetHubEntriesResponse = GetHubEntriesResponse
215-
{ notifications :: [NotificationHubEntry]
216+
{ notifications :: [NotificationHubEntry UnifiedDisplayInfo HydratedEventPayload]
216217
}
217218

218219
instance ToJSON GetHubEntriesResponse where

0 commit comments

Comments
 (0)