module Model.Notification
( module Model.Notification.Types
, module Model.Notification.Notify
, addNotification
, addBroadcastNotification
, changeNotificationsDelivery
, lookupUserNotifications
, countUserNotifications
, lookupUndeliveredNotifications
, removeNotification
, removeNotifications
, cleanNotifications
, removeMatchingNotifications
, notificationJSON
) where
import Control.Monad (mfilter)
import Data.Int (Int64)
import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))
import Database.PostgreSQL.Typed (pgSQL)
import Has
import qualified JSON
import Service.DB
import Model.SQL
import Model.Id.Types
import Model.Party
import Model.Volume.Types
import Model.Segment
import Model.Tag.Types
import Model.Notification.Types
import Model.Notification.Notify
import Model.Notification.SQL
useTDB
addNotification :: (MonadDB c m, MonadHas Party c m) => Notification -> m Notification
addNotification n@Notification{..} = do
u <- peeks partyRow
(i, t) <- dbQuery1' [pgSQL|INSERT INTO notification (target, notice, delivered, agent, party, volume, container, segment, asset, comment, tag, permission, release) VALUES (${partyId $ partyRow $ accountParty notificationTarget}, ${notificationNotice}, ${notificationDelivered}, ${partyId u}, ${partyId <$> notificationParty}, ${volumeId <$> notificationVolume}, ${notificationContainerId}, ${notificationSegment}, ${notificationAssetId}, ${notificationCommentId}, ${tagId <$> notificationTag}, ${notificationPermission}, ${notificationRelease}) RETURNING id, time|]
return n
{ notificationId = i
, notificationTime = t
, notificationAgent = u
}
addBroadcastNotification :: (MonadDB c m, MonadHas Party c m) => Notification -> m Int
addBroadcastNotification Notification{..} = do
u <- peeks (partyId . partyRow)
dbExecute [pgSQL|INSERT INTO notification (target, notice, delivered, agent, party, volume, container, segment, asset, comment, tag, permission, release) SELECT target, notice, ${notificationDelivered}, ${u}, ${partyId <$> notificationParty}, ${volumeId <$> notificationVolume}, ${notificationContainerId}, ${notificationSegment}, ${notificationAssetId}, ${notificationCommentId}, ${tagId <$> notificationTag}, ${notificationPermission}, ${notificationRelease} FROM notify_view WHERE notice = ${notificationNotice} AND delivery > 'none' AND target <> ${u}|]
changeNotificationsDelivery :: MonadDB c m => [Notification] -> Delivery -> m Int
changeNotificationsDelivery nl d =
dbExecute [pgSQL|UPDATE notification SET delivered = ${d} WHERE id = ANY (${map notificationId nl}) AND delivered < ${d}|]
lookupUserNotifications :: (MonadDB c m, MonadHas Account c m) => m [Notification]
lookupUserNotifications = do
u <- peek
dbQuery $ ($ u) <$> $(selectQuery selectTargetNotification "$WHERE target = ${view u :: Id Party} ORDER BY notification.id DESC")
countUserNotifications :: (MonadDB c m, MonadHas (Id Party) c m) => m Int64
countUserNotifications = do
u <- peek
dbQuery1' $ fromMaybe 0 <$> [pgSQL|$SELECT count(id) FROM notification WHERE target = ${u :: Id Party} AND delivered = 'none'|]
lookupUndeliveredNotifications :: MonadDB c m => Delivery -> m [Notification]
lookupUndeliveredNotifications d =
dbQuery $(selectQuery selectNotification "JOIN notify_view USING (target, notice) WHERE delivery >= ${d} AND delivered = 'none' ORDER BY notification.target, notification.id")
removeNotification :: (MonadDB c m, MonadHas (Id Party) c m) => Id Notification -> m Bool
removeNotification i = do
p <- peek
dbExecute1 [pgSQL|DELETE FROM notification WHERE id = ${i} AND target = ${p :: Id Party}|]
removeNotifications :: (MonadDB c m, MonadHas (Id Party) c m) => m Int
removeNotifications = do
p <- peek
dbExecute [pgSQL|DELETE FROM notification WHERE target = ${p :: Id Party} AND agent <> ${partyId $ partyRow nobodyParty}|]
cleanNotifications :: MonadDB c m => m Int
cleanNotifications =
dbExecute [pgSQL|DELETE FROM notification WHERE delivered > 'none' AND time < CURRENT_TIMESTAMP interval '30 days'|]
removeMatchingNotifications :: MonadDB c m => Notification -> m Int
removeMatchingNotifications Notification{..} =
dbExecute [pgSQL|DELETE FROM notification
WHERE notice = ${notificationNotice}
AND target = COALESCE(${mfilter (no /=) $ Just $ partyId $ partyRow $ accountParty notificationTarget}, target)
AND agent = COALESCE(${mfilter (no /=) $ Just $ partyId notificationAgent}, agent)
AND COALESCE(party, 1) = COALESCE(${partyId <$> notificationParty}, party, 1)
AND COALESCE(volume, 1) = COALESCE(${volumeId <$> notificationVolume}, volume, 1)
AND COALESCE(container, 1) = COALESCE(${notificationContainerId}, container, 1)
AND COALESCE(segment, 'empty') <@ ${fromMaybe fullSegment notificationSegment}
AND COALESCE(asset, 1) = COALESCE(${notificationAssetId}, asset, 1)
AND COALESCE(comment, 1) = COALESCE(${notificationCommentId}, comment, 1)
AND COALESCE(tag, 1) = COALESCE(${tagId <$> notificationTag}, tag, 1)
|]
where
no :: Num (IdType a) => Id a
no = Id $ 1
notificationJSON :: JSON.ToNestedObject o u => Notification -> JSON.Record (Id Notification) o
notificationJSON Notification{..} = JSON.Record notificationId $
"notice" JSON..= notificationNotice
<> "time" JSON..= notificationTime
<> "delivered" JSON..= notificationDelivered
<> "agent" JSON..=. JSON.recordObject ( partyRowJSON notificationAgent)
<> "party" `JSON.kvObjectOrEmpty` (partyId <$> notificationParty)
<> "permission" `JSON.kvObjectOrEmpty` notificationPermission
<> "volume" `JSON.kvObjectOrEmpty` (volumeId <$> notificationVolume)
<> "container" `JSON.kvObjectOrEmpty` notificationContainerId
<> "segment" `JSON.kvObjectOrEmpty` notificationSegment
<> "asset" `JSON.kvObjectOrEmpty` notificationAssetId
<> "comment" `JSON.kvObjectOrEmpty` notificationCommentId
<> "tag" `JSON.kvObjectOrEmpty` (tagName <$> notificationTag)