S2S: Group: Remove: Implement resource-active mode
This commit is contained in:
parent
a36eda1e2b
commit
9df437a043
1 changed files with 294 additions and 0 deletions
|
@ -3956,6 +3956,18 @@ groupReject = topicReject groupResource LocalResourceGroup
|
|||
-- * Send an Accept on the Remove:
|
||||
-- * To: Actor B
|
||||
-- * CC: Actor A, B's followers, my followers
|
||||
-- * If C is my resources collection:
|
||||
-- * Verify A is authorized by me to remove resources from me
|
||||
-- * Verify B is an active resource of mine
|
||||
-- * Remove the whole Effort record from DB
|
||||
-- * Forward the Remove to my followers
|
||||
-- * Send a Revoke on the delegator-Grant I had for B:
|
||||
-- * To: Actor B
|
||||
-- * CC: Actor A, B's followers, my followers
|
||||
-- * Send a Revoke on every extention-Grant I extended on every
|
||||
-- delegation Grant I got from B
|
||||
-- * To: The child/member to whom I'd sent the Grant
|
||||
-- * CC: -
|
||||
-- * If I'm B, being removed from the children of a parent of mine:
|
||||
-- * Record this Remove in the Source record
|
||||
-- * Forward to followers
|
||||
|
@ -3979,6 +3991,8 @@ groupRemove now groupID (Verse authorIdMsig body) remove = do
|
|||
removeChildActive item
|
||||
(Left (Right (ATGroupParents j)), _) | j == groupID ->
|
||||
removeParentActive item
|
||||
(Left (Right (ATGroupEfforts j)), _) | j == groupID ->
|
||||
removeResourceActive item
|
||||
(_, Left (LocalActorGroup j)) | j == groupID ->
|
||||
case collection of
|
||||
Left (Right (ATGroupParents j)) | j /= groupID ->
|
||||
|
@ -4872,6 +4886,286 @@ groupRemove now groupID (Verse authorIdMsig body) remove = do
|
|||
Just inboxItemID ->
|
||||
doneDB inboxItemID "[Child-passive] Saw the removal attempt, just waiting for the Revoke"
|
||||
|
||||
removeResourceActive resource = do
|
||||
|
||||
-- If resource is local, find it in our DB
|
||||
-- If resource is remote, HTTP GET it, verify it's an actor of Group
|
||||
-- type, and store in our DB (if it's already there, no need for HTTP)
|
||||
--
|
||||
-- NOTE: This is a blocking HTTP GET done right here in the handler,
|
||||
-- which is NOT a good idea. Ideally, it would be done async, and the
|
||||
-- handler result would be sent later in a separate (e.g. Accept) activity.
|
||||
-- But for the PoC level, the current situation will hopefully do.
|
||||
resourceDB <-
|
||||
bitraverse
|
||||
(\ la ->
|
||||
case resourceToNG =<< actorToResource la of
|
||||
Just ng -> withDBExcept $ getLocalResourceEntityE (resourceFromNG ng) "Resource not found in DB"
|
||||
Nothing -> throwE "Local resource of non-resource type"
|
||||
)
|
||||
(\ u@(ObjURI h lu) -> do
|
||||
instanceID <-
|
||||
lift $ withDB $ either entityKey id <$> insertBy' (Instance h)
|
||||
result <-
|
||||
ExceptT $ first (T.pack . displayException) <$>
|
||||
fetchRemoteActor' instanceID h lu
|
||||
case result of
|
||||
Left Nothing -> throwE "Resource @id mismatch"
|
||||
Left (Just err) -> throwE $ T.pack $ displayException err
|
||||
Right Nothing -> throwE "Resource isn't an actor"
|
||||
Right (Just actor) -> do
|
||||
case remoteActorType $ entityVal actor of
|
||||
AP.ActorTypeTeam -> pure ()
|
||||
_ -> throwE "Remote resource type isn't Group"
|
||||
return (u, actor)
|
||||
)
|
||||
resource
|
||||
|
||||
-- Verify that a capability is provided
|
||||
uCap <- do
|
||||
let muCap = AP.activityCapability $ actbActivity body
|
||||
fromMaybeE muCap "No capability provided"
|
||||
|
||||
-- Verify the sender is authorized by me to remove a resource
|
||||
verifyCapability''
|
||||
uCap
|
||||
authorIdMsig
|
||||
(LocalResourceGroup groupID)
|
||||
AP.RoleAdmin
|
||||
|
||||
maybeNew <- withDBExcept $ do
|
||||
|
||||
-- Grab me from DB
|
||||
(group, actorRecip) <- lift $ do
|
||||
p <- getJust groupID
|
||||
(p,) <$> getJust (groupActor p)
|
||||
|
||||
-- Verify it's an active resource of mine
|
||||
efforts <- lift $ case resourceDB of
|
||||
Left r ->
|
||||
fmap (map $ \ (s, d, E.Value a, E.Value t) -> (s, d, Left (a, t))) $
|
||||
E.select $ E.from $ \ (effort `E.InnerJoin` topic `E.InnerJoin` accept `E.InnerJoin` send) -> do
|
||||
E.on $ effort E.^. EffortId E.==. send E.^. EffortUsSendDelegatorEffort
|
||||
E.on $ topic E.^. EffortTopicLocalId E.==. accept E.^. EffortThemAcceptLocalTopic
|
||||
E.on $ effort E.^. EffortId E.==. topic E.^. EffortTopicLocalEffort
|
||||
E.where_ $
|
||||
effort E.^. EffortHolder E.==. E.val groupID E.&&.
|
||||
topic E.^. EffortTopicLocalTopic E.==. E.val (localResourceID r)
|
||||
return
|
||||
( effort E.^. EffortId
|
||||
, send
|
||||
, accept E.^. EffortThemAcceptLocalId
|
||||
, topic E.^. EffortTopicLocalId
|
||||
)
|
||||
Right (_, Entity a _) ->
|
||||
fmap (map $ \ (s, d, E.Value a, E.Value t) -> (s, d, Right (a, t))) $
|
||||
E.select $ E.from $ \ (effort `E.InnerJoin` topic `E.InnerJoin` accept `E.InnerJoin` send) -> do
|
||||
E.on $ effort E.^. EffortId E.==. send E.^. EffortUsSendDelegatorEffort
|
||||
E.on $ topic E.^. EffortTopicRemoteId E.==. accept E.^. EffortThemAcceptRemoteTopic
|
||||
E.on $ effort E.^. EffortId E.==. topic E.^. EffortTopicRemoteEffort
|
||||
E.where_ $
|
||||
effort E.^. EffortHolder E.==. E.val groupID E.&&.
|
||||
topic E.^. EffortTopicRemoteTopic E.==. E.val a
|
||||
return
|
||||
( effort E.^. EffortId
|
||||
, send
|
||||
, accept E.^. EffortThemAcceptRemoteId
|
||||
, topic E.^. EffortTopicRemoteId
|
||||
)
|
||||
(E.Value effortID, Entity sendID (EffortUsSendDelegator _ grantID), topic) <-
|
||||
verifySingleE efforts "No effort" "Multiple efforts"
|
||||
|
||||
maybeRemoveDB <- lift $ insertToInbox now authorIdMsig body (actorInbox actorRecip) False
|
||||
lift $ for maybeRemoveDB $ \ (inboxItemID, _removeDB) -> do
|
||||
|
||||
-- Grab extension-Grants that I'm about to revoke
|
||||
distributes <- selectList [EffortUsDistributeEffort ==. sendID] []
|
||||
leafs <- selectList [EffortUsLeafEffort ==. sendID] []
|
||||
|
||||
-- Delete the whole Effort record
|
||||
deleteWhere [EffortRemoveSend ==. sendID]
|
||||
let distributeIDs = map entityKey distributes
|
||||
deleteWhere [EffortUsDistributeFromLocalDistribute <-. distributeIDs]
|
||||
deleteWhere [EffortUsDistributeFromRemoteDistribute <-. distributeIDs]
|
||||
deleteWhere [EffortUsDistributeId <-. distributeIDs]
|
||||
let leafIDs = map entityKey leafs
|
||||
deleteWhere [EffortUsLeafFromLocalLeaf <-. leafIDs]
|
||||
deleteWhere [EffortUsLeafFromRemoteLeaf <-. leafIDs]
|
||||
deleteWhere [EffortUsLeafToLocalLeaf <-. leafIDs]
|
||||
deleteWhere [EffortUsLeafToRemoteLeaf <-. leafIDs]
|
||||
deleteWhere [EffortUsLeafId <-. leafIDs]
|
||||
case topic of
|
||||
Left (localID, _) -> do
|
||||
deleteWhere [EffortThemDelegateLocalEffort ==. localID]
|
||||
delete localID
|
||||
Right (remoteID, _) -> do
|
||||
deleteWhere [EffortThemDelegateRemoteEffort ==. remoteID]
|
||||
delete remoteID
|
||||
delete sendID
|
||||
origin <-
|
||||
requireEitherAlt
|
||||
(getKeyBy $ UniqueEffortOriginUs effortID)
|
||||
(getKeyBy $ UniqueEffortOriginThem effortID)
|
||||
"Neither us nor them"
|
||||
"Both us and them"
|
||||
case origin of
|
||||
Left usID -> do
|
||||
deleteBy $ UniqueEffortUsAccept usID
|
||||
deleteBy $ UniqueEffortUsGestureLocal usID
|
||||
deleteBy $ UniqueEffortUsGestureRemote usID
|
||||
delete usID
|
||||
Right themID -> do
|
||||
deleteBy $ UniqueEffortThemGestureLocal themID
|
||||
deleteBy $ UniqueEffortThemGestureRemote themID
|
||||
delete themID
|
||||
case topic of
|
||||
Left (_, l) -> delete l
|
||||
Right (_, r) -> delete r
|
||||
delete effortID
|
||||
|
||||
-- Prepare forwarding Remove to my followers
|
||||
sieve <- lift $ do
|
||||
topicHash <- encodeKeyHashid groupID
|
||||
let topicByHash =
|
||||
LocalActorGroup topicHash
|
||||
return $ makeRecipientSet [] [localActorFollowers topicByHash]
|
||||
|
||||
-- Prepare main Revoke activity and insert to my outbox
|
||||
revoke@(actionRevoke, _, _, _) <-
|
||||
lift $ prepareMainRevoke resourceDB grantID
|
||||
let recipByKey = LocalActorGroup groupID
|
||||
revokeID <- insertEmptyOutboxItem' (actorOutbox actorRecip) now
|
||||
_luRevoke <- updateOutboxItem' recipByKey revokeID actionRevoke
|
||||
|
||||
-- Prepare and insert Revokes on all the extension-Grants
|
||||
revokesD <- for distributes $ \ (Entity _ (EffortUsDistribute _ startID grantID)) -> do
|
||||
DestUsStart acceptID _ <- getJust startID
|
||||
DestUsAccept destID _ <- getJust acceptID
|
||||
child <- do
|
||||
c <- getDestTopic destID
|
||||
bitraverse
|
||||
(\case
|
||||
Right j -> pure $ LocalActorGroup j
|
||||
Left _ -> error "I'm a group but I have a child who is a Project"
|
||||
)
|
||||
pure
|
||||
(bimap snd snd c)
|
||||
return (child, grantID)
|
||||
revokesL <- for leafs $ \ (Entity _ (EffortUsLeaf _ enableID grantID)) -> do
|
||||
CollabEnable collabID _ <- getJust enableID
|
||||
recip <- getCollabRecip collabID
|
||||
return
|
||||
( bimap
|
||||
(LocalActorPerson . collabRecipLocalPerson . entityVal)
|
||||
(collabRecipRemoteActor . entityVal)
|
||||
recip
|
||||
, grantID
|
||||
)
|
||||
revokes <- for (revokesD ++ revokesL) $ \ (actor, grantID) -> do
|
||||
ext@(actionExt, _, _, _) <- prepareExtRevoke actor grantID
|
||||
let recipByKey = LocalActorGroup groupID
|
||||
extID <- insertEmptyOutboxItem' (actorOutbox actorRecip) now
|
||||
_luExt <- updateOutboxItem' recipByKey extID actionExt
|
||||
return (extID, ext)
|
||||
|
||||
return (groupActor group, sieve, revokeID, revoke, revokes, inboxItemID)
|
||||
|
||||
case maybeNew of
|
||||
Nothing -> done "I already have this activity in my inbox"
|
||||
Just (topicActorID, sieve, revokeID, (actionRevoke, localRecipsRevoke, remoteRecipsRevoke, fwdHostsRevoke), revokes, inboxItemID) -> do
|
||||
let topicByID = LocalActorGroup groupID
|
||||
forwardActivity authorIdMsig body topicByID topicActorID sieve
|
||||
lift $ do
|
||||
sendActivity
|
||||
topicByID topicActorID localRecipsRevoke
|
||||
remoteRecipsRevoke fwdHostsRevoke revokeID actionRevoke
|
||||
for_ revokes $ \ (extID, (actionExt, localRecipsExt, remoteRecipsExt, fwdHostsExt)) ->
|
||||
sendActivity
|
||||
topicByID topicActorID localRecipsExt
|
||||
remoteRecipsExt fwdHostsExt extID actionExt
|
||||
doneDB inboxItemID "[Resource-active] Deleted the Effort, forwarded Remove, sent Revokes"
|
||||
|
||||
where
|
||||
|
||||
prepareMainRevoke resource grantID = do
|
||||
encodeRouteHome <- getEncodeRouteHome
|
||||
encodeRouteLocal <- getEncodeRouteLocal
|
||||
|
||||
recipHash <- encodeKeyHashid groupID
|
||||
let topicByHash = LocalActorGroup recipHash
|
||||
|
||||
resourceHash <- bitraverse (hashLocalResource . bmap entityKey) pure resource
|
||||
|
||||
audRemover <- makeAudSenderOnly authorIdMsig
|
||||
let audResource =
|
||||
case resourceHash of
|
||||
Left lr ->
|
||||
let la = resourceToActor lr
|
||||
in AudLocal [la] [localActorFollowers la]
|
||||
Right (ObjURI h lu, Entity _ actor) ->
|
||||
AudRemote h [lu] (maybeToList $ remoteActorFollowers actor)
|
||||
audMe = AudLocal [] [localActorFollowers topicByHash]
|
||||
|
||||
(recipientSet, remoteActors, fwdHosts, audLocal, audRemote) =
|
||||
collectAudience [audRemover, audResource, audMe]
|
||||
|
||||
recips = map encodeRouteHome audLocal ++ audRemote
|
||||
|
||||
uRemove <- getActivityURI authorIdMsig
|
||||
luGrant <- do
|
||||
grantHash <- encodeKeyHashid grantID
|
||||
return $ encodeRouteLocal $ activityRoute topicByHash grantHash
|
||||
let action = AP.Action
|
||||
{ AP.actionCapability = Nothing
|
||||
, AP.actionSummary = Nothing
|
||||
, AP.actionAudience = AP.Audience recips [] [] [] [] []
|
||||
, AP.actionFulfills = [uRemove]
|
||||
, AP.actionSpecific = AP.RevokeActivity AP.Revoke
|
||||
{ AP.revokeObject = luGrant :| []
|
||||
}
|
||||
}
|
||||
|
||||
return (action, recipientSet, remoteActors, fwdHosts)
|
||||
|
||||
prepareExtRevoke recipient grantID = do
|
||||
encodeRouteHome <- getEncodeRouteHome
|
||||
encodeRouteLocal <- getEncodeRouteLocal
|
||||
|
||||
groupHash <- encodeKeyHashid groupID
|
||||
let topicByHash = LocalActorGroup groupHash
|
||||
|
||||
audRecip <-
|
||||
case recipient of
|
||||
Left a -> do
|
||||
h <- hashLocalActor a
|
||||
return $ AudLocal [h] [localActorFollowers h]
|
||||
Right actorID -> do
|
||||
actor <- getJust actorID
|
||||
ObjURI h lu <- getRemoteActorURI actor
|
||||
return $
|
||||
AudRemote h [lu] (maybeToList $ remoteActorFollowers actor)
|
||||
|
||||
let (recipientSet, remoteActors, fwdHosts, audLocal, audRemote) =
|
||||
collectAudience [audRecip]
|
||||
|
||||
recips = map encodeRouteHome audLocal ++ audRemote
|
||||
|
||||
uRemove <- lift $ getActivityURI authorIdMsig
|
||||
luGrant <- do
|
||||
grantHash <- encodeKeyHashid grantID
|
||||
return $ encodeRouteLocal $ activityRoute topicByHash grantHash
|
||||
let action = AP.Action
|
||||
{ AP.actionCapability = Nothing
|
||||
, AP.actionSummary = Nothing
|
||||
, AP.actionAudience = AP.Audience recips [] [] [] [] []
|
||||
, AP.actionFulfills = [uRemove]
|
||||
, AP.actionSpecific = AP.RevokeActivity AP.Revoke
|
||||
{ AP.revokeObject = luGrant :| []
|
||||
}
|
||||
}
|
||||
|
||||
return (action, recipientSet, remoteActors, fwdHosts)
|
||||
|
||||
-- Meaning: An actor is revoking Grant activities
|
||||
-- Behavior:
|
||||
-- * For each revoked activity:
|
||||
|
|
Loading…
Reference in a new issue