Client, UI: "Apply" button for local MRs & PublishMergeR form for remote MRs
This commit is contained in:
parent
ba6f22b94b
commit
f10655f2c1
11 changed files with 290 additions and 8 deletions
|
@ -30,6 +30,7 @@ module Vervis.Client
|
||||||
--, unresolve
|
--, unresolve
|
||||||
offerPatches
|
offerPatches
|
||||||
, offerMerge
|
, offerMerge
|
||||||
|
, applyPatches
|
||||||
, createDeck
|
, createDeck
|
||||||
, createLoom
|
, createLoom
|
||||||
, createRepo
|
, createRepo
|
||||||
|
@ -74,6 +75,7 @@ import Data.Either.Local
|
||||||
import Database.Persist.Local
|
import Database.Persist.Local
|
||||||
|
|
||||||
import Vervis.ActivityPub
|
import Vervis.ActivityPub
|
||||||
|
import Vervis.Cloth
|
||||||
import Vervis.Data.Ticket
|
import Vervis.Data.Ticket
|
||||||
import Vervis.FedURI
|
import Vervis.FedURI
|
||||||
import Vervis.Foundation
|
import Vervis.Foundation
|
||||||
|
@ -722,6 +724,106 @@ offerMerge senderHash title desc uTracker uTargetRepo maybeTargetBranch uOriginR
|
||||||
|
|
||||||
return (Nothing, AP.Audience recips [] [] [] [] [], ticket)
|
return (Nothing, AP.Audience recips [] [] [] [] [], ticket)
|
||||||
|
|
||||||
|
applyPatches
|
||||||
|
:: KeyHashid Person
|
||||||
|
-> FedURI
|
||||||
|
-> ExceptT Text Handler (Maybe HTML, Audience URIMode, Apply URIMode)
|
||||||
|
applyPatches senderHash uObject = do
|
||||||
|
|
||||||
|
bundle <- parseProposalBundle "Apply object" uObject
|
||||||
|
mrInfo <-
|
||||||
|
bifor bundle
|
||||||
|
(\ (loomID, clothID, _) -> do
|
||||||
|
maybeCloth <- lift $ runDB $ getCloth loomID clothID
|
||||||
|
(Entity _ loom, Entity _ cloth, _, _, _, _) <-
|
||||||
|
fromMaybeE maybeCloth "Local bundle not found in DB"
|
||||||
|
return (loomID, clothID, loomRepo loom, ticketLoomBranch cloth)
|
||||||
|
)
|
||||||
|
(\ uBundle -> do
|
||||||
|
manager <- asksSite appHttpManager
|
||||||
|
Doc h b <- AP.fetchAP_T manager $ Left uBundle
|
||||||
|
let mlocal =
|
||||||
|
case b of
|
||||||
|
BundleHosted ml _ -> (h,) <$> ml
|
||||||
|
BundleOffer ml _ -> ml
|
||||||
|
(hBundle, blocal) <-
|
||||||
|
fromMaybeE mlocal "Remote bundle doesn't have 'context'"
|
||||||
|
unless (hBundle == h) $
|
||||||
|
throwE "Bundle @id mismatch!"
|
||||||
|
|
||||||
|
Doc _ ticket <-
|
||||||
|
AP.fetchAP_T manager $
|
||||||
|
Left $ ObjURI hBundle $ AP.bundleContext blocal
|
||||||
|
(hMR, mr) <- fromMaybeE (AP.ticketAttachment ticket) "Ticket doesn't have attachment"
|
||||||
|
(hT, tlocal) <- fromMaybeE (AP.ticketLocal ticket) "Ticket doesn't have followers"
|
||||||
|
unless (hT == hBundle) $
|
||||||
|
throwE "Ticket @id mismatch!"
|
||||||
|
uContext@(ObjURI hC _) <- fromMaybeE (AP.ticketContext ticket) "Ticket doesn't have context"
|
||||||
|
unless (hC == hT) $
|
||||||
|
throwE "Ticket and tracker on different instances"
|
||||||
|
|
||||||
|
Doc hC' (AP.Actor aloc adet) <- AP.fetchAP_T manager $ Left uContext
|
||||||
|
unless (hC' == hC) $
|
||||||
|
throwE "Tracker @id mismatch!"
|
||||||
|
unless (AP.actorType adet == AP.ActorTypePatchTracker) $
|
||||||
|
throwE "Ticket context isn't a PatchTracker"
|
||||||
|
return
|
||||||
|
( uContext
|
||||||
|
, AP.actorFollowers aloc
|
||||||
|
, AP.ticketParticipants tlocal
|
||||||
|
, bimap (ObjURI hMR) (hMR,) $ AP.mrTarget mr
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
encodeRouteLocal <- getEncodeRouteLocal
|
||||||
|
encodeRouteHome <- getEncodeRouteHome
|
||||||
|
hashRepo <- getEncodeKeyHashid
|
||||||
|
hashLoom <- getEncodeKeyHashid
|
||||||
|
hashCloth <- getEncodeKeyHashid
|
||||||
|
hLocal <- asksSite siteInstanceHost
|
||||||
|
|
||||||
|
let target =
|
||||||
|
case mrInfo of
|
||||||
|
Left (_, _, repoID, maybeBranch) ->
|
||||||
|
let luRepo = encodeRouteLocal $ RepoR $ hashRepo repoID
|
||||||
|
in case maybeBranch of
|
||||||
|
Nothing -> Left $ ObjURI hLocal luRepo
|
||||||
|
Just b ->
|
||||||
|
Right
|
||||||
|
( hLocal
|
||||||
|
, AP.Branch
|
||||||
|
{ AP.branchName = b
|
||||||
|
, AP.branchRef = "/refs/heads/" <> b
|
||||||
|
, AP.branchRepo = luRepo
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Right (_, _, _, remoteTarget) -> remoteTarget
|
||||||
|
|
||||||
|
audAuthor =
|
||||||
|
AudLocal
|
||||||
|
[]
|
||||||
|
[LocalStagePersonFollowers senderHash]
|
||||||
|
audCloth =
|
||||||
|
case mrInfo of
|
||||||
|
Left (loomID, clothID, _, _) ->
|
||||||
|
let loomHash = hashLoom loomID
|
||||||
|
clothHash = hashCloth clothID
|
||||||
|
in AudLocal
|
||||||
|
[LocalActorLoom loomHash]
|
||||||
|
[ LocalStageLoomFollowers loomHash
|
||||||
|
, LocalStageClothFollowers loomHash clothHash
|
||||||
|
]
|
||||||
|
Right (ObjURI h luTracker, mluFollowers, luTicketFollowers, _) ->
|
||||||
|
AudRemote h
|
||||||
|
[luTracker]
|
||||||
|
(catMaybes [mluFollowers, Just luTicketFollowers])
|
||||||
|
|
||||||
|
(_, _, _, audLocal, audRemote) = collectAudience [audAuthor, audCloth]
|
||||||
|
|
||||||
|
recips = map encodeRouteHome audLocal ++ audRemote
|
||||||
|
|
||||||
|
return (Nothing, Audience recips [] [] [] [] [], Apply uObject target)
|
||||||
|
|
||||||
createDeck
|
createDeck
|
||||||
:: (MonadHandler m, HandlerSite m ~ App, MonadSite m, SiteEnv m ~ App)
|
:: (MonadHandler m, HandlerSite m ~ App, MonadSite m, SiteEnv m ~ App)
|
||||||
=> KeyHashid Person
|
=> KeyHashid Person
|
||||||
|
|
|
@ -21,6 +21,7 @@ module Vervis.Darcs
|
||||||
--, lastChange
|
--, lastChange
|
||||||
, readPatch
|
, readPatch
|
||||||
, writePostApplyHooks
|
, writePostApplyHooks
|
||||||
|
, canApplyDarcsPatch
|
||||||
, applyDarcsPatch
|
, applyDarcsPatch
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
@ -399,6 +400,11 @@ writePostApplyHooks = do
|
||||||
liftIO $
|
liftIO $
|
||||||
writeDefaultsFile path hook authority (keyHashidText repoHash)
|
writeDefaultsFile path hook authority (keyHashidText repoHash)
|
||||||
|
|
||||||
|
canApplyDarcsPatch repoPath patch = do
|
||||||
|
let input = BL.fromStrict $ TE.encodeUtf8 patch
|
||||||
|
exitCode <- runProcess $ setStdin (byteStringInput input) $ proc "darcs" ["apply", "--all", "--no-allow-conflicts", "--dry-run", "--repodir='" ++ repoPath ++ "'"]
|
||||||
|
return $ exitCode == ExitSuccess
|
||||||
|
|
||||||
applyDarcsPatch repoPath patch = do
|
applyDarcsPatch repoPath patch = do
|
||||||
let input = BL.fromStrict $ TE.encodeUtf8 patch
|
let input = BL.fromStrict $ TE.encodeUtf8 patch
|
||||||
runProcessE "darcs apply" $ setStdin (byteStringInput input) $ proc "darcs" ["apply", "--all", "--no-allow-conflicts", "--repodir='" ++ repoPath ++ "'"]
|
runProcessE "darcs apply" $ setStdin (byteStringInput input) $ proc "darcs" ["apply", "--all", "--no-allow-conflicts", "--repodir='" ++ repoPath ++ "'"]
|
||||||
|
|
|
@ -22,6 +22,7 @@ module Vervis.Git
|
||||||
--, lastCommitTime
|
--, lastCommitTime
|
||||||
, writePostReceiveHooks
|
, writePostReceiveHooks
|
||||||
, generateGitPatches
|
, generateGitPatches
|
||||||
|
, canApplyGitPatches
|
||||||
, applyGitPatches
|
, applyGitPatches
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
@ -54,6 +55,7 @@ import Data.Time.Clock.POSIX (posixSecondsToUTCTime)
|
||||||
import Data.Traversable (for)
|
import Data.Traversable (for)
|
||||||
import Data.Word (Word32)
|
import Data.Word (Word32)
|
||||||
import Database.Persist
|
import Database.Persist
|
||||||
|
import System.Exit
|
||||||
import System.FilePath
|
import System.FilePath
|
||||||
import System.Hourglass (timeCurrent)
|
import System.Hourglass (timeCurrent)
|
||||||
import System.Process.Typed
|
import System.Process.Typed
|
||||||
|
@ -386,12 +388,20 @@ generateGitPatches targetRepoPath targetBranch originRepoURI originBranch tempDi
|
||||||
]
|
]
|
||||||
Right t -> return t
|
Right t -> return t
|
||||||
|
|
||||||
|
canApplyGitPatches repoPath branch patches tempDir = do
|
||||||
|
runProcessE "git clone" $ proc "git" ["clone", "--verbose", "--single-branch", "--branch", branch, "--", repoPath, tempDir]
|
||||||
|
runProcessE "git config" $ proc "git" ["-C", tempDir, "config", "user.name", "vervis"]
|
||||||
|
runProcessE "git config" $ proc "git" ["-C", tempDir, "config", "user.email", "vervis@vervis.vervis"]
|
||||||
|
let input = BL.concat $ NE.toList $ NE.map (BL.fromStrict . TE.encodeUtf8) patches
|
||||||
|
exitCode <- lift $ runProcess $ setStdin (byteStringInput input) $ proc "git" ["-C", tempDir, "am"]
|
||||||
|
return $ exitCode == ExitSuccess
|
||||||
|
|
||||||
-- Since 'git am' doesn't work on a bare repo, clone target repo into the given
|
-- Since 'git am' doesn't work on a bare repo, clone target repo into the given
|
||||||
-- temporary directory, apply there, and finally push
|
-- temporary directory, apply there, and finally push
|
||||||
applyGitPatches repoPath branch patches tempDir = do
|
applyGitPatches repoPath branch patches tempDir = do
|
||||||
runProcessE "git clone" $ proc "git" ["clone", "--verbose", "--single-branch", "--branch", branch, "--", repoPath, tempDir]
|
runProcessE "git clone" $ proc "git" ["clone", "--verbose", "--single-branch", "--branch", branch, "--", repoPath, tempDir]
|
||||||
let input = BL.concat $ NE.toList $ NE.map (BL.fromStrict . TE.encodeUtf8) patches
|
|
||||||
runProcessE "git am" $ setStdin (byteStringInput input) $ proc "git" ["-C", tempDir, "am"]
|
|
||||||
runProcessE "git config" $ proc "git" ["-C", tempDir, "config", "user.name", "vervis"]
|
runProcessE "git config" $ proc "git" ["-C", tempDir, "config", "user.name", "vervis"]
|
||||||
runProcessE "git config" $ proc "git" ["-C", tempDir, "config", "user.email", "vervis@vervis.vervis"]
|
runProcessE "git config" $ proc "git" ["-C", tempDir, "config", "user.email", "vervis@vervis.vervis"]
|
||||||
|
let input = BL.concat $ NE.toList $ NE.map (BL.fromStrict . TE.encodeUtf8) patches
|
||||||
|
runProcessE "git am" $ setStdin (byteStringInput input) $ proc "git" ["-C", tempDir, "am"]
|
||||||
runProcessE "git push" $ proc "git" ["-C", tempDir, "push"]
|
runProcessE "git push" $ proc "git" ["-C", tempDir, "push"]
|
||||||
|
|
|
@ -29,6 +29,9 @@ module Vervis.Handler.Client
|
||||||
|
|
||||||
, getPublishOfferMergeR
|
, getPublishOfferMergeR
|
||||||
, postPublishOfferMergeR
|
, postPublishOfferMergeR
|
||||||
|
|
||||||
|
, getPublishMergeR
|
||||||
|
, postPublishMergeR
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
|
@ -1142,3 +1145,41 @@ postPublishOfferMergeR = do
|
||||||
then setMessage "Merge Request created"
|
then setMessage "Merge Request created"
|
||||||
else setMessage "Offer published"
|
else setMessage "Offer published"
|
||||||
redirect dest
|
redirect dest
|
||||||
|
|
||||||
|
mergeForm :: Form (FedURI, FedURI)
|
||||||
|
mergeForm = renderDivs $ (,)
|
||||||
|
<$> areq fedUriField "Patch bundle to apply" Nothing
|
||||||
|
<*> areq fedUriField "Grant activity to use for authorization" Nothing
|
||||||
|
|
||||||
|
getPublishMergeR :: Handler Html
|
||||||
|
getPublishMergeR = do
|
||||||
|
((_, widget), enctype) <- runFormPost mergeForm
|
||||||
|
defaultLayout
|
||||||
|
[whamlet|
|
||||||
|
<h1>Merge a merge request
|
||||||
|
<form method=POST action=@{PublishMergeR} enctype=#{enctype}>
|
||||||
|
^{widget}
|
||||||
|
<input type=submit>
|
||||||
|
|]
|
||||||
|
|
||||||
|
postPublishMergeR :: Handler ()
|
||||||
|
postPublishMergeR = do
|
||||||
|
federation <- getsYesod $ appFederation . appSettings
|
||||||
|
unless federation badMethod
|
||||||
|
|
||||||
|
(uBundle, uCap) <- runFormPostRedirect PublishMergeR mergeForm
|
||||||
|
|
||||||
|
(ep@(Entity pid _), a) <- getSender
|
||||||
|
senderHash <- encodeKeyHashid pid
|
||||||
|
|
||||||
|
result <- runExceptT $ do
|
||||||
|
(maybeSummary, audience, apply) <- applyPatches senderHash uBundle
|
||||||
|
applyC ep a (Just uCap) maybeSummary audience apply
|
||||||
|
|
||||||
|
case result of
|
||||||
|
Left err -> do
|
||||||
|
setMessage $ toHtml err
|
||||||
|
redirect PublishMergeR
|
||||||
|
Right _ -> do
|
||||||
|
setMessage "Apply activity sent"
|
||||||
|
redirect HomeR
|
||||||
|
|
|
@ -26,6 +26,7 @@ module Vervis.Handler.Cloth
|
||||||
|
|
||||||
, getClothDepR
|
, getClothDepR
|
||||||
|
|
||||||
|
, postClothApplyR
|
||||||
, postClothFollowR
|
, postClothFollowR
|
||||||
, postClothUnfollowR
|
, postClothUnfollowR
|
||||||
, postClothReplyR
|
, postClothReplyR
|
||||||
|
@ -62,16 +63,19 @@ module Vervis.Handler.Cloth
|
||||||
where
|
where
|
||||||
|
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
|
import Control.Monad.Trans.Except
|
||||||
import Data.Bifunctor
|
import Data.Bifunctor
|
||||||
import Data.Bitraversable
|
import Data.Bitraversable
|
||||||
import Data.Bool
|
import Data.Bool
|
||||||
import Data.Function
|
import Data.Function
|
||||||
import Data.Functor
|
import Data.Functor
|
||||||
import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
|
import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
|
||||||
|
import Data.Maybe
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Data.These
|
import Data.These
|
||||||
import Data.Traversable
|
import Data.Traversable
|
||||||
import Database.Persist
|
import Database.Persist
|
||||||
|
import Network.HTTP.Types.Method
|
||||||
import Text.Blaze.Html (Html, preEscapedToHtml)
|
import Text.Blaze.Html (Html, preEscapedToHtml)
|
||||||
import Yesod.Auth
|
import Yesod.Auth
|
||||||
import Yesod.Core
|
import Yesod.Core
|
||||||
|
@ -93,6 +97,7 @@ import Yesod.RenderSource
|
||||||
|
|
||||||
import qualified Web.ActivityPub as AP
|
import qualified Web.ActivityPub as AP
|
||||||
|
|
||||||
|
import Control.Monad.Trans.Except.Local
|
||||||
import Data.Paginate.Local
|
import Data.Paginate.Local
|
||||||
import Database.Persist.Local
|
import Database.Persist.Local
|
||||||
import Yesod.Persist.Local
|
import Yesod.Persist.Local
|
||||||
|
@ -115,9 +120,13 @@ import Vervis.Style
|
||||||
import Vervis.Ticket
|
import Vervis.Ticket
|
||||||
import Vervis.Time (showDate)
|
import Vervis.Time (showDate)
|
||||||
import Vervis.Web.Actor
|
import Vervis.Web.Actor
|
||||||
|
import Vervis.Web.Repo
|
||||||
|
import Vervis.Widget
|
||||||
import Vervis.Widget.Discussion
|
import Vervis.Widget.Discussion
|
||||||
import Vervis.Widget.Person
|
import Vervis.Widget.Person
|
||||||
|
|
||||||
|
import qualified Vervis.Client as C
|
||||||
|
|
||||||
getClothR :: KeyHashid Loom -> KeyHashid TicketLoom -> Handler TypedContent
|
getClothR :: KeyHashid Loom -> KeyHashid TicketLoom -> Handler TypedContent
|
||||||
getClothR loomHash clothHash = do
|
getClothR loomHash clothHash = do
|
||||||
(repoID, mbranch, ticket, author, resolve, proposal) <- runDB $ do
|
(repoID, mbranch, ticket, author, resolve, proposal) <- runDB $ do
|
||||||
|
@ -270,7 +279,7 @@ getClothR loomHash clothHash = do
|
||||||
(Entity _ loom, Entity _ cloth, Entity ticketID ticket, author, _maybe_ResolveAndEitherTrlOrTrr, proposal) <-
|
(Entity _ loom, Entity _ cloth, Entity ticketID ticket, author, _maybe_ResolveAndEitherTrlOrTrr, proposal) <-
|
||||||
getCloth404 loomHash clothHash
|
getCloth404 loomHash clothHash
|
||||||
(ticket,,,,,,,)
|
(ticket,,,,,,,)
|
||||||
<$> getLocalRepo (loomRepo loom) (ticketLoomBranch cloth)
|
<$> getLocalRepo' (loomRepo loom) (ticketLoomBranch cloth)
|
||||||
<*> bitraverse
|
<*> bitraverse
|
||||||
(\ (Entity _ (TicketAuthorLocal _ personID _)) -> do
|
(\ (Entity _ (TicketAuthorLocal _ personID _)) -> do
|
||||||
p <- getJust personID
|
p <- getJust personID
|
||||||
|
@ -298,12 +307,18 @@ getClothR loomHash clothHash = do
|
||||||
(justThere proposal)
|
(justThere proposal)
|
||||||
<*> traverse
|
<*> traverse
|
||||||
(\ (bundleID :| _) -> do
|
(\ (bundleID :| _) -> do
|
||||||
ids <- selectKeysList [PatchBundle ==. bundleID] [Desc PatchId]
|
ps <- selectList [PatchBundle ==. bundleID] [Desc PatchId]
|
||||||
case nonEmpty ids of
|
case nonEmpty ps of
|
||||||
Nothing -> error "Bundle without any Patches in DB"
|
Nothing -> error "Bundle without any Patches in DB"
|
||||||
Just ne -> return (bundleID, ne)
|
Just ne -> return (bundleID, ne)
|
||||||
)
|
)
|
||||||
(justHere proposal)
|
(justHere proposal)
|
||||||
|
mbundle' <- for mbundle $ \ (bundleID, patches) -> do
|
||||||
|
let patchIDs = NE.map entityKey patches
|
||||||
|
diffs = NE.map (patchContent . entityVal) $ NE.reverse patches
|
||||||
|
(repoID, _, _, maybeBranch) = targetRepo
|
||||||
|
errorOrCanApply <- runExceptT $ canApplyPatches repoID maybeBranch diffs
|
||||||
|
return (bundleID, patchIDs, errorOrCanApply)
|
||||||
hashMessageKey <- handlerToWidget getEncodeKeyHashid
|
hashMessageKey <- handlerToWidget getEncodeKeyHashid
|
||||||
let desc :: Widget
|
let desc :: Widget
|
||||||
desc = toWidget $ markupHTML $ ticketDescription ticket
|
desc = toWidget $ markupHTML $ ticketDescription ticket
|
||||||
|
@ -325,10 +340,19 @@ getClothR loomHash clothHash = do
|
||||||
(ClothFollowR loomHash clothHash)
|
(ClothFollowR loomHash clothHash)
|
||||||
(ClothUnfollowR loomHash clothHash)
|
(ClothUnfollowR loomHash clothHash)
|
||||||
(ticketFollowers ticket)
|
(ticketFollowers ticket)
|
||||||
|
applyButton label =
|
||||||
|
buttonW POST label $ ClothApplyR loomHash clothHash
|
||||||
hashBundle <- handlerToWidget getEncodeKeyHashid
|
hashBundle <- handlerToWidget getEncodeKeyHashid
|
||||||
hashPatch <- handlerToWidget getEncodeKeyHashid
|
hashPatch <- handlerToWidget getEncodeKeyHashid
|
||||||
$(widgetFile "cloth/one")
|
$(widgetFile "cloth/one")
|
||||||
where
|
where
|
||||||
|
getLocalRepo' repoID mbranch = do
|
||||||
|
repo <- getJust repoID
|
||||||
|
actor <- getJust $ repoActor repo
|
||||||
|
repoHash <- encodeKeyHashid repoID
|
||||||
|
unless (isJust mbranch == (repoVcs repo == VCSGit)) $
|
||||||
|
error "VCS and cloth-branch mismatch"
|
||||||
|
return (repoID, repoHash, actorName actor, mbranch)
|
||||||
getLocalRepo repoID mbranch = do
|
getLocalRepo repoID mbranch = do
|
||||||
repo <- getJust repoID
|
repo <- getJust repoID
|
||||||
actor <- getJust $ repoActor repo
|
actor <- getJust $ repoActor repo
|
||||||
|
@ -591,6 +615,50 @@ getClothDepR _ _ _ = do
|
||||||
tdc
|
tdc
|
||||||
-}
|
-}
|
||||||
|
|
||||||
|
postClothApplyR :: KeyHashid Loom -> KeyHashid TicketLoom -> Handler ()
|
||||||
|
postClothApplyR loomHash clothHash = do
|
||||||
|
ep@(Entity personID person) <- requireAuth
|
||||||
|
|
||||||
|
(grantIDs, proposal, actor) <- runDB $ do
|
||||||
|
(Entity loomID _, _, _, _, _, proposal) <- getCloth404 loomHash clothHash
|
||||||
|
|
||||||
|
grantIDs <-
|
||||||
|
E.select $ E.from $ \ (topic `E.InnerJoin` recip `E.InnerJoin` enable) -> do
|
||||||
|
E.on $ topic E.^. CollabTopicLoomCollab E.==. enable E.^. CollabEnableCollab
|
||||||
|
E.on $ topic E.^. CollabTopicLoomCollab E.==. recip E.^. CollabRecipLocalCollab
|
||||||
|
E.where_ $
|
||||||
|
topic E.^. CollabTopicLoomLoom E.==. E.val loomID E.&&.
|
||||||
|
recip E.^. CollabRecipLocalPerson E.==. E.val personID
|
||||||
|
return $ enable E.^. CollabEnableGrant
|
||||||
|
|
||||||
|
actor <- getJust $ personActor person
|
||||||
|
|
||||||
|
return (map E.unValue grantIDs, proposal, actor)
|
||||||
|
|
||||||
|
result <- runExceptT $ do
|
||||||
|
|
||||||
|
bundleID :| _ <-
|
||||||
|
fromMaybeE (justHere proposal) "No patch bundle to apply"
|
||||||
|
grantID <-
|
||||||
|
case grantIDs of
|
||||||
|
[] -> throwE "You don't have access to this patch tracker"
|
||||||
|
[g] -> return g
|
||||||
|
_ -> error "Multiple grants for same person on same loom"
|
||||||
|
bundleRoute <- BundleR loomHash clothHash <$> encodeKeyHashid bundleID
|
||||||
|
encodeRouteHome <- getEncodeRouteHome
|
||||||
|
personHash <- encodeKeyHashid personID
|
||||||
|
(maybeSummary, audience, apply) <-
|
||||||
|
C.applyPatches personHash $ encodeRouteHome bundleRoute
|
||||||
|
uCap <-
|
||||||
|
encodeRouteHome . LoomOutboxItemR loomHash <$>
|
||||||
|
encodeKeyHashid grantID
|
||||||
|
applyC ep actor (Just uCap) maybeSummary audience apply
|
||||||
|
|
||||||
|
case result of
|
||||||
|
Left e -> setMessage $ toHtml e
|
||||||
|
Right _ -> setMessage "Patches applied successfully!"
|
||||||
|
redirect $ ClothR loomHash clothHash
|
||||||
|
|
||||||
postClothFollowR :: KeyHashid Loom -> KeyHashid TicketLoom -> Handler ()
|
postClothFollowR :: KeyHashid Loom -> KeyHashid TicketLoom -> Handler ()
|
||||||
postClothFollowR _ = error "Temporarily disabled"
|
postClothFollowR _ = error "Temporarily disabled"
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
module Vervis.Web.Repo
|
module Vervis.Web.Repo
|
||||||
( serveCommit
|
( serveCommit
|
||||||
, generatePatches
|
, generatePatches
|
||||||
|
, canApplyPatches
|
||||||
, applyPatches
|
, applyPatches
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
@ -142,6 +143,27 @@ generatePatches (clothID, targetRepoID, hasBundle, tipInfo) = unless hasBundle $
|
||||||
bundleID <- insert $ Bundle clothID True
|
bundleID <- insert $ Bundle clothID True
|
||||||
insertMany_ $ NE.toList $ NE.map (Patch bundleID now PatchMediaTypeGit) $ NE.reverse patches
|
insertMany_ $ NE.toList $ NE.map (Patch bundleID now PatchMediaTypeGit) $ NE.reverse patches
|
||||||
|
|
||||||
|
canApplyPatches
|
||||||
|
:: (MonadSite m, SiteEnv m ~ App)
|
||||||
|
=> RepoId -> Maybe Text -> NonEmpty Text -> ExceptT Text m Bool
|
||||||
|
canApplyPatches repoID maybeBranch diffs = do
|
||||||
|
repoPath <- do
|
||||||
|
repoHash <- encodeKeyHashid repoID
|
||||||
|
repoDir <- askRepoDir repoHash
|
||||||
|
liftIO $ makeAbsolute repoDir
|
||||||
|
case maybeBranch of
|
||||||
|
Just branch -> do
|
||||||
|
ExceptT $ liftIO $ runExceptT $
|
||||||
|
withSystemTempDirectory "vervis-canApplyPatches" $
|
||||||
|
canApplyGitPatches repoPath (T.unpack branch) diffs
|
||||||
|
Nothing -> do
|
||||||
|
patch <-
|
||||||
|
case diffs of
|
||||||
|
t :| [] -> return t
|
||||||
|
_ :| (_ : _) ->
|
||||||
|
throwE "Darcs repo given multiple patch bundles"
|
||||||
|
canApplyDarcsPatch repoPath patch
|
||||||
|
|
||||||
applyPatches
|
applyPatches
|
||||||
:: (MonadSite m, SiteEnv m ~ App)
|
:: (MonadSite m, SiteEnv m ~ App)
|
||||||
=> RepoId -> Maybe Text -> NonEmpty Text -> ExceptT Text m ()
|
=> RepoId -> Maybe Text -> NonEmpty Text -> ExceptT Text m ()
|
||||||
|
|
|
@ -96,6 +96,7 @@ module Web.ActivityPub
|
||||||
, httpPostAPBytes
|
, httpPostAPBytes
|
||||||
, Fetched (..)
|
, Fetched (..)
|
||||||
, fetchAP
|
, fetchAP
|
||||||
|
, fetchAP_T
|
||||||
, fetchAPID
|
, fetchAPID
|
||||||
, fetchAPID'
|
, fetchAPID'
|
||||||
, fetchTip
|
, fetchTip
|
||||||
|
@ -1940,6 +1941,9 @@ fetchAP' m u = ExceptT $ second responseBody <$> httpGetAP m u
|
||||||
fetchAP :: (MonadIO m, UriMode u, FromJSON a) => Manager -> Either (ObjURI u) (SubURI u) -> ExceptT String m a
|
fetchAP :: (MonadIO m, UriMode u, FromJSON a) => Manager -> Either (ObjURI u) (SubURI u) -> ExceptT String m a
|
||||||
fetchAP m u = withExceptT displayException $ fetchAP' m u
|
fetchAP m u = withExceptT displayException $ fetchAP' m u
|
||||||
|
|
||||||
|
fetchAP_T :: (MonadIO m, UriMode u, FromJSON a) => Manager -> Either (ObjURI u) (SubURI u) -> ExceptT Text m a
|
||||||
|
fetchAP_T m u = withExceptT T.pack $ fetchAP m u
|
||||||
|
|
||||||
{-
|
{-
|
||||||
fetchAPH :: (MonadIO m, ActivityPub a) => Manager -> Text -> LocalURI -> ExceptT String m a
|
fetchAPH :: (MonadIO m, ActivityPub a) => Manager -> Text -> LocalURI -> ExceptT String m a
|
||||||
fetchAPH m h lu = do
|
fetchAPH m h lu = do
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* This file is part of Vervis.
|
/* This file is part of Vervis.
|
||||||
*
|
*
|
||||||
* Written in 2016 by fr33domlover <fr33domlover@riseup.net>.
|
* Written in 2016, 2022 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.
|
||||||
*
|
*
|
||||||
|
@ -17,3 +17,12 @@
|
||||||
|
|
||||||
.#{cIrrelevant}
|
.#{cIrrelevant}
|
||||||
color: #{light gray}
|
color: #{light gray}
|
||||||
|
|
||||||
|
.apply-error
|
||||||
|
color: #{light red}
|
||||||
|
|
||||||
|
.apply-no
|
||||||
|
color: #{light yellow}
|
||||||
|
|
||||||
|
.apply-yes
|
||||||
|
color: #{light green}
|
||||||
|
|
|
@ -44,7 +44,7 @@ $maybe originRepo <- moriginRepo
|
||||||
$nothing
|
$nothing
|
||||||
#{branch}
|
#{branch}
|
||||||
|
|
||||||
$with (repoHash, name, maybeBranch) <- targetRepo
|
$with (_repoID, repoHash, name, maybeBranch) <- targetRepo
|
||||||
<div>
|
<div>
|
||||||
Target:
|
Target:
|
||||||
<a href=@{RepoR repoHash}>
|
<a href=@{RepoR repoHash}>
|
||||||
|
@ -54,7 +54,7 @@ $with (repoHash, name, maybeBranch) <- targetRepo
|
||||||
<a href=@{RepoBranchSourceR repoHash branch []}>
|
<a href=@{RepoBranchSourceR repoHash branch []}>
|
||||||
#{branch}
|
#{branch}
|
||||||
|
|
||||||
$maybe (bundleID, patchIDs) <- mbundle
|
$maybe (bundleID, patchIDs, errorOrCanApply) <- mbundle'
|
||||||
<div>
|
<div>
|
||||||
Bundle
|
Bundle
|
||||||
<a href=@{BundleR loomHash clothHash (hashBundle bundleID)}>
|
<a href=@{BundleR loomHash clothHash (hashBundle bundleID)}>
|
||||||
|
@ -65,6 +65,21 @@ $maybe (bundleID, patchIDs) <- mbundle
|
||||||
<li>
|
<li>
|
||||||
<a href=@{PatchR loomHash clothHash (hashBundle bundleID) (hashPatch patchID)}>
|
<a href=@{PatchR loomHash clothHash (hashBundle bundleID) (hashPatch patchID)}>
|
||||||
#{keyHashidText $ hashPatch patchID}
|
#{keyHashidText $ hashPatch patchID}
|
||||||
|
<div>
|
||||||
|
Status:
|
||||||
|
$case errorOrCanApply
|
||||||
|
$of Left e
|
||||||
|
<span .apply-error>
|
||||||
|
[Error! #{e}]
|
||||||
|
^{applyButton "Try applying anyway"}
|
||||||
|
$of Right False
|
||||||
|
<span .apply-no>
|
||||||
|
[Apply check failed! Possibly conflicts exist]
|
||||||
|
^{applyButton "Try applying anyway"}
|
||||||
|
$of Right True
|
||||||
|
<span .apply-yes>
|
||||||
|
[Can apply!]
|
||||||
|
^{applyButton "Apply"}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<span>
|
<span>
|
||||||
|
|
|
@ -30,3 +30,6 @@ $# <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||||
<li>
|
<li>
|
||||||
<a href=@{PublishOfferMergeR}>
|
<a href=@{PublishOfferMergeR}>
|
||||||
Open a merge request
|
Open a merge request
|
||||||
|
<li>
|
||||||
|
<a href=@{PublishMergeR}>
|
||||||
|
Merge a merge request
|
||||||
|
|
|
@ -131,6 +131,7 @@
|
||||||
/inbox InboxDebugR GET
|
/inbox InboxDebugR GET
|
||||||
|
|
||||||
/publish/offer-merge PublishOfferMergeR GET POST
|
/publish/offer-merge PublishOfferMergeR GET POST
|
||||||
|
/publish/merge PublishMergeR GET POST
|
||||||
|
|
||||||
---- Person ------------------------------------------------------------------
|
---- Person ------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -270,6 +271,7 @@
|
||||||
-- /looms/#LoomKeyHashid/cloths/#TicketLoomKeyHashid/unclaim ClothUnclaimR POST
|
-- /looms/#LoomKeyHashid/cloths/#TicketLoomKeyHashid/unclaim ClothUnclaimR POST
|
||||||
-- /looms/#LoomKeyHashid/cloths/#TicketLoomKeyHashid/assign ClothAssignR GET POST
|
-- /looms/#LoomKeyHashid/cloths/#TicketLoomKeyHashid/assign ClothAssignR GET POST
|
||||||
-- /looms/#LoomKeyHashid/cloths/#TicketLoomKeyHashid/unassign ClothUnassignR POST
|
-- /looms/#LoomKeyHashid/cloths/#TicketLoomKeyHashid/unassign ClothUnassignR POST
|
||||||
|
/looms/#LoomKeyHashid/cloths/#TicketLoomKeyHashid/apply ClothApplyR POST
|
||||||
/looms/#LoomKeyHashid/cloths/#TicketLoomKeyHashid/follow ClothFollowR POST
|
/looms/#LoomKeyHashid/cloths/#TicketLoomKeyHashid/follow ClothFollowR POST
|
||||||
/looms/#LoomKeyHashid/cloths/#TicketLoomKeyHashid/unfollow ClothUnfollowR POST
|
/looms/#LoomKeyHashid/cloths/#TicketLoomKeyHashid/unfollow ClothUnfollowR POST
|
||||||
/looms/#LoomKeyHashid/cloths/#TicketLoomKeyHashid/reply ClothReplyR POST
|
/looms/#LoomKeyHashid/cloths/#TicketLoomKeyHashid/reply ClothReplyR POST
|
||||||
|
|
Loading…
Reference in a new issue