S2S: Component: Accept: Port team-mode from Project

This commit is contained in:
Pere Lev 2024-07-01 13:44:23 +03:00
parent cdd43292bc
commit 40ab419946
No known key found for this signature in database
GPG key ID: 5252C5C863E5E57D
2 changed files with 257 additions and 52 deletions

View file

@ -231,6 +231,37 @@ actorFollow parseFollowee grabActor unread getFollowee getSieve makeLocalActor m
-- * If I've already seen the project's accept, respond with error -- * If I've already seen the project's accept, respond with error
-- * Otherwise, just ignore the Accept -- * Otherwise, just ignore the Accept
-- * Otherwise respond with error -- * Otherwise respond with error
--
-- * Add-a-Team mode
-- * Give me a new team active SquadOriginUs
-- * Respond with error, we aren't supposed to get any Accept
-- * Give me a new team passive SquadOriginThem
-- * Option 1: I haven't yet seen parent's Accept
-- * Verify sender is the parent
-- * Option 2: I saw it, but not my collaborator's Accept
-- * Verify the accept is authorized
-- * Otherwise respond with error, no Accept is needed
--
-- * Insert the Accept to my inbox
--
-- * In team-passive mode,
-- * Option 1: Record team's Accept in the Dest record
-- * Option 2: Record my collaborator's Accept in the Squad record
-- * Prepare to send my own Accept
--
-- * Forward the Accept to my followers
--
-- * Possibly send a Grant/Accept:
-- * Team-passive
-- * In option 2
-- * Accept
-- * Object: The Add
-- * Fulfills: My collaborator's Accept
-- * To: Team
-- * CC:
-- - Team's followers
-- - My followers
-- - The Accept sender (my collaborator)
topicAccept topicAccept
:: forall topic. :: forall topic.
(PersistRecordBackend topic SqlBackend, ToBackendKey SqlBackend topic) (PersistRecordBackend topic SqlBackend, ToBackendKey SqlBackend topic)
@ -246,14 +277,6 @@ topicAccept grabResource topicComponent now recipKey (Verse authorIdMsig body) a
-- Check input -- Check input
acceptee <- parseAccept accept acceptee <- parseAccept accept
-- Verify the capability URI, if provided, is one of:
-- * Outbox item URI of a local actor, i.e. a local activity
-- * A remote URI
maybeCap <-
traverse
(nameExceptT "Accept capability" . parseActivityURI')
(AP.activityCapability $ actbActivity body)
-- Grab me from DB -- Grab me from DB
(resourceID, recipActorID, recipActor) <- lift $ withDB $ do (resourceID, recipActorID, recipActor) <- lift $ withDB $ do
resourceID <- grabResource <$> getJust recipKey resourceID <- grabResource <$> getJust recipKey
@ -261,7 +284,7 @@ topicAccept grabResource topicComponent now recipKey (Verse authorIdMsig body) a
recipActor <- getJust recipActorID recipActor <- getJust recipActorID
return (resourceID, recipActorID, recipActor) return (resourceID, recipActorID, recipActor)
collabOrStem <- withDBExcept $ do mode <- withDBExcept $ do
-- Find the accepted activity in our DB -- Find the accepted activity in our DB
accepteeDB <- do accepteeDB <- do
@ -274,20 +297,30 @@ topicAccept grabResource topicComponent now recipKey (Verse authorIdMsig body) a
-- component, grabbing the Stem record from our DB -- component, grabbing the Stem record from our DB
maybeCollabOrStem <- maybeCollabOrStem <-
lift $ runMaybeT $ lift $ runMaybeT $
Left . Left <$> tryInviteCollab accepteeDB <|> Left . Left . Left <$> tryInviteCollab accepteeDB <|>
Left . Right <$> tryJoinCollab accepteeDB <|> Left . Left . Right <$> tryJoinCollab accepteeDB <|>
Right . Left <$> tryInviteComp accepteeDB <|> Left . Right . Left <$> tryInviteComp accepteeDB <|>
Right . Right <$> tryAddComp accepteeDB Left . Right . Right <$> tryAddComp accepteeDB <|>
Right <$> tryAddTeamActive resourceID accepteeDB <|>
Right <$> tryAddTeamPassive resourceID accepteeDB
fromMaybeE maybeCollabOrStem "Accepted activity isn't an Invite/Join/Add I'm aware of" fromMaybeE maybeCollabOrStem "Accepted activity isn't an Invite/Join/Add I'm aware of"
case collabOrStem of case mode of
Left collab -> Left (Left collab) ->
topicAcceptCollab maybeCap recipActorID recipActor collab topicAcceptCollab recipActorID recipActor collab
Right stem -> Left (Right stem) ->
topicAcceptStem maybeCap recipActorID recipActor stem topicAcceptStem recipActorID recipActor stem
Right team -> addTeam team
where where
meID = recipKey
toComponent = topicComponent
meComponent = toComponent recipKey
meResource = componentResource meComponent
meActor = resourceToActor meResource
topicResource :: forall f. f topic -> LocalResourceBy f topicResource :: forall f. f topic -> LocalResourceBy f
topicResource = componentResource . topicComponent topicResource = componentResource . topicComponent
@ -343,6 +376,41 @@ topicAccept grabResource topicComponent now recipKey (Verse authorIdMsig body) a
lift $ (,remoteActorFollowers actor,remoteActivityID) <$> getRemoteActorURI actor lift $ (,remoteActorFollowers actor,remoteActivityID) <$> getRemoteActorURI actor
return (stemID, originID, Right adder) return (stemID, originID, Right adder)
verifySquadHolder :: ResourceId -> SquadId -> MaybeT ActDB ()
verifySquadHolder meResourceID squadID = do
Squad _ r <- lift $ getJust squadID
guard $ r == meResourceID
tryAddTeamActive' r squadID = do
usID <- MaybeT $ getKeyBy $ UniqueSquadOriginUs squadID
verifySquadHolder r squadID
topic <- lift $ getSquadTeam squadID
return (squadID, topic, Left ())
tryAddTeamActive r (Left (_actorByKey, _actorEntity, itemID)) = do
SquadUsGestureLocal squadID _ <-
MaybeT $ getValBy $ UniqueSquadUsGestureLocalActivity itemID
tryAddTeamActive' r squadID
tryAddTeamActive r (Right remoteActivityID) = do
SquadUsGestureRemote squadID _ _ <-
MaybeT $ getValBy $ UniqueSquadUsGestureRemoteActivity remoteActivityID
tryAddTeamActive' r squadID
tryAddTeamPassive' r themID = do
SquadOriginThem squadID <- lift $ getJust themID
verifySquadHolder r squadID
topic <- lift $ getSquadTeam squadID
return (squadID, topic, Right themID)
tryAddTeamPassive r (Left (_actorByKey, _actorEntity, itemID)) = do
SquadThemGestureLocal themID _ <-
MaybeT $ getValBy $ UniqueSquadThemGestureLocalAdd itemID
tryAddTeamPassive' r themID
tryAddTeamPassive r (Right remoteActivityID) = do
SquadThemGestureRemote themID _ _ <-
MaybeT $ getValBy $ UniqueSquadThemGestureRemoteAdd remoteActivityID
tryAddTeamPassive' r themID
prepareGrant isInvite sender role = do prepareGrant isInvite sender role = do
encodeRouteHome <- getEncodeRouteHome encodeRouteHome <- getEncodeRouteHome
encodeRouteLocal <- getEncodeRouteLocal encodeRouteLocal <- getEncodeRouteLocal
@ -405,7 +473,15 @@ topicAccept grabResource topicComponent now recipKey (Verse authorIdMsig body) a
return (action, recipientSet, remoteActors, fwdHosts) return (action, recipientSet, remoteActors, fwdHosts)
topicAcceptCollab maybeCap recipActorID recipActor collab = do topicAcceptCollab recipActorID recipActor collab = do
-- Verify the capability URI, if provided, is one of:
-- * Outbox item URI of a local actor, i.e. a local activity
-- * A remote URI
maybeCap <-
traverse
(nameExceptT "Accept capability" . parseActivityURI')
(AP.activityCapability $ actbActivity body)
maybeNew <- withDBExcept $ do maybeNew <- withDBExcept $ do
@ -568,7 +644,15 @@ topicAccept grabResource topicComponent now recipKey (Verse authorIdMsig body) a
return (action, recipientSet, remoteActors, fwdHosts) return (action, recipientSet, remoteActors, fwdHosts)
topicAcceptStem maybeCap recipActorID recipActor stem = do topicAcceptStem recipActorID recipActor stem = do
-- Verify the capability URI, if provided, is one of:
-- * Outbox item URI of a local actor, i.e. a local activity
-- * A remote URI
maybeCap <-
traverse
(nameExceptT "Accept capability" . parseActivityURI')
(AP.activityCapability $ actbActivity body)
maybeNew <- withDBExcept $ do maybeNew <- withDBExcept $ do
@ -695,6 +779,159 @@ topicAccept grabResource topicComponent now recipKey (Verse authorIdMsig body) a
remoteRecipsReact fwdHostsReact reactID actionReact remoteRecipsReact fwdHostsReact reactID actionReact
doneDB inboxItemID "Forwarded the Accept and published an Accept" doneDB inboxItemID "Forwarded the Accept and published an Accept"
theyIsAuthor' :: Either (a, GroupId) (b, RemoteActorId) -> Bool
theyIsAuthor' ident =
let author = bimap (view _1) (remoteAuthorId . view _1) authorIdMsig
in author == bimap (LocalActorGroup . snd) snd ident
addTeam (squadID, topic, mode) = do
(themID, mode') <-
case mode of
-- Team-active mode
-- Respond with error, we aren't supposed to get any Accept
Left () -> throwE "Team-active (SquadOriginUs) mode, I'm not expecting any Accept"
-- Team-passive mode
-- Option 1: I haven't yet seen team's Accept
-- * Verify sender is the team
-- Option 2: I saw it, but not my collaborator's Accept
-- * Verify the accept is authorized
-- Otherwise respond with error, no Accept is needed
Right themID -> (themID,) <$> do
(maybeTeamAccept, maybeUsGesture) <-
lift $ withDB $ liftA2 (,)
(case bimap fst fst topic of
Left localID -> (() <$) <$> getBy (UniqueSquadThemAcceptLocalTopic localID)
Right remoteID -> (() <$) <$> getBy (UniqueSquadThemAcceptRemoteTopic remoteID)
)
(do l <- getBy $ UniqueSquadUsGestureLocal squadID
r <- getBy $ UniqueSquadUsGestureRemote squadID
case (isJust l, isJust r) of
(False, False) -> pure Nothing
(False, True) -> pure $ Just ()
(True, False) -> pure $ Just ()
(True, True) -> error "Both SquadUsGestureLocal and SquadUsGestureRemote"
)
case (isJust maybeTeamAccept, isJust maybeUsGesture) of
(False, True) -> error "Impossible/bug, didn't see team's Accept but recorded my collaborator's Accept"
(False, False) -> do
unless (theyIsAuthor' topic) $
throwE "The Accept I'm waiting for is from my new team"
return $ Left ()
(True, False) -> do
let muCap = AP.activityCapability $ actbActivity body
uCap <- fromMaybeE muCap "No capability provided"
verifyCapability''
uCap
authorIdMsig
meResource
AP.RoleAdmin
return $ Right ()
(True, True) -> throwE "Just waiting for Grant from team, or already have it, anyway not needing any further Accept"
maybeNew <- withDBExcept $ do
-- Grab me from DB
meResourceID <- lift $ grabResource <$> getJust meID
Resource meActorID <- lift $ getJust meResourceID
meActorDB <- lift $ getJust meActorID
maybeAcceptDB <- lift $ insertToInbox now authorIdMsig body (actorInbox meActorDB) False
for maybeAcceptDB $ \ (inboxItemID, acceptDB) -> do
idsForGrant <-
lift $ case mode' of
-- Getting an Accept from the team
-- Record team's Accept in the Squad record
Left () -> do
case (topic, acceptDB) of
(Left (localID, _), Left (_, _, acceptID)) ->
insert_ $ SquadThemAcceptLocal themID localID acceptID
(Right (remoteID, _), Right (_, _, acceptID)) ->
insert_ $ SquadThemAcceptRemote themID remoteID acceptID
_ -> error "topicAccept impossible v"
return Nothing
-- Getting an Accept from my collaborator
-- Record my collaborator's Accept in the Squad record
-- Prepare to send my own Accept
Right () -> Just <$> do
case acceptDB of
Left (_, _, acceptID) ->
insert_ $ SquadUsGestureLocal squadID acceptID
Right (author, _, acceptID) ->
insert_ $ SquadUsGestureRemote squadID (remoteAuthorId author) acceptID
acceptID <- insertEmptyOutboxItem' (actorOutbox meActorDB) now
insert_ $ SquadUsAccept squadID acceptID
return acceptID
-- Prepare forwarding of Accept to my followers
sieve <- do
h <- hashLocalActor meActor
return $ makeRecipientSet [] [localActorFollowers h]
maybeAct <-
for idsForGrant $ \ acceptID -> lift $ do
accept@(actionAccept, _, _, _) <-
prepareSquadAccept (bimap snd snd topic)
_luAccept <- updateOutboxItem' meActor acceptID actionAccept
return (acceptID, accept)
return (meActorID, sieve, maybeAct, inboxItemID)
case maybeNew of
Nothing -> done "I already have this activity in my inbox"
Just (recipActorID, sieve, maybeGrant, inboxItemID) -> do
forwardActivity authorIdMsig body meActor recipActorID sieve
lift $ for_ maybeGrant $ \ (grantID, (actionGrant, localRecipsGrant, remoteRecipsGrant, fwdHostsGrant)) ->
sendActivity
meActor recipActorID localRecipsGrant
remoteRecipsGrant fwdHostsGrant grantID actionGrant
doneDB inboxItemID "[Team] Forwarded the Accept and maybe published a Grant/Accept"
where
prepareSquadAccept topic = do
encodeRouteHome <- getEncodeRouteHome
audMyCollab <- lift $ makeAudSenderOnly authorIdMsig
audSquad <-
case topic of
Left j -> do
h <- encodeKeyHashid j
return $
AudLocal [LocalActorGroup h] [LocalStageGroupFollowers h]
Right raID -> do
ra <- getJust raID
ObjURI h lu <- getRemoteActorURI ra
return $
AudRemote h [lu] (maybeToList $ remoteActorFollowers ra)
audMe <-
AudLocal [] . pure . localActorFollowers <$>
hashLocalActor meActor
uCollabAccept <- lift $ getActivityURI authorIdMsig
let uAdd = AP.acceptObject accept
(recipientSet, remoteActors, fwdHosts, audLocal, audRemote) =
collectAudience [audMyCollab, audSquad, audMe]
recips = map encodeRouteHome audLocal ++ audRemote
action = AP.Action
{ AP.actionCapability = Nothing
, AP.actionSummary = Nothing
, AP.actionAudience = AP.Audience recips [] [] [] [] []
, AP.actionFulfills = [uCollabAccept]
, AP.actionSpecific = AP.AcceptActivity AP.Accept
{ AP.acceptObject = uAdd
, AP.acceptResult = Nothing
}
}
return (action, recipientSet, remoteActors, fwdHosts)
topicReject topicReject
:: (PersistRecordBackend topic SqlBackend, ToBackendKey SqlBackend topic) :: (PersistRecordBackend topic SqlBackend, ToBackendKey SqlBackend topic)
=> (topic -> ResourceId) => (topic -> ResourceId)

View file

@ -541,38 +541,6 @@ deckFollow now recipDeckID verse follow = do
-- Access -- Access
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
-- Meaning: An actor accepted something
-- Behavior:
-- * If it's on an Invite where I'm the resource:
-- * Verify the Accept is by the Invite target
-- * Forward the Accept to my followers
-- * Send a Grant:
-- * To: Accepter (i.e. Invite target)
-- * CC: Invite sender, Accepter's followers, my followers
-- * If it's on a Join where I'm the resource:
-- * Verify the Accept is authorized
-- * Forward the Accept to my followers
-- * Send a Grant:
-- * To: Join sender
-- * CC: Accept sender, Join sender's followers, my followers
-- * If it's an Invite (that I know about) where I'm invited to a project:
-- * If I haven't yet seen the project's approval:
-- * Verify the author is the project
-- * Record the approval in the Stem record in DB
-- * If I saw project's approval, but not my collaborators' approval:
-- * Verify the Accept is authorized
-- * Record the approval in the Stem record in DB
-- * Forward to my followers
-- * Publish and send an Accept:
-- * To: Inviter, project, Accept author
-- * CC: Project followers, my followers
-- * Record it in the Stem record in DB as well
-- * If I already saw both approvals, respond with error
-- * If it's an Add (that I know about and already Accepted) where I'm
-- invited to a project:
-- * If I've already seen the project's accept, respond with error
-- * Otherwise, just ignore the Accept
-- * Otherwise respond with error
deckAccept deckAccept
:: UTCTime :: UTCTime
-> DeckId -> DeckId