mirror of
https://code.sup39.dev/repos/Wqawg
synced 2024-12-27 16:44:52 +09:00
S2S: sharerCreateNoteF & projectCreateNoteF can handle sharer-hosted tickets
This commit is contained in:
parent
edaa3c49b2
commit
c91908941b
3 changed files with 242 additions and 191 deletions
|
@ -149,11 +149,6 @@ parseComment luParent = do
|
||||||
MessageR shr hid -> (shr,) <$> decodeKeyHashidE hid "Non-existent local message hashid"
|
MessageR shr hid -> (shr,) <$> decodeKeyHashidE hid "Non-existent local message hashid"
|
||||||
_ -> throwE "Not a local message route"
|
_ -> throwE "Not a local message route"
|
||||||
|
|
||||||
data NoteContext
|
|
||||||
= NoteContextSharerTicket ShrIdent TicketAuthorLocalId
|
|
||||||
| NoteContextProjectTicket ShrIdent PrjIdent LocalTicketId
|
|
||||||
deriving Eq
|
|
||||||
|
|
||||||
noteC
|
noteC
|
||||||
:: Entity Person
|
:: Entity Person
|
||||||
-> Sharer
|
-> Sharer
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
-}
|
-}
|
||||||
|
|
||||||
module Vervis.ActivityPub
|
module Vervis.ActivityPub
|
||||||
( hostIsLocal
|
( NoteContext (..)
|
||||||
|
, hostIsLocal
|
||||||
, verifyHostLocal
|
, verifyHostLocal
|
||||||
, parseContext
|
, parseContext
|
||||||
, parseParent
|
, parseParent
|
||||||
|
@ -43,6 +44,7 @@ module Vervis.ActivityPub
|
||||||
, deliverLocal
|
, deliverLocal
|
||||||
, RemoteRecipient (..)
|
, RemoteRecipient (..)
|
||||||
, deliverLocal'
|
, deliverLocal'
|
||||||
|
, insertRemoteActivityToLocalInboxes
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
|
@ -119,6 +121,11 @@ import Vervis.Time
|
||||||
import Vervis.Widget.Repo
|
import Vervis.Widget.Repo
|
||||||
import Vervis.Widget.Sharer
|
import Vervis.Widget.Sharer
|
||||||
|
|
||||||
|
data NoteContext
|
||||||
|
= NoteContextSharerTicket ShrIdent TicketAuthorLocalId
|
||||||
|
| NoteContextProjectTicket ShrIdent PrjIdent LocalTicketId
|
||||||
|
deriving Eq
|
||||||
|
|
||||||
hostIsLocal :: (MonadSite m, SiteEnv m ~ App) => Host -> m Bool
|
hostIsLocal :: (MonadSite m, SiteEnv m ~ App) => Host -> m Bool
|
||||||
hostIsLocal h = asksSite $ (== h) . appInstanceHost . appSettings
|
hostIsLocal h = asksSite $ (== h) . appInstanceHost . appSettings
|
||||||
|
|
||||||
|
@ -132,7 +139,7 @@ verifyHostLocal h t = do
|
||||||
parseContext
|
parseContext
|
||||||
:: (MonadSite m, SiteEnv m ~ App)
|
:: (MonadSite m, SiteEnv m ~ App)
|
||||||
=> FedURI
|
=> FedURI
|
||||||
-> ExceptT Text m (Either (ShrIdent, PrjIdent, KeyHashid LocalTicket) FedURI)
|
-> ExceptT Text m (Either NoteContext FedURI)
|
||||||
parseContext uContext = do
|
parseContext uContext = do
|
||||||
let ObjURI hContext luContext = uContext
|
let ObjURI hContext luContext = uContext
|
||||||
local <- hostIsLocal hContext
|
local <- hostIsLocal hContext
|
||||||
|
@ -142,7 +149,12 @@ parseContext uContext = do
|
||||||
Nothing -> throwE "Local context isn't a valid route"
|
Nothing -> throwE "Local context isn't a valid route"
|
||||||
Just r -> return r
|
Just r -> return r
|
||||||
case route of
|
case route of
|
||||||
ProjectTicketR shr prj num -> return (shr, prj, num)
|
SharerTicketR shr talkhid ->
|
||||||
|
NoteContextSharerTicket shr <$>
|
||||||
|
decodeKeyHashidE talkhid "Note context invalid talkhid"
|
||||||
|
ProjectTicketR shr prj ltkhid ->
|
||||||
|
NoteContextProjectTicket shr prj <$>
|
||||||
|
decodeKeyHashidE ltkhid "Note context invalid ltkhid"
|
||||||
_ -> throwE "Local context isn't a ticket route"
|
_ -> throwE "Local context isn't a ticket route"
|
||||||
else return $ Right uContext
|
else return $ Right uContext
|
||||||
|
|
||||||
|
@ -735,15 +747,25 @@ data RemoteRecipient = RemoteRecipient
|
||||||
-- * Insert activity to inboxes of actors
|
-- * Insert activity to inboxes of actors
|
||||||
-- * If collections are listed, insert activity to the local members and return
|
-- * If collections are listed, insert activity to the local members and return
|
||||||
-- the remote members
|
-- the remote members
|
||||||
deliverLocal'
|
insertActivityToLocalInboxes
|
||||||
:: Bool -- ^ Whether to deliver to collection only if owner actor is addressed
|
:: PersistRecordBackend record SqlBackend
|
||||||
-> LocalActor
|
=> (InboxId -> InboxItemId -> record)
|
||||||
-> InboxId
|
-- ^ Database record to insert as an new inbox item to each inbox
|
||||||
-> OutboxItemId
|
-> Bool
|
||||||
|
-- ^ Whether to deliver to collection only if owner actor is addressed
|
||||||
|
-> Maybe LocalActor
|
||||||
|
-- ^ An actor whose collections are excluded from requiring an owner, i.e.
|
||||||
|
-- even if owner is required, this actor's collections will be delivered
|
||||||
|
-- to, even if this actor isn't addressed. This is meant to be the
|
||||||
|
-- activity's author.
|
||||||
|
-> Maybe InboxId
|
||||||
|
-- ^ A user person's inbox to exclude from delivery, even if this person is
|
||||||
|
-- listed in the recipient set. This is meant to be the activity's
|
||||||
|
-- author.
|
||||||
-> LocalRecipientSet
|
-> LocalRecipientSet
|
||||||
-> AppDB [((InstanceId, Host), NonEmpty RemoteRecipient)]
|
-> AppDB [((InstanceId, Host), NonEmpty RemoteRecipient)]
|
||||||
deliverLocal' requireOwner author ibidAuthor obiid recips = do
|
insertActivityToLocalInboxes makeInboxItem requireOwner mauthor mibidAuthor recips = do
|
||||||
ibidsSharer <- L.delete ibidAuthor <$> getSharerInboxes recips
|
ibidsSharer <- deleteAuthor <$> getSharerInboxes recips
|
||||||
ibidsOther <- concat <$> traverse getOtherInboxes recips
|
ibidsOther <- concat <$> traverse getOtherInboxes recips
|
||||||
|
|
||||||
(ibidsFollowers, remotesFollowers) <- do
|
(ibidsFollowers, remotesFollowers) <- do
|
||||||
|
@ -754,13 +776,23 @@ deliverLocal' requireOwner author ibidAuthor obiid recips = do
|
||||||
|
|
||||||
ibidsTeams <- foldl' LO.union [] <$> traverse getTeams recips
|
ibidsTeams <- foldl' LO.union [] <$> traverse getTeams recips
|
||||||
|
|
||||||
let ibids = L.delete ibidAuthor (ibidsFollowers `LO.union` ibidsTeams `LO.union` ibidsSharer) ++ ibidsOther
|
let ibids = deleteAuthor (ibidsFollowers `LO.union` ibidsTeams `LO.union` ibidsSharer) ++ ibidsOther
|
||||||
ibiids <- insertMany $ replicate (length ibids) $ InboxItem True
|
ibiids <- insertMany $ replicate (length ibids) $ InboxItem True
|
||||||
insertMany_ $
|
insertMany_ $ zipWith makeInboxItem ibids ibiids
|
||||||
map (\ (ibid, ibiid) -> InboxItemLocal ibid obiid ibiid)
|
|
||||||
(zip ibids ibiids)
|
|
||||||
return remotesFollowers
|
return remotesFollowers
|
||||||
where
|
where
|
||||||
|
isAuthor :: LocalActor -> Bool
|
||||||
|
isAuthor =
|
||||||
|
case mauthor of
|
||||||
|
Nothing -> const False
|
||||||
|
Just author -> (== author)
|
||||||
|
|
||||||
|
deleteAuthor :: [InboxId] -> [InboxId]
|
||||||
|
deleteAuthor =
|
||||||
|
case mibidAuthor of
|
||||||
|
Nothing -> id
|
||||||
|
Just ibidAuthor -> L.delete ibidAuthor
|
||||||
|
|
||||||
getSharerInboxes :: LocalRecipientSet -> AppDB [InboxId]
|
getSharerInboxes :: LocalRecipientSet -> AppDB [InboxId]
|
||||||
getSharerInboxes sharers = do
|
getSharerInboxes sharers = do
|
||||||
let shrs =
|
let shrs =
|
||||||
|
@ -801,7 +833,7 @@ deliverLocal' requireOwner author ibidAuthor obiid recips = do
|
||||||
[shr | (shr, s) <- sharers
|
[shr | (shr, s) <- sharers
|
||||||
, let d = localRecipSharerDirect s
|
, let d = localRecipSharerDirect s
|
||||||
in localRecipSharerFollowers d &&
|
in localRecipSharerFollowers d &&
|
||||||
(localRecipSharer d || not requireOwner || LocalActorSharer shr == author)
|
(localRecipSharer d || not requireOwner || isAuthor (LocalActorSharer shr))
|
||||||
]
|
]
|
||||||
sids <- selectKeysList [SharerIdent <-. shrs] []
|
sids <- selectKeysList [SharerIdent <-. shrs] []
|
||||||
map (personFollowers . entityVal) <$> selectList [PersonIdent <-. sids] []
|
map (personFollowers . entityVal) <$> selectList [PersonIdent <-. sids] []
|
||||||
|
@ -838,7 +870,7 @@ deliverLocal' requireOwner author ibidAuthor obiid recips = do
|
||||||
[prj | (prj, j) <- projects
|
[prj | (prj, j) <- projects
|
||||||
, let d = localRecipProjectDirect j
|
, let d = localRecipProjectDirect j
|
||||||
in localRecipProjectFollowers d &&
|
in localRecipProjectFollowers d &&
|
||||||
(localRecipProject d || not requireOwner || LocalActorProject shr prj == author)
|
(localRecipProject d || not requireOwner || isAuthor (LocalActorProject shr prj))
|
||||||
]
|
]
|
||||||
fsidsJ <-
|
fsidsJ <-
|
||||||
map (projectFollowers . entityVal) <$>
|
map (projectFollowers . entityVal) <$>
|
||||||
|
@ -848,7 +880,7 @@ deliverLocal' requireOwner author ibidAuthor obiid recips = do
|
||||||
then
|
then
|
||||||
[ (prj, localRecipProjectTicketRelated j)
|
[ (prj, localRecipProjectTicketRelated j)
|
||||||
| (prj, j) <- projects
|
| (prj, j) <- projects
|
||||||
, localRecipProject (localRecipProjectDirect j) || LocalActorProject shr prj == author
|
, localRecipProject (localRecipProjectDirect j) || isAuthor (LocalActorProject shr prj)
|
||||||
]
|
]
|
||||||
else
|
else
|
||||||
map (second localRecipProjectTicketRelated) projects
|
map (second localRecipProjectTicketRelated) projects
|
||||||
|
@ -882,7 +914,7 @@ deliverLocal' requireOwner author ibidAuthor obiid recips = do
|
||||||
[rp | (rp, r) <- repos
|
[rp | (rp, r) <- repos
|
||||||
, let d = localRecipRepoDirect r
|
, let d = localRecipRepoDirect r
|
||||||
in localRecipRepoFollowers d &&
|
in localRecipRepoFollowers d &&
|
||||||
(localRecipRepo d || not requireOwner || LocalActorRepo shr rp == author)
|
(localRecipRepo d || not requireOwner || isAuthor (LocalActorRepo shr rp))
|
||||||
]
|
]
|
||||||
in map (repoFollowers . entityVal) <$>
|
in map (repoFollowers . entityVal) <$>
|
||||||
selectList [RepoSharer ==. sid, RepoIdent <-. rps] []
|
selectList [RepoSharer ==. sid, RepoIdent <-. rps] []
|
||||||
|
@ -935,7 +967,7 @@ deliverLocal' requireOwner author ibidAuthor obiid recips = do
|
||||||
getProjectTeams sid projects = do
|
getProjectTeams sid projects = do
|
||||||
let prjs =
|
let prjs =
|
||||||
[prj | (prj, LocalProjectRelatedSet d ts) <- projects
|
[prj | (prj, LocalProjectRelatedSet d ts) <- projects
|
||||||
, (localRecipProject d || not requireOwner || LocalActorProject shr prj == author) &&
|
, (localRecipProject d || not requireOwner || isAuthor (LocalActorProject shr prj)) &&
|
||||||
(localRecipProjectTeam d || any (localRecipTicketTeam . snd) ts)
|
(localRecipProjectTeam d || any (localRecipTicketTeam . snd) ts)
|
||||||
]
|
]
|
||||||
jids <- selectKeysList [ProjectSharer ==. sid, ProjectIdent <-. prjs] []
|
jids <- selectKeysList [ProjectSharer ==. sid, ProjectIdent <-. prjs] []
|
||||||
|
@ -946,8 +978,36 @@ deliverLocal' requireOwner author ibidAuthor obiid recips = do
|
||||||
[rp | (rp, r) <- repos
|
[rp | (rp, r) <- repos
|
||||||
, let d = localRecipRepoDirect r
|
, let d = localRecipRepoDirect r
|
||||||
in localRecipRepoTeam d &&
|
in localRecipRepoTeam d &&
|
||||||
(localRecipRepo d || not requireOwner || LocalActorRepo shr rp == author)
|
(localRecipRepo d || not requireOwner || isAuthor (LocalActorRepo shr rp))
|
||||||
]
|
]
|
||||||
rids <- selectKeysList [RepoSharer ==. sid, RepoIdent <-. rps] []
|
rids <- selectKeysList [RepoSharer ==. sid, RepoIdent <-. rps] []
|
||||||
pids <- map (repoCollabPerson . entityVal) <$> selectList [RepoCollabRepo <-. rids] []
|
pids <- map (repoCollabPerson . entityVal) <$> selectList [RepoCollabRepo <-. rids] []
|
||||||
map (personInbox . entityVal) <$> selectList [PersonId <-. pids] [Asc PersonInbox]
|
map (personInbox . entityVal) <$> selectList [PersonId <-. pids] [Asc PersonInbox]
|
||||||
|
|
||||||
|
-- | Given a list of local recipients, which may include actors and
|
||||||
|
-- collections,
|
||||||
|
--
|
||||||
|
-- * Insert activity to inboxes of actors
|
||||||
|
-- * If collections are listed, insert activity to the local members and return
|
||||||
|
-- the remote members
|
||||||
|
deliverLocal'
|
||||||
|
:: Bool -- ^ Whether to deliver to collection only if owner actor is addressed
|
||||||
|
-> LocalActor
|
||||||
|
-> InboxId
|
||||||
|
-> OutboxItemId
|
||||||
|
-> LocalRecipientSet
|
||||||
|
-> AppDB [((InstanceId, Host), NonEmpty RemoteRecipient)]
|
||||||
|
deliverLocal' requireOwner author ibidAuthor obiid =
|
||||||
|
insertActivityToLocalInboxes makeItem requireOwner (Just author) (Just ibidAuthor)
|
||||||
|
where
|
||||||
|
makeItem ibid ibiid = InboxItemLocal ibid obiid ibiid
|
||||||
|
|
||||||
|
insertRemoteActivityToLocalInboxes
|
||||||
|
:: Bool
|
||||||
|
-> RemoteActivityId
|
||||||
|
-> LocalRecipientSet
|
||||||
|
-> AppDB [((InstanceId, Host), NonEmpty RemoteRecipient)]
|
||||||
|
insertRemoteActivityToLocalInboxes requireOwner ractid =
|
||||||
|
insertActivityToLocalInboxes makeItem requireOwner Nothing Nothing
|
||||||
|
where
|
||||||
|
makeItem ibid ibiid = InboxItemRemote ibid ractid ibiid
|
||||||
|
|
|
@ -27,6 +27,7 @@ import Control.Monad.Trans.Except
|
||||||
import Control.Monad.Trans.Maybe
|
import Control.Monad.Trans.Maybe
|
||||||
import Data.Bifunctor
|
import Data.Bifunctor
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
|
import Data.Either
|
||||||
import Data.Foldable
|
import Data.Foldable
|
||||||
import Data.Function
|
import Data.Function
|
||||||
import Data.List (sort, deleteBy, nub, union, unionBy, partition)
|
import Data.List (sort, deleteBy, nub, union, unionBy, partition)
|
||||||
|
@ -55,6 +56,7 @@ import Web.ActivityPub
|
||||||
import Yesod.ActivityPub
|
import Yesod.ActivityPub
|
||||||
import Yesod.FedURI
|
import Yesod.FedURI
|
||||||
import Yesod.Hashids
|
import Yesod.Hashids
|
||||||
|
import Yesod.MonadSite
|
||||||
|
|
||||||
import Control.Monad.Trans.Except.Local
|
import Control.Monad.Trans.Except.Local
|
||||||
import Data.Tuple.Local
|
import Data.Tuple.Local
|
||||||
|
@ -69,6 +71,7 @@ import Vervis.Foundation
|
||||||
import Vervis.Model
|
import Vervis.Model
|
||||||
import Vervis.Model.Ident
|
import Vervis.Model.Ident
|
||||||
import Vervis.Settings
|
import Vervis.Settings
|
||||||
|
import Vervis.Ticket
|
||||||
|
|
||||||
sharerCreateNoteF
|
sharerCreateNoteF
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
|
@ -101,56 +104,55 @@ sharerCreateNoteF now shrRecip author body (Note mluNote _ _ muParent muContext
|
||||||
Right _ ->
|
Right _ ->
|
||||||
Right <$> insertToInbox luCreate (personInbox personRecip)
|
Right <$> insertToInbox luCreate (personInbox personRecip)
|
||||||
where
|
where
|
||||||
checkContextParent context mparent = runExceptT $ do
|
checkContextParent (Left context) mparent = runExceptT $ do
|
||||||
case context of
|
did <-
|
||||||
Left (shr, prj, ltkhid) -> do
|
case context of
|
||||||
mdid <- lift $ runMaybeT $ do
|
NoteContextSharerTicket shr talid -> do
|
||||||
sid <- MaybeT $ getKeyBy $ UniqueSharer shr
|
(_, Entity _ lt, _, project) <- do
|
||||||
jid <- MaybeT $ getKeyBy $ UniqueProject prj sid
|
mticket <- lift $ getSharerTicket shr talid
|
||||||
ltid <- decodeKeyHashidM ltkhid
|
fromMaybeE mticket "Note context no such local sharer-hosted ticket"
|
||||||
lt <- MaybeT $ get ltid
|
|
||||||
tpl <-
|
|
||||||
MaybeT $ getValBy $
|
|
||||||
UniqueTicketProjectLocal $ localTicketTicket lt
|
|
||||||
guard $ ticketProjectLocalProject tpl == jid
|
|
||||||
return $ localTicketDiscuss lt
|
return $ localTicketDiscuss lt
|
||||||
did <- fromMaybeE mdid "Context: No such local ticket"
|
NoteContextProjectTicket shr prj ltid -> do
|
||||||
for_ mparent $ \ parent ->
|
(_, _, _, Entity _ lt, _, _) <- do
|
||||||
case parent of
|
mticket <- lift $ getProjectTicket shr prj ltid
|
||||||
Left (shrP, lmidP) ->
|
fromMaybeE mticket "Note context no such local project-hosted ticket"
|
||||||
void $ getLocalParentMessageId did shrP lmidP
|
return $ localTicketDiscuss lt
|
||||||
Right (ObjURI hParent luParent) -> do
|
for_ mparent $ \ parent ->
|
||||||
mrm <- lift $ runMaybeT $ do
|
case parent of
|
||||||
iid <- MaybeT $ getKeyBy $ UniqueInstance hParent
|
Left (shrP, lmidP) ->
|
||||||
roid <- MaybeT $ getKeyBy $ UniqueRemoteObject iid luParent
|
void $ getLocalParentMessageId did shrP lmidP
|
||||||
MaybeT $ getValBy $ UniqueRemoteMessageIdent roid
|
Right (ObjURI hParent luParent) -> do
|
||||||
for_ mrm $ \ rm -> do
|
mrm <- lift $ runMaybeT $ do
|
||||||
let mid = remoteMessageRest rm
|
iid <- MaybeT $ getKeyBy $ UniqueInstance hParent
|
||||||
m <- lift $ getJust mid
|
roid <- MaybeT $ getKeyBy $ UniqueRemoteObject iid luParent
|
||||||
unless (messageRoot m == did) $
|
MaybeT $ getValBy $ UniqueRemoteMessageIdent roid
|
||||||
throwE "Remote parent belongs to a different discussion"
|
for_ mrm $ \ rm -> do
|
||||||
Right (ObjURI hContext luContext) -> do
|
let mid = remoteMessageRest rm
|
||||||
mdid <- lift $ runMaybeT $ do
|
m <- lift $ getJust mid
|
||||||
iid <- MaybeT $ getKeyBy $ UniqueInstance hContext
|
unless (messageRoot m == did) $
|
||||||
roid <- MaybeT $ getKeyBy $ UniqueRemoteObject iid luContext
|
throwE "Remote parent belongs to a different discussion"
|
||||||
rd <- MaybeT $ getValBy $ UniqueRemoteDiscussionIdent roid
|
checkContextParent (Right (ObjURI hContext luContext)) mparent = runExceptT $ do
|
||||||
return $ remoteDiscussionDiscuss rd
|
mdid <- lift $ runMaybeT $ do
|
||||||
for_ mparent $ \ parent ->
|
iid <- MaybeT $ getKeyBy $ UniqueInstance hContext
|
||||||
case parent of
|
roid <- MaybeT $ getKeyBy $ UniqueRemoteObject iid luContext
|
||||||
Left (shrP, lmidP) -> do
|
rd <- MaybeT $ getValBy $ UniqueRemoteDiscussionIdent roid
|
||||||
did <- fromMaybeE mdid "Local parent inexistent, no RemoteDiscussion"
|
return $ remoteDiscussionDiscuss rd
|
||||||
void $ getLocalParentMessageId did shrP lmidP
|
for_ mparent $ \ parent ->
|
||||||
Right (ObjURI hParent luParent) -> do
|
case parent of
|
||||||
mrm <- lift $ runMaybeT $ do
|
Left (shrP, lmidP) -> do
|
||||||
iid <- MaybeT $ getKeyBy $ UniqueInstance hParent
|
did <- fromMaybeE mdid "Local parent inexistent, no RemoteDiscussion"
|
||||||
roid <- MaybeT $ getKeyBy $ UniqueRemoteObject iid luParent
|
void $ getLocalParentMessageId did shrP lmidP
|
||||||
MaybeT $ getValBy $ UniqueRemoteMessageIdent roid
|
Right (ObjURI hParent luParent) -> do
|
||||||
for_ mrm $ \ rm -> do
|
mrm <- lift $ runMaybeT $ do
|
||||||
let mid = remoteMessageRest rm
|
iid <- MaybeT $ getKeyBy $ UniqueInstance hParent
|
||||||
m <- lift $ getJust mid
|
roid <- MaybeT $ getKeyBy $ UniqueRemoteObject iid luParent
|
||||||
did <- fromMaybeE mdid "Remote parent known, but no context RemoteDiscussion"
|
MaybeT $ getValBy $ UniqueRemoteMessageIdent roid
|
||||||
unless (messageRoot m == did) $
|
for_ mrm $ \ rm -> do
|
||||||
throwE "Remote parent belongs to a different discussion"
|
let mid = remoteMessageRest rm
|
||||||
|
m <- lift $ getJust mid
|
||||||
|
did <- fromMaybeE mdid "Remote parent known, but no context RemoteDiscussion"
|
||||||
|
unless (messageRoot m == did) $
|
||||||
|
throwE "Remote parent belongs to a different discussion"
|
||||||
insertToInbox luCreate ibidRecip = do
|
insertToInbox luCreate ibidRecip = do
|
||||||
let iidAuthor = remoteAuthorInstance author
|
let iidAuthor = remoteAuthorInstance author
|
||||||
roid <-
|
roid <-
|
||||||
|
@ -167,12 +169,6 @@ sharerCreateNoteF now shrRecip author body (Note mluNote _ _ muParent muContext
|
||||||
return $ "Activity already exists in inbox of /s/" <> recip
|
return $ "Activity already exists in inbox of /s/" <> recip
|
||||||
Just _ -> return $ "Activity inserted to inbox of /s/" <> recip
|
Just _ -> return $ "Activity inserted to inbox of /s/" <> recip
|
||||||
|
|
||||||
data CreateNoteRecipColl
|
|
||||||
= CreateNoteRecipProjectFollowers
|
|
||||||
| CreateNoteRecipTicketParticipants
|
|
||||||
| CreateNoteRecipTicketTeam
|
|
||||||
deriving Eq
|
|
||||||
|
|
||||||
projectCreateNoteF
|
projectCreateNoteF
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
-> ShrIdent
|
-> ShrIdent
|
||||||
|
@ -195,84 +191,94 @@ projectCreateNoteF now shrRecip prjRecip author body (Note mluNote _ _ muParent
|
||||||
if uParent == uContext
|
if uParent == uContext
|
||||||
then return Nothing
|
then return Nothing
|
||||||
else Just <$> parseParent uParent
|
else Just <$> parseParent uParent
|
||||||
|
(localRecips, _remoteRecips) <- do
|
||||||
|
mrecips <- parseAudience $ activityAudience $ actbActivity body
|
||||||
|
fromMaybeE mrecips "Create Note with no recipients"
|
||||||
|
msig <- checkForward shrRecip prjRecip
|
||||||
case context of
|
case context of
|
||||||
Right _ -> return $ recip <> " not using; context isn't local"
|
Right _ -> return "Not using; context isn't local"
|
||||||
Left (shr, prj, ltkhid) ->
|
Left (NoteContextSharerTicket shr talid) -> do
|
||||||
if shr /= shrRecip || prj /= prjRecip
|
mremotesHttp <- runDBExcept $ do
|
||||||
then return $ recip <> " not using; context is a different project"
|
(jid, ibid) <- lift getProjectRecip404
|
||||||
else do
|
(_, _, _, project) <- do
|
||||||
msig <- checkForward shrRecip prjRecip
|
mticket <- lift $ getSharerTicket shr talid
|
||||||
hLocal <- getsYesod $ appInstanceHost . appSettings
|
fromMaybeE mticket "Context: No such sharer-ticket"
|
||||||
let colls =
|
case project of
|
||||||
findRelevantCollections hLocal ltkhid $
|
Left (Entity _ tpl)
|
||||||
activityAudience $ actbActivity body
|
| ticketProjectLocalProject tpl == jid -> do
|
||||||
mremotesHttp <- runDBExcept $ do
|
mractid <- lift $ insertToProjectInbox ibid luCreate
|
||||||
(sid, fsidProject, fsidTicket, jid, ibid, did, meparent) <- getContextAndParent ltkhid mparent
|
case mractid of
|
||||||
lift $ join <$> do
|
Nothing -> return $ Left "Activity already in my inbox"
|
||||||
mmid <- insertToDiscussion luCreate luNote published ibid did meparent fsidTicket
|
Just ractid ->
|
||||||
for mmid $ \ (ractid, mid) -> do
|
case msig of
|
||||||
updateOrphans luNote did mid
|
Nothing ->
|
||||||
for msig $ \ sig -> do
|
return $ Left
|
||||||
remoteRecips <- deliverLocal ractid colls sid fsidProject fsidTicket
|
"Context is a sharer-ticket, \
|
||||||
(sig,) <$> deliverRemoteDB (actbBL body) ractid jid sig remoteRecips
|
\but no inbox forwarding \
|
||||||
lift $ for_ mremotesHttp $ \ (sig, remotesHttp) -> do
|
\header for me, so doing \
|
||||||
let handler e = logError $ "Project inbox handler: delivery failed! " <> T.pack (displayException e)
|
\nothing, just storing in inbox"
|
||||||
forkHandler handler $
|
Just sig -> lift $ Right <$> do
|
||||||
deliverRemoteHTTP now shrRecip prjRecip (actbBL body) sig remotesHttp
|
let sieve =
|
||||||
return $ recip <> " inserted new ticket comment"
|
makeRecipientSet
|
||||||
|
[]
|
||||||
|
[ LocalPersonCollectionProjectFollowers shrRecip prjRecip
|
||||||
|
, LocalPersonCollectionProjectTeam shrRecip prjRecip
|
||||||
|
]
|
||||||
|
remoteRecips <- insertRemoteActivityToLocalInboxes False ractid $ localRecipSieve' sieve False False localRecips
|
||||||
|
(sig,) <$> deliverRemoteDB (actbBL body) ractid jid sig remoteRecips
|
||||||
|
_ -> return $ Left "Context is a sharer-ticket of another project"
|
||||||
|
case mremotesHttp of
|
||||||
|
Left msg -> return msg
|
||||||
|
Right (sig, remotesHttp) -> do
|
||||||
|
forkWorker "projectCreateNoteF inbox forwarding by http" $ deliverRemoteHTTP now shrRecip prjRecip (actbBL body) sig remotesHttp
|
||||||
|
return "Stored to inbox and did inbox forwarding"
|
||||||
|
Left (NoteContextProjectTicket shr prj ltid) -> do
|
||||||
|
mremotesHttp <- runDBExcept $ do
|
||||||
|
(jid, ibid) <- lift getProjectRecip404
|
||||||
|
(_, _, _, Entity _ lt, Entity _ tpl, _) <- do
|
||||||
|
mticket <- lift $ getProjectTicket shr prj ltid
|
||||||
|
fromMaybeE mticket "Context: No such project-ticket"
|
||||||
|
if ticketProjectLocalProject tpl == jid
|
||||||
|
then do
|
||||||
|
mractid <- lift $ insertToProjectInbox ibid luCreate
|
||||||
|
case mractid of
|
||||||
|
Nothing -> return $ Left "Activity already in my inbox"
|
||||||
|
Just ractid -> do
|
||||||
|
let did = localTicketDiscuss lt
|
||||||
|
meparent <- traverse (getParent did) mparent
|
||||||
|
mmid <- lift $ insertToDiscussion luNote published did meparent ractid
|
||||||
|
case mmid of
|
||||||
|
Nothing -> return $ Left "I already have this comment, just storing in inbox"
|
||||||
|
Just mid -> lift $ do
|
||||||
|
updateOrphans luNote did mid
|
||||||
|
case msig of
|
||||||
|
Nothing ->
|
||||||
|
return $ Left "Storing in inbox, caching comment, no inbox forwarding header"
|
||||||
|
Just sig -> Right <$> do
|
||||||
|
ltkhid <- encodeKeyHashid ltid
|
||||||
|
let sieve =
|
||||||
|
makeRecipientSet
|
||||||
|
[]
|
||||||
|
[ LocalPersonCollectionProjectFollowers shrRecip prjRecip
|
||||||
|
, LocalPersonCollectionProjectTeam shrRecip prjRecip
|
||||||
|
, LocalPersonCollectionProjectTicketFollowers shrRecip prjRecip ltkhid
|
||||||
|
, LocalPersonCollectionProjectTicketTeam shrRecip prjRecip ltkhid
|
||||||
|
]
|
||||||
|
remoteRecips <- insertRemoteActivityToLocalInboxes False ractid $ localRecipSieve' sieve False False localRecips
|
||||||
|
(sig,) <$> deliverRemoteDB (actbBL body) ractid jid sig remoteRecips
|
||||||
|
else return $ Left "Context is a project-ticket of another project"
|
||||||
|
case mremotesHttp of
|
||||||
|
Left msg -> return msg
|
||||||
|
Right (sig, remotesHttp) -> do
|
||||||
|
forkWorker "projectCreateNoteF inbox forwarding by http" $ deliverRemoteHTTP now shrRecip prjRecip (actbBL body) sig remotesHttp
|
||||||
|
return "Stored to inbox, cached comment, and did inbox forwarding"
|
||||||
where
|
where
|
||||||
findRelevantCollections hLocal ctx = nub . mapMaybe decide . concatRecipients
|
getProjectRecip404 = do
|
||||||
where
|
sid <- getKeyBy404 $ UniqueSharer shrRecip
|
||||||
decide u = do
|
Entity jid j <- getBy404 $ UniqueProject prjRecip sid
|
||||||
let ObjURI h lu = u
|
return (jid, projectInbox j)
|
||||||
guard $ h == hLocal
|
insertToProjectInbox ibid luCreate = do
|
||||||
route <- decodeRouteLocal lu
|
|
||||||
case route of
|
|
||||||
ProjectFollowersR shr prj
|
|
||||||
| shr == shrRecip && prj == prjRecip
|
|
||||||
-> Just CreateNoteRecipProjectFollowers
|
|
||||||
ProjectTicketParticipantsR shr prj tkhid
|
|
||||||
| shr == shrRecip && prj == prjRecip && tkhid == ctx
|
|
||||||
-> Just CreateNoteRecipTicketParticipants
|
|
||||||
ProjectTicketTeamR shr prj tkhid
|
|
||||||
| shr == shrRecip && prj == prjRecip && tkhid == ctx
|
|
||||||
-> Just CreateNoteRecipTicketTeam
|
|
||||||
_ -> Nothing
|
|
||||||
recip = T.concat ["/s/", shr2text shrRecip, "/p/", prj2text prjRecip]
|
|
||||||
getContextAndParent ltkhid mparent = do
|
|
||||||
mt <- do
|
|
||||||
sid <- lift $ getKeyBy404 $ UniqueSharer shrRecip
|
|
||||||
Entity jid j <- lift $ getBy404 $ UniqueProject prjRecip sid
|
|
||||||
ltid <- decodeKeyHashidE ltkhid "Context: Not a valid ticket khid"
|
|
||||||
mlt <- lift $ get ltid
|
|
||||||
for mlt $ \ lt -> do
|
|
||||||
mtpl <- lift $ getValBy $ UniqueTicketProjectLocal $ localTicketTicket lt
|
|
||||||
tpl <- fromMaybeE mtpl "No TPL"
|
|
||||||
unless (ticketProjectLocalProject tpl == jid) $
|
|
||||||
throwE "Context: Local ticket khid belongs to different project"
|
|
||||||
return (jid, projectInbox j, projectFollowers j, sid, lt)
|
|
||||||
(jid, ibid, fsidProject, sid, lt) <- fromMaybeE mt "Context: No such local ticket"
|
|
||||||
let did = localTicketDiscuss lt
|
|
||||||
meparent <- for mparent $ \ parent ->
|
|
||||||
case parent of
|
|
||||||
Left (shrParent, lmidParent) -> Left <$> getLocalParentMessageId did shrParent lmidParent
|
|
||||||
Right p@(ObjURI hParent luParent) -> do
|
|
||||||
mrm <- lift $ runMaybeT $ do
|
|
||||||
iid <- MaybeT $ getKeyBy $ UniqueInstance hParent
|
|
||||||
roid <- MaybeT $ getKeyBy $ UniqueRemoteObject iid luParent
|
|
||||||
MaybeT $ getValBy $ UniqueRemoteMessageIdent roid
|
|
||||||
case mrm of
|
|
||||||
Just rm -> Left <$> do
|
|
||||||
let mid = remoteMessageRest rm
|
|
||||||
m <- lift $ getJust mid
|
|
||||||
unless (messageRoot m == did) $
|
|
||||||
throwE "Remote parent belongs to a different discussion"
|
|
||||||
return mid
|
|
||||||
Nothing -> return $ Right p
|
|
||||||
return (sid, fsidProject, localTicketFollowers lt, jid, ibid, did, meparent)
|
|
||||||
insertToDiscussion luCreate luNote published ibid did meparent fsid = do
|
|
||||||
let iidAuthor = remoteAuthorInstance author
|
let iidAuthor = remoteAuthorInstance author
|
||||||
raidAuthor = remoteAuthorId author
|
|
||||||
roid <-
|
roid <-
|
||||||
either entityKey id <$> insertBy' (RemoteObject iidAuthor luCreate)
|
either entityKey id <$> insertBy' (RemoteObject iidAuthor luCreate)
|
||||||
ractid <- either entityKey id <$> insertBy' RemoteActivity
|
ractid <- either entityKey id <$> insertBy' RemoteActivity
|
||||||
|
@ -280,6 +286,29 @@ projectCreateNoteF now shrRecip prjRecip author body (Note mluNote _ _ muParent
|
||||||
, remoteActivityContent = persistJSONFromBL $ actbBL body
|
, remoteActivityContent = persistJSONFromBL $ actbBL body
|
||||||
, remoteActivityReceived = now
|
, remoteActivityReceived = now
|
||||||
}
|
}
|
||||||
|
ibiid <- insert $ InboxItem False
|
||||||
|
new <- isRight <$> insertBy' (InboxItemRemote ibid ractid ibiid)
|
||||||
|
return $
|
||||||
|
if new
|
||||||
|
then Just ractid
|
||||||
|
else Nothing
|
||||||
|
getParent did (Left (shrParent, lmidParent)) = Left <$> getLocalParentMessageId did shrParent lmidParent
|
||||||
|
getParent did (Right p@(ObjURI hParent luParent)) = do
|
||||||
|
mrm <- lift $ runMaybeT $ do
|
||||||
|
iid <- MaybeT $ getKeyBy $ UniqueInstance hParent
|
||||||
|
roid <- MaybeT $ getKeyBy $ UniqueRemoteObject iid luParent
|
||||||
|
MaybeT $ getValBy $ UniqueRemoteMessageIdent roid
|
||||||
|
case mrm of
|
||||||
|
Just rm -> Left <$> do
|
||||||
|
let mid = remoteMessageRest rm
|
||||||
|
m <- lift $ getJust mid
|
||||||
|
unless (messageRoot m == did) $
|
||||||
|
throwE "Remote parent belongs to a different discussion"
|
||||||
|
return mid
|
||||||
|
Nothing -> return $ Right p
|
||||||
|
insertToDiscussion luNote published did meparent ractid = do
|
||||||
|
let iidAuthor = remoteAuthorInstance author
|
||||||
|
raidAuthor = remoteAuthorId author
|
||||||
mid <- insert Message
|
mid <- insert Message
|
||||||
{ messageCreated = published
|
{ messageCreated = published
|
||||||
, messageSource = src
|
, messageSource = src
|
||||||
|
@ -290,11 +319,11 @@ projectCreateNoteF now shrRecip prjRecip author body (Note mluNote _ _ muParent
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
, messageRoot = did
|
, messageRoot = did
|
||||||
}
|
}
|
||||||
roid2 <-
|
roidNote <-
|
||||||
either entityKey id <$> insertBy' (RemoteObject iidAuthor luNote)
|
either entityKey id <$> insertBy' (RemoteObject iidAuthor luNote)
|
||||||
mrmid <- insertUnique RemoteMessage
|
mrmid <- insertUnique RemoteMessage
|
||||||
{ remoteMessageAuthor = raidAuthor
|
{ remoteMessageAuthor = raidAuthor
|
||||||
, remoteMessageIdent = roid2
|
, remoteMessageIdent = roidNote
|
||||||
, remoteMessageRest = mid
|
, remoteMessageRest = mid
|
||||||
, remoteMessageCreate = ractid
|
, remoteMessageCreate = ractid
|
||||||
, remoteMessageLostParent =
|
, remoteMessageLostParent =
|
||||||
|
@ -306,11 +335,7 @@ projectCreateNoteF now shrRecip prjRecip author body (Note mluNote _ _ muParent
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
delete mid
|
delete mid
|
||||||
return Nothing
|
return Nothing
|
||||||
Just _ -> do
|
Just _ -> return $ Just mid
|
||||||
-- insertUnique_ $ RemoteFollow raidAuthor fsid False True
|
|
||||||
ibiid <- insert $ InboxItem False
|
|
||||||
insert_ $ InboxItemRemote ibid ractid ibiid
|
|
||||||
return $ Just (ractid, mid)
|
|
||||||
updateOrphans luNote did mid = do
|
updateOrphans luNote did mid = do
|
||||||
let hAuthor = objUriAuthority $ remoteAuthorURI author
|
let hAuthor = objUriAuthority $ remoteAuthorURI author
|
||||||
uNote = ObjURI hAuthor luNote
|
uNote = ObjURI hAuthor luNote
|
||||||
|
@ -341,32 +366,3 @@ projectCreateNoteF now shrRecip prjRecip author body (Note mluNote _ _ muParent
|
||||||
rm E.^. RemoteMessageLostParent E.==. E.just (E.val uNote) E.&&.
|
rm E.^. RemoteMessageLostParent E.==. E.just (E.val uNote) E.&&.
|
||||||
m E.^. MessageRoot `op` E.val did
|
m E.^. MessageRoot `op` E.val did
|
||||||
return (rm E.^. RemoteMessageId, m E.^. MessageId)
|
return (rm E.^. RemoteMessageId, m E.^. MessageId)
|
||||||
deliverLocal
|
|
||||||
:: RemoteActivityId
|
|
||||||
-> [CreateNoteRecipColl]
|
|
||||||
-> SharerId
|
|
||||||
-> FollowerSetId
|
|
||||||
-> FollowerSetId
|
|
||||||
-> AppDB [((InstanceId, Host), NonEmpty RemoteRecipient)]
|
|
||||||
deliverLocal ractid recips sid fsidProject fsidTicket = do
|
|
||||||
(teamPids, teamRemotes) <-
|
|
||||||
if CreateNoteRecipTicketTeam `elem` recips
|
|
||||||
then getTicketTeam sid
|
|
||||||
else return ([], [])
|
|
||||||
(tfsPids, tfsRemotes) <-
|
|
||||||
if CreateNoteRecipTicketParticipants `elem` recips
|
|
||||||
then getFollowers fsidTicket
|
|
||||||
else return ([], [])
|
|
||||||
(jfsPids, jfsRemotes) <-
|
|
||||||
if CreateNoteRecipProjectFollowers `elem` recips
|
|
||||||
then getFollowers fsidProject
|
|
||||||
else return ([], [])
|
|
||||||
let pids = union teamPids tfsPids `union` jfsPids
|
|
||||||
remotes = teamRemotes `unionRemotes` tfsRemotes `unionRemotes` jfsRemotes
|
|
||||||
for_ pids $ \ pid -> do
|
|
||||||
ibid <- personInbox <$> getJust pid
|
|
||||||
ibiid <- insert $ InboxItem True
|
|
||||||
mibrid <- insertUnique $ InboxItemRemote ibid ractid ibiid
|
|
||||||
when (isNothing mibrid) $
|
|
||||||
delete ibiid
|
|
||||||
return remotes
|
|
||||||
|
|
Loading…
Reference in a new issue