1
0
Fork 0
mirror of https://code.sup39.dev/repos/Wqawg synced 2024-12-28 07:24:53 +09:00

S2S sharer inbox: Handle Offer{Ticket} yay!

This commit is contained in:
fr33domlover 2019-06-15 14:51:48 +00:00
parent 2abb6a44a4
commit 68bdaf65a7
5 changed files with 140 additions and 17 deletions

View file

@ -15,6 +15,7 @@
module Control.Monad.Trans.Except.Local module Control.Monad.Trans.Except.Local
( fromMaybeE ( fromMaybeE
, verifyNothingE
) )
where where
@ -23,3 +24,7 @@ import Control.Monad.Trans.Except
fromMaybeE :: Monad m => Maybe a -> e -> ExceptT e m a fromMaybeE :: Monad m => Maybe a -> e -> ExceptT e m a
fromMaybeE Nothing t = throwE t fromMaybeE Nothing t = throwE t
fromMaybeE (Just x) _ = return x fromMaybeE (Just x) _ = return x
verifyNothingE :: Monad m => Maybe a -> e -> ExceptT e m ()
verifyNothingE Nothing _ = return ()
verifyNothingE (Just _) e = throwE e

View file

@ -152,8 +152,8 @@ parseComment luParent = do
createNoteC :: Text -> Note -> Handler (Either Text LocalMessageId) createNoteC :: Text -> Note -> Handler (Either Text LocalMessageId)
createNoteC host (Note mluNote luAttrib aud muParent muContext mpublished source content) = runExceptT $ do createNoteC host (Note mluNote luAttrib aud muParent muContext mpublished source content) = runExceptT $ do
verifyHostLocal host "Attributed to non-local actor" verifyHostLocal host "Attributed to non-local actor"
verifyNothing mluNote "Note specifies an id" verifyNothingE mluNote "Note specifies an id"
verifyNothing mpublished "Note specifies published" verifyNothingE mpublished "Note specifies published"
uContext <- fromMaybeE muContext "Note without context" uContext <- fromMaybeE muContext "Note without context"
recips <- nonEmptyE (concatRecipients aud) "Note without recipients" recips <- nonEmptyE (concatRecipients aud) "Note without recipients"
(mparent, localRecips, mticket, remoteRecips) <- parseRecipsContextParent recips uContext muParent (mparent, localRecips, mticket, remoteRecips) <- parseRecipsContextParent recips uContext muParent
@ -230,10 +230,6 @@ createNoteC host (Note mluNote luAttrib aud muParent muContext mpublished source
lift $ forkWorker "Outbox POST handler: async HTTP delivery" $ deliverRemoteHttp (furiHost uContext) obid doc remotesHttp lift $ forkWorker "Outbox POST handler: async HTTP delivery" $ deliverRemoteHttp (furiHost uContext) obid doc remotesHttp
return lmid return lmid
where where
verifyNothing :: Monad m => Maybe a -> e -> ExceptT e m ()
verifyNothing Nothing _ = return ()
verifyNothing (Just _) e = throwE e
nonEmptyE :: Monad m => [a] -> e -> ExceptT e m (NonEmpty a) nonEmptyE :: Monad m => [a] -> e -> ExceptT e m (NonEmpty a)
nonEmptyE l e = nonEmptyE l e =
case nonEmpty l of case nonEmpty l of

View file

@ -96,6 +96,7 @@ import Yesod.Persist.Local
import Vervis.ActivityPub import Vervis.ActivityPub
import Vervis.ActorKey import Vervis.ActorKey
import Vervis.Federation.Discussion import Vervis.Federation.Discussion
import Vervis.Federation.Ticket
import Vervis.Foundation import Vervis.Foundation
import Vervis.Model import Vervis.Model
import Vervis.Model.Ident import Vervis.Model.Ident
@ -389,15 +390,6 @@ prependError t a = do
Left e -> throwE $ t <> ": " <> e Left e -> throwE $ t <> ": " <> e
Right x -> return x Right x -> return x
parseProject :: Monad m => LocalURI -> ExceptT Text m (ShrIdent, PrjIdent)
parseProject luRecip = do
route <- case decodeRouteLocal luRecip of
Nothing -> throwE "Got Create Note with recipient that isn't a valid route"
Just r -> return r
case route of
ProjectR shr prj -> return (shr, prj)
_ -> throwE "Got Create Note with non-project recipient"
parseTicket :: Monad m => (ShrIdent, PrjIdent) -> LocalURI -> ExceptT Text m Int parseTicket :: Monad m => (ShrIdent, PrjIdent) -> LocalURI -> ExceptT Text m Int
parseTicket project luContext = do parseTicket project luContext = do
route <- case decodeRouteLocal luContext of route <- case decodeRouteLocal luContext of
@ -454,9 +446,13 @@ handleSharerInbox _now shrRecip (Left pidAuthor) _raw activity = do
"Activity already exists in inbox of /s/" <> recip "Activity already exists in inbox of /s/" <> recip
Just _ -> Just _ ->
return $ "Activity inserted to inbox of /s/" <> recip return $ "Activity inserted to inbox of /s/" <> recip
handleSharerInbox now shrRecip (Right iidSender) raw activity = handleSharerInbox now shrRecip (Right iidAuthor) raw activity =
case activitySpecific activity of case activitySpecific activity of
CreateActivity (Create note) -> sharerCreateNoteRemoteF now shrRecip iidSender raw activity note CreateActivity (Create note) ->
sharerCreateNoteRemoteF now shrRecip iidAuthor raw activity note
OfferActivity offer ->
sharerOfferTicketRemoteF
now shrRecip iidAuthor raw (activityId activity) offer
_ -> return "Unsupported activity type" _ -> return "Unsupported activity type"
handleProjectInbox handleProjectInbox

View file

@ -0,0 +1,125 @@
{- This file is part of Vervis.
-
- Written in 2019 by fr33domlover <fr33domlover@riseup.net>.
-
- Copying is an act of love. Please copy, reuse and share.
-
- The author(s) have dedicated all copyright and related and neighboring
- rights to this software to the public domain worldwide. This software is
- distributed without any warranty.
-
- You should have received a copy of the CC0 Public Domain Dedication along
- with this software. If not, see
- <http://creativecommons.org/publicdomain/zero/1.0/>.
-}
module Vervis.Federation.Ticket
( sharerOfferTicketRemoteF
)
where
import Control.Monad
import Control.Monad.Trans.Class
import Control.Monad.Trans.Except
import Data.Aeson
import Data.Foldable
import Data.Maybe
import Data.Text (Text)
import Data.Time.Clock
import Database.Persist
import Yesod.Persist.Core
import Database.Persist.JSON
import Network.FedURI
import Web.ActivityPub
import Yesod.FedURI
import Control.Monad.Trans.Except.Local
import Database.Persist.Local
import Yesod.Persist.Local
import Vervis.ActivityPub
import Vervis.Foundation
import Vervis.Model
import Vervis.Model.Ident
sharerOfferTicketRemoteF
:: UTCTime
-> ShrIdent
-> InstanceId
-> Object
-> LocalURI
-> Offer
-> ExceptT Text Handler Text
sharerOfferTicketRemoteF
now shrRecip iidAuthor raw luOffer (Offer ticket uTarget) = do
verifyNothingE (ticketLocal ticket) "Ticket with 'id'"
_published <-
fromMaybeE (ticketPublished ticket) "Ticket without 'published'"
verifyNothingE (ticketName ticket) "Ticket with 'name'"
verifyNothingE (ticketAssignedTo ticket) "Ticket with 'assignedTo'"
when (ticketIsResolved ticket) $ throwE "Ticket resolved"
(hProject, shrProject, prjProject) <- parseTarget uTarget
unless (null $ ticketDependedBy ticket) $ throwE "Ticket has rdeps"
let checkDep' = checkDep hProject shrProject prjProject
deps <- traverse checkDep' $ ticketDependsOn ticket
local <- hostIsLocal hProject
runDBExcept $ do
ibidRecip <- lift $ do
sid <- getKeyBy404 $ UniqueSharer shrRecip
p <- getValBy404 $ UniquePersonIdent sid
return $ personInbox p
when local $ checkTargetAndDeps shrProject prjProject deps
lift $ insertToInbox ibidRecip
where
parseTarget u = do
let (h, lu) = f2l u
(shr, prj) <- parseProject lu
return (h, shr, prj)
where
parseProject lu = do
route <- case decodeRouteLocal lu of
Nothing -> throwE "Expected project route, got invalid route"
Just r -> return r
case route of
ProjectR shr prj -> return (shr, prj)
_ -> throwE "Expected project route, got non-project route"
checkDep hProject shrProject prjProject u = do
let (h, lu) = f2l u
unless (h == hProject) $
throwE "Dep belongs to different host"
(shrTicket, prjTicket, num) <- parseTicket lu
unless (shrTicket == shrProject) $
throwE "Dep belongs to different sharer under same host"
unless (prjTicket == prjProject) $
throwE "Dep belongs to different project under same sharer"
return num
where
parseTicket lu = do
route <- case decodeRouteLocal lu of
Nothing -> throwE "Expected ticket route, got invalid route"
Just r -> return r
case route of
TicketR shr prj num -> return (shr, prj, num)
_ -> throwE "Expected ticket route, got non-ticket route"
checkTargetAndDeps shrProject prjProject deps = do
msid <- lift $ getKeyBy $ UniqueSharer shrProject
sid <- fromMaybeE msid "Offer target: no such local sharer"
mjid <- lift $ getKeyBy $ UniqueProject prjProject sid
jid <- fromMaybeE mjid "Offer target: no such local project"
for_ deps $ \ dep -> do
mt <- lift $ getBy $ UniqueTicket jid dep
unless (isJust mt) $
throwE "Local dep: No such ticket number in DB"
insertToInbox ibidRecip = do
let jsonObj = PersistJSON raw
ract = RemoteActivity iidAuthor luOffer jsonObj now
ractid <- either entityKey id <$> insertBy' ract
ibiid <- insert $ InboxItem True
mibrid <- insertUnique $ InboxItemRemote ibidRecip ractid ibiid
let recip = shr2text shrRecip
case mibrid of
Nothing -> do
delete ibiid
return $ "Activity already exists in inbox of /s/" <> recip
Just _ -> return $ "Activity inserted to inbox of /s/" <> recip

View file

@ -127,6 +127,7 @@ library
Vervis.Discussion Vervis.Discussion
Vervis.Federation Vervis.Federation
Vervis.Federation.Discussion Vervis.Federation.Discussion
Vervis.Federation.Ticket
Vervis.Field.Key Vervis.Field.Key
Vervis.Field.Person Vervis.Field.Person
Vervis.Field.Project Vervis.Field.Project