Switch to converged handlers than handle both local and remote activities
I was writing a topicLocalInvite handler when I realized how cumbersome it's becoming, to have separate handlers for local activities. While it allows me to pick custom specific message names and parameters (which is why I took that approach in the first place), it causes a lot of duplication and complexity (because I have to write the remote-activity handlers anyway; adding local ones doesn't reduce complexity). So this commit switches the entire system to communicate only using AP/FF activities, including between local actors.
This commit is contained in:
parent
d5d6b0af61
commit
d33f272ede
26 changed files with 871 additions and 760 deletions
8
migrations/531_2023-06-15_follow_request.model
Normal file
8
migrations/531_2023-06-15_follow_request.model
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
FollowRequest
|
||||||
|
actor ActorId
|
||||||
|
target FollowerSetId
|
||||||
|
public Bool
|
||||||
|
follow OutboxItemId
|
||||||
|
|
||||||
|
UniqueFollowRequest actor target
|
||||||
|
UniqueFollowRequestFollow follow
|
|
@ -1838,6 +1838,19 @@ followC (Entity senderPersonID senderPerson) senderActor maybeCap localRecips re
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- Meaning: The human wants to invite someone A to a resource R
|
||||||
|
-- Behavior:
|
||||||
|
-- * Some basic sanity checks
|
||||||
|
-- * Parse the Invite
|
||||||
|
-- * Make sure not inviting myself
|
||||||
|
-- * Verify that a capability is specified
|
||||||
|
-- * If resource is local, verify it exists in DB
|
||||||
|
-- * Verify the target A and resource R are addressed in the Invite
|
||||||
|
-- * Insert Invite to my inbox
|
||||||
|
-- * Asynchrnously:
|
||||||
|
-- * Deliver a request to the resource
|
||||||
|
-- * Deliver a notification to the target
|
||||||
|
-- * Deliver a notification to my followers
|
||||||
inviteC
|
inviteC
|
||||||
:: Entity Person
|
:: Entity Person
|
||||||
-> Actor
|
-> Actor
|
||||||
|
@ -1853,11 +1866,11 @@ inviteC
|
||||||
-> AP.Invite URIMode
|
-> AP.Invite URIMode
|
||||||
-> ExceptT Text Handler OutboxItemId
|
-> ExceptT Text Handler OutboxItemId
|
||||||
inviteC (Entity senderPersonID senderPerson) senderActor maybeCap localRecips remoteRecips fwdHosts action invite = do
|
inviteC (Entity senderPersonID senderPerson) senderActor maybeCap localRecips remoteRecips fwdHosts action invite = do
|
||||||
error "Temporarily disabled due to switch to new actor system"
|
error "Disabled for actor refactoring"
|
||||||
{-
|
{-
|
||||||
-- Check input
|
-- Check input
|
||||||
(resource, recipient) <- parseInvite (Left senderPersonID) invite
|
(resource, recipient) <- parseInvite (Left senderPersonID) invite
|
||||||
capID <- fromMaybeE maybeCap "No capability provided"
|
_capID <- fromMaybeE maybeCap "No capability provided"
|
||||||
|
|
||||||
-- If resource is remote, HTTP GET it and its managing actor, and insert to
|
-- If resource is remote, HTTP GET it and its managing actor, and insert to
|
||||||
-- our DB. If resource is local, find it in our DB.
|
-- our DB. If resource is local, find it in our DB.
|
||||||
|
@ -1866,7 +1879,7 @@ inviteC (Entity senderPersonID senderPerson) senderActor maybeCap localRecips re
|
||||||
(runDBExcept . flip getGrantResource "Grant context not found in DB")
|
(runDBExcept . flip getGrantResource "Grant context not found in DB")
|
||||||
(\ u@(ObjURI h lu) -> do
|
(\ u@(ObjURI h lu) -> do
|
||||||
instanceID <-
|
instanceID <-
|
||||||
lift $ runDB $ either entityKey id <$> insertBy' (Instance h)
|
lift $ withDB $ either entityKey id <$> insertBy' (Instance h)
|
||||||
result <-
|
result <-
|
||||||
ExceptT $ first (T.pack . show) <$>
|
ExceptT $ first (T.pack . show) <$>
|
||||||
fetchRemoteResource instanceID h lu
|
fetchRemoteResource instanceID h lu
|
||||||
|
@ -1888,7 +1901,7 @@ inviteC (Entity senderPersonID senderPerson) senderActor maybeCap localRecips re
|
||||||
lift $ runDB $ either entityKey id <$> insertBy' (Instance h)
|
lift $ runDB $ either entityKey id <$> insertBy' (Instance h)
|
||||||
result <-
|
result <-
|
||||||
ExceptT $ first (T.pack . displayException) <$>
|
ExceptT $ first (T.pack . displayException) <$>
|
||||||
fetchRemoteActor instanceID h lu
|
fetchRemoteActor' instanceID h lu
|
||||||
case result of
|
case result of
|
||||||
Left Nothing -> throwE "Recipient @id mismatch"
|
Left Nothing -> throwE "Recipient @id mismatch"
|
||||||
Left (Just err) -> throwE $ T.pack $ displayException err
|
Left (Just err) -> throwE $ T.pack $ displayException err
|
||||||
|
@ -1910,27 +1923,25 @@ inviteC (Entity senderPersonID senderPerson) senderActor maybeCap localRecips re
|
||||||
now <- liftIO getCurrentTime
|
now <- liftIO getCurrentTime
|
||||||
senderHash <- encodeKeyHashid senderPersonID
|
senderHash <- encodeKeyHashid senderPersonID
|
||||||
|
|
||||||
|
? <- withDBExcept $ do
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(obiidInvite, deliverHttpInvite) <- runDBExcept $ do
|
(obiidInvite, deliverHttpInvite) <- runDBExcept $ do
|
||||||
|
|
||||||
-- If resource is local, verify the specified capability gives relevant
|
-- Insert the Invite activity to author's outbox
|
||||||
-- access to it.
|
|
||||||
case resourceDB of
|
|
||||||
Left r -> do
|
|
||||||
capability <-
|
|
||||||
case capID of
|
|
||||||
Left (actor, _, item) -> return (actor, item)
|
|
||||||
Right _ -> throwE "Capability is a remote URI, i.e. not authored by the local topic"
|
|
||||||
verifyCapability capability (Left senderPersonID) (bmap entityKey r)
|
|
||||||
Right _ -> pure ()
|
|
||||||
|
|
||||||
-- Insert new Collab to DB
|
|
||||||
inviteID <- lift $ insertEmptyOutboxItem (actorOutbox senderActor) now
|
inviteID <- lift $ insertEmptyOutboxItem (actorOutbox senderActor) now
|
||||||
case resourceDB of
|
|
||||||
Left localResource ->
|
|
||||||
lift $ insertCollab localResource recipientDB inviteID
|
|
||||||
Right _ -> pure ()
|
|
||||||
|
|
||||||
-- Insert the Grant activity to author's outbox
|
|
||||||
_luInvite <- lift $ updateOutboxItem (LocalActorPerson senderPersonID) inviteID action
|
_luInvite <- lift $ updateOutboxItem (LocalActorPerson senderPersonID) inviteID action
|
||||||
|
|
||||||
-- Deliver the Invite activity to local recipients, and schedule
|
-- Deliver the Invite activity to local recipients, and schedule
|
||||||
|
@ -1986,6 +1997,22 @@ inviteC (Entity senderPersonID senderPerson) senderActor maybeCap localRecips re
|
||||||
-- Return instructions for HTTP delivery to remote recipients
|
-- Return instructions for HTTP delivery to remote recipients
|
||||||
return (inviteID, deliverHttpInvite)
|
return (inviteID, deliverHttpInvite)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Notify the resource
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Launch asynchronous HTTP delivery of the Grant activity
|
-- Launch asynchronous HTTP delivery of the Grant activity
|
||||||
lift $ do
|
lift $ do
|
||||||
forkWorker "inviteC: async HTTP Grant delivery" deliverHttpInvite
|
forkWorker "inviteC: async HTTP Grant delivery" deliverHttpInvite
|
||||||
|
@ -1995,20 +2022,20 @@ inviteC (Entity senderPersonID senderPerson) senderActor maybeCap localRecips re
|
||||||
where
|
where
|
||||||
|
|
||||||
fetchRemoteResource instanceID host localURI = do
|
fetchRemoteResource instanceID host localURI = do
|
||||||
maybeActor <- runSiteDB $ runMaybeT $ do
|
maybeActor <- withDB $ runMaybeT $ do
|
||||||
roid <- MaybeT $ getKeyBy $ UniqueRemoteObject instanceID localURI
|
roid <- MaybeT $ getKeyBy $ UniqueRemoteObject instanceID localURI
|
||||||
MaybeT $ getBy $ UniqueRemoteActor roid
|
MaybeT $ getBy $ UniqueRemoteActor roid
|
||||||
case maybeActor of
|
case maybeActor of
|
||||||
Just actor -> return $ Right $ Left actor
|
Just actor -> return $ Right $ Left actor
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
manager <- asksSite getHttpManager
|
manager <- asksEnv getHttpManager
|
||||||
errorOrResource <- fetchResource manager host localURI
|
errorOrResource <- fetchResource manager host localURI
|
||||||
case errorOrResource of
|
case errorOrResource of
|
||||||
Left maybeError ->
|
Left maybeError ->
|
||||||
return $ Left $ maybe ResultIdMismatch ResultGetError maybeError
|
return $ Left $ maybe ResultIdMismatch ResultGetError maybeError
|
||||||
Right resource -> do
|
Right resource -> do
|
||||||
case resource of
|
case resource of
|
||||||
ResourceActor (AP.Actor local detail) -> runSiteDB $ do
|
ResourceActor (AP.Actor local detail) -> withDB $ do
|
||||||
roid <- either entityKey id <$> insertBy' (RemoteObject instanceID localURI)
|
roid <- either entityKey id <$> insertBy' (RemoteObject instanceID localURI)
|
||||||
let ra = RemoteActor
|
let ra = RemoteActor
|
||||||
{ remoteActorIdent = roid
|
{ remoteActorIdent = roid
|
||||||
|
@ -2020,8 +2047,8 @@ inviteC (Entity senderPersonID senderPerson) senderActor maybeCap localRecips re
|
||||||
}
|
}
|
||||||
Right . Left . either id id <$> insertByEntity' ra
|
Right . Left . either id id <$> insertByEntity' ra
|
||||||
ResourceChild luId luManager -> do
|
ResourceChild luId luManager -> do
|
||||||
roid <- runSiteDB $ either entityKey id <$> insertBy' (RemoteObject instanceID localURI)
|
roid <- withDB $ either entityKey id <$> insertBy' (RemoteObject instanceID localURI)
|
||||||
result <- fetchRemoteActor instanceID host luManager
|
result <- fetchRemoteActor' instanceID host luManager
|
||||||
return $
|
return $
|
||||||
case result of
|
case result of
|
||||||
Left e -> Left $ ResultSomeException e
|
Left e -> Left $ ResultSomeException e
|
||||||
|
@ -2038,23 +2065,6 @@ inviteC (Entity senderPersonID senderPerson) senderActor maybeCap localRecips re
|
||||||
routes <- lookup p $ recipPeople localRecips
|
routes <- lookup p $ recipPeople localRecips
|
||||||
guard $ routePerson routes
|
guard $ routePerson routes
|
||||||
|
|
||||||
insertCollab resource recipient inviteID = do
|
|
||||||
collabID <- insert Collab
|
|
||||||
case resource of
|
|
||||||
GrantResourceRepo (Entity repoID _) ->
|
|
||||||
insert_ $ CollabTopicRepo collabID repoID
|
|
||||||
GrantResourceDeck (Entity deckID _) ->
|
|
||||||
insert_ $ CollabTopicDeck collabID deckID
|
|
||||||
GrantResourceLoom (Entity loomID _) ->
|
|
||||||
insert_ $ CollabTopicLoom collabID loomID
|
|
||||||
fulfillsID <- insert $ CollabFulfillsInvite collabID
|
|
||||||
insert_ $ CollabInviterLocal fulfillsID inviteID
|
|
||||||
case recipient of
|
|
||||||
Left (GrantRecipPerson (Entity personID _)) ->
|
|
||||||
insert_ $ CollabRecipLocal collabID personID
|
|
||||||
Right (remoteActorID, _) ->
|
|
||||||
insert_ $ CollabRecipRemote collabID remoteActorID
|
|
||||||
|
|
||||||
hashGrantRecip (GrantRecipPerson k) =
|
hashGrantRecip (GrantRecipPerson k) =
|
||||||
GrantRecipPerson <$> encodeKeyHashid k
|
GrantRecipPerson <$> encodeKeyHashid k
|
||||||
-}
|
-}
|
||||||
|
|
|
@ -77,6 +77,7 @@ module Vervis.Access
|
||||||
, grantResourceLocalActor
|
, grantResourceLocalActor
|
||||||
|
|
||||||
, verifyCapability
|
, verifyCapability
|
||||||
|
, verifyCapability'
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
|
@ -89,6 +90,8 @@ import Control.Monad.Trans.Maybe
|
||||||
import Control.Monad.Trans.Reader
|
import Control.Monad.Trans.Reader
|
||||||
import Data.Barbie
|
import Data.Barbie
|
||||||
import Data.Bifunctor
|
import Data.Bifunctor
|
||||||
|
import Data.Bitraversable
|
||||||
|
import Data.ByteString (ByteString)
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Database.Persist
|
import Database.Persist
|
||||||
|
@ -99,6 +102,7 @@ import Yesod.Core.Handler
|
||||||
import qualified Database.Esqueleto as E
|
import qualified Database.Esqueleto as E
|
||||||
|
|
||||||
import Control.Concurrent.Actor
|
import Control.Concurrent.Actor
|
||||||
|
import Network.FedURI
|
||||||
import Web.Actor.Persist (stageHashidsContext)
|
import Web.Actor.Persist (stageHashidsContext)
|
||||||
import Yesod.Hashids
|
import Yesod.Hashids
|
||||||
import Yesod.MonadSite
|
import Yesod.MonadSite
|
||||||
|
@ -107,6 +111,7 @@ import Control.Monad.Trans.Except.Local
|
||||||
import Data.Either.Local
|
import Data.Either.Local
|
||||||
import Database.Persist.Local
|
import Database.Persist.Local
|
||||||
|
|
||||||
|
import Vervis.Actor
|
||||||
import Vervis.Foundation
|
import Vervis.Foundation
|
||||||
import Vervis.Model
|
import Vervis.Model
|
||||||
import Vervis.Model.Role
|
import Vervis.Model.Role
|
||||||
|
@ -383,3 +388,23 @@ verifyCapability (capActor, capItem) actor resource = do
|
||||||
-- Since there are currently no roles, and grants allow only the "Admin"
|
-- Since there are currently no roles, and grants allow only the "Admin"
|
||||||
-- role that supports every operation, we don't need to check role access
|
-- role that supports every operation, we don't need to check role access
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
|
verifyCapability'
|
||||||
|
:: MonadIO m
|
||||||
|
=> (LocalActorBy Key, OutboxItemId)
|
||||||
|
-> Either
|
||||||
|
(LocalActorBy Key, ActorId, OutboxItemId)
|
||||||
|
(RemoteAuthor, LocalURI, Maybe ByteString)
|
||||||
|
-> GrantResourceBy Key
|
||||||
|
-> ExceptT Text (ReaderT SqlBackend m) ()
|
||||||
|
verifyCapability' cap actor resource = do
|
||||||
|
actorP <- processActor actor
|
||||||
|
verifyCapability cap actorP resource
|
||||||
|
where
|
||||||
|
processActor = bitraverse processLocal processRemote
|
||||||
|
where
|
||||||
|
processLocal (actorByKey, _, _) =
|
||||||
|
case actorByKey of
|
||||||
|
LocalActorPerson personID -> return personID
|
||||||
|
_ -> throwE "Non-person local actors can't get Grants at the moment"
|
||||||
|
processRemote (author, _, _) = pure $ remoteAuthorId author
|
||||||
|
|
|
@ -55,11 +55,12 @@ module Vervis.Actor
|
||||||
-- * AP system base types
|
-- * AP system base types
|
||||||
, RemoteAuthor (..)
|
, RemoteAuthor (..)
|
||||||
, ActivityBody (..)
|
, ActivityBody (..)
|
||||||
, VerseRemote (..)
|
--, VerseRemote (..)
|
||||||
|
, Verse (..)
|
||||||
|
|
||||||
-- * Behavior utility types
|
-- * Behavior utility types
|
||||||
, Verse
|
--, Verse
|
||||||
, Event (..)
|
--, Event (..)
|
||||||
, Env (..)
|
, Env (..)
|
||||||
, Act
|
, Act
|
||||||
, ActE
|
, ActE
|
||||||
|
@ -87,6 +88,7 @@ import Control.Monad.Trans.Maybe
|
||||||
import Control.Monad.Trans.Except
|
import Control.Monad.Trans.Except
|
||||||
import Control.Monad.Trans.Reader
|
import Control.Monad.Trans.Reader
|
||||||
import Data.Barbie
|
import Data.Barbie
|
||||||
|
import Data.Bifunctor
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
import Data.Foldable
|
import Data.Foldable
|
||||||
import Data.Function
|
import Data.Function
|
||||||
|
@ -290,6 +292,27 @@ data ActivityBody = ActivityBody
|
||||||
, actbActivity :: AP.Activity URIMode
|
, actbActivity :: AP.Activity URIMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data Verse = Verse
|
||||||
|
{ verseSource :: Either (LocalActorBy Key, ActorId, OutboxItemId) (RemoteAuthor, LocalURI, Maybe ByteString)
|
||||||
|
, verseBody :: ActivityBody
|
||||||
|
--, verseLocalRecips :: RecipientRoutes
|
||||||
|
}
|
||||||
|
|
||||||
|
instance Message Verse where
|
||||||
|
summarize (Verse (Left (actor, _, itemID)) body) =
|
||||||
|
let typ = AP.activityType $ AP.activitySpecific $ actbActivity body
|
||||||
|
in T.concat [typ, " ", T.pack $ show actor, " ", T.pack $ show itemID]
|
||||||
|
summarize (Verse (Right (author, luAct, _)) body) =
|
||||||
|
let ObjURI h _ = remoteAuthorURI author
|
||||||
|
typ = AP.activityType $ AP.activitySpecific $ actbActivity body
|
||||||
|
in T.concat [typ, " ", renderObjURI $ ObjURI h luAct]
|
||||||
|
refer (Verse (Left (actor, _, itemID)) _body) =
|
||||||
|
T.concat [T.pack $ show actor, " ", T.pack $ show itemID]
|
||||||
|
refer (Verse (Right (author, luAct, _)) _body) =
|
||||||
|
let ObjURI h _ = remoteAuthorURI author
|
||||||
|
in renderObjURI $ ObjURI h luAct
|
||||||
|
|
||||||
|
{-
|
||||||
data VerseRemote = VerseRemote
|
data VerseRemote = VerseRemote
|
||||||
{ verseAuthor :: RemoteAuthor
|
{ verseAuthor :: RemoteAuthor
|
||||||
, verseBody :: ActivityBody
|
, verseBody :: ActivityBody
|
||||||
|
@ -341,6 +364,14 @@ data Event
|
||||||
| EventRemoteJoinLocalTopicFwdToFollower RemoteActivityId
|
| EventRemoteJoinLocalTopicFwdToFollower RemoteActivityId
|
||||||
-- ^ A remote actor asked to Join a local topic, and the local topic is
|
-- ^ A remote actor asked to Join a local topic, and the local topic is
|
||||||
-- forwarding the Join to me because I'm following the topic
|
-- forwarding the Join to me because I'm following the topic
|
||||||
|
| EventTopicHandleLocalInvite PersonId OutboxItemId BL.ByteString ByteString FedURI (Either (GrantRecipBy Key) FedURI)
|
||||||
|
-- ^ I'm a resource and a local Person has published an invite-for-me.
|
||||||
|
-- Params: Sender person, Invite ID, Invite activity body, forwarding
|
||||||
|
-- signature header, capability URI, invite target.
|
||||||
|
| EventLocalInviteLocalTopicFwdToFollower OutboxItemId
|
||||||
|
-- ^ An authorized local actor sent an Invite-to-a-local-topic, and the
|
||||||
|
-- local topic is forwarding the Invite to me because I'm following the
|
||||||
|
-- topic
|
||||||
| EventUnknown
|
| EventUnknown
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
|
@ -356,6 +387,7 @@ instance Message Verse where
|
||||||
refer (Right (VerseRemote author _body _fwd uri)) =
|
refer (Right (VerseRemote author _body _fwd uri)) =
|
||||||
let ObjURI h _ = remoteAuthorURI author
|
let ObjURI h _ = remoteAuthorURI author
|
||||||
in renderObjURI $ ObjURI h uri
|
in renderObjURI $ ObjURI h uri
|
||||||
|
-}
|
||||||
|
|
||||||
type YesodRender y = Route y -> [(Text, Text)] -> Text
|
type YesodRender y = Route y -> [(Text, Text)] -> Text
|
||||||
|
|
||||||
|
@ -470,22 +502,24 @@ data RemoteRecipient = RemoteRecipient
|
||||||
-- This function reads the follower sets and remote recipient data from the
|
-- This function reads the follower sets and remote recipient data from the
|
||||||
-- PostgreSQL database. Don't use it inside a database transaction.
|
-- PostgreSQL database. Don't use it inside a database transaction.
|
||||||
sendToLocalActors
|
sendToLocalActors
|
||||||
:: Event
|
:: Either (LocalActorBy Key, ActorId, OutboxItemId) (RemoteAuthor, LocalURI)
|
||||||
-- ^ Event to send to local live actors
|
-- ^ Author of the activity being sent
|
||||||
|
-> ActivityBody
|
||||||
|
-- ^ Activity to send
|
||||||
-> Bool
|
-> Bool
|
||||||
-- ^ Whether to deliver to collection only if owner actor is addressed
|
-- ^ Whether to deliver to collection only if owner actor is addressed
|
||||||
-> Maybe (LocalActorBy Key)
|
-> Maybe (LocalActorBy Key)
|
||||||
-- ^ An actor whose collections are excluded from requiring an owner, i.e.
|
-- ^ An actor whose collections are excluded from requiring an owner, i.e.
|
||||||
-- even if owner is required, this actor's collections will be delivered
|
-- 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
|
-- to, even if this actor isn't addressed. This is meant to be the
|
||||||
-- activity's author.
|
-- activity's sender.
|
||||||
-> Maybe (LocalActorBy Key)
|
-> Maybe (LocalActorBy Key)
|
||||||
-- ^ An actor whose inbox to exclude from delivery, even if this actor is
|
-- ^ An actor whose inbox to exclude from delivery, even if this actor is
|
||||||
-- listed in the recipient set. This is meant to be the activity's
|
-- listed in the recipient set. This is meant to be the activity's
|
||||||
-- author.
|
-- sender.
|
||||||
-> RecipientRoutes
|
-> RecipientRoutes
|
||||||
-> Act [((InstanceId, Host), NonEmpty RemoteRecipient)]
|
-> Act [((InstanceId, Host), NonEmpty RemoteRecipient)]
|
||||||
sendToLocalActors event requireOwner mauthor maidAuthor recips = do
|
sendToLocalActors authorAndId body requireOwner mauthor maidAuthor recips = do
|
||||||
|
|
||||||
-- Unhash actor and work item hashids
|
-- Unhash actor and work item hashids
|
||||||
people <- unhashKeys $ recipPeople recips
|
people <- unhashKeys $ recipPeople recips
|
||||||
|
@ -608,7 +642,9 @@ sendToLocalActors event requireOwner mauthor maidAuthor recips = do
|
||||||
in case maidAuthor of
|
in case maidAuthor of
|
||||||
Nothing -> s
|
Nothing -> s
|
||||||
Just a -> HS.delete a s
|
Just a -> HS.delete a s
|
||||||
sendMany liveRecips $ Left event
|
authorAndId' =
|
||||||
|
second (\ (author, luAct) -> (author, luAct, Nothing)) authorAndId
|
||||||
|
sendMany liveRecips $ Verse authorAndId' body
|
||||||
|
|
||||||
-- Return remote followers, to whom we need to deliver via HTTP
|
-- Return remote followers, to whom we need to deliver via HTTP
|
||||||
return remoteFollowers
|
return remoteFollowers
|
||||||
|
|
|
@ -20,6 +20,7 @@ module Vervis.Actor.Common
|
||||||
, topicAccept
|
, topicAccept
|
||||||
, topicReject
|
, topicReject
|
||||||
, topicInvite
|
, topicInvite
|
||||||
|
--, topicHandleLocalInvite
|
||||||
, topicJoin
|
, topicJoin
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
@ -33,6 +34,7 @@ import Control.Monad.Trans.Class
|
||||||
import Control.Monad.Trans.Except
|
import Control.Monad.Trans.Except
|
||||||
import Control.Monad.Trans.Maybe
|
import Control.Monad.Trans.Maybe
|
||||||
import Control.Monad.Trans.Reader
|
import Control.Monad.Trans.Reader
|
||||||
|
import Data.Bifoldable
|
||||||
import Data.Bifunctor
|
import Data.Bifunctor
|
||||||
import Data.Bitraversable
|
import Data.Bitraversable
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
|
@ -92,13 +94,10 @@ actorFollow
|
||||||
-> (a -> Act [Aud URIMode])
|
-> (a -> Act [Aud URIMode])
|
||||||
-> UTCTime
|
-> UTCTime
|
||||||
-> Key r
|
-> Key r
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Follow URIMode
|
-> AP.Follow URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
actorFollow parseFollowee grabActor unread getFollowee getSieve makeLocalActor makeAudience now recipID author body mfwd luFollow (AP.Follow uObject _ hide) = do
|
actorFollow parseFollowee grabActor unread getFollowee getSieve makeLocalActor makeAudience now recipID (Verse authorIdMsig body) (AP.Follow uObject _ hide) = do
|
||||||
|
|
||||||
-- Check input
|
-- Check input
|
||||||
followee <- nameExceptT "Follow object" $ do
|
followee <- nameExceptT "Follow object" $ do
|
||||||
|
@ -107,6 +106,7 @@ actorFollow parseFollowee grabActor unread getFollowee getSieve makeLocalActor m
|
||||||
case routeOrRemote of
|
case routeOrRemote of
|
||||||
Left route -> pure route
|
Left route -> pure route
|
||||||
Right _ -> throwE "Remote, so definitely not me/mine"
|
Right _ -> throwE "Remote, so definitely not me/mine"
|
||||||
|
-- Verify the followee is me or a subobject of mine
|
||||||
parseFollowee route
|
parseFollowee route
|
||||||
verifyNothingE
|
verifyNothingE
|
||||||
(AP.activityCapability $ actbActivity body)
|
(AP.activityCapability $ actbActivity body)
|
||||||
|
@ -114,28 +114,37 @@ actorFollow parseFollowee grabActor unread getFollowee getSieve makeLocalActor m
|
||||||
|
|
||||||
maybeFollow <- withDBExcept $ do
|
maybeFollow <- withDBExcept $ do
|
||||||
|
|
||||||
-- Find recipient actor in DB
|
-- Find me in DB
|
||||||
recip <- lift $ getJust recipID
|
recip <- lift $ getJust recipID
|
||||||
let recipActorID = grabActor recip
|
let recipActorID = grabActor recip
|
||||||
recipActor <- lift $ getJust recipActorID
|
recipActor <- lift $ getJust recipActorID
|
||||||
|
|
||||||
-- Insert the Follow to actor's inbox
|
-- Insert the Follow to my inbox
|
||||||
mractid <- lift $ insertToInbox now author body (actorInbox recipActor) luFollow unread
|
maybeFollowDB <- lift $ insertToInbox now authorIdMsig body (actorInbox recipActor) unread
|
||||||
for mractid $ \ followID -> do
|
for maybeFollowDB $ \ followDB -> do
|
||||||
|
|
||||||
-- Find followee in DB
|
-- Find followee in DB
|
||||||
followerSetID <- getFollowee recipActor followee
|
followerSetID <- getFollowee recipActor followee
|
||||||
|
|
||||||
-- Verify not already following us
|
-- Verify not already following me
|
||||||
let followerID = remoteAuthorId author
|
case followDB of
|
||||||
maybeFollow <-
|
Left (_, followerID, followID) -> do
|
||||||
lift $ getBy $ UniqueRemoteFollow followerID followerSetID
|
maybeFollow <- lift $ getBy $ UniqueFollow followerID followerSetID
|
||||||
verifyNothingE maybeFollow "You're already following this object"
|
verifyNothingE maybeFollow "You're already following this object"
|
||||||
|
Right (author, _, followID) -> do
|
||||||
|
let followerID = remoteAuthorId author
|
||||||
|
maybeFollow <- lift $ getBy $ UniqueRemoteFollow followerID followerSetID
|
||||||
|
verifyNothingE maybeFollow "You're already following this object"
|
||||||
|
|
||||||
-- Record the new follow in DB
|
-- Record the new follow in DB
|
||||||
acceptID <-
|
acceptID <-
|
||||||
lift $ insertEmptyOutboxItem' (actorOutbox recipActor) now
|
lift $ insertEmptyOutboxItem' (actorOutbox recipActor) now
|
||||||
lift $ insert_ $ RemoteFollow followerID followerSetID (not hide) followID acceptID
|
lift $ case followDB of
|
||||||
|
Left (_actorByKey, actorID, followID) ->
|
||||||
|
insert_ $ Follow actorID followerSetID (not hide) followID acceptID
|
||||||
|
Right (author, _luFollow, followID) -> do
|
||||||
|
let authorID = remoteAuthorId author
|
||||||
|
insert_ $ RemoteFollow authorID followerSetID (not hide) followID acceptID
|
||||||
|
|
||||||
-- Prepare an Accept activity and insert to actor's outbox
|
-- Prepare an Accept activity and insert to actor's outbox
|
||||||
accept@(actionAccept, localRecipsAccept, remoteRecipsAccept, fwdHostsAccept) <-
|
accept@(actionAccept, localRecipsAccept, remoteRecipsAccept, fwdHostsAccept) <-
|
||||||
|
@ -143,20 +152,15 @@ actorFollow parseFollowee grabActor unread getFollowee getSieve makeLocalActor m
|
||||||
_luAccept <- lift $ updateOutboxItem' (makeLocalActor recipID) acceptID actionAccept
|
_luAccept <- lift $ updateOutboxItem' (makeLocalActor recipID) acceptID actionAccept
|
||||||
|
|
||||||
sieve <- lift $ getSieve followee
|
sieve <- lift $ getSieve followee
|
||||||
return (recipActorID, followID, acceptID, sieve, accept)
|
return (recipActorID, acceptID, sieve, accept)
|
||||||
|
|
||||||
case maybeFollow of
|
case maybeFollow of
|
||||||
Nothing -> done "I already have this activity in my inbox"
|
Nothing -> done "I already have this activity in my inbox"
|
||||||
Just (actorID, followID, acceptID, sieve, (actionAccept, localRecipsAccept, remoteRecipsAccept, fwdHostsAccept)) -> do
|
Just (actorID, acceptID, sieve, (actionAccept, localRecipsAccept, remoteRecipsAccept, fwdHostsAccept)) -> do
|
||||||
lift $ for_ mfwd $ \ (localRecips, sig) ->
|
forwardActivity authorIdMsig body (makeLocalActor recipID) actorID sieve
|
||||||
forwardActivity
|
|
||||||
(actbBL body) localRecips sig actorID
|
|
||||||
(makeLocalActor recipID) sieve
|
|
||||||
(EventRemoteFollowLocalRecipFwdToFollower followID)
|
|
||||||
lift $ sendActivity
|
lift $ sendActivity
|
||||||
(makeLocalActor recipID) actorID localRecipsAccept
|
(makeLocalActor recipID) actorID localRecipsAccept
|
||||||
remoteRecipsAccept fwdHostsAccept acceptID
|
remoteRecipsAccept fwdHostsAccept acceptID actionAccept
|
||||||
EventAcceptRemoteFollow actionAccept
|
|
||||||
done "Recorded Follow and published Accept"
|
done "Recorded Follow and published Accept"
|
||||||
|
|
||||||
where
|
where
|
||||||
|
@ -164,14 +168,8 @@ actorFollow parseFollowee grabActor unread getFollowee getSieve makeLocalActor m
|
||||||
prepareAccept followee = do
|
prepareAccept followee = do
|
||||||
encodeRouteHome <- getEncodeRouteHome
|
encodeRouteHome <- getEncodeRouteHome
|
||||||
|
|
||||||
ra <- getJust $ remoteAuthorId author
|
audSender <- makeAudSenderWithFollowers authorIdMsig
|
||||||
|
uFollow <- lift $ getActivityURI authorIdMsig
|
||||||
let ObjURI hAuthor luAuthor = remoteAuthorURI author
|
|
||||||
|
|
||||||
audSender =
|
|
||||||
AudRemote hAuthor
|
|
||||||
[luAuthor]
|
|
||||||
(maybeToList $ remoteActorFollowers ra)
|
|
||||||
|
|
||||||
audsRecip <- lift $ makeAudience followee
|
audsRecip <- lift $ makeAudience followee
|
||||||
|
|
||||||
|
@ -185,7 +183,7 @@ actorFollow parseFollowee grabActor unread getFollowee getSieve makeLocalActor m
|
||||||
, AP.actionAudience = AP.Audience recips [] [] [] [] []
|
, AP.actionAudience = AP.Audience recips [] [] [] [] []
|
||||||
, AP.actionFulfills = []
|
, AP.actionFulfills = []
|
||||||
, AP.actionSpecific = AP.AcceptActivity AP.Accept
|
, AP.actionSpecific = AP.AcceptActivity AP.Accept
|
||||||
{ AP.acceptObject = ObjURI hAuthor luFollow
|
{ AP.acceptObject = uFollow
|
||||||
, AP.acceptResult = Nothing
|
, AP.acceptResult = Nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,13 +196,10 @@ topicAccept
|
||||||
-> (forall f. f topic -> GrantResourceBy f)
|
-> (forall f. f topic -> GrantResourceBy f)
|
||||||
-> UTCTime
|
-> UTCTime
|
||||||
-> Key topic
|
-> Key topic
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Accept URIMode
|
-> AP.Accept URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
topicAccept topicActor topicResource now recipKey author body mfwd luAccept accept = do
|
topicAccept topicActor topicResource now recipKey (Verse authorIdMsig body) accept = do
|
||||||
|
|
||||||
-- Check input
|
-- Check input
|
||||||
acceptee <- parseAccept accept
|
acceptee <- parseAccept accept
|
||||||
|
@ -219,7 +214,7 @@ topicAccept topicActor topicResource now recipKey author body mfwd luAccept acce
|
||||||
|
|
||||||
maybeNew <- withDBExcept $ do
|
maybeNew <- withDBExcept $ do
|
||||||
|
|
||||||
-- Grab recipient deck from DB
|
-- Grab me from DB
|
||||||
(recipActorID, recipActor) <- lift $ do
|
(recipActorID, recipActor) <- lift $ do
|
||||||
recip <- getJust recipKey
|
recip <- getJust recipKey
|
||||||
let actorID = topicActor recip
|
let actorID = topicActor recip
|
||||||
|
@ -263,9 +258,13 @@ topicAccept topicActor topicResource now recipKey author body mfwd luAccept acce
|
||||||
(getBy $ UniqueCollabRecipRemote collabID)
|
(getBy $ UniqueCollabRecipRemote collabID)
|
||||||
"Found Collab with no recip"
|
"Found Collab with no recip"
|
||||||
"Found Collab with multiple recips"
|
"Found Collab with multiple recips"
|
||||||
case recip of
|
case (recip, authorIdMsig) of
|
||||||
Right (Entity crrid crr)
|
(Left (Entity crlid crl), Left (LocalActorPerson personID, _, _))
|
||||||
| collabRecipRemoteActor crr == remoteAuthorId author -> return (fulfillsID, crrid)
|
| collabRecipLocalPerson crl == personID ->
|
||||||
|
return (fulfillsID, Left crlid)
|
||||||
|
(Right (Entity crrid crr), Right (author, _, _))
|
||||||
|
| collabRecipRemoteActor crr == remoteAuthorId author ->
|
||||||
|
return (fulfillsID, Right crrid)
|
||||||
_ -> throwE "Accepting an Invite whose recipient is someone else"
|
_ -> throwE "Accepting an Invite whose recipient is someone else"
|
||||||
|
|
||||||
-- If accepting a Join, verify accepter has permission
|
-- If accepting a Join, verify accepter has permission
|
||||||
|
@ -275,9 +274,9 @@ topicAccept topicActor topicResource now recipKey author body mfwd luAccept acce
|
||||||
case capID of
|
case capID of
|
||||||
Left (capActor, _, capItem) -> return (capActor, capItem)
|
Left (capActor, _, capItem) -> return (capActor, capItem)
|
||||||
Right _ -> throwE "Capability is a remote URI, i.e. not authored by the local resource"
|
Right _ -> throwE "Capability is a remote URI, i.e. not authored by the local resource"
|
||||||
verifyCapability
|
verifyCapability'
|
||||||
capability
|
capability
|
||||||
(Right $ remoteAuthorId author)
|
authorIdMsig
|
||||||
(topicResource recipKey)
|
(topicResource recipKey)
|
||||||
return fulfillsID
|
return fulfillsID
|
||||||
|
|
||||||
|
@ -285,27 +284,33 @@ topicAccept topicActor topicResource now recipKey author body mfwd luAccept acce
|
||||||
maybeEnabled <- lift $ getBy $ UniqueCollabEnable collabID
|
maybeEnabled <- lift $ getBy $ UniqueCollabEnable collabID
|
||||||
verifyNothingE maybeEnabled "I already sent a Grant for this Invite/Join"
|
verifyNothingE maybeEnabled "I already sent a Grant for this Invite/Join"
|
||||||
|
|
||||||
mractid <- lift $ insertToInbox now author body (actorInbox recipActor) luAccept False
|
maybeAcceptDB <- lift $ insertToInbox now authorIdMsig body (actorInbox recipActor) False
|
||||||
for mractid $ \ acceptID -> do
|
for maybeAcceptDB $ \ acceptDB -> do
|
||||||
|
|
||||||
-- Record the Accept on the Collab
|
-- Record the Accept on the Collab
|
||||||
case idsForAccept of
|
case (idsForAccept, acceptDB) of
|
||||||
Left (fulfillsID, recipID) -> do
|
(Left (fulfillsID, Left recipID), Left (_, _, acceptID)) -> do
|
||||||
maybeAccept <- lift $ insertUnique $ CollabRecipRemoteAccept recipID fulfillsID acceptID
|
maybeAccept <- lift $ insertUnique $ CollabRecipLocalAccept recipID fulfillsID acceptID
|
||||||
unless (isNothing maybeAccept) $ do
|
unless (isNothing maybeAccept) $
|
||||||
lift $ delete acceptID
|
|
||||||
throwE "This Invite already has an Accept by recip"
|
throwE "This Invite already has an Accept by recip"
|
||||||
Right fulfillsID -> do
|
(Left (fulfillsID, Right recipID), Right (_, _, acceptID)) -> do
|
||||||
maybeAccept <- lift $ insertUnique $ CollabApproverRemote fulfillsID (remoteAuthorId author) acceptID
|
maybeAccept <- lift $ insertUnique $ CollabRecipRemoteAccept recipID fulfillsID acceptID
|
||||||
unless (isNothing maybeAccept) $ do
|
unless (isJust maybeAccept) $
|
||||||
lift $ delete acceptID
|
throwE "This Invite already has an Accept by recip"
|
||||||
|
(Right fulfillsID, Left (_, _, acceptID)) -> do
|
||||||
|
maybeAccept <- lift $ insertUnique $ CollabApproverLocal fulfillsID acceptID
|
||||||
|
unless (isJust maybeAccept) $
|
||||||
throwE "This Join already has an Accept"
|
throwE "This Join already has an Accept"
|
||||||
|
(Right fulfillsID, Right (author, _, acceptID)) -> do
|
||||||
|
maybeAccept <- lift $ insertUnique $ CollabApproverRemote fulfillsID (remoteAuthorId author) acceptID
|
||||||
|
unless (isJust maybeAccept) $
|
||||||
|
throwE "This Join already has an Accept"
|
||||||
|
_ -> error "topicAccept impossible"
|
||||||
|
|
||||||
-- Prepare forwarding of Accept to my followers
|
-- Prepare forwarding of Accept to my followers
|
||||||
let recipByID = grantResourceLocalActor $ topicResource recipKey
|
let recipByID = grantResourceLocalActor $ topicResource recipKey
|
||||||
recipByHash <- hashLocalActor recipByID
|
recipByHash <- hashLocalActor recipByID
|
||||||
let sieve = makeRecipientSet [] [localActorFollowers recipByHash]
|
let sieve = makeRecipientSet [] [localActorFollowers recipByHash]
|
||||||
isInvite = isLeft collab
|
|
||||||
|
|
||||||
grantInfo <- do
|
grantInfo <- do
|
||||||
|
|
||||||
|
@ -315,29 +320,23 @@ topicAccept topicActor topicResource now recipKey author body mfwd luAccept acce
|
||||||
|
|
||||||
-- Prepare a Grant activity and insert to my outbox
|
-- Prepare a Grant activity and insert to my outbox
|
||||||
let inviterOrJoiner = either snd snd collab
|
let inviterOrJoiner = either snd snd collab
|
||||||
|
isInvite = isLeft collab
|
||||||
grant@(actionGrant, _, _, _) <-
|
grant@(actionGrant, _, _, _) <-
|
||||||
lift $ prepareGrant isInvite inviterOrJoiner
|
lift $ prepareGrant isInvite inviterOrJoiner
|
||||||
let recipByKey = grantResourceLocalActor $ topicResource recipKey
|
let recipByKey = grantResourceLocalActor $ topicResource recipKey
|
||||||
_luGrant <- lift $ updateOutboxItem' recipByKey grantID actionGrant
|
_luGrant <- lift $ updateOutboxItem' recipByKey grantID actionGrant
|
||||||
return (grantID, grant)
|
return (grantID, grant)
|
||||||
|
|
||||||
return (recipActorID, isInvite, acceptID, sieve, grantInfo)
|
return (recipActorID, sieve, grantInfo)
|
||||||
|
|
||||||
case maybeNew of
|
case maybeNew of
|
||||||
Nothing -> done "I already have this activity in my inbox"
|
Nothing -> done "I already have this activity in my inbox"
|
||||||
Just (recipActorID, isInvite, acceptID, sieve, (grantID, (actionGrant, localRecipsGrant, remoteRecipsGrant, fwdHostsGrant))) -> do
|
Just (recipActorID, sieve, (grantID, (actionGrant, localRecipsGrant, remoteRecipsGrant, fwdHostsGrant))) -> do
|
||||||
let recipByID = grantResourceLocalActor $ topicResource recipKey
|
let recipByID = grantResourceLocalActor $ topicResource recipKey
|
||||||
lift $ for_ mfwd $ \ (localRecips, sig) -> do
|
forwardActivity authorIdMsig body recipByID recipActorID sieve
|
||||||
forwardActivity
|
|
||||||
(actbBL body) localRecips sig recipActorID recipByID sieve
|
|
||||||
(if isInvite
|
|
||||||
then EventRemoteAcceptInviteLocalResourceFwdToFollower acceptID
|
|
||||||
else EventRemoteApproveJoinLocalResourceFwdToFollower acceptID
|
|
||||||
)
|
|
||||||
lift $ sendActivity
|
lift $ sendActivity
|
||||||
recipByID recipActorID localRecipsGrant
|
recipByID recipActorID localRecipsGrant
|
||||||
remoteRecipsGrant fwdHostsGrant grantID
|
remoteRecipsGrant fwdHostsGrant grantID actionGrant
|
||||||
(EventGrantAfterRemoteAccept grantID) actionGrant
|
|
||||||
done "Forwarded the Accept and published a Grant"
|
done "Forwarded the Accept and published a Grant"
|
||||||
|
|
||||||
where
|
where
|
||||||
|
@ -371,12 +370,15 @@ topicAccept topicActor topicResource now recipKey author body mfwd luAccept acce
|
||||||
encodeRouteHome <- getEncodeRouteHome
|
encodeRouteHome <- getEncodeRouteHome
|
||||||
encodeRouteLocal <- getEncodeRouteLocal
|
encodeRouteLocal <- getEncodeRouteLocal
|
||||||
|
|
||||||
accepter <- getJust $ remoteAuthorId author
|
audAccepter <- makeAudSenderWithFollowers authorIdMsig
|
||||||
|
audApprover <- lift $ makeAudSenderOnly authorIdMsig
|
||||||
recipHash <- encodeKeyHashid recipKey
|
recipHash <- encodeKeyHashid recipKey
|
||||||
let topicByHash = grantResourceLocalActor $ topicResource recipHash
|
let topicByHash = grantResourceLocalActor $ topicResource recipHash
|
||||||
|
|
||||||
senderHash <- bitraverse hashLocalActor pure sender
|
senderHash <- bitraverse hashLocalActor pure sender
|
||||||
|
|
||||||
|
uAccepter <- lift $ getActorURI authorIdMsig
|
||||||
|
|
||||||
let audience =
|
let audience =
|
||||||
if isInvite
|
if isInvite
|
||||||
then
|
then
|
||||||
|
@ -385,9 +387,6 @@ topicAccept topicActor topicResource now recipKey author body mfwd luAccept acce
|
||||||
Left actor -> AudLocal [actor] []
|
Left actor -> AudLocal [actor] []
|
||||||
Right (ObjURI h lu, _followers) ->
|
Right (ObjURI h lu, _followers) ->
|
||||||
AudRemote h [lu] []
|
AudRemote h [lu] []
|
||||||
audAccepter =
|
|
||||||
let ObjURI h lu = remoteAuthorURI author
|
|
||||||
in AudRemote h [lu] (maybeToList $ remoteActorFollowers accepter)
|
|
||||||
audTopic = AudLocal [] [localActorFollowers topicByHash]
|
audTopic = AudLocal [] [localActorFollowers topicByHash]
|
||||||
in [audInviter, audAccepter, audTopic]
|
in [audInviter, audAccepter, audTopic]
|
||||||
else
|
else
|
||||||
|
@ -396,9 +395,6 @@ topicAccept topicActor topicResource now recipKey author body mfwd luAccept acce
|
||||||
Left actor -> AudLocal [actor] [localActorFollowers actor]
|
Left actor -> AudLocal [actor] [localActorFollowers actor]
|
||||||
Right (ObjURI h lu, followers) ->
|
Right (ObjURI h lu, followers) ->
|
||||||
AudRemote h [lu] (maybeToList followers)
|
AudRemote h [lu] (maybeToList followers)
|
||||||
audApprover =
|
|
||||||
let ObjURI h lu = remoteAuthorURI author
|
|
||||||
in AudRemote h [lu] []
|
|
||||||
audTopic = AudLocal [] [localActorFollowers topicByHash]
|
audTopic = AudLocal [] [localActorFollowers topicByHash]
|
||||||
in [audJoiner, audApprover, audTopic]
|
in [audJoiner, audApprover, audTopic]
|
||||||
|
|
||||||
|
@ -417,7 +413,7 @@ topicAccept topicActor topicResource now recipKey author body mfwd luAccept acce
|
||||||
encodeRouteLocal $ renderLocalActor topicByHash
|
encodeRouteLocal $ renderLocalActor topicByHash
|
||||||
, AP.grantTarget =
|
, AP.grantTarget =
|
||||||
if isInvite
|
if isInvite
|
||||||
then remoteAuthorURI author
|
then uAccepter
|
||||||
else case senderHash of
|
else case senderHash of
|
||||||
Left actor ->
|
Left actor ->
|
||||||
encodeRouteHome $ renderLocalActor actor
|
encodeRouteHome $ renderLocalActor actor
|
||||||
|
@ -438,13 +434,10 @@ topicReject
|
||||||
-> (forall f. f topic -> GrantResourceBy f)
|
-> (forall f. f topic -> GrantResourceBy f)
|
||||||
-> UTCTime
|
-> UTCTime
|
||||||
-> Key topic
|
-> Key topic
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Reject URIMode
|
-> AP.Reject URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
topicReject topicActor topicResource now recipKey author body mfwd luReject reject = do
|
topicReject topicActor topicResource now recipKey (Verse authorIdMsig body) reject = do
|
||||||
|
|
||||||
-- Check input
|
-- Check input
|
||||||
rejectee <- parseReject reject
|
rejectee <- parseReject reject
|
||||||
|
@ -459,7 +452,7 @@ topicReject topicActor topicResource now recipKey author body mfwd luReject reje
|
||||||
|
|
||||||
maybeNew <- withDBExcept $ do
|
maybeNew <- withDBExcept $ do
|
||||||
|
|
||||||
-- Grab recipient deck from DB
|
-- Grab me from DB
|
||||||
(recipActorID, recipActor) <- lift $ do
|
(recipActorID, recipActor) <- lift $ do
|
||||||
recip <- getJust recipKey
|
recip <- getJust recipKey
|
||||||
let actorID = topicActor recip
|
let actorID = topicActor recip
|
||||||
|
@ -503,9 +496,13 @@ topicReject topicActor topicResource now recipKey author body mfwd luReject reje
|
||||||
(getBy $ UniqueCollabRecipRemote collabID)
|
(getBy $ UniqueCollabRecipRemote collabID)
|
||||||
"Found Collab with no recip"
|
"Found Collab with no recip"
|
||||||
"Found Collab with multiple recips"
|
"Found Collab with multiple recips"
|
||||||
case recip of
|
case (recip, authorIdMsig) of
|
||||||
Right (Entity crrid crr)
|
(Left (Entity crlid crl), Left (LocalActorPerson personID, _, _))
|
||||||
| collabRecipRemoteActor crr == remoteAuthorId author -> return (fulfillsID, crrid, deleteInviter)
|
| collabRecipLocalPerson crl == personID ->
|
||||||
|
return (fulfillsID, Left crlid, deleteInviter)
|
||||||
|
(Right (Entity crrid crr), Right (author, _, _))
|
||||||
|
| collabRecipRemoteActor crr == remoteAuthorId author ->
|
||||||
|
return (fulfillsID, Right crrid, deleteInviter)
|
||||||
_ -> throwE "Rejecting an Invite whose recipient is someone else"
|
_ -> throwE "Rejecting an Invite whose recipient is someone else"
|
||||||
|
|
||||||
-- If rejecting a Join, verify accepter has permission
|
-- If rejecting a Join, verify accepter has permission
|
||||||
|
@ -515,9 +512,9 @@ topicReject topicActor topicResource now recipKey author body mfwd luReject reje
|
||||||
case capID of
|
case capID of
|
||||||
Left (capActor, _, capItem) -> return (capActor, capItem)
|
Left (capActor, _, capItem) -> return (capActor, capItem)
|
||||||
Right _ -> throwE "Capability is a remote URI, i.e. not authored by the local resource"
|
Right _ -> throwE "Capability is a remote URI, i.e. not authored by the local resource"
|
||||||
verifyCapability
|
verifyCapability'
|
||||||
capability
|
capability
|
||||||
(Right $ remoteAuthorId author)
|
authorIdMsig
|
||||||
(topicResource recipKey)
|
(topicResource recipKey)
|
||||||
return (fulfillsID, deleteRecipJoin, deleteRecip)
|
return (fulfillsID, deleteRecipJoin, deleteRecip)
|
||||||
|
|
||||||
|
@ -527,7 +524,11 @@ topicReject topicActor topicResource now recipKey author body mfwd luReject reje
|
||||||
|
|
||||||
-- Verify the Collab isn't already accepted/approved
|
-- Verify the Collab isn't already accepted/approved
|
||||||
case idsForReject of
|
case idsForReject of
|
||||||
Left (_fulfillsID, recipID, _) -> do
|
Left (_fulfillsID, Left recipID, _) -> do
|
||||||
|
mval <-
|
||||||
|
lift $ getBy $ UniqueCollabRecipLocalAcceptCollab recipID
|
||||||
|
verifyNothingE mval "Invite is already accepted"
|
||||||
|
Left (_fulfillsID, Right recipID, _) -> do
|
||||||
mval <-
|
mval <-
|
||||||
lift $ getBy $ UniqueCollabRecipRemoteAcceptCollab recipID
|
lift $ getBy $ UniqueCollabRecipRemoteAcceptCollab recipID
|
||||||
verifyNothingE mval "Invite is already accepted"
|
verifyNothingE mval "Invite is already accepted"
|
||||||
|
@ -537,13 +538,13 @@ topicReject topicActor topicResource now recipKey author body mfwd luReject reje
|
||||||
unless (isNothing mval1 && isNothing mval2) $
|
unless (isNothing mval1 && isNothing mval2) $
|
||||||
throwE "Join is already approved"
|
throwE "Join is already approved"
|
||||||
|
|
||||||
mractid <- lift $ insertToInbox now author body (actorInbox recipActor) luReject False
|
maybeRejectDB <- lift $ insertToInbox now authorIdMsig body (actorInbox recipActor) False
|
||||||
for mractid $ \ rejectID -> do
|
for maybeRejectDB $ \ rejectDB -> do
|
||||||
|
|
||||||
-- Delete the whole Collab record
|
-- Delete the whole Collab record
|
||||||
case idsForReject of
|
case idsForReject of
|
||||||
Left (fulfillsID, recipID, deleteInviter) -> lift $ do
|
Left (fulfillsID, recipID, deleteInviter) -> lift $ do
|
||||||
delete recipID
|
bitraverse_ delete delete recipID
|
||||||
deleteTopic
|
deleteTopic
|
||||||
deleteInviter
|
deleteInviter
|
||||||
delete fulfillsID
|
delete fulfillsID
|
||||||
|
@ -558,36 +559,29 @@ topicReject topicActor topicResource now recipKey author body mfwd luReject reje
|
||||||
let recipByID = grantResourceLocalActor $ topicResource recipKey
|
let recipByID = grantResourceLocalActor $ topicResource recipKey
|
||||||
recipByHash <- hashLocalActor recipByID
|
recipByHash <- hashLocalActor recipByID
|
||||||
let sieve = makeRecipientSet [] [localActorFollowers recipByHash]
|
let sieve = makeRecipientSet [] [localActorFollowers recipByHash]
|
||||||
isInvite = isLeft collab
|
|
||||||
|
|
||||||
newRejectInfo <- do
|
newRejectInfo <- do
|
||||||
|
|
||||||
-- Prepare a Reject activity and insert to my outbox
|
-- Prepare a Reject activity and insert to my outbox
|
||||||
newRejectID <- lift $ insertEmptyOutboxItem' (actorOutbox recipActor) now
|
newRejectID <- lift $ insertEmptyOutboxItem' (actorOutbox recipActor) now
|
||||||
let inviterOrJoiner = either (view _2) (view _2) collab
|
let inviterOrJoiner = either (view _2) (view _2) collab
|
||||||
|
isInvite = isLeft collab
|
||||||
newReject@(actionReject, _, _, _) <-
|
newReject@(actionReject, _, _, _) <-
|
||||||
lift $ prepareReject isInvite inviterOrJoiner
|
lift $ prepareReject isInvite inviterOrJoiner
|
||||||
let recipByKey = grantResourceLocalActor $ topicResource recipKey
|
let recipByKey = grantResourceLocalActor $ topicResource recipKey
|
||||||
_luNewReject <- lift $ updateOutboxItem' recipByKey newRejectID actionReject
|
_luNewReject <- lift $ updateOutboxItem' recipByKey newRejectID actionReject
|
||||||
return (newRejectID, newReject)
|
return (newRejectID, newReject)
|
||||||
|
|
||||||
return (recipActorID, isInvite, rejectID, sieve, newRejectInfo)
|
return (recipActorID, sieve, newRejectInfo)
|
||||||
|
|
||||||
case maybeNew of
|
case maybeNew of
|
||||||
Nothing -> done "I already have this activity in my inbox"
|
Nothing -> done "I already have this activity in my inbox"
|
||||||
Just (recipActorID, isInvite, rejectID, sieve, (newRejectID, (action, localRecips, remoteRecips, fwdHosts))) -> do
|
Just (recipActorID, sieve, (newRejectID, (action, localRecips, remoteRecips, fwdHosts))) -> do
|
||||||
let recipByID = grantResourceLocalActor $ topicResource recipKey
|
let recipByID = grantResourceLocalActor $ topicResource recipKey
|
||||||
lift $ for_ mfwd $ \ (localRecips, sig) -> do
|
forwardActivity authorIdMsig body recipByID recipActorID sieve
|
||||||
forwardActivity
|
|
||||||
(actbBL body) localRecips sig recipActorID recipByID sieve
|
|
||||||
(if isInvite
|
|
||||||
then EventRemoteRejectInviteLocalResourceFwdToFollower rejectID
|
|
||||||
else EventRemoteForbidJoinLocalResourceFwdToFollower rejectID
|
|
||||||
)
|
|
||||||
lift $ sendActivity
|
lift $ sendActivity
|
||||||
recipByID recipActorID localRecips
|
recipByID recipActorID localRecips
|
||||||
remoteRecips fwdHosts newRejectID
|
remoteRecips fwdHosts newRejectID action
|
||||||
(EventRejectAfterRemoteReject newRejectID) action
|
|
||||||
done "Forwarded the Reject and published my own Reject"
|
done "Forwarded the Reject and published my own Reject"
|
||||||
|
|
||||||
where
|
where
|
||||||
|
@ -623,12 +617,15 @@ topicReject topicActor topicResource now recipKey author body mfwd luReject reje
|
||||||
encodeRouteHome <- getEncodeRouteHome
|
encodeRouteHome <- getEncodeRouteHome
|
||||||
encodeRouteLocal <- getEncodeRouteLocal
|
encodeRouteLocal <- getEncodeRouteLocal
|
||||||
|
|
||||||
rejecter <- getJust $ remoteAuthorId author
|
audRejecter <- makeAudSenderWithFollowers authorIdMsig
|
||||||
|
audForbidder <- lift $ makeAudSenderOnly authorIdMsig
|
||||||
recipHash <- encodeKeyHashid recipKey
|
recipHash <- encodeKeyHashid recipKey
|
||||||
let topicByHash = grantResourceLocalActor $ topicResource recipHash
|
let topicByHash = grantResourceLocalActor $ topicResource recipHash
|
||||||
|
|
||||||
senderHash <- bitraverse hashLocalActor pure sender
|
senderHash <- bitraverse hashLocalActor pure sender
|
||||||
|
|
||||||
|
uReject <- lift $ getActivityURI authorIdMsig
|
||||||
|
|
||||||
let audience =
|
let audience =
|
||||||
if isInvite
|
if isInvite
|
||||||
then
|
then
|
||||||
|
@ -637,9 +634,6 @@ topicReject topicActor topicResource now recipKey author body mfwd luReject reje
|
||||||
Left actor -> AudLocal [actor] []
|
Left actor -> AudLocal [actor] []
|
||||||
Right (ObjURI h lu, _followers) ->
|
Right (ObjURI h lu, _followers) ->
|
||||||
AudRemote h [lu] []
|
AudRemote h [lu] []
|
||||||
audRejecter =
|
|
||||||
let ObjURI h lu = remoteAuthorURI author
|
|
||||||
in AudRemote h [lu] (maybeToList $ remoteActorFollowers rejecter)
|
|
||||||
audTopic = AudLocal [] [localActorFollowers topicByHash]
|
audTopic = AudLocal [] [localActorFollowers topicByHash]
|
||||||
in [audInviter, audRejecter, audTopic]
|
in [audInviter, audRejecter, audTopic]
|
||||||
else
|
else
|
||||||
|
@ -648,9 +642,6 @@ topicReject topicActor topicResource now recipKey author body mfwd luReject reje
|
||||||
Left actor -> AudLocal [actor] [localActorFollowers actor]
|
Left actor -> AudLocal [actor] [localActorFollowers actor]
|
||||||
Right (ObjURI h lu, followers) ->
|
Right (ObjURI h lu, followers) ->
|
||||||
AudRemote h [lu] (maybeToList followers)
|
AudRemote h [lu] (maybeToList followers)
|
||||||
audForbidder =
|
|
||||||
let ObjURI h lu = remoteAuthorURI author
|
|
||||||
in AudRemote h [lu] []
|
|
||||||
audTopic = AudLocal [] [localActorFollowers topicByHash]
|
audTopic = AudLocal [] [localActorFollowers topicByHash]
|
||||||
in [audJoiner, audForbidder, audTopic]
|
in [audJoiner, audForbidder, audTopic]
|
||||||
|
|
||||||
|
@ -662,10 +653,7 @@ topicReject topicActor topicResource now recipKey author body mfwd luReject reje
|
||||||
{ AP.actionCapability = Nothing
|
{ AP.actionCapability = Nothing
|
||||||
, AP.actionSummary = Nothing
|
, AP.actionSummary = Nothing
|
||||||
, AP.actionAudience = AP.Audience recips [] [] [] [] []
|
, AP.actionAudience = AP.Audience recips [] [] [] [] []
|
||||||
, AP.actionFulfills =
|
, AP.actionFulfills = [uReject]
|
||||||
[ let ObjURI h _ = remoteAuthorURI author
|
|
||||||
in ObjURI h luReject
|
|
||||||
]
|
|
||||||
, AP.actionSpecific = AP.RejectActivity AP.Reject
|
, AP.actionSpecific = AP.RejectActivity AP.Reject
|
||||||
{ AP.rejectObject = AP.rejectObject reject
|
{ AP.rejectObject = AP.rejectObject reject
|
||||||
}
|
}
|
||||||
|
@ -684,13 +672,10 @@ topicInvite
|
||||||
-> (CollabId -> Key topic -> ct)
|
-> (CollabId -> Key topic -> ct)
|
||||||
-> UTCTime
|
-> UTCTime
|
||||||
-> Key topic
|
-> Key topic
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Invite URIMode
|
-> AP.Invite URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
topicInvite grabActor topicResource topicField topicCollabField collabTopicCtor now topicKey author body mfwd luInvite invite = do
|
topicInvite grabActor topicResource topicField topicCollabField collabTopicCtor now topicKey (Verse authorIdMsig body) invite = do
|
||||||
|
|
||||||
-- Check capability
|
-- Check capability
|
||||||
capability <- do
|
capability <- do
|
||||||
|
@ -713,8 +698,8 @@ topicInvite grabActor topicResource topicField topicCollabField collabTopicCtor
|
||||||
|
|
||||||
-- Check invite
|
-- Check invite
|
||||||
targetByKey <- do
|
targetByKey <- do
|
||||||
(resource, recipient) <-
|
let author = bimap (view _1) (remoteAuthorURI . view _1) authorIdMsig
|
||||||
parseInvite (Right $ remoteAuthorURI author) invite
|
(resource, recipient) <- parseInvite author invite
|
||||||
unless (Left (topicResource topicKey) == resource) $
|
unless (Left (topicResource topicKey) == resource) $
|
||||||
throwE "Invite topic isn't me"
|
throwE "Invite topic isn't me"
|
||||||
return recipient
|
return recipient
|
||||||
|
@ -747,17 +732,14 @@ topicInvite grabActor topicResource topicField topicCollabField collabTopicCtor
|
||||||
|
|
||||||
maybeNew <- withDBExcept $ do
|
maybeNew <- withDBExcept $ do
|
||||||
|
|
||||||
-- Grab topic from DB
|
-- Grab me from DB
|
||||||
(topicActorID, topicActor) <- lift $ do
|
(topicActorID, topicActor) <- lift $ do
|
||||||
recip <- getJust topicKey
|
recip <- getJust topicKey
|
||||||
let actorID = grabActor recip
|
let actorID = grabActor recip
|
||||||
(actorID,) <$> getJust actorID
|
(actorID,) <$> getJust actorID
|
||||||
|
|
||||||
-- Verify the specified capability gives relevant access
|
-- Verify the specified capability gives relevant access
|
||||||
verifyCapability
|
verifyCapability' capability authorIdMsig (topicResource topicKey)
|
||||||
capability
|
|
||||||
(Right $ remoteAuthorId author)
|
|
||||||
(topicResource topicKey)
|
|
||||||
|
|
||||||
-- Verify that target doesn't already have a Collab for me
|
-- Verify that target doesn't already have a Collab for me
|
||||||
existingCollabIDs <-
|
existingCollabIDs <-
|
||||||
|
@ -785,11 +767,11 @@ topicInvite grabActor topicResource topicField topicCollabField collabTopicCtor
|
||||||
[_] -> throwE "I already have a Collab for the target"
|
[_] -> throwE "I already have a Collab for the target"
|
||||||
_ -> error "Multiple collabs found for target"
|
_ -> error "Multiple collabs found for target"
|
||||||
|
|
||||||
mractid <- lift $ insertToInbox now author body (actorInbox topicActor) luInvite False
|
maybeInviteDB <- lift $ insertToInbox now authorIdMsig body (actorInbox topicActor) False
|
||||||
lift $ for mractid $ \ inviteID -> do
|
lift $ for maybeInviteDB $ \ inviteDB -> do
|
||||||
|
|
||||||
-- Insert Collab record to DB
|
-- Insert Collab record to DB
|
||||||
insertCollab targetDB inviteID
|
insertCollab targetDB inviteDB
|
||||||
|
|
||||||
-- Prepare forwarding Invite to my followers
|
-- Prepare forwarding Invite to my followers
|
||||||
sieve <- do
|
sieve <- do
|
||||||
|
@ -797,26 +779,27 @@ topicInvite grabActor topicResource topicField topicCollabField collabTopicCtor
|
||||||
let topicByHash =
|
let topicByHash =
|
||||||
grantResourceLocalActor $ topicResource topicHash
|
grantResourceLocalActor $ topicResource topicHash
|
||||||
return $ makeRecipientSet [] [localActorFollowers topicByHash]
|
return $ makeRecipientSet [] [localActorFollowers topicByHash]
|
||||||
return (topicActorID, inviteID, sieve)
|
return (topicActorID, sieve)
|
||||||
|
|
||||||
case maybeNew of
|
case maybeNew of
|
||||||
Nothing -> done "I already have this activity in my inbox"
|
Nothing -> done "I already have this activity in my inbox"
|
||||||
Just (topicActorID, inviteID, sieve) -> do
|
Just (topicActorID, sieve) -> do
|
||||||
let topicByID = grantResourceLocalActor $ topicResource topicKey
|
let topicByID = grantResourceLocalActor $ topicResource topicKey
|
||||||
lift $ for_ mfwd $ \ (localRecips, sig) -> do
|
forwardActivity authorIdMsig body topicByID topicActorID sieve
|
||||||
forwardActivity
|
|
||||||
(actbBL body) localRecips sig topicActorID topicByID sieve
|
|
||||||
(EventRemoteInviteLocalTopicFwdToFollower inviteID)
|
|
||||||
done "Recorded and forwarded the Invite"
|
done "Recorded and forwarded the Invite"
|
||||||
|
|
||||||
where
|
where
|
||||||
|
|
||||||
insertCollab recipient inviteID = do
|
insertCollab recipient inviteDB = do
|
||||||
collabID <- insert Collab
|
collabID <- insert Collab
|
||||||
fulfillsID <- insert $ CollabFulfillsInvite collabID
|
fulfillsID <- insert $ CollabFulfillsInvite collabID
|
||||||
insert_ $ collabTopicCtor collabID topicKey
|
insert_ $ collabTopicCtor collabID topicKey
|
||||||
let authorID = remoteAuthorId author
|
case inviteDB of
|
||||||
insert_ $ CollabInviterRemote fulfillsID authorID inviteID
|
Left (_, _, inviteID) ->
|
||||||
|
insert_ $ CollabInviterLocal fulfillsID inviteID
|
||||||
|
Right (author, _, inviteID) -> do
|
||||||
|
let authorID = remoteAuthorId author
|
||||||
|
insert_ $ CollabInviterRemote fulfillsID authorID inviteID
|
||||||
case recipient of
|
case recipient of
|
||||||
Left (GrantRecipPerson (Entity personID _)) ->
|
Left (GrantRecipPerson (Entity personID _)) ->
|
||||||
insert_ $ CollabRecipLocal collabID personID
|
insert_ $ CollabRecipLocal collabID personID
|
||||||
|
@ -834,13 +817,10 @@ topicJoin
|
||||||
-> (CollabId -> Key topic -> ct)
|
-> (CollabId -> Key topic -> ct)
|
||||||
-> UTCTime
|
-> UTCTime
|
||||||
-> Key topic
|
-> Key topic
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Join URIMode
|
-> AP.Join URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
topicJoin grabActor topicResource topicField topicCollabField collabTopicCtor now topicKey author body mfwd luJoin join = do
|
topicJoin grabActor topicResource topicField topicCollabField collabTopicCtor now topicKey (Verse authorIdMsig body) join = do
|
||||||
|
|
||||||
-- Check input
|
-- Check input
|
||||||
resource <- parseJoin join
|
resource <- parseJoin join
|
||||||
|
@ -849,58 +829,81 @@ topicJoin grabActor topicResource topicField topicCollabField collabTopicCtor no
|
||||||
|
|
||||||
maybeNew <- withDBExcept $ do
|
maybeNew <- withDBExcept $ do
|
||||||
|
|
||||||
-- Grab topic from DB
|
-- Grab me from DB
|
||||||
(topicActorID, topicActor) <- lift $ do
|
(topicActorID, topicActor) <- lift $ do
|
||||||
recip <- getJust topicKey
|
recip <- getJust topicKey
|
||||||
let actorID = grabActor recip
|
let actorID = grabActor recip
|
||||||
(actorID,) <$> getJust actorID
|
(actorID,) <$> getJust actorID
|
||||||
|
|
||||||
-- Verify that target doesn't already have a Collab for me
|
-- Verify that target doesn't already have a Collab for me
|
||||||
existingCollabIDs <- lift $ do
|
existingCollabIDs <- lift $
|
||||||
let targetID = remoteAuthorId author
|
case authorIdMsig of
|
||||||
E.select $ E.from $ \ (topic `E.InnerJoin` recipr) -> do
|
Left (LocalActorPerson personID, _, _) ->
|
||||||
E.on $
|
E.select $ E.from $ \ (topic `E.InnerJoin` recipl) -> do
|
||||||
topic E.^. topicCollabField E.==.
|
E.on $
|
||||||
recipr E.^. CollabRecipRemoteCollab
|
topic E.^. topicCollabField E.==.
|
||||||
E.where_ $
|
recipl E.^. CollabRecipLocalCollab
|
||||||
topic E.^. topicField E.==. E.val topicKey E.&&.
|
E.where_ $
|
||||||
recipr E.^. CollabRecipRemoteActor E.==. E.val targetID
|
topic E.^. topicField E.==. E.val topicKey E.&&.
|
||||||
return $ recipr E.^. CollabRecipRemoteCollab
|
recipl E.^. CollabRecipLocalPerson E.==. E.val personID
|
||||||
|
return $ recipl E.^. CollabRecipLocalCollab
|
||||||
|
Left (_, _, _) -> pure []
|
||||||
|
Right (author, _, _) -> do
|
||||||
|
let targetID = remoteAuthorId author
|
||||||
|
E.select $ E.from $ \ (topic `E.InnerJoin` recipr) -> do
|
||||||
|
E.on $
|
||||||
|
topic E.^. topicCollabField E.==.
|
||||||
|
recipr E.^. CollabRecipRemoteCollab
|
||||||
|
E.where_ $
|
||||||
|
topic E.^. topicField E.==. E.val topicKey E.&&.
|
||||||
|
recipr E.^. CollabRecipRemoteActor E.==. E.val targetID
|
||||||
|
return $ recipr E.^. CollabRecipRemoteCollab
|
||||||
case existingCollabIDs of
|
case existingCollabIDs of
|
||||||
[] -> pure ()
|
[] -> pure ()
|
||||||
[_] -> throwE "I already have a Collab for the target"
|
[_] -> throwE "I already have a Collab for the target"
|
||||||
_ -> error "Multiple collabs found for target"
|
_ -> error "Multiple collabs found for target"
|
||||||
|
|
||||||
mractid <- lift $ insertToInbox now author body (actorInbox topicActor) luJoin False
|
maybeJoinDB <- lift $ insertToInbox now authorIdMsig body (actorInbox topicActor) False
|
||||||
lift $ for mractid $ \ joinID -> do
|
for maybeJoinDB $ \ joinDB -> do
|
||||||
|
|
||||||
-- Insert Collab record to DB
|
-- Insert Collab record to DB
|
||||||
insertCollab joinID
|
joinDB' <-
|
||||||
|
bitraverse
|
||||||
|
(\ (authorByKey, _, joinID) ->
|
||||||
|
case authorByKey of
|
||||||
|
LocalActorPerson personID -> pure (personID, joinID)
|
||||||
|
_ -> throwE "Non-person local actors can't get Grants currently"
|
||||||
|
)
|
||||||
|
pure
|
||||||
|
joinDB
|
||||||
|
lift $ insertCollab joinDB'
|
||||||
|
|
||||||
-- Prepare forwarding Join to my followers
|
-- Prepare forwarding Join to my followers
|
||||||
sieve <- do
|
sieve <- lift $ do
|
||||||
topicHash <- encodeKeyHashid topicKey
|
topicHash <- encodeKeyHashid topicKey
|
||||||
let topicByHash =
|
let topicByHash =
|
||||||
grantResourceLocalActor $ topicResource topicHash
|
grantResourceLocalActor $ topicResource topicHash
|
||||||
return $ makeRecipientSet [] [localActorFollowers topicByHash]
|
return $ makeRecipientSet [] [localActorFollowers topicByHash]
|
||||||
return (topicActorID, joinID, sieve)
|
return (topicActorID, sieve)
|
||||||
|
|
||||||
case maybeNew of
|
case maybeNew of
|
||||||
Nothing -> done "I already have this activity in my inbox"
|
Nothing -> done "I already have this activity in my inbox"
|
||||||
Just (topicActorID, joinID, sieve) -> do
|
Just (topicActorID, sieve) -> do
|
||||||
let topicByID = grantResourceLocalActor $ topicResource topicKey
|
let topicByID = grantResourceLocalActor $ topicResource topicKey
|
||||||
lift $ for_ mfwd $ \ (localRecips, sig) -> do
|
forwardActivity authorIdMsig body topicByID topicActorID sieve
|
||||||
forwardActivity
|
|
||||||
(actbBL body) localRecips sig topicActorID topicByID sieve
|
|
||||||
(EventRemoteJoinLocalTopicFwdToFollower joinID)
|
|
||||||
done "Recorded and forwarded the Join"
|
done "Recorded and forwarded the Join"
|
||||||
|
|
||||||
where
|
where
|
||||||
|
|
||||||
insertCollab joinID = do
|
insertCollab joinDB = do
|
||||||
collabID <- insert Collab
|
collabID <- insert Collab
|
||||||
fulfillsID <- insert $ CollabFulfillsJoin collabID
|
fulfillsID <- insert $ CollabFulfillsJoin collabID
|
||||||
insert_ $ collabTopicCtor collabID topicKey
|
insert_ $ collabTopicCtor collabID topicKey
|
||||||
let authorID = remoteAuthorId author
|
case joinDB of
|
||||||
recipID <- insert $ CollabRecipRemote collabID authorID
|
Left (personID, joinID) -> do
|
||||||
insert_ $ CollabRecipRemoteJoin recipID fulfillsID joinID
|
recipID <- insert $ CollabRecipLocal collabID personID
|
||||||
|
insert_ $ CollabRecipLocalJoin recipID fulfillsID joinID
|
||||||
|
Right (author, _, joinID) -> do
|
||||||
|
let authorID = remoteAuthorId author
|
||||||
|
recipID <- insert $ CollabRecipRemote collabID authorID
|
||||||
|
insert_ $ CollabRecipRemoteJoin recipID fulfillsID joinID
|
||||||
|
|
|
@ -82,13 +82,10 @@ import Vervis.Ticket
|
||||||
deckFollow
|
deckFollow
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
-> DeckId
|
-> DeckId
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Follow URIMode
|
-> AP.Follow URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
deckFollow now recipDeckID author body mfwd luFollow follow = do
|
deckFollow now recipDeckID verse follow = do
|
||||||
recipDeckHash <- encodeKeyHashid recipDeckID
|
recipDeckHash <- encodeKeyHashid recipDeckID
|
||||||
actorFollow
|
actorFollow
|
||||||
(\case
|
(\case
|
||||||
|
@ -111,13 +108,13 @@ deckFollow now recipDeckID author body mfwd luFollow follow = do
|
||||||
(\ _ -> pure $ makeRecipientSet [] [])
|
(\ _ -> pure $ makeRecipientSet [] [])
|
||||||
LocalActorDeck
|
LocalActorDeck
|
||||||
(\ _ -> pure [])
|
(\ _ -> pure [])
|
||||||
now recipDeckID author body mfwd luFollow follow
|
now recipDeckID verse follow
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
-- Access
|
-- Access
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- Meaning: A remote actor accepted something
|
-- Meaning: An actor accepted something
|
||||||
-- Behavior:
|
-- Behavior:
|
||||||
-- * If it's on an Invite where I'm the resource:
|
-- * If it's on an Invite where I'm the resource:
|
||||||
-- * Verify the Accept is by the Invite target
|
-- * Verify the Accept is by the Invite target
|
||||||
|
@ -135,15 +132,12 @@ deckFollow now recipDeckID author body mfwd luFollow follow = do
|
||||||
deckAccept
|
deckAccept
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
-> DeckId
|
-> DeckId
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Accept URIMode
|
-> AP.Accept URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
deckAccept = topicAccept deckActor GrantResourceDeck
|
deckAccept = topicAccept deckActor GrantResourceDeck
|
||||||
|
|
||||||
-- Meaning: A remote actor rejected something
|
-- Meaning: An actor rejected something
|
||||||
-- Behavior:
|
-- Behavior:
|
||||||
-- * If it's on an Invite where I'm the resource:
|
-- * If it's on an Invite where I'm the resource:
|
||||||
-- * Verify the Reject is by the Invite target
|
-- * Verify the Reject is by the Invite target
|
||||||
|
@ -163,15 +157,12 @@ deckAccept = topicAccept deckActor GrantResourceDeck
|
||||||
deckReject
|
deckReject
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
-> DeckId
|
-> DeckId
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Reject URIMode
|
-> AP.Reject URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
deckReject = topicReject deckActor GrantResourceDeck
|
deckReject = topicReject deckActor GrantResourceDeck
|
||||||
|
|
||||||
-- Meaning: A remote actor A invited someone B to a resource
|
-- Meaning: An actor A invited actor B to a resource
|
||||||
-- Behavior:
|
-- Behavior:
|
||||||
-- * Verify the resource is me
|
-- * Verify the resource is me
|
||||||
-- * Verify A isn't inviting themselves
|
-- * Verify A isn't inviting themselves
|
||||||
|
@ -182,10 +173,7 @@ deckReject = topicReject deckActor GrantResourceDeck
|
||||||
deckInvite
|
deckInvite
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
-> DeckId
|
-> DeckId
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Invite URIMode
|
-> AP.Invite URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
deckInvite =
|
deckInvite =
|
||||||
|
@ -193,7 +181,7 @@ deckInvite =
|
||||||
deckActor GrantResourceDeck
|
deckActor GrantResourceDeck
|
||||||
CollabTopicDeckDeck CollabTopicDeckCollab CollabTopicDeck
|
CollabTopicDeckDeck CollabTopicDeckCollab CollabTopicDeck
|
||||||
|
|
||||||
-- Meaning: A remote actor A asked to join a resource
|
-- Meaning: An actor A asked to join a resource
|
||||||
-- Behavior:
|
-- Behavior:
|
||||||
-- * Verify the resource is me
|
-- * Verify the resource is me
|
||||||
-- * Verify A doesn't already have an invite/join/grant for me
|
-- * Verify A doesn't already have an invite/join/grant for me
|
||||||
|
@ -202,10 +190,7 @@ deckInvite =
|
||||||
deckJoin
|
deckJoin
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
-> DeckId
|
-> DeckId
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Join URIMode
|
-> AP.Join URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
deckJoin =
|
deckJoin =
|
||||||
|
@ -217,7 +202,7 @@ deckJoin =
|
||||||
-- Ambiguous: Following/Resolving
|
-- Ambiguous: Following/Resolving
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- Meaning: A remote actor is undoing some previous action
|
-- Meaning: An actor is undoing some previous action
|
||||||
-- Behavior:
|
-- Behavior:
|
||||||
-- * If they're undoing their Following of me, or a ticket of mine:
|
-- * If they're undoing their Following of me, or a ticket of mine:
|
||||||
-- * Record it in my DB
|
-- * Record it in my DB
|
||||||
|
@ -231,13 +216,10 @@ deckJoin =
|
||||||
deckUndo
|
deckUndo
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
-> DeckId
|
-> DeckId
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Undo URIMode
|
-> AP.Undo URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
deckUndo now recipDeckID author body mfwd luUndo (AP.Undo uObject) = do
|
deckUndo now recipDeckID (Verse authorIdMsig body) (AP.Undo uObject) = do
|
||||||
|
|
||||||
-- Check input
|
-- Check input
|
||||||
undone <-
|
undone <-
|
||||||
|
@ -255,14 +237,14 @@ deckUndo now recipDeckID author body mfwd luUndo (AP.Undo uObject) = do
|
||||||
|
|
||||||
maybeNew <- withDBExcept $ do
|
maybeNew <- withDBExcept $ do
|
||||||
|
|
||||||
-- Grab recipient deck from DB
|
-- Grab me from DB
|
||||||
(deckRecip, actorRecip) <- lift $ do
|
(deckRecip, actorRecip) <- lift $ do
|
||||||
p <- getJust recipDeckID
|
p <- getJust recipDeckID
|
||||||
(p,) <$> getJust (deckActor p)
|
(p,) <$> getJust (deckActor p)
|
||||||
|
|
||||||
-- Insert the Undo to deck's inbox
|
-- Insert the Undo to my inbox
|
||||||
mractid <- lift $ insertToInbox now author body (actorInbox actorRecip) luUndo False
|
mractid <- lift $ insertToInbox now authorIdMsig body (actorInbox actorRecip) False
|
||||||
for mractid $ \ undoID -> do
|
for mractid $ \ _undoDB -> do
|
||||||
|
|
||||||
maybeUndo <- runMaybeT $ do
|
maybeUndo <- runMaybeT $ do
|
||||||
|
|
||||||
|
@ -271,7 +253,7 @@ deckUndo now recipDeckID author body mfwd luUndo (AP.Undo uObject) = do
|
||||||
|
|
||||||
let followers = actorFollowers actorRecip
|
let followers = actorFollowers actorRecip
|
||||||
asum
|
asum
|
||||||
[ tryUnfollow followers undoneDB
|
[ tryUnfollow followers undoneDB authorIdMsig
|
||||||
, tryUnresolve maybeCapability undoneDB
|
, tryUnresolve maybeCapability undoneDB
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -285,28 +267,43 @@ deckUndo now recipDeckID author body mfwd luUndo (AP.Undo uObject) = do
|
||||||
accept@(actionAccept, _, _, _) <- lift $ lift $ prepareAccept audience
|
accept@(actionAccept, _, _, _) <- lift $ lift $ prepareAccept audience
|
||||||
_luAccept <- lift $ updateOutboxItem' (LocalActorDeck recipDeckID) acceptID actionAccept
|
_luAccept <- lift $ updateOutboxItem' (LocalActorDeck recipDeckID) acceptID actionAccept
|
||||||
|
|
||||||
return (deckActor deckRecip, undoID, sieve, acceptID, accept)
|
return (deckActor deckRecip, sieve, acceptID, accept)
|
||||||
|
|
||||||
case maybeNew of
|
case maybeNew of
|
||||||
Nothing -> done "I already have this activity in my inbox"
|
Nothing -> done "I already have this activity in my inbox"
|
||||||
Just (actorID, undoID, sieve, acceptID, (actionAccept, localRecipsAccept, remoteRecipsAccept, fwdHostsAccept)) -> do
|
Just (actorID, sieve, acceptID, (actionAccept, localRecipsAccept, remoteRecipsAccept, fwdHostsAccept)) -> do
|
||||||
lift $ for_ mfwd $ \ (localRecips, sig) -> do
|
forwardActivity
|
||||||
forwardActivity
|
authorIdMsig body (LocalActorDeck recipDeckID) actorID sieve
|
||||||
(actbBL body) localRecips sig actorID
|
|
||||||
(LocalActorDeck recipDeckID) sieve
|
|
||||||
(EventRemoteUnresolveLocalResourceFwdToFollower undoID)
|
|
||||||
lift $ sendActivity
|
lift $ sendActivity
|
||||||
(LocalActorDeck recipDeckID) actorID localRecipsAccept
|
(LocalActorDeck recipDeckID) actorID localRecipsAccept
|
||||||
remoteRecipsAccept fwdHostsAccept acceptID
|
remoteRecipsAccept fwdHostsAccept acceptID actionAccept
|
||||||
EventAcceptRemoteFollow actionAccept
|
|
||||||
done
|
done
|
||||||
"Undid the Follow/Resolve, forwarded the Undo and published \
|
"Undid the Follow/Resolve, forwarded the Undo and published \
|
||||||
\Accept"
|
\Accept"
|
||||||
|
|
||||||
where
|
where
|
||||||
|
|
||||||
tryUnfollow _ (Left _) = mzero
|
verifyTargetTicket followerSetID = do
|
||||||
tryUnfollow deckFollowersID (Right remoteActivityID) = do
|
ticketID <-
|
||||||
|
MaybeT $ lift $ getKeyBy $ UniqueTicketFollowers followerSetID
|
||||||
|
TicketDeck _ d <-
|
||||||
|
MaybeT $ lift $ getValBy $ UniqueTicketDeck ticketID
|
||||||
|
guard $ d == recipDeckID
|
||||||
|
|
||||||
|
tryUnfollow deckFollowersID (Left (_actorByKey, _actorE, outboxItemID)) (Left (_, actorID, _)) = do
|
||||||
|
Entity followID follow <-
|
||||||
|
MaybeT $ lift $ getBy $ UniqueFollowFollow outboxItemID
|
||||||
|
let followerID = followActor follow
|
||||||
|
followerSetID = followTarget follow
|
||||||
|
verifyTargetMe followerSetID <|> verifyTargetTicket followerSetID
|
||||||
|
unless (followerID == actorID) $
|
||||||
|
lift $ throwE "You're trying to Undo someone else's Follow"
|
||||||
|
lift $ lift $ delete followID
|
||||||
|
audSenderOnly <- lift $ lift $ lift $ makeAudSenderOnly authorIdMsig
|
||||||
|
return (makeRecipientSet [] [], [audSenderOnly])
|
||||||
|
where
|
||||||
|
verifyTargetMe followerSetID = guard $ followerSetID == deckFollowersID
|
||||||
|
tryUnfollow deckFollowersID (Right remoteActivityID) (Right (author, _, _)) = do
|
||||||
Entity remoteFollowID remoteFollow <-
|
Entity remoteFollowID remoteFollow <-
|
||||||
MaybeT $ lift $ getBy $ UniqueRemoteFollowFollow remoteActivityID
|
MaybeT $ lift $ getBy $ UniqueRemoteFollowFollow remoteActivityID
|
||||||
let followerID = remoteFollowActor remoteFollow
|
let followerID = remoteFollowActor remoteFollow
|
||||||
|
@ -315,17 +312,11 @@ deckUndo now recipDeckID author body mfwd luUndo (AP.Undo uObject) = do
|
||||||
unless (followerID == remoteAuthorId author) $
|
unless (followerID == remoteAuthorId author) $
|
||||||
lift $ throwE "You're trying to Undo someone else's Follow"
|
lift $ throwE "You're trying to Undo someone else's Follow"
|
||||||
lift $ lift $ delete remoteFollowID
|
lift $ lift $ delete remoteFollowID
|
||||||
let ObjURI hAuthor luAuthor = remoteAuthorURI author
|
audSenderOnly <- lift $ lift $ lift $ makeAudSenderOnly authorIdMsig
|
||||||
audSenderOnly = AudRemote hAuthor [luAuthor] []
|
|
||||||
return (makeRecipientSet [] [], [audSenderOnly])
|
return (makeRecipientSet [] [], [audSenderOnly])
|
||||||
where
|
where
|
||||||
verifyTargetMe followerSetID = guard $ followerSetID == deckFollowersID
|
verifyTargetMe followerSetID = guard $ followerSetID == deckFollowersID
|
||||||
verifyTargetTicket followerSetID = do
|
tryUnfollow _ _ _ = mzero
|
||||||
ticketID <-
|
|
||||||
MaybeT $ lift $ getKeyBy $ UniqueTicketFollowers followerSetID
|
|
||||||
TicketDeck _ d <-
|
|
||||||
MaybeT $ lift $ getValBy $ UniqueTicketDeck ticketID
|
|
||||||
guard $ d == recipDeckID
|
|
||||||
|
|
||||||
tryUnresolve maybeCapability undone = do
|
tryUnresolve maybeCapability undone = do
|
||||||
(deleteFromDB, ticketID) <- findTicket undone
|
(deleteFromDB, ticketID) <- findTicket undone
|
||||||
|
@ -343,22 +334,16 @@ deckUndo now recipDeckID author body mfwd luUndo (AP.Undo uObject) = do
|
||||||
Left c -> pure c
|
Left c -> pure c
|
||||||
Right _ -> throwE "Capability is a remote URI, i.e. not authored by me"
|
Right _ -> throwE "Capability is a remote URI, i.e. not authored by me"
|
||||||
lift $
|
lift $
|
||||||
verifyCapability
|
verifyCapability'
|
||||||
capability
|
capability
|
||||||
(Right $ remoteAuthorId author)
|
authorIdMsig
|
||||||
(GrantResourceDeck recipDeckID)
|
(GrantResourceDeck recipDeckID)
|
||||||
|
|
||||||
lift $ lift deleteFromDB
|
lift $ lift deleteFromDB
|
||||||
|
|
||||||
recipDeckHash <- encodeKeyHashid recipDeckID
|
recipDeckHash <- encodeKeyHashid recipDeckID
|
||||||
taskHash <- encodeKeyHashid taskID
|
taskHash <- encodeKeyHashid taskID
|
||||||
audSender <- lift $ do
|
audSender <- lift $ lift $ makeAudSenderWithFollowers authorIdMsig
|
||||||
ra <- lift $ getJust $ remoteAuthorId author
|
|
||||||
let ObjURI hAuthor luAuthor = remoteAuthorURI author
|
|
||||||
return $
|
|
||||||
AudRemote hAuthor
|
|
||||||
[luAuthor]
|
|
||||||
(maybeToList $ remoteActorFollowers ra)
|
|
||||||
return
|
return
|
||||||
( makeRecipientSet
|
( makeRecipientSet
|
||||||
[]
|
[]
|
||||||
|
@ -399,8 +384,8 @@ deckUndo now recipDeckID author body mfwd luUndo (AP.Undo uObject) = do
|
||||||
prepareAccept audience = do
|
prepareAccept audience = do
|
||||||
encodeRouteHome <- getEncodeRouteHome
|
encodeRouteHome <- getEncodeRouteHome
|
||||||
|
|
||||||
let ObjURI hAuthor _ = remoteAuthorURI author
|
uUndo <- getActivityURI authorIdMsig
|
||||||
(recipientSet, remoteActors, fwdHosts, audLocal, audRemote) =
|
let (recipientSet, remoteActors, fwdHosts, audLocal, audRemote) =
|
||||||
collectAudience audience
|
collectAudience audience
|
||||||
|
|
||||||
recips = map encodeRouteHome audLocal ++ audRemote
|
recips = map encodeRouteHome audLocal ++ audRemote
|
||||||
|
@ -410,7 +395,7 @@ deckUndo now recipDeckID author body mfwd luUndo (AP.Undo uObject) = do
|
||||||
, AP.actionAudience = AP.Audience recips [] [] [] [] []
|
, AP.actionAudience = AP.Audience recips [] [] [] [] []
|
||||||
, AP.actionFulfills = []
|
, AP.actionFulfills = []
|
||||||
, AP.actionSpecific = AP.AcceptActivity AP.Accept
|
, AP.actionSpecific = AP.AcceptActivity AP.Accept
|
||||||
{ AP.acceptObject = ObjURI hAuthor luUndo
|
{ AP.acceptObject = uUndo
|
||||||
, AP.acceptResult = Nothing
|
, AP.acceptResult = Nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -421,27 +406,15 @@ deckUndo now recipDeckID author body mfwd luUndo (AP.Undo uObject) = do
|
||||||
-- Main behavior function
|
-- Main behavior function
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
deckBehavior
|
deckBehavior :: UTCTime -> DeckId -> Verse -> ActE (Text, Act (), Next)
|
||||||
:: UTCTime -> DeckId -> Verse -> ExceptT Text Act (Text, Act (), Next)
|
deckBehavior now deckID verse@(Verse _authorIdMsig body) =
|
||||||
deckBehavior _now _deckID (Left event) =
|
|
||||||
case event of
|
|
||||||
EventRemoteFwdLocalActivity _ _ ->
|
|
||||||
throwE "Got a forwarded local activity, I don't need those"
|
|
||||||
_ -> throwE $ "Unsupported event for Deck: " <> T.pack (show event)
|
|
||||||
deckBehavior now deckID (Right (VerseRemote author body mfwd luActivity)) =
|
|
||||||
case AP.activitySpecific $ actbActivity body of
|
case AP.activitySpecific $ actbActivity body of
|
||||||
AP.AcceptActivity accept ->
|
AP.AcceptActivity accept -> deckAccept now deckID verse accept
|
||||||
deckAccept now deckID author body mfwd luActivity accept
|
AP.FollowActivity follow -> deckFollow now deckID verse follow
|
||||||
AP.FollowActivity follow ->
|
AP.InviteActivity invite -> deckInvite now deckID verse invite
|
||||||
deckFollow now deckID author body mfwd luActivity follow
|
AP.JoinActivity join -> deckJoin now deckID verse join
|
||||||
AP.InviteActivity invite ->
|
AP.RejectActivity reject -> deckReject now deckID verse reject
|
||||||
deckInvite now deckID author body mfwd luActivity invite
|
AP.UndoActivity undo -> deckUndo now deckID verse undo
|
||||||
AP.JoinActivity join ->
|
|
||||||
deckJoin now deckID author body mfwd luActivity join
|
|
||||||
AP.RejectActivity reject ->
|
|
||||||
deckReject now deckID author body mfwd luActivity reject
|
|
||||||
AP.UndoActivity undo ->
|
|
||||||
deckUndo now deckID author body mfwd luActivity undo
|
|
||||||
_ -> throwE "Unsupported activity type for Deck"
|
_ -> throwE "Unsupported activity type for Deck"
|
||||||
|
|
||||||
instance VervisActor Deck where
|
instance VervisActor Deck where
|
||||||
|
|
|
@ -52,14 +52,8 @@ import Vervis.Model
|
||||||
import Vervis.Persist.Discussion
|
import Vervis.Persist.Discussion
|
||||||
import Vervis.Ticket
|
import Vervis.Ticket
|
||||||
|
|
||||||
groupBehavior
|
groupBehavior :: UTCTime -> GroupId -> Verse -> ActE (Text, Act (), Next)
|
||||||
:: UTCTime -> GroupId -> Verse -> ExceptT Text Act (Text, Act (), Next)
|
groupBehavior now groupID _verse@(Verse _authorIdMsig body) =
|
||||||
groupBehavior now groupID (Left event) =
|
|
||||||
case event of
|
|
||||||
EventRemoteFwdLocalActivity _ _ ->
|
|
||||||
throwE "Got a forwarded local activity, I don't need those"
|
|
||||||
_ -> throwE $ "Unsupported event for Group: " <> T.pack (show event)
|
|
||||||
groupBehavior now groupID (Right (VerseRemote author body mfwd luActivity)) =
|
|
||||||
case AP.activitySpecific $ actbActivity body of
|
case AP.activitySpecific $ actbActivity body of
|
||||||
_ -> throwE "Unsupported activity type for Group"
|
_ -> throwE "Unsupported activity type for Group"
|
||||||
|
|
||||||
|
|
|
@ -52,14 +52,8 @@ import Vervis.Model
|
||||||
import Vervis.Persist.Discussion
|
import Vervis.Persist.Discussion
|
||||||
import Vervis.Ticket
|
import Vervis.Ticket
|
||||||
|
|
||||||
loomBehavior
|
loomBehavior :: UTCTime -> LoomId -> Verse -> ActE (Text, Act (), Next)
|
||||||
:: UTCTime -> LoomId -> Verse -> ExceptT Text Act (Text, Act (), Next)
|
loomBehavior now loomID _verse@(Verse _authorIdMsig body) =
|
||||||
loomBehavior now loomID (Left event) =
|
|
||||||
case event of
|
|
||||||
EventRemoteFwdLocalActivity _ _ ->
|
|
||||||
throwE "Got a forwarded local activity, I don't need those"
|
|
||||||
_ -> throwE $ "Unsupported event for Loom: " <> T.pack (show event)
|
|
||||||
loomBehavior now loomID (Right (VerseRemote author body mfwd luActivity)) =
|
|
||||||
case AP.activitySpecific $ actbActivity body of
|
case AP.activitySpecific $ actbActivity body of
|
||||||
_ -> throwE "Unsupported activity type for Loom"
|
_ -> throwE "Unsupported activity type for Loom"
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ import Data.Time.Clock
|
||||||
import Data.Traversable
|
import Data.Traversable
|
||||||
import Database.Persist
|
import Database.Persist
|
||||||
import Database.Persist.Sql
|
import Database.Persist.Sql
|
||||||
|
import Optics.Core
|
||||||
import Yesod.Persist.Core
|
import Yesod.Persist.Core
|
||||||
|
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
|
@ -60,6 +61,7 @@ import Vervis.Cloth
|
||||||
import Vervis.Data.Actor
|
import Vervis.Data.Actor
|
||||||
import Vervis.Data.Collab
|
import Vervis.Data.Collab
|
||||||
import Vervis.Data.Discussion
|
import Vervis.Data.Discussion
|
||||||
|
import Vervis.Data.Follow
|
||||||
import Vervis.FedURI
|
import Vervis.FedURI
|
||||||
import Vervis.Federation.Util
|
import Vervis.Federation.Util
|
||||||
import Vervis.Foundation
|
import Vervis.Foundation
|
||||||
|
@ -68,6 +70,7 @@ import Vervis.Recipient (makeRecipientSet, LocalStageBy (..), Aud (..), collectA
|
||||||
import Vervis.Persist.Actor
|
import Vervis.Persist.Actor
|
||||||
import Vervis.Persist.Collab
|
import Vervis.Persist.Collab
|
||||||
import Vervis.Persist.Discussion
|
import Vervis.Persist.Discussion
|
||||||
|
import Vervis.Persist.Follow
|
||||||
import Vervis.Ticket
|
import Vervis.Ticket
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
@ -82,13 +85,10 @@ import Vervis.Ticket
|
||||||
personFollow
|
personFollow
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
-> PersonId
|
-> PersonId
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Follow URIMode
|
-> AP.Follow URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
personFollow now recipPersonID author body mfwd luFollow follow = do
|
personFollow now recipPersonID verse follow = do
|
||||||
recipPersonHash <- encodeKeyHashid recipPersonID
|
recipPersonHash <- encodeKeyHashid recipPersonID
|
||||||
actorFollow
|
actorFollow
|
||||||
(\case
|
(\case
|
||||||
|
@ -103,9 +103,9 @@ personFollow now recipPersonID author body mfwd luFollow follow = do
|
||||||
(\ () -> pure $ makeRecipientSet [] [])
|
(\ () -> pure $ makeRecipientSet [] [])
|
||||||
LocalActorPerson
|
LocalActorPerson
|
||||||
(\ () -> pure [])
|
(\ () -> pure [])
|
||||||
now recipPersonID author body mfwd luFollow follow
|
now recipPersonID verse follow
|
||||||
|
|
||||||
-- Meaning: A remote actor is undoing some previous action
|
-- Meaning: Someone is undoing some previous action
|
||||||
-- Behavior:
|
-- Behavior:
|
||||||
-- * Insert to my inbox
|
-- * Insert to my inbox
|
||||||
-- * If they're undoing their Following of me:
|
-- * If they're undoing their Following of me:
|
||||||
|
@ -114,13 +114,10 @@ personFollow now recipPersonID author body mfwd luFollow follow = do
|
||||||
personUndo
|
personUndo
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
-> PersonId
|
-> PersonId
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Undo URIMode
|
-> AP.Undo URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
personUndo now recipPersonID author body _mfwd luUndo (AP.Undo uObject) = do
|
personUndo now recipPersonID (Verse authorIdMsig body) (AP.Undo uObject) = do
|
||||||
|
|
||||||
-- Check input
|
-- Check input
|
||||||
undone <-
|
undone <-
|
||||||
|
@ -129,14 +126,14 @@ personUndo now recipPersonID author body _mfwd luUndo (AP.Undo uObject) = do
|
||||||
|
|
||||||
maybeUndo <- withDBExcept $ do
|
maybeUndo <- withDBExcept $ do
|
||||||
|
|
||||||
-- Grab recipient person from DB
|
-- Grab me from DB
|
||||||
(personRecip, actorRecip) <- lift $ do
|
(personRecip, actorRecip) <- lift $ do
|
||||||
p <- getJust recipPersonID
|
p <- getJust recipPersonID
|
||||||
(p,) <$> getJust (personActor p)
|
(p,) <$> getJust (personActor p)
|
||||||
|
|
||||||
-- Insert the Undo to person's inbox
|
-- Insert the Undo to person's inbox
|
||||||
mractid <- lift $ insertToInbox now author body (actorInbox actorRecip) luUndo False
|
maybeUndoDB <- lift $ insertToInbox now authorIdMsig body (actorInbox actorRecip) False
|
||||||
for mractid $ \ undoID -> do
|
for maybeUndoDB $ \ undoDB -> do
|
||||||
|
|
||||||
maybeUndo <- runMaybeT $ do
|
maybeUndo <- runMaybeT $ do
|
||||||
|
|
||||||
|
@ -144,7 +141,7 @@ personUndo now recipPersonID author body _mfwd luUndo (AP.Undo uObject) = do
|
||||||
undoneDB <- MaybeT $ getActivity undone
|
undoneDB <- MaybeT $ getActivity undone
|
||||||
|
|
||||||
let followers = actorFollowers actorRecip
|
let followers = actorFollowers actorRecip
|
||||||
tryUnfollow followers undoneDB
|
tryUnfollow followers undoneDB undoDB
|
||||||
|
|
||||||
for maybeUndo $ \ () -> do
|
for maybeUndo $ \ () -> do
|
||||||
|
|
||||||
|
@ -161,14 +158,12 @@ personUndo now recipPersonID author body _mfwd luUndo (AP.Undo uObject) = do
|
||||||
Just (Just (actorID, acceptID, (actionAccept, localRecipsAccept, remoteRecipsAccept, fwdHostsAccept))) -> do
|
Just (Just (actorID, acceptID, (actionAccept, localRecipsAccept, remoteRecipsAccept, fwdHostsAccept))) -> do
|
||||||
lift $ sendActivity
|
lift $ sendActivity
|
||||||
(LocalActorPerson recipPersonID) actorID localRecipsAccept
|
(LocalActorPerson recipPersonID) actorID localRecipsAccept
|
||||||
remoteRecipsAccept fwdHostsAccept acceptID
|
remoteRecipsAccept fwdHostsAccept acceptID actionAccept
|
||||||
EventAcceptRemoteFollow actionAccept
|
|
||||||
done "Undid the Follow and published Accept"
|
done "Undid the Follow and published Accept"
|
||||||
|
|
||||||
where
|
where
|
||||||
|
|
||||||
tryUnfollow _ (Left _) = mzero
|
tryUnfollow personFollowersID (Right remoteActivityID) (Right (author, _, _)) = do
|
||||||
tryUnfollow personFollowersID (Right remoteActivityID) = do
|
|
||||||
Entity remoteFollowID remoteFollow <-
|
Entity remoteFollowID remoteFollow <-
|
||||||
MaybeT $ lift $ getBy $ UniqueRemoteFollowFollow remoteActivityID
|
MaybeT $ lift $ getBy $ UniqueRemoteFollowFollow remoteActivityID
|
||||||
let followerID = remoteFollowActor remoteFollow
|
let followerID = remoteFollowActor remoteFollow
|
||||||
|
@ -177,13 +172,23 @@ personUndo now recipPersonID author body _mfwd luUndo (AP.Undo uObject) = do
|
||||||
unless (followerID == remoteAuthorId author) $
|
unless (followerID == remoteAuthorId author) $
|
||||||
lift $ throwE "You're trying to Undo someone else's Follow"
|
lift $ throwE "You're trying to Undo someone else's Follow"
|
||||||
lift $ lift $ delete remoteFollowID
|
lift $ lift $ delete remoteFollowID
|
||||||
|
tryUnfollow personFollowersID (Left (_, _, outboxItemID)) (Left (_, actorID, _)) = do
|
||||||
|
Entity followID follow <-
|
||||||
|
MaybeT $ lift $ getBy $ UniqueFollowFollow outboxItemID
|
||||||
|
let followerID = followActor follow
|
||||||
|
followerSetID = followTarget follow
|
||||||
|
guard $ followerSetID == personFollowersID
|
||||||
|
unless (followerID == actorID) $
|
||||||
|
lift $ throwE "You're trying to Undo someone else's Follow"
|
||||||
|
lift $ lift $ delete followID
|
||||||
|
tryUnfollow _ _ _ = mzero
|
||||||
|
|
||||||
prepareAccept = do
|
prepareAccept = do
|
||||||
encodeRouteHome <- getEncodeRouteHome
|
encodeRouteHome <- getEncodeRouteHome
|
||||||
|
|
||||||
let ObjURI hAuthor luAuthor = remoteAuthorURI author
|
audSender <- makeAudSenderOnly authorIdMsig
|
||||||
audSender = AudRemote hAuthor [luAuthor] []
|
uUndo <- getActivityURI authorIdMsig
|
||||||
(recipientSet, remoteActors, fwdHosts, audLocal, audRemote) =
|
let (recipientSet, remoteActors, fwdHosts, audLocal, audRemote) =
|
||||||
collectAudience [audSender]
|
collectAudience [audSender]
|
||||||
|
|
||||||
recips = map encodeRouteHome audLocal ++ audRemote
|
recips = map encodeRouteHome audLocal ++ audRemote
|
||||||
|
@ -193,47 +198,44 @@ personUndo now recipPersonID author body _mfwd luUndo (AP.Undo uObject) = do
|
||||||
, AP.actionAudience = AP.Audience recips [] [] [] [] []
|
, AP.actionAudience = AP.Audience recips [] [] [] [] []
|
||||||
, AP.actionFulfills = []
|
, AP.actionFulfills = []
|
||||||
, AP.actionSpecific = AP.AcceptActivity AP.Accept
|
, AP.actionSpecific = AP.AcceptActivity AP.Accept
|
||||||
{ AP.acceptObject = ObjURI hAuthor luUndo
|
{ AP.acceptObject = uUndo
|
||||||
, AP.acceptResult = Nothing
|
, AP.acceptResult = Nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (action, recipientSet, remoteActors, fwdHosts)
|
return (action, recipientSet, remoteActors, fwdHosts)
|
||||||
|
|
||||||
-- Meaning: A remote actor accepted something
|
-- Meaning: An actor accepted something
|
||||||
-- Behavior:
|
-- Behavior:
|
||||||
-- * Insert to my inbox
|
-- * Insert to my inbox
|
||||||
-- * If it's a Follow I sent to them, add to my following list in DB
|
-- * If it's a Follow I sent to them, add to my following list in DB
|
||||||
personAccept
|
personAccept
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
-> PersonId
|
-> PersonId
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Accept URIMode
|
-> AP.Accept URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
personAccept now recipPersonID author body _mfwd luAccept accept = do
|
personAccept now recipPersonID (Verse authorIdMsig body) accept = do
|
||||||
|
|
||||||
-- Check input
|
-- Check input
|
||||||
acceptee <- parseAccept accept
|
acceptee <- parseAccept accept
|
||||||
|
|
||||||
maybeAccept <- withDBExcept $ do
|
maybeNew <- withDBExcept $ do
|
||||||
|
|
||||||
-- Grab recipient person from DB
|
-- Grab me from DB
|
||||||
(personRecip, actorRecip) <- lift $ do
|
(personRecip, actorRecip) <- lift $ do
|
||||||
p <- getJust recipPersonID
|
p <- getJust recipPersonID
|
||||||
(p,) <$> getJust (personActor p)
|
(p,) <$> getJust (personActor p)
|
||||||
|
|
||||||
mractid <- lift $ insertToInbox now author body (actorInbox actorRecip) luAccept True
|
maybeAcceptDB <- lift $ insertToInbox now authorIdMsig body (actorInbox actorRecip) True
|
||||||
for mractid $ \ acceptID -> runMaybeT $ do
|
for maybeAcceptDB $ \ acceptDB -> runMaybeT $ do
|
||||||
|
|
||||||
-- Find the accepted activity in our DB
|
-- Find the accepted activity in our DB
|
||||||
accepteeDB <- MaybeT $ getActivity acceptee
|
accepteeDB <- MaybeT $ getActivity acceptee
|
||||||
|
|
||||||
tryFollow (personActor personRecip) accepteeDB acceptID
|
tryFollow (personActor personRecip) accepteeDB acceptDB
|
||||||
|
|
||||||
case maybeAccept of
|
case maybeNew of
|
||||||
Nothing -> done "I already have this activity in my inbox"
|
Nothing -> done "I already have this activity in my inbox"
|
||||||
Just Nothing -> done "Not my Follow; Just inserted to my inbox"
|
Just Nothing -> done "Not my Follow; Just inserted to my inbox"
|
||||||
Just (Just ()) ->
|
Just (Just ()) ->
|
||||||
|
@ -241,7 +243,7 @@ personAccept now recipPersonID author body _mfwd luAccept accept = do
|
||||||
|
|
||||||
where
|
where
|
||||||
|
|
||||||
tryFollow actorID (Left (_, _, outboxItemID)) acceptID = do
|
tryFollow actorID (Left (_, _, outboxItemID)) (Right (author, _, acceptID)) = do
|
||||||
Entity key val <-
|
Entity key val <-
|
||||||
MaybeT $ lift $
|
MaybeT $ lift $
|
||||||
getBy $ UniqueFollowRemoteRequestActivity outboxItemID
|
getBy $ UniqueFollowRemoteRequestActivity outboxItemID
|
||||||
|
@ -261,42 +263,55 @@ personAccept now recipPersonID author body _mfwd luAccept accept = do
|
||||||
, followRemoteFollow = outboxItemID
|
, followRemoteFollow = outboxItemID
|
||||||
, followRemoteAccept = acceptID
|
, followRemoteAccept = acceptID
|
||||||
}
|
}
|
||||||
|
tryFollow actorID (Left (_, _, outboxItemID)) (Left (authorByKey, _, acceptID)) = do
|
||||||
|
Entity key val <-
|
||||||
|
MaybeT $ lift $ getBy $ UniqueFollowRequestFollow outboxItemID
|
||||||
|
guard $ followRequestActor val == actorID
|
||||||
|
targetByKey <-
|
||||||
|
lift $ lift $ followeeActor <$> getFollowee' (followRequestTarget val)
|
||||||
|
unless (authorByKey == targetByKey) $
|
||||||
|
lift $ throwE "You're Accepting a Follow I sent to someone else"
|
||||||
|
lift $ lift $ delete key
|
||||||
|
lift $ lift $ insert_ Follow
|
||||||
|
{ followActor = actorID
|
||||||
|
, followTarget = followRequestTarget val
|
||||||
|
, followPublic = followRequestPublic val
|
||||||
|
, followFollow = outboxItemID
|
||||||
|
, followAccept = acceptID
|
||||||
|
}
|
||||||
tryFollow _ (Right _) _ = mzero
|
tryFollow _ (Right _) _ = mzero
|
||||||
|
|
||||||
-- Meaning: A remote actor rejected something
|
-- Meaning: An actor rejected something
|
||||||
-- Behavior:
|
-- Behavior:
|
||||||
-- * Insert to my inbox
|
-- * Insert to my inbox
|
||||||
-- * If it's a Follow I sent to them, remove record from my DB
|
-- * If it's a Follow I sent to them, remove record from my DB
|
||||||
personReject
|
personReject
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
-> PersonId
|
-> PersonId
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Reject URIMode
|
-> AP.Reject URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
personReject now recipPersonID author body _mfwd luReject reject = do
|
personReject now recipPersonID (Verse authorIdMsig body) reject = do
|
||||||
|
|
||||||
-- Check input
|
-- Check input
|
||||||
rejectee <- parseReject reject
|
rejectee <- parseReject reject
|
||||||
|
|
||||||
maybeReject <- withDBExcept $ do
|
maybeNew <- withDBExcept $ do
|
||||||
|
|
||||||
-- Grab recipient person from DB
|
-- Grab me from DB
|
||||||
(personRecip, actorRecip) <- lift $ do
|
(personRecip, actorRecip) <- lift $ do
|
||||||
p <- getJust recipPersonID
|
p <- getJust recipPersonID
|
||||||
(p,) <$> getJust (personActor p)
|
(p,) <$> getJust (personActor p)
|
||||||
|
|
||||||
mractid <- lift $ insertToInbox now author body (actorInbox actorRecip) luReject True
|
maybeRejectDB <- lift $ insertToInbox now authorIdMsig body (actorInbox actorRecip) True
|
||||||
for mractid $ \ rejectID -> runMaybeT $ do
|
for maybeRejectDB $ \ _rejectDB -> runMaybeT $ do
|
||||||
|
|
||||||
-- Find the rejected activity in our DB
|
-- Find the rejected activity in our DB
|
||||||
rejecteeDB <- MaybeT $ getActivity rejectee
|
rejecteeDB <- MaybeT $ getActivity rejectee
|
||||||
|
|
||||||
tryFollow rejecteeDB
|
tryFollow (personActor personRecip) rejecteeDB authorIdMsig
|
||||||
|
|
||||||
case maybeReject of
|
case maybeNew of
|
||||||
Nothing -> done "I already have this activity in my inbox"
|
Nothing -> done "I already have this activity in my inbox"
|
||||||
Just Nothing -> done "Not my Follow; Just inserted to my inbox"
|
Just Nothing -> done "Not my Follow; Just inserted to my inbox"
|
||||||
Just (Just ()) ->
|
Just (Just ()) ->
|
||||||
|
@ -304,7 +319,7 @@ personReject now recipPersonID author body _mfwd luReject reject = do
|
||||||
|
|
||||||
where
|
where
|
||||||
|
|
||||||
tryFollow (Left (_, _, outboxItemID)) = do
|
tryFollow _actorID (Left (_, _, outboxItemID)) (Right (author, _, _)) = do
|
||||||
Entity key val <-
|
Entity key val <-
|
||||||
MaybeT $ lift $
|
MaybeT $ lift $
|
||||||
getBy $ UniqueFollowRemoteRequestActivity outboxItemID
|
getBy $ UniqueFollowRemoteRequestActivity outboxItemID
|
||||||
|
@ -316,7 +331,16 @@ personReject now recipPersonID author body _mfwd luReject reject = do
|
||||||
unless (remoteAuthorURI author == uRecip) $
|
unless (remoteAuthorURI author == uRecip) $
|
||||||
lift $ throwE "You're Rejecting a Follow I sent to someone else"
|
lift $ throwE "You're Rejecting a Follow I sent to someone else"
|
||||||
lift $ lift $ delete key
|
lift $ lift $ delete key
|
||||||
tryFollow (Right _) = mzero
|
tryFollow actorID (Left (_, _, outboxItemID)) (Left (authorByKey, _, _)) = do
|
||||||
|
Entity key val <-
|
||||||
|
MaybeT $ lift $ getBy $ UniqueFollowRequestFollow outboxItemID
|
||||||
|
guard $ followRequestActor val == actorID
|
||||||
|
targetByKey <-
|
||||||
|
lift $ lift $ followeeActor <$> getFollowee' (followRequestTarget val)
|
||||||
|
unless (authorByKey == targetByKey) $
|
||||||
|
lift $ throwE "You're Rejecting a Follow I sent to someone else"
|
||||||
|
lift $ lift $ delete key
|
||||||
|
tryFollow _ (Right _) _ = mzero
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
-- Commenting
|
-- Commenting
|
||||||
|
@ -327,18 +351,16 @@ personReject now recipPersonID author body _mfwd luReject reject = do
|
||||||
personCreateNote
|
personCreateNote
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
-> PersonId
|
-> PersonId
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Note URIMode
|
-> AP.Note URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
personCreateNote now recipPersonID author body mfwd luCreate note = do
|
personCreateNote now recipPersonID (Verse authorIdMsig body) note = do
|
||||||
|
|
||||||
-- Check input
|
-- Check input
|
||||||
(luNote, published, Comment maybeParent topic source content) <- do
|
(luNote, published, Comment maybeParent topic source content) <- do
|
||||||
(luId, luAuthor, published, comment) <- parseRemoteComment note
|
(luId, luAuthor, published, comment) <- parseRemoteComment note
|
||||||
unless (luAuthor == objUriLocal (remoteAuthorURI author)) $
|
uCreateAuthor <- lift $ getActorURI authorIdMsig
|
||||||
|
unless (luAuthor == objUriLocal uCreateAuthor) $
|
||||||
throwE "Create author != note author"
|
throwE "Create author != note author"
|
||||||
return (luId, published, comment)
|
return (luId, published, comment)
|
||||||
|
|
||||||
|
@ -352,7 +374,7 @@ personCreateNote now recipPersonID author body mfwd luCreate note = do
|
||||||
|
|
||||||
Right uContext -> do
|
Right uContext -> do
|
||||||
checkContextParent uContext maybeParent
|
checkContextParent uContext maybeParent
|
||||||
lift $ insertToInbox now author body (actorInbox recipActor) luCreate True
|
lift $ insertToInbox now authorIdMsig body (actorInbox recipActor) True
|
||||||
|
|
||||||
Left (CommentTopicTicket deckID taskID) -> do
|
Left (CommentTopicTicket deckID taskID) -> do
|
||||||
(_, _, Entity _ ticket, _, _) <- do
|
(_, _, Entity _ ticket, _, _) <- do
|
||||||
|
@ -360,7 +382,7 @@ personCreateNote now recipPersonID author body mfwd luCreate note = do
|
||||||
fromMaybeE mticket "Context: No such deck-ticket"
|
fromMaybeE mticket "Context: No such deck-ticket"
|
||||||
let did = ticketDiscuss ticket
|
let did = ticketDiscuss ticket
|
||||||
_ <- traverse (getMessageParent did) maybeParent
|
_ <- traverse (getMessageParent did) maybeParent
|
||||||
lift $ insertToInbox now author body (actorInbox recipActor) luCreate True
|
lift $ insertToInbox now authorIdMsig body (actorInbox recipActor) True
|
||||||
|
|
||||||
Left (CommentTopicCloth loomID clothID) -> do
|
Left (CommentTopicCloth loomID clothID) -> do
|
||||||
(_, _, Entity _ ticket, _, _, _) <- do
|
(_, _, Entity _ ticket, _, _, _) <- do
|
||||||
|
@ -368,7 +390,7 @@ personCreateNote now recipPersonID author body mfwd luCreate note = do
|
||||||
fromMaybeE mticket "Context: No such loom-cloth"
|
fromMaybeE mticket "Context: No such loom-cloth"
|
||||||
let did = ticketDiscuss ticket
|
let did = ticketDiscuss ticket
|
||||||
_ <- traverse (getMessageParent did) maybeParent
|
_ <- traverse (getMessageParent did) maybeParent
|
||||||
lift $ insertToInbox now author body (actorInbox recipActor) luCreate True
|
lift $ insertToInbox now authorIdMsig body (actorInbox recipActor) True
|
||||||
|
|
||||||
done $
|
done $
|
||||||
case mractid of
|
case mractid of
|
||||||
|
@ -409,344 +431,165 @@ personCreateNote now recipPersonID author body mfwd luCreate note = do
|
||||||
personInvite
|
personInvite
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
-> PersonId
|
-> PersonId
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Invite URIMode
|
-> AP.Invite URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
personInvite now recipPersonID author body mfwd luInvite invite = do
|
personInvite now recipPersonID (Verse authorIdMsig body) invite = do
|
||||||
|
|
||||||
-- Check input
|
-- Check input
|
||||||
recipient <- do
|
recipient <- do
|
||||||
(_resource, target) <-
|
let author = bimap (view _1) (remoteAuthorURI . view _1) authorIdMsig
|
||||||
parseInvite (Right $ remoteAuthorURI author) invite
|
(_resource, target) <- parseInvite author invite
|
||||||
return target
|
return target
|
||||||
|
|
||||||
maybeInvite <- withDBExcept $ do
|
maybeNew <- withDBExcept $ do
|
||||||
|
|
||||||
-- Grab recipient person from DB
|
-- Grab me from DB
|
||||||
(personRecip, actorRecip) <- lift $ do
|
(personRecip, actorRecip) <- lift $ do
|
||||||
p <- getJust recipPersonID
|
p <- getJust recipPersonID
|
||||||
(p,) <$> getJust (personActor p)
|
(p,) <$> getJust (personActor p)
|
||||||
|
|
||||||
mractid <- lift $ insertToInbox now author body (actorInbox actorRecip) luInvite True
|
maybeInviteDB <- lift $ insertToInbox now authorIdMsig body (actorInbox actorRecip) True
|
||||||
for mractid $ \ inviteID ->
|
for maybeInviteDB $ \ _inviteDB ->
|
||||||
return (personActor personRecip, inviteID)
|
return $ personActor personRecip
|
||||||
|
|
||||||
case maybeInvite of
|
case maybeNew of
|
||||||
Nothing -> done "I already have this activity in my inbox"
|
Nothing -> done "I already have this activity in my inbox"
|
||||||
Just (actorID, inviteID) -> do
|
Just actorID -> do
|
||||||
let targetIsRecip =
|
let targetIsRecip =
|
||||||
case recipient of
|
case recipient of
|
||||||
Left (GrantRecipPerson p) -> p == recipPersonID
|
Left (GrantRecipPerson p) -> p == recipPersonID
|
||||||
_ -> False
|
_ -> False
|
||||||
if not targetIsRecip
|
if not targetIsRecip
|
||||||
then done "I'm not the target; Inserted to inbox"
|
then done "I'm not the target; Inserted to inbox"
|
||||||
else case mfwd of
|
else do
|
||||||
Nothing ->
|
recipHash <- encodeKeyHashid recipPersonID
|
||||||
done
|
let sieve =
|
||||||
"I'm the target; Inserted to inbox; \
|
makeRecipientSet
|
||||||
\Forwarding not approved"
|
[]
|
||||||
Just (localRecips, sig) -> do
|
[LocalStagePersonFollowers recipHash]
|
||||||
recipHash <- encodeKeyHashid recipPersonID
|
forwardActivity
|
||||||
let sieve =
|
authorIdMsig body (LocalActorPerson recipPersonID)
|
||||||
makeRecipientSet
|
actorID sieve
|
||||||
[]
|
done
|
||||||
[LocalStagePersonFollowers recipHash]
|
"I'm the target; Inserted to inbox; \
|
||||||
lift $ forwardActivity
|
\Forwarded to followers if addressed"
|
||||||
(actbBL body) localRecips sig
|
|
||||||
actorID
|
|
||||||
(LocalActorPerson recipPersonID) sieve
|
|
||||||
(EventRemoteInviteLocalRecipFwdToFollower inviteID)
|
|
||||||
done
|
|
||||||
"I'm the target; Inserted to inbox; \
|
|
||||||
\Forwarded to followers if addressed"
|
|
||||||
|
|
||||||
-- Meaning: Someone asked to join a resource
|
-- Meaning: Someone asked to join a resource
|
||||||
-- Behavior: Insert to my inbox
|
-- Behavior: Insert to my inbox
|
||||||
personJoin
|
personJoin
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
-> PersonId
|
-> PersonId
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Join URIMode
|
-> AP.Join URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
personJoin now recipPersonID author body mfwd luJoin join = do
|
personJoin now recipPersonID (Verse authorIdMsig body) join = do
|
||||||
|
|
||||||
-- Check input
|
-- Check input
|
||||||
_resource <- parseJoin join
|
_resource <- parseJoin join
|
||||||
|
|
||||||
maybeJoinID <- lift $ withDB $ do
|
maybeJoinID <- lift $ withDB $ do
|
||||||
|
|
||||||
-- Grab recipient person from DB
|
-- Grab me from DB
|
||||||
(_personRecip, actorRecip) <- do
|
(_personRecip, actorRecip) <- do
|
||||||
p <- getJust recipPersonID
|
p <- getJust recipPersonID
|
||||||
(p,) <$> getJust (personActor p)
|
(p,) <$> getJust (personActor p)
|
||||||
|
|
||||||
insertToInbox now author body (actorInbox actorRecip) luJoin True
|
insertToInbox now authorIdMsig body (actorInbox actorRecip) True
|
||||||
|
|
||||||
case maybeJoinID of
|
case maybeJoinID of
|
||||||
Nothing -> done "I already have this activity in my inbox"
|
Nothing -> done "I already have this activity in my inbox"
|
||||||
Just _joinID -> done "Inserted to my inbox"
|
Just _joinID -> done "Inserted to my inbox"
|
||||||
|
|
||||||
-- Meaning: A remote actor published a Grant
|
-- Meaning: An actor published a Grant
|
||||||
-- Behavior:
|
-- Behavior:
|
||||||
-- * Insert to my inbox
|
-- * Insert to my inbox
|
||||||
personGrant
|
personGrant
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
-> PersonId
|
-> PersonId
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Grant URIMode
|
-> AP.Grant URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
personGrant now recipPersonID author body mfwd luGrant grant = do
|
personGrant now recipPersonID (Verse authorIdMsig body) grant = do
|
||||||
|
|
||||||
-- Check input
|
-- Check input
|
||||||
(_remoteResource, recipient) <- do
|
target <- do
|
||||||
let u@(ObjURI h _) = remoteAuthorURI author
|
h <- lift $ objUriAuthority <$> getActorURI authorIdMsig
|
||||||
(resource, recip, _mresult, _mstart, _mend) <- parseGrant h grant
|
(resource, recip, _mresult, _mstart, _mend) <- parseGrant h grant
|
||||||
resourceURI <-
|
case (recip, authorIdMsig) of
|
||||||
case resource of
|
(Left (GrantRecipPerson p), Left (LocalActorPerson p', _, _))
|
||||||
Right r -> return (u, r)
|
| p == p' ->
|
||||||
_ -> error "Remote Grant but parseGrant identified local resource"
|
throwE "Grant sender and target are the same local Person"
|
||||||
when (recip == Right u) $
|
(Right uRecip, Right (author, _, _))
|
||||||
throwE "Grant sender and target are the same remote actor"
|
| uRecip == remoteAuthorURI author ->
|
||||||
return (resourceURI, recip)
|
throwE "Grant sender and target are the same remote actor"
|
||||||
|
_ -> pure ()
|
||||||
|
return recip
|
||||||
|
|
||||||
maybeGrant <- withDBExcept $ do
|
maybeGrant <- withDBExcept $ do
|
||||||
|
|
||||||
-- Grab recipient person from DB
|
-- Grab me from DB
|
||||||
(personRecip, actorRecip) <- lift $ do
|
(personRecip, actorRecip) <- lift $ do
|
||||||
p <- getJust recipPersonID
|
p <- getJust recipPersonID
|
||||||
(p,) <$> getJust (personActor p)
|
(p,) <$> getJust (personActor p)
|
||||||
|
|
||||||
mractid <- lift $ insertToInbox now author body (actorInbox actorRecip) luGrant True
|
mractid <- lift $ insertToInbox now authorIdMsig body (actorInbox actorRecip) True
|
||||||
for mractid $ \ grantID ->
|
for mractid $ \ _grantDB -> return $ personActor personRecip
|
||||||
return (personActor personRecip, grantID)
|
|
||||||
|
|
||||||
case maybeGrant of
|
case maybeGrant of
|
||||||
Nothing -> done "I already have this activity in my inbox"
|
Nothing -> done "I already have this activity in my inbox"
|
||||||
Just (_actorID, _grantID) -> do
|
Just _actorID -> do
|
||||||
let targetIsRecip =
|
let targetIsRecip =
|
||||||
case recipient of
|
case target of
|
||||||
Left (GrantRecipPerson p) -> p == recipPersonID
|
Left (GrantRecipPerson p) -> p == recipPersonID
|
||||||
_ -> False
|
_ -> False
|
||||||
if not targetIsRecip
|
if not targetIsRecip
|
||||||
then done "I'm not the target; Inserted to inbox"
|
then done "I'm not the target; Inserted to inbox"
|
||||||
else done "I'm the target; Inserted to inbox"
|
else done "I'm the target; Inserted to inbox"
|
||||||
|
|
||||||
-- Meaning: A remote actor has revoked some previously published Grants
|
-- Meaning: An actor has revoked some previously published Grants
|
||||||
-- Behavior: Insert to my inbox
|
-- Behavior: Insert to my inbox
|
||||||
personRevoke
|
personRevoke
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
-> PersonId
|
-> PersonId
|
||||||
-> RemoteAuthor
|
-> Verse
|
||||||
-> ActivityBody
|
|
||||||
-> Maybe (RecipientRoutes, ByteString)
|
|
||||||
-> LocalURI
|
|
||||||
-> AP.Revoke URIMode
|
-> AP.Revoke URIMode
|
||||||
-> ActE (Text, Act (), Next)
|
-> ActE (Text, Act (), Next)
|
||||||
personRevoke now recipPersonID author body _mfwd luRevoke (AP.Revoke _lus) = do
|
personRevoke now recipPersonID (Verse authorIdMsig body) (AP.Revoke _lus) = do
|
||||||
|
|
||||||
maybeRevoke <- lift $ withDB $ do
|
maybeRevoke <- lift $ withDB $ do
|
||||||
|
|
||||||
-- Grab recipient person from DB
|
-- Grab me from DB
|
||||||
(_personRecip, actorRecip) <- do
|
(_personRecip, actorRecip) <- do
|
||||||
p <- getJust recipPersonID
|
p <- getJust recipPersonID
|
||||||
(p,) <$> getJust (personActor p)
|
(p,) <$> getJust (personActor p)
|
||||||
|
|
||||||
insertToInbox now author body (actorInbox actorRecip) luRevoke True
|
insertToInbox now authorIdMsig body (actorInbox actorRecip) True
|
||||||
|
|
||||||
case maybeRevoke of
|
case maybeRevoke of
|
||||||
Nothing -> done "I already have this activity in my inbox"
|
Nothing -> done "I already have this activity in my inbox"
|
||||||
Just _revokeID -> done "Inserted to my inbox"
|
Just _revokeDB -> done "Inserted to my inbox"
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
-- Main behavior function
|
-- Main behavior function
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
insertActivityToInbox
|
|
||||||
:: MonadIO m
|
|
||||||
=> UTCTime -> ActorId -> OutboxItemId -> ReaderT SqlBackend m Bool
|
|
||||||
insertActivityToInbox now recipActorID outboxItemID = do
|
|
||||||
inboxID <- actorInbox <$> getJust recipActorID
|
|
||||||
inboxItemID <- insert $ InboxItem True now
|
|
||||||
maybeItem <- insertUnique $ InboxItemLocal inboxID outboxItemID inboxItemID
|
|
||||||
case maybeItem of
|
|
||||||
Nothing -> do
|
|
||||||
delete inboxItemID
|
|
||||||
return False
|
|
||||||
Just _ -> return True
|
|
||||||
|
|
||||||
personBehavior :: UTCTime -> PersonId -> Verse -> ActE (Text, Act (), Next)
|
personBehavior :: UTCTime -> PersonId -> Verse -> ActE (Text, Act (), Next)
|
||||||
personBehavior now personID (Left event) =
|
personBehavior now personID verse@(Verse _authorIdMsig body) =
|
||||||
case event of
|
|
||||||
-- Meaning: Someone X received an Invite and forwarded it to me because
|
|
||||||
-- I'm a follower of X
|
|
||||||
-- Behavior: Insert to my inbox
|
|
||||||
EventRemoteInviteLocalRecipFwdToFollower inviteID -> do
|
|
||||||
lift $ withDB $ do
|
|
||||||
(_personRecip, actorRecip) <- do
|
|
||||||
p <- getJust personID
|
|
||||||
(p,) <$> getJust (personActor p)
|
|
||||||
let inboxID = actorInbox actorRecip
|
|
||||||
itemID <- insert $ InboxItem True now
|
|
||||||
insert_ $ InboxItemRemote inboxID inviteID itemID
|
|
||||||
done "Inserted Invite to inbox"
|
|
||||||
-- Meaning: A remote actor has forwarded to me a local activity
|
|
||||||
-- Behavior: Insert it to my inbox
|
|
||||||
EventRemoteFwdLocalActivity authorByKey outboxItemID -> withDBExcept $ do
|
|
||||||
recipPerson <- lift $ getJust personID
|
|
||||||
verifyLocalActivityExistsInDB authorByKey outboxItemID
|
|
||||||
if LocalActorPerson personID == authorByKey
|
|
||||||
then done "Received activity authored by self, ignoring"
|
|
||||||
else do
|
|
||||||
inserted <- lift $ insertActivityToInbox now (personActor recipPerson) outboxItemID
|
|
||||||
done $
|
|
||||||
if inserted
|
|
||||||
then "Activity inserted to my inbox"
|
|
||||||
else "Activity already exists in my inbox, ignoring"
|
|
||||||
-- Meaning: A deck/loom received an Undo{Resolve} and forwarded it to
|
|
||||||
-- me because I'm a follower of the deck/loom or the ticket
|
|
||||||
-- Behavior: Insert to my inbox
|
|
||||||
EventRemoteUnresolveLocalResourceFwdToFollower undoID -> do
|
|
||||||
lift $ withDB $ do
|
|
||||||
(_personRecip, actorRecip) <- do
|
|
||||||
p <- getJust personID
|
|
||||||
(p,) <$> getJust (personActor p)
|
|
||||||
let inboxID = actorInbox actorRecip
|
|
||||||
itemID <- insert $ InboxItem True now
|
|
||||||
insert_ $ InboxItemRemote inboxID undoID itemID
|
|
||||||
done "Inserted Undo{Resolve} to inbox"
|
|
||||||
-- Meaning: A remote actor accepted an Invite on a local resource, I'm
|
|
||||||
-- being forwarded as a follower of the resource
|
|
||||||
--
|
|
||||||
-- Behavior: Insert the Accept to my inbox
|
|
||||||
EventRemoteAcceptInviteLocalResourceFwdToFollower acceptID -> do
|
|
||||||
lift $ withDB $ do
|
|
||||||
(_personRecip, actorRecip) <- do
|
|
||||||
p <- getJust personID
|
|
||||||
(p,) <$> getJust (personActor p)
|
|
||||||
let inboxID = actorInbox actorRecip
|
|
||||||
itemID <- insert $ InboxItem True now
|
|
||||||
insert_ $ InboxItemRemote inboxID acceptID itemID
|
|
||||||
done "Inserted Accept{Invite} to inbox"
|
|
||||||
-- Meaning: A remote actor approved a Join on a local resource, I'm
|
|
||||||
-- being forwarded as a follower of the resource
|
|
||||||
--
|
|
||||||
-- Behavior: Insert the Accept to my inbox
|
|
||||||
EventRemoteApproveJoinLocalResourceFwdToFollower acceptID -> do
|
|
||||||
lift $ withDB $ do
|
|
||||||
(_personRecip, actorRecip) <- do
|
|
||||||
p <- getJust personID
|
|
||||||
(p,) <$> getJust (personActor p)
|
|
||||||
let inboxID = actorInbox actorRecip
|
|
||||||
itemID <- insert $ InboxItem True now
|
|
||||||
insert_ $ InboxItemRemote inboxID acceptID itemID
|
|
||||||
done "Inserted Accept{Join} to inbox"
|
|
||||||
-- Meaning: Local resource sent a Grant, I'm the
|
|
||||||
-- inviter/approver/target/follower
|
|
||||||
--
|
|
||||||
-- Behavior: Insert the Grant to my inbox
|
|
||||||
EventGrantAfterRemoteAccept grantID -> do
|
|
||||||
_ <- lift $ withDB $ do
|
|
||||||
(personRecip, _actorRecip) <- do
|
|
||||||
p <- getJust personID
|
|
||||||
(p,) <$> getJust (personActor p)
|
|
||||||
insertActivityToInbox now (personActor personRecip) grantID
|
|
||||||
done "Inserted Grant to my inbox"
|
|
||||||
-- Meaning: A remote actor rejected an Invite on a local resource, I'm
|
|
||||||
-- being forwarded as a follower of the resource
|
|
||||||
--
|
|
||||||
-- Behavior: Insert the Accept to my inbox
|
|
||||||
EventRemoteRejectInviteLocalResourceFwdToFollower rejectID -> do
|
|
||||||
lift $ withDB $ do
|
|
||||||
(_personRecip, actorRecip) <- do
|
|
||||||
p <- getJust personID
|
|
||||||
(p,) <$> getJust (personActor p)
|
|
||||||
let inboxID = actorInbox actorRecip
|
|
||||||
itemID <- insert $ InboxItem True now
|
|
||||||
insert_ $ InboxItemRemote inboxID rejectID itemID
|
|
||||||
done "Inserted Reject{Invite} to inbox"
|
|
||||||
-- Meaning: A remote actor disapproved a Join on a local resource, I'm
|
|
||||||
-- being forwarded as a follower of the resource
|
|
||||||
--
|
|
||||||
-- Behavior: Insert the Reject to my inbox
|
|
||||||
EventRemoteForbidJoinLocalResourceFwdToFollower rejectID -> do
|
|
||||||
lift $ withDB $ do
|
|
||||||
(_personRecip, actorRecip) <- do
|
|
||||||
p <- getJust personID
|
|
||||||
(p,) <$> getJust (personActor p)
|
|
||||||
let inboxID = actorInbox actorRecip
|
|
||||||
itemID <- insert $ InboxItem True now
|
|
||||||
insert_ $ InboxItemRemote inboxID rejectID itemID
|
|
||||||
done "Inserted Reject{Join} to inbox"
|
|
||||||
-- Meaning: Local resource sent a Reject on Invite/Join, I'm the
|
|
||||||
-- inviter/disapprover/target/follower
|
|
||||||
--
|
|
||||||
-- Behavior: Insert the Reject to my inbox
|
|
||||||
EventRejectAfterRemoteReject rejectID -> do
|
|
||||||
_ <- lift $ withDB $ do
|
|
||||||
(personRecip, _actorRecip) <- do
|
|
||||||
p <- getJust personID
|
|
||||||
(p,) <$> getJust (personActor p)
|
|
||||||
insertActivityToInbox now (personActor personRecip) rejectID
|
|
||||||
done "Inserted Reject to my inbox"
|
|
||||||
-- Meaning: An authorized remote actor sent an Invite on a local
|
|
||||||
-- resource, I'm being forwarded as a follower of the resource
|
|
||||||
--
|
|
||||||
-- Behavior: Insert the Invite to my inbox
|
|
||||||
EventRemoteInviteLocalTopicFwdToFollower inviteID -> do
|
|
||||||
lift $ withDB $ do
|
|
||||||
(_personRecip, actorRecip) <- do
|
|
||||||
p <- getJust personID
|
|
||||||
(p,) <$> getJust (personActor p)
|
|
||||||
let inboxID = actorInbox actorRecip
|
|
||||||
itemID <- insert $ InboxItem True now
|
|
||||||
insert_ $ InboxItemRemote inboxID inviteID itemID
|
|
||||||
done "Inserted Invite to inbox"
|
|
||||||
-- Meaning: A remote actor sent a Join on a local resource, I'm being
|
|
||||||
-- forwarded as a follower of the resource
|
|
||||||
--
|
|
||||||
-- Behavior: Insert the Join to my inbox
|
|
||||||
EventRemoteJoinLocalTopicFwdToFollower joinID -> do
|
|
||||||
lift $ withDB $ do
|
|
||||||
(_personRecip, actorRecip) <- do
|
|
||||||
p <- getJust personID
|
|
||||||
(p,) <$> getJust (personActor p)
|
|
||||||
let inboxID = actorInbox actorRecip
|
|
||||||
itemID <- insert $ InboxItem True now
|
|
||||||
insert_ $ InboxItemRemote inboxID joinID itemID
|
|
||||||
done "Inserted Invite to inbox"
|
|
||||||
_ -> throwE $ "Unsupported event for Person: " <> T.pack (show event)
|
|
||||||
personBehavior now personID (Right (VerseRemote author body mfwd luActivity)) =
|
|
||||||
case AP.activitySpecific $ actbActivity body of
|
case AP.activitySpecific $ actbActivity body of
|
||||||
AP.AcceptActivity accept ->
|
AP.AcceptActivity accept -> personAccept now personID verse accept
|
||||||
personAccept now personID author body mfwd luActivity accept
|
|
||||||
AP.CreateActivity (AP.Create obj mtarget) ->
|
AP.CreateActivity (AP.Create obj mtarget) ->
|
||||||
case obj of
|
case obj of
|
||||||
AP.CreateNote _ note ->
|
AP.CreateNote _ note ->
|
||||||
personCreateNote now personID author body mfwd luActivity note
|
personCreateNote now personID verse note
|
||||||
_ -> throwE "Unsupported create object type for people"
|
_ -> throwE "Unsupported create object type for people"
|
||||||
AP.FollowActivity follow ->
|
AP.FollowActivity follow -> personFollow now personID verse follow
|
||||||
personFollow now personID author body mfwd luActivity follow
|
AP.GrantActivity grant -> personGrant now personID verse grant
|
||||||
AP.GrantActivity grant ->
|
AP.InviteActivity invite -> personInvite now personID verse invite
|
||||||
personGrant now personID author body mfwd luActivity grant
|
AP.JoinActivity join -> personJoin now personID verse join
|
||||||
AP.InviteActivity invite ->
|
AP.RejectActivity reject -> personReject now personID verse reject
|
||||||
personInvite now personID author body mfwd luActivity invite
|
AP.RevokeActivity revoke -> personRevoke now personID verse revoke
|
||||||
AP.JoinActivity join ->
|
AP.UndoActivity undo -> personUndo now personID verse undo
|
||||||
personJoin now personID author body mfwd luActivity join
|
|
||||||
AP.RejectActivity reject ->
|
|
||||||
personReject now personID author body mfwd luActivity reject
|
|
||||||
AP.RevokeActivity revoke ->
|
|
||||||
personRevoke now personID author body mfwd luActivity revoke
|
|
||||||
AP.UndoActivity undo ->
|
|
||||||
personUndo now personID author body mfwd luActivity undo
|
|
||||||
_ -> throwE "Unsupported activity type for Person"
|
_ -> throwE "Unsupported activity type for Person"
|
||||||
|
|
||||||
instance VervisActor Person where
|
instance VervisActor Person where
|
||||||
|
|
|
@ -52,14 +52,8 @@ import Vervis.Model
|
||||||
import Vervis.Persist.Discussion
|
import Vervis.Persist.Discussion
|
||||||
import Vervis.Ticket
|
import Vervis.Ticket
|
||||||
|
|
||||||
repoBehavior
|
repoBehavior :: UTCTime -> RepoId -> Verse -> ActE (Text, Act (), Next)
|
||||||
:: UTCTime -> RepoId -> Verse -> ExceptT Text Act (Text, Act (), Next)
|
repoBehavior now repoID _verse@(Verse _authorIdMsig body) =
|
||||||
repoBehavior now repoID (Left event) =
|
|
||||||
case event of
|
|
||||||
EventRemoteFwdLocalActivity _ _ ->
|
|
||||||
throwE "Got a forwarded local activity, I don't need those"
|
|
||||||
_ -> throwE $ "Unsupported event for Repo: " <> T.pack (show event)
|
|
||||||
repoBehavior now repoID (Right (VerseRemote author body mfwd luActivity)) =
|
|
||||||
case AP.activitySpecific $ actbActivity body of
|
case AP.activitySpecific $ actbActivity body of
|
||||||
_ -> throwE "Unsupported activity type for Repo"
|
_ -> throwE "Unsupported activity type for Repo"
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,11 @@ module Vervis.Actor2
|
||||||
( -- * Sending messages to actors
|
( -- * Sending messages to actors
|
||||||
sendActivity
|
sendActivity
|
||||||
, forwardActivity
|
, forwardActivity
|
||||||
|
-- * Preparing a new activity
|
||||||
|
, makeAudSenderOnly
|
||||||
|
, makeAudSenderWithFollowers
|
||||||
|
, getActivityURI
|
||||||
|
, getActorURI
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
|
@ -31,10 +36,13 @@ import Control.Monad.IO.Class
|
||||||
import Control.Monad.Trans.Class
|
import Control.Monad.Trans.Class
|
||||||
import Control.Monad.Trans.Except
|
import Control.Monad.Trans.Except
|
||||||
import Data.Barbie
|
import Data.Barbie
|
||||||
|
import Data.Bifunctor
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
import Data.Either
|
import Data.Either
|
||||||
|
import Data.Foldable
|
||||||
import Data.Hashable
|
import Data.Hashable
|
||||||
import Data.List.NonEmpty (NonEmpty)
|
import Data.List.NonEmpty (NonEmpty)
|
||||||
|
import Data.Maybe
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Data.Time.Clock
|
import Data.Time.Clock
|
||||||
import Data.Traversable
|
import Data.Traversable
|
||||||
|
@ -58,23 +66,16 @@ import Web.Actor.Persist
|
||||||
|
|
||||||
import qualified Web.ActivityPub as AP
|
import qualified Web.ActivityPub as AP
|
||||||
|
|
||||||
|
import Control.Monad.Trans.Except.Local
|
||||||
|
|
||||||
import Vervis.Actor
|
import Vervis.Actor
|
||||||
import Vervis.Data.Actor
|
import Vervis.Data.Actor
|
||||||
import Vervis.FedURI
|
import Vervis.FedURI
|
||||||
import Vervis.Foundation
|
import Vervis.Foundation
|
||||||
import Vervis.Model hiding (Actor, Message)
|
import Vervis.Model hiding (Actor, Message)
|
||||||
import Vervis.Recipient (renderLocalActor, localRecipSieve')
|
import Vervis.Recipient (renderLocalActor, localRecipSieve', localActorFollowers, Aud (..), ParsedAudience (..), parseAudience')
|
||||||
import Vervis.Settings
|
import Vervis.Settings
|
||||||
|
|
||||||
instance StageWebRoute Env where
|
|
||||||
type StageRoute Env = Route App
|
|
||||||
askUrlRenderParams = do
|
|
||||||
Env _ _ _ _ _ render _ _ <- askEnv
|
|
||||||
case cast render of
|
|
||||||
Nothing -> error "Env site isn't App"
|
|
||||||
Just r -> pure r
|
|
||||||
pageParamName _ = "page"
|
|
||||||
|
|
||||||
askLatestInstanceKey :: Act (Maybe (Route App, ActorKey))
|
askLatestInstanceKey :: Act (Maybe (Route App, ActorKey))
|
||||||
askLatestInstanceKey = do
|
askLatestInstanceKey = do
|
||||||
maybeTVar <- asksEnv envActorKeys
|
maybeTVar <- asksEnv envActorKeys
|
||||||
|
@ -173,15 +174,28 @@ sendActivity
|
||||||
-- ^ Instances for which the sender is approving to forward this activity
|
-- ^ Instances for which the sender is approving to forward this activity
|
||||||
-> OutboxItemId
|
-> OutboxItemId
|
||||||
-- ^ DB ID of the item in the author's outbox
|
-- ^ DB ID of the item in the author's outbox
|
||||||
-> Event
|
|
||||||
-- ^ Event to send to local live actors
|
|
||||||
-> AP.Action URIMode
|
-> AP.Action URIMode
|
||||||
-- ^ Activity to send to remote actors
|
-- ^ Activity to send to remote actors
|
||||||
-> Act ()
|
-> Act ()
|
||||||
sendActivity senderByKey senderActorID localRecips remoteRecips fwdHosts itemID event action = do
|
sendActivity senderByKey senderActorID localRecips remoteRecips fwdHosts itemID action = do
|
||||||
moreRemoteRecips <-
|
moreRemoteRecips <- do
|
||||||
let justSender = Just senderByKey
|
let justSender = Just senderByKey
|
||||||
in sendToLocalActors event True justSender justSender localRecips
|
author = (senderByKey, senderActorID, itemID)
|
||||||
|
encodeRouteLocal <- getEncodeRouteLocal
|
||||||
|
itemHash <- encodeKeyHashid itemID
|
||||||
|
senderByHash <- hashLocalActor senderByKey
|
||||||
|
hLocal <- asksEnv stageInstanceHost
|
||||||
|
let act =
|
||||||
|
let luId = encodeRouteLocal $ activityRoute senderByHash itemHash
|
||||||
|
luActor = encodeRouteLocal $ renderLocalActor senderByHash
|
||||||
|
in AP.makeActivity luId luActor action
|
||||||
|
bodyBL = A.encode $ AP.Doc hLocal act
|
||||||
|
bodyO <-
|
||||||
|
case A.eitherDecode' bodyBL of
|
||||||
|
Left s -> error $ "Parsing encoded activity failed: " ++ s
|
||||||
|
Right o -> return o
|
||||||
|
let body = ActivityBody bodyBL bodyO act
|
||||||
|
sendToLocalActors (Left author) body True justSender justSender localRecips
|
||||||
envelope <- do
|
envelope <- do
|
||||||
senderByHash <- hashLocalActor senderByKey
|
senderByHash <- hashLocalActor senderByKey
|
||||||
prepareSendH senderActorID senderByHash itemID action
|
prepareSendH senderActorID senderByHash itemID action
|
||||||
|
@ -210,20 +224,20 @@ prepareForwardIK
|
||||||
:: (Route App, ActorKey)
|
:: (Route App, ActorKey)
|
||||||
-> LocalActorBy KeyHashid
|
-> LocalActorBy KeyHashid
|
||||||
-> BL.ByteString
|
-> BL.ByteString
|
||||||
-> ByteString
|
-> Maybe ByteString
|
||||||
-> Act (AP.Errand URIMode)
|
-> Act (AP.Errand URIMode)
|
||||||
prepareForwardIK (keyR, akey) fwderByHash body proof = do
|
prepareForwardIK (keyR, akey) fwderByHash body mproof = do
|
||||||
let sign = actorKeySign akey
|
let sign = actorKeySign akey
|
||||||
fwderR = renderLocalActor fwderByHash
|
fwderR = renderLocalActor fwderByHash
|
||||||
prepareToForward keyR sign True fwderR body proof
|
prepareToForward keyR sign True fwderR body mproof
|
||||||
|
|
||||||
prepareForwardAK
|
prepareForwardAK
|
||||||
:: ActorId
|
:: ActorId
|
||||||
-> LocalActorBy KeyHashid
|
-> LocalActorBy KeyHashid
|
||||||
-> BL.ByteString
|
-> BL.ByteString
|
||||||
-> ByteString
|
-> Maybe ByteString
|
||||||
-> ActDB (AP.Errand URIMode)
|
-> ActDB (AP.Errand URIMode)
|
||||||
prepareForwardAK actorID fwderByHash body proof = do
|
prepareForwardAK actorID fwderByHash body mproof = do
|
||||||
Entity keyID key <- do
|
Entity keyID key <- do
|
||||||
mk <- getBy $ UniqueSigKey actorID
|
mk <- getBy $ UniqueSigKey actorID
|
||||||
case mk of
|
case mk of
|
||||||
|
@ -233,31 +247,31 @@ prepareForwardAK actorID fwderByHash body proof = do
|
||||||
let keyR = stampRoute fwderByHash keyHash
|
let keyR = stampRoute fwderByHash keyHash
|
||||||
sign = actorKeySign $ sigKeyMaterial key
|
sign = actorKeySign $ sigKeyMaterial key
|
||||||
fwderR = renderLocalActor fwderByHash
|
fwderR = renderLocalActor fwderByHash
|
||||||
prepareToForward keyR sign False fwderR body proof
|
prepareToForward keyR sign False fwderR body mproof
|
||||||
|
|
||||||
prepareForwardP
|
prepareForwardP
|
||||||
:: ActorId
|
:: ActorId
|
||||||
-> LocalActorBy KeyHashid
|
-> LocalActorBy KeyHashid
|
||||||
-> BL.ByteString
|
-> BL.ByteString
|
||||||
-> ByteString
|
-> Maybe ByteString
|
||||||
-> ActDB (AP.Errand URIMode)
|
-> ActDB (AP.Errand URIMode)
|
||||||
prepareForwardP actorID fwderByHash body proof = do
|
prepareForwardP actorID fwderByHash body mproof = do
|
||||||
maybeKey <- lift askLatestInstanceKey
|
maybeKey <- lift askLatestInstanceKey
|
||||||
case maybeKey of
|
case maybeKey of
|
||||||
Nothing -> prepareForwardAK actorID fwderByHash body proof
|
Nothing -> prepareForwardAK actorID fwderByHash body mproof
|
||||||
Just key -> lift $ prepareForwardIK key fwderByHash body proof
|
Just key -> lift $ prepareForwardIK key fwderByHash body mproof
|
||||||
|
|
||||||
prepareForwardH
|
prepareForwardH
|
||||||
:: ActorId
|
:: ActorId
|
||||||
-> LocalActorBy KeyHashid
|
-> LocalActorBy KeyHashid
|
||||||
-> BL.ByteString
|
-> BL.ByteString
|
||||||
-> ByteString
|
-> Maybe ByteString
|
||||||
-> Act (AP.Errand URIMode)
|
-> Act (AP.Errand URIMode)
|
||||||
prepareForwardH actorID fwderByHash body proof = do
|
prepareForwardH actorID fwderByHash body mproof = do
|
||||||
maybeKey <- askLatestInstanceKey
|
maybeKey <- askLatestInstanceKey
|
||||||
case maybeKey of
|
case maybeKey of
|
||||||
Nothing -> withDB $ prepareForwardAK actorID fwderByHash body proof
|
Nothing -> withDB $ prepareForwardAK actorID fwderByHash body mproof
|
||||||
Just key -> prepareForwardIK key fwderByHash body proof
|
Just key -> prepareForwardIK key fwderByHash body mproof
|
||||||
|
|
||||||
-- | Given a list of local recipients, which may include actors and
|
-- | Given a list of local recipients, which may include actors and
|
||||||
-- collections,
|
-- collections,
|
||||||
|
@ -269,26 +283,92 @@ prepareForwardH actorID fwderByHash body proof = do
|
||||||
--
|
--
|
||||||
-- This function reads remote recipient data and the sender's signing key from
|
-- This function reads remote recipient data and the sender's signing key from
|
||||||
-- the PostgreSQL database. Don't use it inside a database transaction.
|
-- the PostgreSQL database. Don't use it inside a database transaction.
|
||||||
|
--
|
||||||
|
-- For a remote author, no forwarding is done if a signature isn't provided.
|
||||||
forwardActivity
|
forwardActivity
|
||||||
:: BL.ByteString
|
:: Either (LocalActorBy Key, ActorId, OutboxItemId) (RemoteAuthor, LocalURI, Maybe ByteString)
|
||||||
-> RecipientRoutes
|
-> ActivityBody
|
||||||
-> ByteString
|
|
||||||
-> ActorId
|
|
||||||
-> LocalActorBy Key
|
-> LocalActorBy Key
|
||||||
|
-> ActorId
|
||||||
-> RecipientRoutes
|
-> RecipientRoutes
|
||||||
-> Event
|
-> ActE ()
|
||||||
-> Act ()
|
forwardActivity sourceMaybeForward body fwderByKey fwderActorID sieve = do
|
||||||
forwardActivity body localRecips sig fwderActorID fwderByKey sieve event = do
|
let maybeForward =
|
||||||
remoteRecips <-
|
case sourceMaybeForward of
|
||||||
let localRecipsFinal = localRecipSieve' sieve False False localRecips
|
Left l -> Just $ Left l
|
||||||
justSender = Just fwderByKey
|
Right (author, luAct, msig) ->
|
||||||
in sendToLocalActors event False justSender justSender localRecipsFinal
|
Right . (author,luAct,) <$> msig
|
||||||
errand <- do
|
for_ maybeForward $ \ source -> do
|
||||||
fwderByHash <- hashLocalActor fwderByKey
|
localRecips <- do
|
||||||
prepareForwardH fwderActorID fwderByHash body sig
|
mrecips <- parseAudience' $ AP.activityAudience $ actbActivity body
|
||||||
let remoteRecipsList =
|
paudLocalRecips <$> fromMaybeE mrecips "Activity with no recipients"
|
||||||
concatMap
|
remoteRecips <-
|
||||||
(\ ((_, h), rrs) -> NE.toList $ NE.map (ObjURI h . remoteRecipientId) rrs)
|
let localRecipsFinal = localRecipSieve' sieve False False localRecips
|
||||||
remoteRecips
|
justSender = Just fwderByKey
|
||||||
dt <- asksEnv stageDeliveryTheater
|
authorAndId =
|
||||||
liftIO $ sendHttp dt (MethodForwardRemote errand) remoteRecipsList
|
second (\ (author, luAct, _sig) -> (author, luAct)) source
|
||||||
|
in lift $ sendToLocalActors authorAndId body False justSender justSender localRecipsFinal
|
||||||
|
errand <- lift $ do
|
||||||
|
fwderByHash <- hashLocalActor fwderByKey
|
||||||
|
let msig =
|
||||||
|
case source of
|
||||||
|
Left _ -> Nothing
|
||||||
|
Right (_, _, b) -> Just b
|
||||||
|
prepareForwardH fwderActorID fwderByHash (actbBL body) msig
|
||||||
|
let remoteRecipsList =
|
||||||
|
concatMap
|
||||||
|
(\ ((_, h), rrs) -> NE.toList $ NE.map (ObjURI h . remoteRecipientId) rrs)
|
||||||
|
remoteRecips
|
||||||
|
dt <- lift $ asksEnv stageDeliveryTheater
|
||||||
|
lift $ liftIO $ sendHttp dt (MethodForwardRemote errand) remoteRecipsList
|
||||||
|
|
||||||
|
makeAudSenderOnly
|
||||||
|
:: Either
|
||||||
|
(LocalActorBy Key, ActorId, OutboxItemId)
|
||||||
|
(RemoteAuthor, LocalURI, Maybe ByteString)
|
||||||
|
-> Act (Aud URIMode)
|
||||||
|
makeAudSenderOnly (Left (actorByKey, _, _)) = do
|
||||||
|
actorByHash <- hashLocalActor actorByKey
|
||||||
|
return $ AudLocal [actorByHash] []
|
||||||
|
makeAudSenderOnly (Right (author, _, _)) = do
|
||||||
|
let ObjURI hAuthor luAuthor = remoteAuthorURI author
|
||||||
|
pure $ AudRemote hAuthor [luAuthor] []
|
||||||
|
|
||||||
|
makeAudSenderWithFollowers
|
||||||
|
:: Either
|
||||||
|
(LocalActorBy Key, ActorId, OutboxItemId)
|
||||||
|
(RemoteAuthor, LocalURI, Maybe ByteString)
|
||||||
|
-> ActDB (Aud URIMode)
|
||||||
|
makeAudSenderWithFollowers (Left (actorByKey, _, _)) = do
|
||||||
|
actorByHash <- hashLocalActor actorByKey
|
||||||
|
return $ AudLocal [actorByHash] [localActorFollowers actorByHash]
|
||||||
|
makeAudSenderWithFollowers (Right (author, _, _)) = do
|
||||||
|
let ObjURI hAuthor luAuthor = remoteAuthorURI author
|
||||||
|
ra <- getJust $ remoteAuthorId author
|
||||||
|
return $
|
||||||
|
AudRemote hAuthor [luAuthor] (maybeToList $ remoteActorFollowers ra)
|
||||||
|
|
||||||
|
getActivityURI
|
||||||
|
:: Either
|
||||||
|
(LocalActorBy Key, ActorId, OutboxItemId)
|
||||||
|
(RemoteAuthor, LocalURI, Maybe ByteString)
|
||||||
|
-> Act FedURI
|
||||||
|
getActivityURI (Left (actorByKey, _, outboxItemID)) = do
|
||||||
|
encodeRouteHome <- getEncodeRouteHome
|
||||||
|
actorByHash <- hashLocalActor actorByKey
|
||||||
|
outboxItemHash <- encodeKeyHashid outboxItemID
|
||||||
|
return $ encodeRouteHome $ activityRoute actorByHash outboxItemHash
|
||||||
|
getActivityURI (Right (author, luAct, _)) = do
|
||||||
|
let ObjURI hAuthor _ = remoteAuthorURI author
|
||||||
|
pure $ ObjURI hAuthor luAct
|
||||||
|
|
||||||
|
getActorURI
|
||||||
|
:: Either
|
||||||
|
(LocalActorBy Key, ActorId, OutboxItemId)
|
||||||
|
(RemoteAuthor, LocalURI, Maybe ByteString)
|
||||||
|
-> Act FedURI
|
||||||
|
getActorURI (Left (actorByKey, _, _)) = do
|
||||||
|
encodeRouteHome <- getEncodeRouteHome
|
||||||
|
actorByHash <- hashLocalActor actorByKey
|
||||||
|
return $ encodeRouteHome $ renderLocalActor actorByHash
|
||||||
|
getActorURI (Right (author, _, _)) = pure $ remoteAuthorURI author
|
||||||
|
|
|
@ -120,7 +120,7 @@ parseTopic u = do
|
||||||
|
|
||||||
parseInvite
|
parseInvite
|
||||||
:: StageRoute Env ~ Route App
|
:: StageRoute Env ~ Route App
|
||||||
=> Either PersonId FedURI
|
=> Either (LocalActorBy Key) FedURI
|
||||||
-> AP.Invite URIMode
|
-> AP.Invite URIMode
|
||||||
-> ActE
|
-> ActE
|
||||||
( Either (GrantResourceBy Key) FedURI
|
( Either (GrantResourceBy Key) FedURI
|
||||||
|
@ -144,7 +144,7 @@ parseInvite sender (AP.Invite instrument object target) = do
|
||||||
recipHash
|
recipHash
|
||||||
"Contains invalid hashid"
|
"Contains invalid hashid"
|
||||||
case recipKey of
|
case recipKey of
|
||||||
GrantRecipPerson p | Left p == sender ->
|
GrantRecipPerson p | Left (LocalActorPerson p) == sender ->
|
||||||
throwE "Invite local sender and recipient are the same Person"
|
throwE "Invite local sender and recipient are the same Person"
|
||||||
_ -> return recipKey
|
_ -> return recipKey
|
||||||
)
|
)
|
||||||
|
|
|
@ -404,12 +404,12 @@ verifyForwardedSig hAuthor luAuthor (Verification malgo keyid input signature) =
|
||||||
else ActivityAuthRemote <$> verifyActorSig' malgo input signature hKey luKey (Just luAuthor)
|
else ActivityAuthRemote <$> verifyActorSig' malgo input signature hKey luKey (Just luAuthor)
|
||||||
|
|
||||||
authenticateActivity
|
authenticateActivity
|
||||||
:: UTCTime
|
:: UTCTime -> ExceptT Text Handler (ActivityAuthentication, ActivityBody)
|
||||||
-- -> ExceptT Text Handler (Either PersonId ActivityDetail, BL.ByteString, Object, Activity)
|
|
||||||
-> ExceptT Text Handler (ActivityAuthentication, ActivityBody)
|
|
||||||
authenticateActivity now = do
|
authenticateActivity now = do
|
||||||
(ra, wv, body) <- do
|
(ra, wv, body) <- do
|
||||||
verifyContentTypeAP_E
|
verifyContentTypeAP_E
|
||||||
|
|
||||||
|
-- Compute input for HTTP Signature verification
|
||||||
proof <- withExceptT (T.pack . displayException) $ ExceptT $ do
|
proof <- withExceptT (T.pack . displayException) $ ExceptT $ do
|
||||||
timeLimit <- getsYesod $ appHttpSigTimeLimit . appSettings
|
timeLimit <- getsYesod $ appHttpSigTimeLimit . appSettings
|
||||||
let requires = [hRequestTarget, hHost, hDigest]
|
let requires = [hRequestTarget, hHost, hDigest]
|
||||||
|
@ -419,6 +419,7 @@ authenticateActivity now = do
|
||||||
toSeconds = toTimeUnit
|
toSeconds = toTimeUnit
|
||||||
in fromIntegral $ toSeconds timeLimit
|
in fromIntegral $ toSeconds timeLimit
|
||||||
prepareToVerifyHttpSig requires wants seconds now
|
prepareToVerifyHttpSig requires wants seconds now
|
||||||
|
|
||||||
(remoteAuthor, body) <-
|
(remoteAuthor, body) <-
|
||||||
withExceptT T.pack $
|
withExceptT T.pack $
|
||||||
(,) <$> verifyActorSig proof
|
(,) <$> verifyActorSig proof
|
||||||
|
@ -429,21 +430,13 @@ authenticateActivity now = do
|
||||||
Right wv -> return wv
|
Right wv -> return wv
|
||||||
return (remoteAuthor, wvdoc, body)
|
return (remoteAuthor, wvdoc, body)
|
||||||
let WithValue raw (Doc hActivity activity) = wv
|
let WithValue raw (Doc hActivity activity) = wv
|
||||||
uSender = remoteAuthorURI ra
|
uSender@(ObjURI hSender luSender) = remoteAuthorURI ra
|
||||||
ObjURI hSender luSender = uSender
|
luAuthor = activityActor activity
|
||||||
auth <-
|
auth <-
|
||||||
if hSender == hActivity
|
case (hSender == hActivity, luSender == luAuthor) of
|
||||||
then do
|
(False, _) -> do
|
||||||
unless (activityActor activity == luSender) $
|
-- Sender and author are on different hosts, therefore require
|
||||||
throwE $ T.concat
|
-- a valid forwarded signature that approves the forwarding
|
||||||
[ "Activity's actor <"
|
|
||||||
, renderObjURI $
|
|
||||||
ObjURI hActivity $ activityActor activity
|
|
||||||
, "> != Signature key's actor <", renderObjURI uSender
|
|
||||||
, ">"
|
|
||||||
]
|
|
||||||
return $ ActivityAuthRemote ra
|
|
||||||
else do
|
|
||||||
ma <- checkForward uSender hActivity (activityActor activity)
|
ma <- checkForward uSender hActivity (activityActor activity)
|
||||||
case ma of
|
case ma of
|
||||||
Nothing -> throwE $ T.concat
|
Nothing -> throwE $ T.concat
|
||||||
|
@ -452,6 +445,28 @@ authenticateActivity now = do
|
||||||
, renderAuthority hSender, ">"
|
, renderAuthority hSender, ">"
|
||||||
]
|
]
|
||||||
Just a -> return a
|
Just a -> return a
|
||||||
|
(True, False) -> do
|
||||||
|
-- Sender and author are different actors on the same host,
|
||||||
|
-- therefore we approve the forwarding without a signature
|
||||||
|
hl <- hostIsLocalOld hActivity
|
||||||
|
if hl
|
||||||
|
then ActivityAuthLocal <$> do
|
||||||
|
route <- parseLocalURI luAuthor
|
||||||
|
parseLocalActorE route
|
||||||
|
else ActivityAuthRemote <$> do
|
||||||
|
let uAuthor = ObjURI hActivity luAuthor
|
||||||
|
instanceID = remoteAuthorInstance ra
|
||||||
|
remoteActorID <- do
|
||||||
|
result <- ExceptT $ first (T.pack . displayException) <$> fetchRemoteActor instanceID hActivity luAuthor
|
||||||
|
case result of
|
||||||
|
Left Nothing -> throwE "Author @id mismatch"
|
||||||
|
Left (Just err) -> throwE $ T.pack $ displayException err
|
||||||
|
Right Nothing -> throwE "Author isn't an actor"
|
||||||
|
Right (Just actor) -> return $ entityKey actor
|
||||||
|
return $ RemoteAuthor uAuthor instanceID remoteActorID
|
||||||
|
(True, True) ->
|
||||||
|
-- Sender and author are the same actor
|
||||||
|
pure $ ActivityAuthRemote ra
|
||||||
|
|
||||||
-- Verify FEP-8b32 jcs-eddsa-2022 VC data integrity proof
|
-- Verify FEP-8b32 jcs-eddsa-2022 VC data integrity proof
|
||||||
for_ (AP.activityProof activity) $ \ proof -> do
|
for_ (AP.activityProof activity) $ \ proof -> do
|
||||||
|
|
|
@ -176,7 +176,8 @@ personCreateNoteF
|
||||||
-> AP.Note URIMode
|
-> AP.Note URIMode
|
||||||
-> ExceptT Text Handler Text
|
-> ExceptT Text Handler Text
|
||||||
personCreateNoteF now recipPersonHash author body mfwd luCreate note = do
|
personCreateNoteF now recipPersonHash author body mfwd luCreate note = do
|
||||||
|
error "personCreateNoteF disabled for refactoring"
|
||||||
|
{-
|
||||||
-- Check input
|
-- Check input
|
||||||
recipPersonID <- decodeKeyHashid404 recipPersonHash
|
recipPersonID <- decodeKeyHashid404 recipPersonHash
|
||||||
(luNote, published, Comment maybeParent topic source content) <- do
|
(luNote, published, Comment maybeParent topic source content) <- do
|
||||||
|
@ -240,6 +241,7 @@ personCreateNoteF now recipPersonHash author body mfwd luCreate note = do
|
||||||
did <- fromMaybeE mdid "Remote parent known, but no context RemoteDiscussion"
|
did <- fromMaybeE mdid "Remote parent known, but no context RemoteDiscussion"
|
||||||
unless (messageRoot m == did) $
|
unless (messageRoot m == did) $
|
||||||
throwE "Remote parent belongs to a different discussion"
|
throwE "Remote parent belongs to a different discussion"
|
||||||
|
-}
|
||||||
|
|
||||||
deckCreateNoteF
|
deckCreateNoteF
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
|
@ -251,7 +253,8 @@ deckCreateNoteF
|
||||||
-> AP.Note URIMode
|
-> AP.Note URIMode
|
||||||
-> ExceptT Text Handler Text
|
-> ExceptT Text Handler Text
|
||||||
deckCreateNoteF now recipDeckHash author body mfwd luCreate note = do
|
deckCreateNoteF now recipDeckHash author body mfwd luCreate note = do
|
||||||
|
error "deckCreateNoteF disabled for refactoring"
|
||||||
|
{-
|
||||||
recipDeckID <- decodeKeyHashid404 recipDeckHash
|
recipDeckID <- decodeKeyHashid404 recipDeckHash
|
||||||
(luNote, published, Comment maybeParent topic source content) <- do
|
(luNote, published, Comment maybeParent topic source content) <- do
|
||||||
(luId, luAuthor, published, comment) <- parseRemoteCommentOld note
|
(luId, luAuthor, published, comment) <- parseRemoteCommentOld note
|
||||||
|
@ -309,6 +312,7 @@ deckCreateNoteF now recipDeckHash author body mfwd luCreate note = do
|
||||||
Right forwardHttp -> do
|
Right forwardHttp -> do
|
||||||
forkWorker "projectCreateNoteF inbox-forwarding" forwardHttp
|
forkWorker "projectCreateNoteF inbox-forwarding" forwardHttp
|
||||||
return "Stored to inbox, cached comment, and did inbox forwarding"
|
return "Stored to inbox, cached comment, and did inbox forwarding"
|
||||||
|
-}
|
||||||
|
|
||||||
loomCreateNoteF
|
loomCreateNoteF
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
|
@ -320,7 +324,8 @@ loomCreateNoteF
|
||||||
-> AP.Note URIMode
|
-> AP.Note URIMode
|
||||||
-> ExceptT Text Handler Text
|
-> ExceptT Text Handler Text
|
||||||
loomCreateNoteF now recipLoomHash author body mfwd luCreate note = do
|
loomCreateNoteF now recipLoomHash author body mfwd luCreate note = do
|
||||||
|
error "loomCreateNoteF disabled for refactoring"
|
||||||
|
{-
|
||||||
recipLoomID <- decodeKeyHashid404 recipLoomHash
|
recipLoomID <- decodeKeyHashid404 recipLoomHash
|
||||||
(luNote, published, Comment maybeParent topic source content) <- do
|
(luNote, published, Comment maybeParent topic source content) <- do
|
||||||
(luId, luAuthor, published, comment) <- parseRemoteCommentOld note
|
(luId, luAuthor, published, comment) <- parseRemoteCommentOld note
|
||||||
|
@ -378,3 +383,4 @@ loomCreateNoteF now recipLoomHash author body mfwd luCreate note = do
|
||||||
Right forwardHttp -> do
|
Right forwardHttp -> do
|
||||||
forkWorker "projectCreateNoteF inbox-forwarding" forwardHttp
|
forkWorker "projectCreateNoteF inbox-forwarding" forwardHttp
|
||||||
return "Stored to inbox, cached comment, and did inbox forwarding"
|
return "Stored to inbox, cached comment, and did inbox forwarding"
|
||||||
|
-}
|
||||||
|
|
|
@ -500,7 +500,8 @@ loomUndoF
|
||||||
-> AP.Undo URIMode
|
-> AP.Undo URIMode
|
||||||
-> ExceptT Text Handler Text
|
-> ExceptT Text Handler Text
|
||||||
loomUndoF now recipLoomHash author body mfwd luUndo (AP.Undo uObject) = do
|
loomUndoF now recipLoomHash author body mfwd luUndo (AP.Undo uObject) = do
|
||||||
|
error "loomUndoF disabled for refactoring"
|
||||||
|
{-
|
||||||
-- Check input
|
-- Check input
|
||||||
recipLoomID <- decodeKeyHashid404 recipLoomHash
|
recipLoomID <- decodeKeyHashid404 recipLoomHash
|
||||||
undone <-
|
undone <-
|
||||||
|
@ -700,6 +701,7 @@ loomUndoF now recipLoomHash author body mfwd luUndo (AP.Undo uObject) = do
|
||||||
}
|
}
|
||||||
|
|
||||||
return (action, recipientSet, remoteActors, fwdHosts)
|
return (action, recipientSet, remoteActors, fwdHosts)
|
||||||
|
-}
|
||||||
|
|
||||||
repoUndoF
|
repoUndoF
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
|
@ -711,7 +713,8 @@ repoUndoF
|
||||||
-> AP.Undo URIMode
|
-> AP.Undo URIMode
|
||||||
-> ExceptT Text Handler Text
|
-> ExceptT Text Handler Text
|
||||||
repoUndoF now recipRepoHash author body mfwd luUndo (AP.Undo uObject) = do
|
repoUndoF now recipRepoHash author body mfwd luUndo (AP.Undo uObject) = do
|
||||||
|
error "repoUndoF disabled for refactoring"
|
||||||
|
{-
|
||||||
-- Check input
|
-- Check input
|
||||||
recipRepoID <- decodeKeyHashid404 recipRepoHash
|
recipRepoID <- decodeKeyHashid404 recipRepoHash
|
||||||
undone <-
|
undone <-
|
||||||
|
@ -839,3 +842,4 @@ repoUndoF now recipRepoHash author body mfwd luUndo (AP.Undo uObject) = do
|
||||||
}
|
}
|
||||||
|
|
||||||
return (action, recipientSet, remoteActors, fwdHosts)
|
return (action, recipientSet, remoteActors, fwdHosts)
|
||||||
|
-}
|
||||||
|
|
|
@ -335,7 +335,8 @@ deckOfferTicketF
|
||||||
-> FedURI
|
-> FedURI
|
||||||
-> ExceptT Text Handler Text
|
-> ExceptT Text Handler Text
|
||||||
deckOfferTicketF now recipDeckHash author body mfwd luOffer ticket uTarget = do
|
deckOfferTicketF now recipDeckHash author body mfwd luOffer ticket uTarget = do
|
||||||
|
error "deckOfferTicketF disabled for refactoring"
|
||||||
|
{-
|
||||||
-- Check input
|
-- Check input
|
||||||
recipDeckID <- decodeKeyHashid404 recipDeckHash
|
recipDeckID <- decodeKeyHashid404 recipDeckHash
|
||||||
(title, desc, source) <- do
|
(title, desc, source) <- do
|
||||||
|
@ -474,6 +475,7 @@ deckOfferTicketF now recipDeckHash author body mfwd luOffer ticket uTarget = do
|
||||||
}
|
}
|
||||||
|
|
||||||
return (action, recipientSet, remoteActors, fwdHosts)
|
return (action, recipientSet, remoteActors, fwdHosts)
|
||||||
|
-}
|
||||||
|
|
||||||
activityAlreadyInInbox hAct luAct inboxID = fmap isJust . runMaybeT $ do
|
activityAlreadyInInbox hAct luAct inboxID = fmap isJust . runMaybeT $ do
|
||||||
instanceID <- MaybeT $ getKeyBy $ UniqueInstance hAct
|
instanceID <- MaybeT $ getKeyBy $ UniqueInstance hAct
|
||||||
|
@ -492,7 +494,8 @@ loomOfferTicketF
|
||||||
-> FedURI
|
-> FedURI
|
||||||
-> ExceptT Text Handler (Text, Maybe (ExceptT Text Worker Text))
|
-> ExceptT Text Handler (Text, Maybe (ExceptT Text Worker Text))
|
||||||
loomOfferTicketF now recipLoomHash author body mfwd luOffer ticket uTarget = do
|
loomOfferTicketF now recipLoomHash author body mfwd luOffer ticket uTarget = do
|
||||||
|
error "loomOfferTicketF disabled for refactoring"
|
||||||
|
{-
|
||||||
-- Check input
|
-- Check input
|
||||||
recipLoomID <- decodeKeyHashid404 recipLoomHash
|
recipLoomID <- decodeKeyHashid404 recipLoomHash
|
||||||
(title, desc, source, originTipOrBundle, targetRepoID, maybeTargetBranch) <- do
|
(title, desc, source, originTipOrBundle, targetRepoID, maybeTargetBranch) <- do
|
||||||
|
@ -808,6 +811,7 @@ loomOfferTicketF now recipLoomHash author body mfwd luOffer ticket uTarget = do
|
||||||
}
|
}
|
||||||
|
|
||||||
return (action, recipientSet, remoteActors, fwdHosts)
|
return (action, recipientSet, remoteActors, fwdHosts)
|
||||||
|
-}
|
||||||
|
|
||||||
repoOfferTicketF
|
repoOfferTicketF
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
|
@ -1130,7 +1134,8 @@ loomApplyF
|
||||||
-> AP.Apply URIMode
|
-> AP.Apply URIMode
|
||||||
-> ExceptT Text Handler (Text, Maybe (ExceptT Text Worker Text))
|
-> ExceptT Text Handler (Text, Maybe (ExceptT Text Worker Text))
|
||||||
loomApplyF now recipLoomHash author body mfwd luApply apply = (,Nothing) <$> do
|
loomApplyF now recipLoomHash author body mfwd luApply apply = (,Nothing) <$> do
|
||||||
|
error "loomApplyF disabled for refactoring"
|
||||||
|
{-
|
||||||
-- Check input
|
-- Check input
|
||||||
recipLoomID <- decodeKeyHashid404 recipLoomHash
|
recipLoomID <- decodeKeyHashid404 recipLoomHash
|
||||||
(repoID, maybeBranch, clothID, bundleID) <- do
|
(repoID, maybeBranch, clothID, bundleID) <- do
|
||||||
|
@ -1295,6 +1300,7 @@ loomApplyF now recipLoomHash author body mfwd luApply apply = (,Nothing) <$> do
|
||||||
}
|
}
|
||||||
|
|
||||||
return (action, recipientSet, remoteActors, fwdHosts)
|
return (action, recipientSet, remoteActors, fwdHosts)
|
||||||
|
-}
|
||||||
|
|
||||||
personOfferDepF
|
personOfferDepF
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
|
@ -1899,7 +1905,8 @@ trackerResolveF
|
||||||
-> AP.Resolve URIMode
|
-> AP.Resolve URIMode
|
||||||
-> ExceptT Text Handler (Text, Maybe (ExceptT Text Worker Text))
|
-> ExceptT Text Handler (Text, Maybe (ExceptT Text Worker Text))
|
||||||
trackerResolveF maybeWorkItem grabActor getWorkItem makeResource trackerFollowers itemFollowers makeLocalActor now recipHash author body mfwd luResolve (AP.Resolve uObject) = (,Nothing) <$> do
|
trackerResolveF maybeWorkItem grabActor getWorkItem makeResource trackerFollowers itemFollowers makeLocalActor now recipHash author body mfwd luResolve (AP.Resolve uObject) = (,Nothing) <$> do
|
||||||
|
error "trackerResolveF disabled for refactoring"
|
||||||
|
{-
|
||||||
-- Check input
|
-- Check input
|
||||||
recipID <- decodeKeyHashid404 recipHash
|
recipID <- decodeKeyHashid404 recipHash
|
||||||
wiID <- nameExceptT "Resolve object" $ do
|
wiID <- nameExceptT "Resolve object" $ do
|
||||||
|
@ -2053,6 +2060,7 @@ trackerResolveF maybeWorkItem grabActor getWorkItem makeResource trackerFollower
|
||||||
}
|
}
|
||||||
|
|
||||||
return (action, recipientSet, remoteActors, fwdHosts)
|
return (action, recipientSet, remoteActors, fwdHosts)
|
||||||
|
-}
|
||||||
|
|
||||||
deckResolveF
|
deckResolveF
|
||||||
:: UTCTime
|
:: UTCTime
|
||||||
|
|
|
@ -15,12 +15,12 @@
|
||||||
|
|
||||||
module Vervis.Federation.Util
|
module Vervis.Federation.Util
|
||||||
( insertToInbox
|
( insertToInbox
|
||||||
, insertToInbox'
|
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Control.Monad.IO.Class
|
import Control.Monad.IO.Class
|
||||||
import Control.Monad.Trans.Reader
|
import Control.Monad.Trans.Reader
|
||||||
|
import Data.ByteString (ByteString)
|
||||||
import Data.Either
|
import Data.Either
|
||||||
import Data.Time.Clock
|
import Data.Time.Clock
|
||||||
import Database.Persist
|
import Database.Persist
|
||||||
|
@ -36,30 +36,32 @@ import Vervis.Federation.Auth
|
||||||
import Vervis.Foundation
|
import Vervis.Foundation
|
||||||
import Vervis.Model
|
import Vervis.Model
|
||||||
|
|
||||||
-- | Insert a remote activity delivered to us into our inbox. Return its
|
-- | Insert an activity delivered to us into our inbox. Return its
|
||||||
-- database ID if the activity wasn't already in our inbox.
|
-- database ID if the activity wasn't already in our inbox.
|
||||||
insertToInbox
|
insertToInbox
|
||||||
:: MonadIO m
|
:: UTCTime
|
||||||
=> UTCTime
|
-> Either
|
||||||
-> RemoteAuthor
|
(LocalActorBy Key, ActorId, OutboxItemId)
|
||||||
|
(RemoteAuthor, LocalURI, Maybe ByteString)
|
||||||
-> ActivityBody
|
-> ActivityBody
|
||||||
-> InboxId
|
-> InboxId
|
||||||
-> LocalURI
|
|
||||||
-> Bool
|
-> Bool
|
||||||
-> ReaderT SqlBackend m (Maybe RemoteActivityId)
|
-> ActDB
|
||||||
insertToInbox now author body ibid luAct unread =
|
(Maybe
|
||||||
fmap fst <$> insertToInbox' now author body ibid luAct unread
|
(Either
|
||||||
|
(LocalActorBy Key, ActorId, OutboxItemId)
|
||||||
insertToInbox'
|
(RemoteAuthor, LocalURI, RemoteActivityId)
|
||||||
:: MonadIO m
|
)
|
||||||
=> UTCTime
|
)
|
||||||
-> RemoteAuthor
|
insertToInbox now (Left a@(_, _, outboxItemID)) body inboxID unread = do
|
||||||
-> ActivityBody
|
inboxItemID <- insert $ InboxItem unread now
|
||||||
-> InboxId
|
maybeItem <- insertUnique $ InboxItemLocal inboxID outboxItemID inboxItemID
|
||||||
-> LocalURI
|
case maybeItem of
|
||||||
-> Bool
|
Nothing -> do
|
||||||
-> ReaderT SqlBackend m (Maybe (RemoteActivityId, InboxItemId))
|
delete inboxItemID
|
||||||
insertToInbox' now author body ibid luAct unread = do
|
return Nothing
|
||||||
|
Just _ -> return $ Just $ Left a
|
||||||
|
insertToInbox now (Right (author, luAct, _)) body inboxID unread = do
|
||||||
let iidAuthor = remoteAuthorInstance author
|
let iidAuthor = remoteAuthorInstance author
|
||||||
roid <-
|
roid <-
|
||||||
either entityKey id <$> insertBy' (RemoteObject iidAuthor luAct)
|
either entityKey id <$> insertBy' (RemoteObject iidAuthor luAct)
|
||||||
|
@ -69,9 +71,9 @@ insertToInbox' now author body ibid luAct unread = do
|
||||||
, remoteActivityReceived = now
|
, remoteActivityReceived = now
|
||||||
}
|
}
|
||||||
ibiid <- insert $ InboxItem unread now
|
ibiid <- insert $ InboxItem unread now
|
||||||
mibrid <- insertUnique $ InboxItemRemote ibid ractid ibiid
|
mibrid <- insertUnique $ InboxItemRemote inboxID ractid ibiid
|
||||||
case mibrid of
|
case mibrid of
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
delete ibiid
|
delete ibiid
|
||||||
return Nothing
|
return Nothing
|
||||||
Just _ -> return $ Just (ractid, ibiid)
|
Just _ -> return $ Just $ Right (author, luAct, ractid)
|
||||||
|
|
|
@ -2936,6 +2936,8 @@ changes hLocal ctx =
|
||||||
, removeField "Ticket" "status"
|
, removeField "Ticket" "status"
|
||||||
-- 530
|
-- 530
|
||||||
, addEntities model_530_join
|
, addEntities model_530_join
|
||||||
|
-- 531
|
||||||
|
, addEntities model_531_follow_request
|
||||||
]
|
]
|
||||||
|
|
||||||
migrateDB
|
migrateDB
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{- This file is part of Vervis.
|
{- This file is part of Vervis.
|
||||||
-
|
-
|
||||||
- Written in 2018, 2019, 2020, 2022 by fr33domlover <fr33domlover@riseup.net>.
|
- Written in 2018, 2019, 2020, 2022, 2023
|
||||||
|
- by fr33domlover <fr33domlover@riseup.net>.
|
||||||
-
|
-
|
||||||
- ♡ Copying is an act of love. Please copy, reuse and share.
|
- ♡ Copying is an act of love. Please copy, reuse and share.
|
||||||
-
|
-
|
||||||
|
@ -60,6 +61,7 @@ module Vervis.Migration.Entities
|
||||||
, model_497_sigkey
|
, model_497_sigkey
|
||||||
, model_508_invite
|
, model_508_invite
|
||||||
, model_530_join
|
, model_530_join
|
||||||
|
, model_531_follow_request
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
|
@ -235,3 +237,6 @@ model_508_invite = $(schema "508_2022-10-19_invite")
|
||||||
|
|
||||||
model_530_join :: [Entity SqlBackend]
|
model_530_join :: [Entity SqlBackend]
|
||||||
model_530_join = $(schema "530_2022-11-01_join")
|
model_530_join = $(schema "530_2022-11-01_join")
|
||||||
|
|
||||||
|
model_531_follow_request :: [Entity SqlBackend]
|
||||||
|
model_531_follow_request = $(schema "531_2023-06-15_follow_request")
|
||||||
|
|
|
@ -85,6 +85,7 @@ module Vervis.Recipient
|
||||||
, ParsedAudience (..)
|
, ParsedAudience (..)
|
||||||
, concatRecipients
|
, concatRecipients
|
||||||
, parseAudience
|
, parseAudience
|
||||||
|
, parseAudience'
|
||||||
|
|
||||||
-- * Creating a recipient set, supporting both local and remote recips
|
-- * Creating a recipient set, supporting both local and remote recips
|
||||||
, Aud (..)
|
, Aud (..)
|
||||||
|
@ -93,6 +94,7 @@ module Vervis.Recipient
|
||||||
where
|
where
|
||||||
|
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
|
import Control.Concurrent.Actor
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Monad.Trans.Except
|
import Control.Monad.Trans.Except
|
||||||
import Control.Monad.Trans.Maybe
|
import Control.Monad.Trans.Maybe
|
||||||
|
@ -108,6 +110,7 @@ import Data.Semigroup
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Data.These
|
import Data.These
|
||||||
import Data.Traversable
|
import Data.Traversable
|
||||||
|
import Data.Typeable
|
||||||
import Database.Persist
|
import Database.Persist
|
||||||
import Database.Persist.Sql
|
import Database.Persist.Sql
|
||||||
import GHC.Generics
|
import GHC.Generics
|
||||||
|
@ -127,6 +130,7 @@ import Yesod.Hashids
|
||||||
import Yesod.MonadSite
|
import Yesod.MonadSite
|
||||||
|
|
||||||
import qualified Web.ActivityPub as AP
|
import qualified Web.ActivityPub as AP
|
||||||
|
import qualified Web.Actor as WA
|
||||||
|
|
||||||
import Data.List.Local
|
import Data.List.Local
|
||||||
import Data.List.NonEmpty.Local
|
import Data.List.NonEmpty.Local
|
||||||
|
@ -143,6 +147,15 @@ import Vervis.FedURI
|
||||||
import Vervis.Foundation
|
import Vervis.Foundation
|
||||||
import Vervis.Model
|
import Vervis.Model
|
||||||
|
|
||||||
|
instance WA.StageWebRoute Env where
|
||||||
|
type StageRoute Env = Route App
|
||||||
|
askUrlRenderParams = do
|
||||||
|
Env _ _ _ _ _ render _ _ <- askEnv
|
||||||
|
case cast render of
|
||||||
|
Nothing -> error "Env site isn't App"
|
||||||
|
Just r -> pure r
|
||||||
|
pageParamName _ = "page"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Actor and collection-of-actors types
|
-- Actor and collection-of-actors types
|
||||||
--
|
--
|
||||||
|
@ -785,6 +798,48 @@ parseRecipients recips = do
|
||||||
Nothing -> Left route
|
Nothing -> Left route
|
||||||
Just recip -> Right recip
|
Just recip -> Right recip
|
||||||
|
|
||||||
|
parseRecipients'
|
||||||
|
:: WA.StageRoute Env ~ Route App
|
||||||
|
=> NonEmpty FedURI -> ActE (RecipientRoutes, [FedURI])
|
||||||
|
parseRecipients' recips = do
|
||||||
|
hLocal <- asksEnv WA.stageInstanceHost
|
||||||
|
let (locals, remotes) = splitRecipients hLocal recips
|
||||||
|
(lusInvalid, routesInvalid, localsSet) = parseLocalRecipients locals
|
||||||
|
unless (null lusInvalid) $
|
||||||
|
throwE $
|
||||||
|
"Local recipients are invalid routes: " <>
|
||||||
|
T.pack (show $ map (renderObjURI . ObjURI hLocal) lusInvalid)
|
||||||
|
unless (null routesInvalid) $ do
|
||||||
|
renderUrl <- WA.askUrlRender
|
||||||
|
throwE $
|
||||||
|
"Local recipients are non-recipient routes: " <>
|
||||||
|
T.pack (show $ map renderUrl routesInvalid)
|
||||||
|
return (localsSet, remotes)
|
||||||
|
where
|
||||||
|
splitRecipients :: Host -> NonEmpty FedURI -> ([LocalURI], [FedURI])
|
||||||
|
splitRecipients home recips =
|
||||||
|
let (local, remote) = NE.partition ((== home) . objUriAuthority) recips
|
||||||
|
in (map objUriLocal local, remote)
|
||||||
|
|
||||||
|
parseLocalRecipients
|
||||||
|
:: [LocalURI] -> ([LocalURI], [Route App], RecipientRoutes)
|
||||||
|
parseLocalRecipients lus =
|
||||||
|
let (lusInvalid, routes) = partitionEithers $ map parseRoute lus
|
||||||
|
(routesInvalid, recips) = partitionEithers $ map parseRecip routes
|
||||||
|
(actors, stages) = partitionEithers recips
|
||||||
|
grouped =
|
||||||
|
map recipientFromActor actors ++ map recipientFromStage stages
|
||||||
|
in (lusInvalid, routesInvalid, groupLocalRecipients grouped)
|
||||||
|
where
|
||||||
|
parseRoute lu =
|
||||||
|
case decodeRouteLocal lu of
|
||||||
|
Nothing -> Left lu
|
||||||
|
Just route -> Right route
|
||||||
|
parseRecip route =
|
||||||
|
case parseLocalRecipient route of
|
||||||
|
Nothing -> Left route
|
||||||
|
Just recip -> Right recip
|
||||||
|
|
||||||
parseAudience
|
parseAudience
|
||||||
:: (MonadSite m, SiteEnv m ~ App)
|
:: (MonadSite m, SiteEnv m ~ App)
|
||||||
=> AP.Audience URIMode
|
=> AP.Audience URIMode
|
||||||
|
@ -811,6 +866,31 @@ parseAudience audience = do
|
||||||
groupByHost :: [FedURI] -> [(Host, NonEmpty LocalURI)]
|
groupByHost :: [FedURI] -> [(Host, NonEmpty LocalURI)]
|
||||||
groupByHost = groupAllExtract objUriAuthority objUriLocal
|
groupByHost = groupAllExtract objUriAuthority objUriLocal
|
||||||
|
|
||||||
|
parseAudience'
|
||||||
|
:: WA.StageRoute Env ~ Route App
|
||||||
|
=> AP.Audience URIMode -> ActE (Maybe (ParsedAudience URIMode))
|
||||||
|
parseAudience' audience = do
|
||||||
|
let recips = concatRecipients audience
|
||||||
|
for (nonEmpty recips) $ \ recipsNE -> do
|
||||||
|
(localsSet, remotes) <- parseRecipients' recipsNE
|
||||||
|
let remotesGrouped =
|
||||||
|
groupByHost $ remotes \\ AP.audienceNonActors audience
|
||||||
|
hosts = map fst remotesGrouped
|
||||||
|
return ParsedAudience
|
||||||
|
{ paudLocalRecips = localsSet
|
||||||
|
, paudRemoteActors = remotesGrouped
|
||||||
|
, paudBlinded =
|
||||||
|
audience { AP.audienceBto = [], AP.audienceBcc = [] }
|
||||||
|
, paudFwdHosts =
|
||||||
|
let nonActorHosts =
|
||||||
|
LO.nubSort $
|
||||||
|
map objUriAuthority $ AP.audienceNonActors audience
|
||||||
|
in LO.isect hosts nonActorHosts
|
||||||
|
}
|
||||||
|
where
|
||||||
|
groupByHost :: [FedURI] -> [(Host, NonEmpty LocalURI)]
|
||||||
|
groupByHost = groupAllExtract objUriAuthority objUriLocal
|
||||||
|
|
||||||
data Aud u
|
data Aud u
|
||||||
= AudLocal [LocalActor] [LocalStage]
|
= AudLocal [LocalActor] [LocalStage]
|
||||||
| AudRemote (Authority u) [LocalURI] [LocalURI]
|
| AudRemote (Authority u) [LocalURI] [LocalURI]
|
||||||
|
|
|
@ -95,7 +95,7 @@ import Yesod.Persist.Local
|
||||||
import qualified Data.Aeson.Encode.Pretty.ToEncoding as P
|
import qualified Data.Aeson.Encode.Pretty.ToEncoding as P
|
||||||
import qualified Web.ActivityPub as AP
|
import qualified Web.ActivityPub as AP
|
||||||
|
|
||||||
import Vervis.Actor (RemoteAuthor (..), ActivityBody (..), VerseRemote (..), Event (..))
|
import Vervis.Actor (RemoteAuthor (..), ActivityBody (..), Verse (..))
|
||||||
import Vervis.ActivityPub
|
import Vervis.ActivityPub
|
||||||
import Vervis.API
|
import Vervis.API
|
||||||
import Vervis.Data.Actor
|
import Vervis.Data.Actor
|
||||||
|
@ -106,6 +106,7 @@ import Vervis.Foundation
|
||||||
import Vervis.Model hiding (Ticket)
|
import Vervis.Model hiding (Ticket)
|
||||||
import Vervis.Model.Ident
|
import Vervis.Model.Ident
|
||||||
import Vervis.Paginate
|
import Vervis.Paginate
|
||||||
|
import Vervis.Persist.Actor
|
||||||
import Vervis.Recipient
|
import Vervis.Recipient
|
||||||
import Vervis.Settings
|
import Vervis.Settings
|
||||||
import Vervis.Ticket
|
import Vervis.Ticket
|
||||||
|
@ -236,26 +237,27 @@ postInbox recipByKey = do
|
||||||
now <- liftIO getCurrentTime
|
now <- liftIO getCurrentTime
|
||||||
result <- runExceptT $ do
|
result <- runExceptT $ do
|
||||||
(auth, body) <- authenticateActivity now
|
(auth, body) <- authenticateActivity now
|
||||||
verse <-
|
authorIdMsig <-
|
||||||
case auth of
|
case auth of
|
||||||
ActivityAuthLocal authorByKey -> Left <$> do
|
ActivityAuthLocal authorByKey -> Left <$> do
|
||||||
outboxItemID <-
|
outboxItemID <-
|
||||||
parseAuthenticatedLocalActivityURI
|
parseAuthenticatedLocalActivityURI
|
||||||
authorByKey
|
authorByKey
|
||||||
(AP.activityId $ actbActivity body)
|
(AP.activityId $ actbActivity body)
|
||||||
return $ EventRemoteFwdLocalActivity authorByKey outboxItemID
|
actorID <- do
|
||||||
|
ment <- lift $ runDB $ getLocalActorEntity authorByKey
|
||||||
|
case ment of
|
||||||
|
Nothing -> throwE "Author not found in DB"
|
||||||
|
Just ent -> return $ localActorID ent
|
||||||
|
return (authorByKey, actorID, outboxItemID)
|
||||||
ActivityAuthRemote author -> Right <$> do
|
ActivityAuthRemote author -> Right <$> do
|
||||||
luActivity <-
|
luActivity <-
|
||||||
fromMaybeE (AP.activityId $ actbActivity body) "Activity without 'id'"
|
fromMaybeE (AP.activityId $ actbActivity body) "Activity without 'id'"
|
||||||
localRecips <- do
|
|
||||||
mrecips <- parseAudience $ AP.activityAudience $ actbActivity body
|
|
||||||
paudLocalRecips <$> fromMaybeE mrecips "Activity with no recipients"
|
|
||||||
recipByHash <- hashLocalActor recipByKey
|
recipByHash <- hashLocalActor recipByKey
|
||||||
msig <- checkForwarding recipByHash
|
msig <- checkForwarding recipByHash
|
||||||
let mfwd = (localRecips,) <$> msig
|
return (author, luActivity, msig)
|
||||||
return $ VerseRemote author body mfwd luActivity
|
|
||||||
theater <- getsYesod appTheater
|
theater <- getsYesod appTheater
|
||||||
r <- liftIO $ callIO theater recipByKey verse
|
r <- liftIO $ callIO theater recipByKey $ Verse authorIdMsig body
|
||||||
case r of
|
case r of
|
||||||
Nothing -> notFound
|
Nothing -> notFound
|
||||||
Just (Left e) -> throwE e
|
Just (Left e) -> throwE e
|
||||||
|
|
|
@ -83,7 +83,7 @@ import Data.Maybe.Local
|
||||||
import Data.Tuple.Local
|
import Data.Tuple.Local
|
||||||
import Database.Persist.Local
|
import Database.Persist.Local
|
||||||
|
|
||||||
import Vervis.Actor (Event)
|
--import Vervis.Actor
|
||||||
import Vervis.ActivityPub
|
import Vervis.ActivityPub
|
||||||
import Vervis.Data.Actor
|
import Vervis.Data.Actor
|
||||||
import Vervis.FedURI
|
import Vervis.FedURI
|
||||||
|
|
|
@ -106,6 +106,7 @@ module Web.ActivityPub
|
||||||
, hForwardedSignature
|
, hForwardedSignature
|
||||||
, Envelope ()
|
, Envelope ()
|
||||||
, Errand ()
|
, Errand ()
|
||||||
|
, encodeForwardingSigHeader
|
||||||
, sending
|
, sending
|
||||||
, retrying
|
, retrying
|
||||||
, deliver
|
, deliver
|
||||||
|
@ -2223,7 +2224,7 @@ httpPostAP manager headers keyid sign uSender value =
|
||||||
data ForwardMode u
|
data ForwardMode u
|
||||||
= SendNoForward
|
= SendNoForward
|
||||||
| SendAllowForward LocalURI
|
| SendAllowForward LocalURI
|
||||||
| ForwardBy (ObjURI u) ByteString
|
| ForwardBy (ObjURI u) (Maybe ByteString)
|
||||||
|
|
||||||
data Envelope u = Envelope
|
data Envelope u = Envelope
|
||||||
{ envelopeKey :: RefURI u
|
{ envelopeKey :: RefURI u
|
||||||
|
@ -2238,9 +2239,30 @@ data Errand u = Errand
|
||||||
, errandHolder :: Bool
|
, errandHolder :: Bool
|
||||||
, errandFwder :: LocalURI
|
, errandFwder :: LocalURI
|
||||||
, errandBody :: BL.ByteString
|
, errandBody :: BL.ByteString
|
||||||
, errandProof :: ByteString
|
, errandProof :: Maybe ByteString
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- | Produce a 'hForwardingSignature' header value for use when forwarding a
|
||||||
|
-- local activity, i.e. an activity of another local actor.
|
||||||
|
encodeForwardingSigHeader
|
||||||
|
:: UriMode u
|
||||||
|
=> UTCTime
|
||||||
|
-> RefURI u
|
||||||
|
-> (ByteString -> S.Signature)
|
||||||
|
-> BL.ByteString
|
||||||
|
-> ObjURI u
|
||||||
|
-> Either S.HttpSigGenError ByteString
|
||||||
|
encodeForwardingSigHeader now ruKey sign body uRecipActor =
|
||||||
|
let digest = formatHttpBodyDigest SHA256 "SHA-256" $ hashlazy body
|
||||||
|
fwder = encodeUtf8 $ renderObjURI uRecipActor
|
||||||
|
req =
|
||||||
|
consHeader hActivityPubForwarder fwder $
|
||||||
|
consHeader hDigest digest defaultRequest
|
||||||
|
keyid = S.KeyId $ TE.encodeUtf8 $ renderRefURI ruKey
|
||||||
|
in signRequestBytes (hDigest :| [hActivityPubForwarder]) Nothing keyid sign now req
|
||||||
|
where
|
||||||
|
consHeader n b r = r { requestHeaders = (n, b) : requestHeaders r }
|
||||||
|
|
||||||
-- | Like 'httpPostAP', except it takes the object as a raw lazy
|
-- | Like 'httpPostAP', except it takes the object as a raw lazy
|
||||||
-- 'BL.ByteString'. It's your responsibility to make sure it's valid JSON.
|
-- 'BL.ByteString'. It's your responsibility to make sure it's valid JSON.
|
||||||
httpPostAPBytes
|
httpPostAPBytes
|
||||||
|
@ -2276,9 +2298,9 @@ httpPostAPBytes manager headers ruKey@(RefURI hKey _) sign mluHolder body fwd uI
|
||||||
except $ first APPostErrorSig $
|
except $ first APPostErrorSig $
|
||||||
signRequestInto hForwardingSignature (hDigest :| [hActivityPubForwarder]) Nothing keyid sign now $
|
signRequestInto hForwardingSignature (hDigest :| [hActivityPubForwarder]) Nothing keyid sign now $
|
||||||
consHeader hActivityPubForwarder (encodeUtf8 $ renderObjURI $ ObjURI hInbox luRecip) req''
|
consHeader hActivityPubForwarder (encodeUtf8 $ renderObjURI $ ObjURI hInbox luRecip) req''
|
||||||
ForwardBy uSender sig ->
|
ForwardBy uSender msig ->
|
||||||
return $
|
return $
|
||||||
consHeader hForwardedSignature sig $
|
maybe id (consHeader hForwardedSignature) msig $
|
||||||
consHeader hActivityPubForwarder (encodeUtf8 $ renderObjURI uSender)
|
consHeader hActivityPubForwarder (encodeUtf8 $ renderObjURI uSender)
|
||||||
req''
|
req''
|
||||||
tryExceptT APPostErrorHTTP $ httpNoBody req''' manager
|
tryExceptT APPostErrorHTTP $ httpNoBody req''' manager
|
||||||
|
@ -2331,16 +2353,16 @@ forwarding
|
||||||
-> Bool
|
-> Bool
|
||||||
-> ObjURI u
|
-> ObjURI u
|
||||||
-> BL.ByteString
|
-> BL.ByteString
|
||||||
-> ByteString
|
-> Maybe ByteString
|
||||||
-> Errand u
|
-> Errand u
|
||||||
forwarding lruKey sign holder (ObjURI hFwder luFwder) body sig =
|
forwarding lruKey sign holder (ObjURI hFwder luFwder) body msig =
|
||||||
Errand
|
Errand
|
||||||
{ errandKey = RefURI hFwder lruKey
|
{ errandKey = RefURI hFwder lruKey
|
||||||
, errandSign = sign
|
, errandSign = sign
|
||||||
, errandHolder = holder
|
, errandHolder = holder
|
||||||
, errandFwder = luFwder
|
, errandFwder = luFwder
|
||||||
, errandBody = body
|
, errandBody = body
|
||||||
, errandProof = sig
|
, errandProof = msig
|
||||||
}
|
}
|
||||||
|
|
||||||
deliver
|
deliver
|
||||||
|
@ -2369,7 +2391,7 @@ forward
|
||||||
-> Errand u
|
-> Errand u
|
||||||
-> ObjURI u
|
-> ObjURI u
|
||||||
-> m (Either APPostError (Response ()))
|
-> m (Either APPostError (Response ()))
|
||||||
forward manager headers (Errand ruKey@(RefURI hKey _) sign holder luFwder body sig) uInbox =
|
forward manager headers (Errand ruKey@(RefURI hKey _) sign holder luFwder body msig) uInbox =
|
||||||
httpPostAPBytes
|
httpPostAPBytes
|
||||||
manager
|
manager
|
||||||
headers
|
headers
|
||||||
|
@ -2377,7 +2399,7 @@ forward manager headers (Errand ruKey@(RefURI hKey _) sign holder luFwder body s
|
||||||
sign
|
sign
|
||||||
(guard holder >> Just luFwder)
|
(guard holder >> Just luFwder)
|
||||||
body
|
body
|
||||||
(ForwardBy (ObjURI hKey luFwder) sig)
|
(ForwardBy (ObjURI hKey luFwder) msig)
|
||||||
uInbox
|
uInbox
|
||||||
|
|
||||||
-- | Result of GETing the keyId URI and processing the JSON document.
|
-- | Result of GETing the keyId URI and processing the JSON document.
|
||||||
|
|
|
@ -193,11 +193,11 @@ prepareToForward
|
||||||
-> Bool
|
-> Bool
|
||||||
-> StageRoute s
|
-> StageRoute s
|
||||||
-> BL.ByteString
|
-> BL.ByteString
|
||||||
-> ByteString
|
-> Maybe ByteString
|
||||||
-> m (AP.Errand u)
|
-> m (AP.Errand u)
|
||||||
prepareToForward keyR sign holder fwderR body sig = do
|
prepareToForward keyR sign holder fwderR body msig = do
|
||||||
encodeRouteLocal <- getEncodeRouteLocal
|
encodeRouteLocal <- getEncodeRouteLocal
|
||||||
encodeRouteHome <- getEncodeRouteHome
|
encodeRouteHome <- getEncodeRouteHome
|
||||||
let lruKey = LocalRefURI $ Left $ encodeRouteLocal keyR
|
let lruKey = LocalRefURI $ Left $ encodeRouteLocal keyR
|
||||||
uFwder = encodeRouteHome fwderR
|
uFwder = encodeRouteHome fwderR
|
||||||
return $ AP.forwarding lruKey sign holder uFwder body sig
|
return $ AP.forwarding lruKey sign holder uFwder body msig
|
||||||
|
|
|
@ -163,6 +163,7 @@ deliverActivityThrow envelope mluFwd uInbox = do
|
||||||
Left e -> liftIO $ throwIO e
|
Left e -> liftIO $ throwIO e
|
||||||
Right response -> return response
|
Right response -> return response
|
||||||
|
|
||||||
|
{-
|
||||||
prepareToForward
|
prepareToForward
|
||||||
:: (MonadSite m, SiteEnv m ~ site, SiteFedURI site, SiteFedURIMode site ~ u)
|
:: (MonadSite m, SiteEnv m ~ site, SiteFedURI site, SiteFedURIMode site ~ u)
|
||||||
=> Route site
|
=> Route site
|
||||||
|
@ -178,6 +179,7 @@ prepareToForward keyR sign holder fwderR body sig = do
|
||||||
let lruKey = LocalRefURI $ Left $ encodeRouteLocal keyR
|
let lruKey = LocalRefURI $ Left $ encodeRouteLocal keyR
|
||||||
uFwder = encodeRouteHome fwderR
|
uFwder = encodeRouteHome fwderR
|
||||||
return $ AP.forwarding lruKey sign holder uFwder body sig
|
return $ AP.forwarding lruKey sign holder uFwder body sig
|
||||||
|
-}
|
||||||
|
|
||||||
forwardActivity
|
forwardActivity
|
||||||
:: ( MonadSite m, SiteEnv m ~ site
|
:: ( MonadSite m, SiteEnv m ~ site
|
||||||
|
|
13
th/models
13
th/models
|
@ -228,11 +228,14 @@ FollowRemote
|
||||||
UniqueFollowRemoteFollow follow
|
UniqueFollowRemoteFollow follow
|
||||||
UniqueFollowRemoteAccept accept
|
UniqueFollowRemoteAccept accept
|
||||||
|
|
||||||
--FollowRequest
|
FollowRequest
|
||||||
-- person PersonId
|
actor ActorId
|
||||||
-- target FollowerSetId
|
target FollowerSetId
|
||||||
--
|
public Bool
|
||||||
-- UniqueFollowRequest person target
|
follow OutboxItemId
|
||||||
|
|
||||||
|
UniqueFollowRequest actor target
|
||||||
|
UniqueFollowRequestFollow follow
|
||||||
|
|
||||||
Follow
|
Follow
|
||||||
actor ActorId
|
actor ActorId
|
||||||
|
|
Loading…
Reference in a new issue