S2S: Group: Implement Create handler, sending back an admin-Grant

This commit is contained in:
Pere Lev 2023-11-21 16:52:16 +02:00
parent ea7476db9d
commit 8d543c0016
No known key found for this signature in database
GPG key ID: 5252C5C863E5E57D
9 changed files with 120 additions and 26 deletions

View file

@ -0,0 +1,5 @@
CollabTopicGroup
collab CollabId
group GroupId
UniqueCollabTopicGroup collab

View file

@ -175,6 +175,9 @@ verifyResourceAddressed localRecips resource = do
verify (GrantResourceProject r) = do verify (GrantResourceProject r) = do
routes <- lookup r $ recipProjects localRecips routes <- lookup r $ recipProjects localRecips
guard $ routeProject routes guard $ routeProject routes
verify (GrantResourceGroup r) = do
routes <- lookup r $ recipGroups localRecips
guard $ routeGroup routes
verifyRemoteAddressed verifyRemoteAddressed
:: Monad m => [(Host, NonEmpty LocalURI)] -> FedURI -> ExceptT Text m () :: Monad m => [(Host, NonEmpty LocalURI)] -> FedURI -> ExceptT Text m ()

View file

@ -18,43 +18,109 @@ module Vervis.Actor.Group
) )
where where
import Control.Applicative
import Control.Exception.Base
import Control.Monad import Control.Monad
import Control.Monad.IO.Class import Control.Monad.IO.Class
import Control.Monad.Logger.CallStack import Control.Monad.Logger.CallStack
import Control.Monad.Trans.Class 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 Data.Barbie
import Data.Bifoldable
import Data.Bifunctor
import Data.Bitraversable
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
import Data.Either
import Data.Foldable import Data.Foldable
import Data.Maybe
import Data.Text (Text) import Data.Text (Text)
import Data.Time.Clock import Data.Time.Clock
import Data.Traversable
import Database.Persist import Database.Persist
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
import qualified Database.Esqueleto as E
import Control.Concurrent.Actor import Control.Concurrent.Actor
import Network.FedURI import Network.FedURI
import Web.Actor
import Web.Actor.Persist
import Yesod.MonadSite import Yesod.MonadSite
import qualified Web.ActivityPub as AP import qualified Web.ActivityPub as AP
import Control.Monad.Trans.Except.Local import Control.Monad.Trans.Except.Local
import Data.Either.Local
import Database.Persist.Local import Database.Persist.Local
import Vervis.Access
import Vervis.ActivityPub
import Vervis.Actor import Vervis.Actor
import Vervis.Actor.Common
import Vervis.Actor2
import Vervis.Cloth import Vervis.Cloth
import Vervis.Data.Actor
import Vervis.Data.Collab
import Vervis.Data.Discussion import Vervis.Data.Discussion
import Vervis.FedURI import Vervis.FedURI
import Vervis.Federation.Util import Vervis.Federation.Util
import Vervis.Foundation import Vervis.Foundation
import Vervis.Model import Vervis.Model hiding (groupCreate)
import Vervis.Recipient (makeRecipientSet, LocalStageBy (..), Aud (..), collectAudience, localActorFollowers, renderLocalActor)
import Vervis.RemoteActorStore
import Vervis.Persist.Actor
import Vervis.Persist.Collab
import Vervis.Persist.Discussion import Vervis.Persist.Discussion
import Vervis.Ticket import Vervis.Ticket
-- Meaning: Someone has created a group with my ID URI
-- Behavior:
-- * Verify I'm in a just-been-created state
-- * Verify my creator and the Create sender are the same actor
-- * Create an admin Collab record in DB
-- * Send an admin Grant to the creator
-- * Get out of the just-been-created state
groupCreateMe
:: UTCTime
-> GroupId
-> Verse
-> ActE (Text, Act (), Next)
groupCreateMe =
topicCreateMe
groupActor GrantResourceGroup
CollabTopicGroupGroup CollabTopicGroup
groupCreate
:: UTCTime
-> GroupId
-> Verse
-> AP.Create URIMode
-> ActE (Text, Act (), Next)
groupCreate now groupID verse (AP.Create obj _muTarget) =
case obj of
AP.CreateTeam _ mlocal -> do
(h, local) <- fromMaybeE mlocal "No group id provided"
let luGroup = AP.actorId local
uMe <- do
groupHash <- encodeKeyHashid groupID
encodeRouteHome <- getEncodeRouteHome
return $ encodeRouteHome $ GroupR groupHash
unless (uMe == ObjURI h luGroup) $
throwE "The created group id isn't me"
groupCreateMe now groupID verse
_ -> throwE "Unsupported Create object for Group"
groupBehavior :: UTCTime -> GroupId -> VerseExt -> ActE (Text, Act (), Next) groupBehavior :: UTCTime -> GroupId -> VerseExt -> ActE (Text, Act (), Next)
groupBehavior now groupID (Left _verse@(Verse _authorIdMsig body)) = groupBehavior now groupID (Left verse@(Verse _authorIdMsig body)) =
case AP.activitySpecific $ actbActivity body of case AP.activitySpecific $ actbActivity body of
AP.CreateActivity create -> groupCreate now groupID verse create
_ -> throwE "Unsupported activity type for Group" _ -> throwE "Unsupported activity type for Group"
groupBehavior _ _ (Right _) = throwE "ClientMsgs aren't supported for Group" groupBehavior _ _ (Right _) = throwE "ClientMsgs aren't supported for Group"

View file

@ -98,6 +98,9 @@ verifyResourceAddressed localRecips resource = do
verify (GrantResourceProject r) = do verify (GrantResourceProject r) = do
routes <- lookup r $ recipProjects localRecips routes <- lookup r $ recipProjects localRecips
guard $ routeProject routes guard $ routeProject routes
verify (GrantResourceGroup r) = do
routes <- lookup r $ recipGroups localRecips
guard $ routeGroup routes
verifyProjectAddressed localRecips projectID = do verifyProjectAddressed localRecips projectID = do
projectHash <- encodeKeyHashid projectID projectHash <- encodeKeyHashid projectID
@ -1131,6 +1134,7 @@ clientRemove now personMeID (ClientMsg maybeCap localRecips remoteRecips fwdHost
Left (GrantResourceDeck d) -> Just $ LocalActorDeck d Left (GrantResourceDeck d) -> Just $ LocalActorDeck d
Left (GrantResourceLoom l) -> Just $ LocalActorLoom l Left (GrantResourceLoom l) -> Just $ LocalActorLoom l
Left (GrantResourceProject l) -> Just $ LocalActorProject l Left (GrantResourceProject l) -> Just $ LocalActorProject l
Left (GrantResourceGroup l) -> Just $ LocalActorGroup l
Right _ -> Nothing Right _ -> Nothing
, case recipientHash of , case recipientHash of
Left (GrantRecipPerson p) -> Just $ LocalActorPerson p Left (GrantRecipPerson p) -> Just $ LocalActorPerson p
@ -1143,6 +1147,7 @@ clientRemove now personMeID (ClientMsg maybeCap localRecips remoteRecips fwdHost
Left (GrantResourceDeck d) -> Just $ LocalStageDeckFollowers d Left (GrantResourceDeck d) -> Just $ LocalStageDeckFollowers d
Left (GrantResourceLoom l) -> Just $ LocalStageLoomFollowers l Left (GrantResourceLoom l) -> Just $ LocalStageLoomFollowers l
Left (GrantResourceProject l) -> Just $ LocalStageProjectFollowers l Left (GrantResourceProject l) -> Just $ LocalStageProjectFollowers l
Left (GrantResourceGroup l) -> Just $ LocalStageGroupFollowers l
Right _ -> Nothing Right _ -> Nothing
, case recipientHash of , case recipientHash of
Left (GrantRecipPerson p) -> Just $ LocalStagePersonFollowers p Left (GrantRecipPerson p) -> Just $ LocalStagePersonFollowers p

View file

@ -1144,6 +1144,8 @@ invite personID uRecipient uResourceCollabs role = do
AudLocal [LocalActorLoom l] [LocalStageLoomFollowers l] AudLocal [LocalActorLoom l] [LocalStageLoomFollowers l]
Left (GrantResourceProject l) -> Left (GrantResourceProject l) ->
AudLocal [LocalActorProject l] [LocalStageProjectFollowers l] AudLocal [LocalActorProject l] [LocalStageProjectFollowers l]
Left (GrantResourceGroup l) ->
AudLocal [LocalActorGroup l] [LocalStageGroupFollowers l]
Right (remoteActor, ObjURI h lu) -> Right (remoteActor, ObjURI h lu) ->
AudRemote h AudRemote h
[lu] [lu]
@ -1259,6 +1261,8 @@ remove personID uRecipient uResourceCollabs = do
AudLocal [LocalActorLoom l] [LocalStageLoomFollowers l] AudLocal [LocalActorLoom l] [LocalStageLoomFollowers l]
Left (GrantResourceProject l) -> Left (GrantResourceProject l) ->
AudLocal [LocalActorProject l] [LocalStageProjectFollowers l] AudLocal [LocalActorProject l] [LocalStageProjectFollowers l]
Left (GrantResourceGroup l) ->
AudLocal [LocalActorGroup l] [LocalStageGroupFollowers l]
Right (remoteActor, ObjURI h lu) -> Right (remoteActor, ObjURI h lu) ->
AudRemote h AudRemote h
[lu] [lu]

View file

@ -455,13 +455,15 @@ grantResourceActorID :: GrantResourceBy Identity -> ActorId
grantResourceActorID (GrantResourceRepo (Identity r)) = repoActor r grantResourceActorID (GrantResourceRepo (Identity r)) = repoActor r
grantResourceActorID (GrantResourceDeck (Identity d)) = deckActor d grantResourceActorID (GrantResourceDeck (Identity d)) = deckActor d
grantResourceActorID (GrantResourceLoom (Identity l)) = loomActor l grantResourceActorID (GrantResourceLoom (Identity l)) = loomActor l
grantResourceActorID (GrantResourceProject (Identity l)) = projectActor l grantResourceActorID (GrantResourceProject (Identity j)) = projectActor j
grantResourceActorID (GrantResourceGroup (Identity g)) = groupActor g
data GrantResourceBy f data GrantResourceBy f
= GrantResourceRepo (f Repo) = GrantResourceRepo (f Repo)
| GrantResourceDeck (f Deck) | GrantResourceDeck (f Deck)
| GrantResourceLoom (f Loom) | GrantResourceLoom (f Loom)
| GrantResourceProject (f Project) | GrantResourceProject (f Project)
| GrantResourceGroup (f Group)
deriving (Generic, FunctorB, TraversableB, ConstraintsB) deriving (Generic, FunctorB, TraversableB, ConstraintsB)
deriving instance AllBF Eq f GrantResourceBy => Eq (GrantResourceBy f) deriving instance AllBF Eq f GrantResourceBy => Eq (GrantResourceBy f)
@ -476,6 +478,8 @@ unhashGrantResourcePure ctx = f
GrantResourceLoom <$> decodeKeyHashidPure ctx l GrantResourceLoom <$> decodeKeyHashidPure ctx l
f (GrantResourceProject l) = f (GrantResourceProject l) =
GrantResourceProject <$> decodeKeyHashidPure ctx l GrantResourceProject <$> decodeKeyHashidPure ctx l
f (GrantResourceGroup l) =
GrantResourceGroup <$> decodeKeyHashidPure ctx l
unhashGrantResource resource = do unhashGrantResource resource = do
ctx <- asksSite siteHashidsContext ctx <- asksSite siteHashidsContext
@ -501,6 +505,8 @@ hashGrantResource (GrantResourceLoom k) =
GrantResourceLoom <$> encodeKeyHashid k GrantResourceLoom <$> encodeKeyHashid k
hashGrantResource (GrantResourceProject k) = hashGrantResource (GrantResourceProject k) =
GrantResourceProject <$> encodeKeyHashid k GrantResourceProject <$> encodeKeyHashid k
hashGrantResource (GrantResourceGroup k) =
GrantResourceGroup <$> encodeKeyHashid k
hashGrantResource' (GrantResourceRepo k) = hashGrantResource' (GrantResourceRepo k) =
GrantResourceRepo <$> WAP.encodeKeyHashid k GrantResourceRepo <$> WAP.encodeKeyHashid k
@ -510,6 +516,8 @@ hashGrantResource' (GrantResourceLoom k) =
GrantResourceLoom <$> WAP.encodeKeyHashid k GrantResourceLoom <$> WAP.encodeKeyHashid k
hashGrantResource' (GrantResourceProject k) = hashGrantResource' (GrantResourceProject k) =
GrantResourceProject <$> WAP.encodeKeyHashid k GrantResourceProject <$> WAP.encodeKeyHashid k
hashGrantResource' (GrantResourceGroup k) =
GrantResourceGroup <$> WAP.encodeKeyHashid k
getGrantResource (GrantResourceRepo k) e = getGrantResource (GrantResourceRepo k) e =
GrantResourceRepo <$> getEntityE k e GrantResourceRepo <$> getEntityE k e
@ -519,6 +527,8 @@ getGrantResource (GrantResourceLoom k) e =
GrantResourceLoom <$> getEntityE k e GrantResourceLoom <$> getEntityE k e
getGrantResource (GrantResourceProject k) e = getGrantResource (GrantResourceProject k) e =
GrantResourceProject <$> getEntityE k e GrantResourceProject <$> getEntityE k e
getGrantResource (GrantResourceGroup k) e =
GrantResourceGroup <$> getEntityE k e
getGrantResource404 = maybe notFound return <=< getGrantResourceEntity getGrantResource404 = maybe notFound return <=< getGrantResourceEntity
where where
@ -530,12 +540,15 @@ getGrantResource404 = maybe notFound return <=< getGrantResourceEntity
fmap GrantResourceLoom <$> getEntity k fmap GrantResourceLoom <$> getEntity k
getGrantResourceEntity (GrantResourceProject k) = getGrantResourceEntity (GrantResourceProject k) =
fmap GrantResourceProject <$> getEntity k fmap GrantResourceProject <$> getEntity k
getGrantResourceEntity (GrantResourceGroup k) =
fmap GrantResourceGroup <$> getEntity k
grantResourceLocalActor :: GrantResourceBy f -> LocalActorBy f grantResourceLocalActor :: GrantResourceBy f -> LocalActorBy f
grantResourceLocalActor (GrantResourceRepo r) = LocalActorRepo r grantResourceLocalActor (GrantResourceRepo r) = LocalActorRepo r
grantResourceLocalActor (GrantResourceDeck d) = LocalActorDeck d grantResourceLocalActor (GrantResourceDeck d) = LocalActorDeck d
grantResourceLocalActor (GrantResourceLoom l) = LocalActorLoom l grantResourceLocalActor (GrantResourceLoom l) = LocalActorLoom l
grantResourceLocalActor (GrantResourceProject l) = LocalActorProject l grantResourceLocalActor (GrantResourceProject l) = LocalActorProject l
grantResourceLocalActor (GrantResourceGroup l) = LocalActorGroup l
data ComponentBy f data ComponentBy f
= ComponentRepo (f Repo) = ComponentRepo (f Repo)
@ -578,6 +591,7 @@ resourceToComponent = \case
GrantResourceDeck k -> Just $ ComponentDeck k GrantResourceDeck k -> Just $ ComponentDeck k
GrantResourceLoom k -> Just $ ComponentLoom k GrantResourceLoom k -> Just $ ComponentLoom k
GrantResourceProject _ -> Nothing GrantResourceProject _ -> Nothing
GrantResourceGroup _ -> Nothing
data GrantRecipBy' f data GrantRecipBy' f
= GrantRecipPerson' (f Person) = GrantRecipPerson' (f Person)

View file

@ -64,6 +64,7 @@ module Vervis.Migration.Entities
, model_531_follow_request , model_531_follow_request
, model_541_project , model_541_project
, model_542_component , model_542_component
, model_551_group_collab
) )
where where
@ -248,3 +249,6 @@ model_541_project = $(schema "541_2023-06-26_project")
model_542_component :: [Entity SqlBackend] model_542_component :: [Entity SqlBackend]
model_542_component = $(schema "542_2023-06-26_component") model_542_component = $(schema "542_2023-06-26_component")
model_551_group_collab :: [Entity SqlBackend]
model_551_group_collab = $(schema "551_2023-11-21_group_collab")

View file

@ -71,23 +71,7 @@ import Vervis.Persist.Actor
getCollabTopic getCollabTopic
:: MonadIO m => CollabId -> ReaderT SqlBackend m (GrantResourceBy Key) :: MonadIO m => CollabId -> ReaderT SqlBackend m (GrantResourceBy Key)
getCollabTopic collabID = do getCollabTopic = fmap snd . getCollabTopic'
maybeRepo <- getValBy $ UniqueCollabTopicRepo collabID
maybeDeck <- getValBy $ UniqueCollabTopicDeck collabID
maybeLoom <- getValBy $ UniqueCollabTopicLoom collabID
maybeProject <- getValBy $ UniqueCollabTopicProject collabID
return $
case (maybeRepo, maybeDeck, maybeLoom, maybeProject) of
(Nothing, Nothing, Nothing, Nothing) -> error "Found Collab without topic"
(Just r, Nothing, Nothing, Nothing) ->
GrantResourceRepo $ collabTopicRepoRepo r
(Nothing, Just d, Nothing, Nothing) ->
GrantResourceDeck $ collabTopicDeckDeck d
(Nothing, Nothing, Just l, Nothing) ->
GrantResourceLoom $ collabTopicLoomLoom l
(Nothing, Nothing, Nothing, Just l) ->
GrantResourceProject $ collabTopicProjectProject l
_ -> error "Found Collab with multiple topics"
getCollabTopic' getCollabTopic'
:: MonadIO m => CollabId -> ReaderT SqlBackend m (ReaderT SqlBackend m (), GrantResourceBy Key) :: MonadIO m => CollabId -> ReaderT SqlBackend m (ReaderT SqlBackend m (), GrantResourceBy Key)
@ -96,17 +80,20 @@ getCollabTopic' collabID = do
maybeDeck <- getBy $ UniqueCollabTopicDeck collabID maybeDeck <- getBy $ UniqueCollabTopicDeck collabID
maybeLoom <- getBy $ UniqueCollabTopicLoom collabID maybeLoom <- getBy $ UniqueCollabTopicLoom collabID
maybeProject <- getBy $ UniqueCollabTopicProject collabID maybeProject <- getBy $ UniqueCollabTopicProject collabID
maybeGroup <- getBy $ UniqueCollabTopicGroup collabID
return $ return $
case (maybeRepo, maybeDeck, maybeLoom, maybeProject) of case (maybeRepo, maybeDeck, maybeLoom, maybeProject, maybeGroup) of
(Nothing, Nothing, Nothing, Nothing) -> error "Found Collab without topic" (Nothing, Nothing, Nothing, Nothing, Nothing) -> error "Found Collab without topic"
(Just (Entity k r), Nothing, Nothing, Nothing) -> (Just (Entity k r), Nothing, Nothing, Nothing, Nothing) ->
(delete k, GrantResourceRepo $ collabTopicRepoRepo r) (delete k, GrantResourceRepo $ collabTopicRepoRepo r)
(Nothing, Just (Entity k d), Nothing, Nothing) -> (Nothing, Just (Entity k d), Nothing, Nothing, Nothing) ->
(delete k, GrantResourceDeck $ collabTopicDeckDeck d) (delete k, GrantResourceDeck $ collabTopicDeckDeck d)
(Nothing, Nothing, Just (Entity k l), Nothing) -> (Nothing, Nothing, Just (Entity k l), Nothing, Nothing) ->
(delete k, GrantResourceLoom $ collabTopicLoomLoom l) (delete k, GrantResourceLoom $ collabTopicLoomLoom l)
(Nothing, Nothing, Nothing, Just (Entity k l)) -> (Nothing, Nothing, Nothing, Just (Entity k l), Nothing) ->
(delete k, GrantResourceProject $ collabTopicProjectProject l) (delete k, GrantResourceProject $ collabTopicProjectProject l)
(Nothing, Nothing, Nothing, Nothing, Just (Entity k l)) ->
(delete k, GrantResourceGroup $ collabTopicGroupGroup l)
_ -> error "Found Collab with multiple topics" _ -> error "Found Collab with multiple topics"
getStemIdent :: MonadIO m => StemId -> ReaderT SqlBackend m (ComponentBy Key) getStemIdent :: MonadIO m => StemId -> ReaderT SqlBackend m (ComponentBy Key)

View file

@ -676,6 +676,12 @@ CollabTopicProject
UniqueCollabTopicProject collab UniqueCollabTopicProject collab
CollabTopicGroup
collab CollabId
group GroupId
UniqueCollabTopicGroup collab
CollabEnable CollabEnable
collab CollabId collab CollabId
grant OutboxItemId grant OutboxItemId