-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathImpl.hs
More file actions
201 lines (176 loc) · 12.7 KB
/
Impl.hs
File metadata and controls
201 lines (176 loc) · 12.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
module Share.Notifications.Impl (server) where
import Control.Lens (forOf, traversed)
import Data.Time
import Servant
import Servant.Server.Generic (AsServerT)
import Share.IDs
import Share.Notifications.API qualified as API
import Share.Notifications.Ops qualified as NotifOps
import Share.Notifications.Queries qualified as NotificationQ
import Share.Postgres qualified as PG
import Share.Postgres.Ops qualified as UserQ
import Share.User (User (..))
import Share.Web.App
import Share.Web.Authorization qualified as AuthZ
hubRoutes :: UserHandle -> API.HubEntriesRoutes (AsServerT WebApp)
hubRoutes userHandle =
API.HubEntriesRoutes
{ getHubEntriesEndpoint = getHubEntriesEndpoint userHandle,
updateHubEntriesEndpoint = updateHubEntriesEndpoint userHandle
}
deliveryMethodRoutes :: UserHandle -> API.DeliveryMethodRoutes (AsServerT WebApp)
deliveryMethodRoutes userHandle =
API.DeliveryMethodRoutes
{ getDeliveryMethodsEndpoint = getDeliveryMethodsEndpoint userHandle,
emailDeliveryRoutes = emailDeliveryRoutes userHandle,
webhookDeliveryRoutes = webhookDeliveryRoutes userHandle
}
subscriptionsRoutes :: UserHandle -> API.SubscriptionRoutes (AsServerT WebApp)
subscriptionsRoutes userHandle =
API.SubscriptionRoutes
{ getSubscriptionsEndpoint = getSubscriptionsEndpoint userHandle,
createSubscriptionEndpoint = createSubscriptionEndpoint userHandle,
deleteSubscriptionEndpoint = deleteSubscriptionEndpoint userHandle,
updateSubscriptionEndpoint = updateSubscriptionEndpoint userHandle,
subscriptionResourceRoutes = subscriptionResourceRoutes userHandle
}
subscriptionResourceRoutes :: UserHandle -> NotificationSubscriptionId -> API.SubscriptionResourceRoutes (AsServerT WebApp)
subscriptionResourceRoutes handle subscriptionId =
API.SubscriptionResourceRoutes
{ subscriptionDeliveryMethodRoutes = subscriptionDeliveryMethodRoutes handle subscriptionId
}
subscriptionDeliveryMethodRoutes :: UserHandle -> NotificationSubscriptionId -> API.SubscriptionDeliveryMethodRoutes (AsServerT WebApp)
subscriptionDeliveryMethodRoutes handle subscriptionId =
API.SubscriptionDeliveryMethodRoutes
{ getSubscriptionDeliveryMethodsEndpoint = getSubscriptionDeliveryMethodsEndpoint handle subscriptionId,
addSubscriptionDeliveryMethodsEndpoint = addSubscriptionDeliveryMethodsEndpoint handle subscriptionId,
removeSubscriptionDeliveryMethodsEndpoint = removeSubscriptionDeliveryMethodsEndpoint handle subscriptionId
}
emailDeliveryRoutes :: UserHandle -> API.EmailRoutes (AsServerT WebApp)
emailDeliveryRoutes userHandle =
API.EmailRoutes
{ createEmailDeliveryMethodEndpoint = createEmailDeliveryMethodEndpoint userHandle,
deleteEmailDeliveryMethodEndpoint = deleteEmailDeliveryMethodEndpoint userHandle,
updateEmailDeliveryMethodEndpoint = updateEmailDeliveryMethodEndpoint userHandle
}
webhookDeliveryRoutes :: UserHandle -> API.WebhookRoutes (AsServerT WebApp)
webhookDeliveryRoutes userHandle =
API.WebhookRoutes
{ createWebhookEndpoint = createWebhookEndpoint userHandle,
deleteWebhookEndpoint = deleteWebhookEndpoint userHandle,
updateWebhookEndpoint = updateWebhookEndpoint userHandle
}
server :: UserHandle -> ServerT API.API WebApp
server userHandle =
API.Routes
{ hubRoutes = hubRoutes userHandle,
deliveryMethodRoutes = deliveryMethodRoutes userHandle,
subscriptionsRoutes = subscriptionsRoutes userHandle
}
getHubEntriesEndpoint :: UserHandle -> UserId -> Maybe Int -> Maybe UTCTime -> Maybe API.StatusFilter -> WebApp API.GetHubEntriesResponse
getHubEntriesEndpoint userHandle callerUserId limit afterTime mayStatusFilter = do
User {user_id = notificationUserId} <- UserQ.expectUserByHandle userHandle
_authZReceipt <- AuthZ.permissionGuard $ AuthZ.checkNotificationsGet callerUserId notificationUserId
notifications <- PG.runTransaction do
notifs <- NotificationQ.listNotificationHubEntryPayloads notificationUserId limit afterTime (API.getStatusFilter <$> mayStatusFilter)
forOf (traversed . traversed) notifs NotifOps.hydrateEvent
pure $ API.GetHubEntriesResponse {notifications}
updateHubEntriesEndpoint :: UserHandle -> UserId -> API.UpdateHubEntriesRequest -> WebApp ()
updateHubEntriesEndpoint userHandle callerUserId API.UpdateHubEntriesRequest {notificationStatus, notificationIds} = do
User {user_id = notificationUserId} <- UserQ.expectUserByHandle userHandle
_authZReceipt <- AuthZ.permissionGuard $ AuthZ.checkNotificationsUpdate callerUserId notificationUserId
PG.runTransaction $ NotificationQ.updateNotificationHubEntries notificationIds notificationStatus
pure ()
getDeliveryMethodsEndpoint :: UserHandle -> UserId -> WebApp API.GetDeliveryMethodsResponse
getDeliveryMethodsEndpoint userHandle callerUserId = do
User {user_id = notificationUserId} <- UserQ.expectUserByHandle userHandle
_authZReceipt <- AuthZ.permissionGuard $ AuthZ.checkDeliveryMethodsView callerUserId notificationUserId
deliveryMethods <- NotifOps.listNotificationDeliveryMethods notificationUserId Nothing
pure $ API.GetDeliveryMethodsResponse {deliveryMethods}
createEmailDeliveryMethodEndpoint :: UserHandle -> UserId -> API.CreateEmailDeliveryMethodRequest -> WebApp API.CreateEmailDeliveryMethodResponse
createEmailDeliveryMethodEndpoint userHandle callerUserId API.CreateEmailDeliveryMethodRequest {email} = do
User {user_id = notificationUserId} <- UserQ.expectUserByHandle userHandle
_authZReceipt <- AuthZ.permissionGuard $ AuthZ.checkDeliveryMethodsManage callerUserId notificationUserId
emailDeliveryMethodId <- PG.runTransaction $ NotificationQ.createEmailDeliveryMethod notificationUserId email
pure $ API.CreateEmailDeliveryMethodResponse {emailDeliveryMethodId}
deleteEmailDeliveryMethodEndpoint :: UserHandle -> UserId -> NotificationEmailDeliveryMethodId -> WebApp ()
deleteEmailDeliveryMethodEndpoint userHandle callerUserId emailDeliveryMethodId = do
User {user_id = notificationUserId} <- UserQ.expectUserByHandle userHandle
_authZReceipt <- AuthZ.permissionGuard $ AuthZ.checkDeliveryMethodsManage callerUserId notificationUserId
PG.runTransaction $ NotificationQ.deleteEmailDeliveryMethod notificationUserId emailDeliveryMethodId
pure ()
updateEmailDeliveryMethodEndpoint :: UserHandle -> UserId -> NotificationEmailDeliveryMethodId -> API.UpdateEmailDeliveryMethodRequest -> WebApp ()
updateEmailDeliveryMethodEndpoint userHandle callerUserId emailDeliveryMethodId API.UpdateEmailDeliveryMethodRequest {email} = do
User {user_id = notificationUserId} <- UserQ.expectUserByHandle userHandle
_authZReceipt <- AuthZ.permissionGuard $ AuthZ.checkDeliveryMethodsManage callerUserId notificationUserId
PG.runTransaction $ NotificationQ.updateEmailDeliveryMethod notificationUserId emailDeliveryMethodId email
pure ()
getSubscriptionDeliveryMethodsEndpoint :: UserHandle -> NotificationSubscriptionId -> UserId -> WebApp API.GetDeliveryMethodsResponse
getSubscriptionDeliveryMethodsEndpoint userHandle subscriptionId callerUserId = do
User {user_id = notificationUserId} <- UserQ.expectUserByHandle userHandle
_authZReceipt <- AuthZ.permissionGuard $ AuthZ.checkDeliveryMethodsView callerUserId notificationUserId
deliveryMethods <- NotifOps.listNotificationDeliveryMethods notificationUserId (Just subscriptionId)
pure $ API.GetDeliveryMethodsResponse {deliveryMethods}
addSubscriptionDeliveryMethodsEndpoint :: UserHandle -> NotificationSubscriptionId -> UserId -> API.AddSubscriptionDeliveryMethodsRequest -> WebApp ()
addSubscriptionDeliveryMethodsEndpoint userHandle subscriptionId callerUserId API.AddSubscriptionDeliveryMethodsRequest {deliveryMethods} = do
User {user_id = notificationUserId} <- UserQ.expectUserByHandle userHandle
_authZReceipt <- AuthZ.permissionGuard $ AuthZ.checkDeliveryMethodsManage callerUserId notificationUserId
PG.runTransaction $ NotificationQ.addSubscriptionDeliveryMethods notificationUserId subscriptionId deliveryMethods
pure ()
removeSubscriptionDeliveryMethodsEndpoint :: UserHandle -> NotificationSubscriptionId -> UserId -> API.RemoveSubscriptionDeliveryMethodsRequest -> WebApp ()
removeSubscriptionDeliveryMethodsEndpoint userHandle subscriptionId callerUserId API.RemoveSubscriptionDeliveryMethodsRequest {deliveryMethods} = do
User {user_id = notificationUserId} <- UserQ.expectUserByHandle userHandle
_authZReceipt <- AuthZ.permissionGuard $ AuthZ.checkDeliveryMethodsManage callerUserId notificationUserId
PG.runTransaction $ NotificationQ.removeSubscriptionDeliveryMethods notificationUserId subscriptionId deliveryMethods
pure ()
createWebhookEndpoint :: UserHandle -> UserId -> API.CreateWebhookRequest -> WebApp API.CreateWebhookResponse
createWebhookEndpoint userHandle callerUserId API.CreateWebhookRequest {url, name = webhookName} = do
User {user_id = notificationUserId} <- UserQ.expectUserByHandle userHandle
_authZReceipt <- AuthZ.permissionGuard $ AuthZ.checkDeliveryMethodsManage callerUserId notificationUserId
webhookId <- NotifOps.createWebhookDeliveryMethod notificationUserId url webhookName
pure $ API.CreateWebhookResponse {webhookId}
deleteWebhookEndpoint :: UserHandle -> UserId -> NotificationWebhookId -> WebApp ()
deleteWebhookEndpoint userHandle callerUserId webhookDeliveryMethodId = do
User {user_id = notificationUserId} <- UserQ.expectUserByHandle userHandle
_authZReceipt <- AuthZ.permissionGuard $ AuthZ.checkDeliveryMethodsManage callerUserId notificationUserId
NotifOps.deleteWebhookDeliveryMethod notificationUserId webhookDeliveryMethodId
pure ()
updateWebhookEndpoint :: UserHandle -> UserId -> NotificationWebhookId -> API.UpdateWebhookRequest -> WebApp ()
updateWebhookEndpoint userHandle callerUserId webhookDeliveryMethodId API.UpdateWebhookRequest {url} = do
User {user_id = notificationUserId} <- UserQ.expectUserByHandle userHandle
_authZReceipt <- AuthZ.permissionGuard $ AuthZ.checkDeliveryMethodsManage callerUserId notificationUserId
NotifOps.updateWebhookDeliveryMethod notificationUserId webhookDeliveryMethodId url
pure ()
getSubscriptionsEndpoint :: UserHandle -> UserId -> WebApp API.GetSubscriptionsResponse
getSubscriptionsEndpoint userHandle callerUserId = do
User {user_id = notificationUserId} <- UserQ.expectUserByHandle userHandle
_authZReceipt <- AuthZ.permissionGuard $ AuthZ.checkSubscriptionsView callerUserId notificationUserId
subscriptions <- PG.runTransaction $ NotificationQ.listNotificationSubscriptions notificationUserId
pure $ API.GetSubscriptionsResponse {subscriptions}
createSubscriptionEndpoint :: UserHandle -> UserId -> API.CreateSubscriptionRequest -> WebApp API.CreateSubscriptionResponse
createSubscriptionEndpoint subscriberHandle callerUserId API.CreateSubscriptionRequest {subscriptionScope, subscriptionTopics, subscriptionFilter} = do
User {user_id = subscriberUserId} <- UserQ.expectUserByHandle subscriberHandle
User {user_id = scopeUserId} <- UserQ.expectUserByHandle subscriptionScope
_authZReceipt <- AuthZ.permissionGuard $ AuthZ.checkSubscriptionsManage callerUserId subscriberUserId
-- NOTE: We allow creating any sort of notification subscription, even for things a user
-- doesn't have access to, but the notification system will only actually create notifications if the caller has access to
-- the resource of a given event for the permission associated to that topic via the
-- 'topic_permission' SQL function.
subscription <- PG.runTransaction $ do
subscriptionId <- NotificationQ.createNotificationSubscription subscriberUserId scopeUserId subscriptionTopics subscriptionFilter
NotificationQ.getNotificationSubscription subscriberUserId subscriptionId
pure $ API.CreateSubscriptionResponse {subscription}
deleteSubscriptionEndpoint :: UserHandle -> UserId -> NotificationSubscriptionId -> WebApp ()
deleteSubscriptionEndpoint userHandle callerUserId subscriptionId = do
User {user_id = notificationUserId} <- UserQ.expectUserByHandle userHandle
_authZReceipt <- AuthZ.permissionGuard $ AuthZ.checkSubscriptionsManage callerUserId notificationUserId
PG.runTransaction $ NotificationQ.deleteNotificationSubscription notificationUserId subscriptionId
pure ()
updateSubscriptionEndpoint :: UserHandle -> UserId -> NotificationSubscriptionId -> API.UpdateSubscriptionRequest -> WebApp API.CreateSubscriptionResponse
updateSubscriptionEndpoint userHandle callerUserId subscriptionId API.UpdateSubscriptionRequest {subscriptionTopics, subscriptionFilter} = do
User {user_id = notificationUserId} <- UserQ.expectUserByHandle userHandle
_authZReceipt <- AuthZ.permissionGuard $ AuthZ.checkSubscriptionsManage callerUserId notificationUserId
subscription <- PG.runTransaction $ do
NotificationQ.updateNotificationSubscription notificationUserId subscriptionId subscriptionTopics subscriptionFilter
NotificationQ.getNotificationSubscription notificationUserId subscriptionId
pure $ API.CreateSubscriptionResponse {subscription}