Add repo-hosted patch routes and GET handlers

This commit is contained in:
fr33domlover 2020-05-26 14:51:11 +00:00
parent e29233a59f
commit d9c00cba1f
2 changed files with 306 additions and 1 deletions

View file

@ -110,6 +110,17 @@
/s/#ShrIdent/r/#RpIdent/d/!new RepoDevNewR GET /s/#ShrIdent/r/#RpIdent/d/!new RepoDevNewR GET
/s/#ShrIdent/r/#RpIdent/d/#ShrIdent RepoDevR GET DELETE POST /s/#ShrIdent/r/#RpIdent/d/#ShrIdent RepoDevR GET DELETE POST
/s/#ShrIdent/r/#RpIdent/pt RepoPatchesR GET
/s/#ShrIdent/r/#RpIdent/pt/#LocalTicketKeyHashid RepoPatchR GET
/s/#ShrIdent/r/#RpIdent/pt/#LocalTicketKeyHashid/d RepoPatchDiscussionR GET
/s/#ShrIdent/r/#RpIdent/pt/#LocalTicketKeyHashid/deps RepoPatchDepsR GET
/s/#ShrIdent/r/#RpIdent/pt/#LocalTicketKeyHashid/rdeps RepoPatchReverseDepsR GET
/s/#ShrIdent/r/#RpIdent/pt/#LocalTicketKeyHashid/followers RepoPatchFollowersR GET
/s/#ShrIdent/r/#RpIdent/pt/#LocalTicketKeyHashid/events RepoPatchEventsR GET
/s/#ShrIdent/r/#RpIdent/pt/#LocalTicketKeyHashid/v/#PatchKeyHashid RepoPatchVersionR GET
/s/#ShrIdent/r/#RpIdent/_darcs/+Texts DarcsDownloadR GET /s/#ShrIdent/r/#RpIdent/_darcs/+Texts DarcsDownloadR GET
/s/#ShrIdent/r/#RpIdent/info/refs GitRefDiscoverR GET /s/#ShrIdent/r/#RpIdent/info/refs GitRefDiscoverR GET

View file

@ -21,13 +21,23 @@ module Vervis.Handler.Patch
, getSharerPatchReverseDepsR , getSharerPatchReverseDepsR
, getSharerPatchFollowersR , getSharerPatchFollowersR
, getSharerPatchEventsR , getSharerPatchEventsR
, getSharerPatchVersionR , getSharerPatchVersionR
, getRepoPatchesR
, getRepoPatchR
, getRepoPatchDiscussionR
, getRepoPatchDepsR
, getRepoPatchReverseDepsR
, getRepoPatchFollowersR
, getRepoPatchEventsR
, getRepoPatchVersionR
) )
where where
import Control.Monad import Control.Monad
import Data.Bifunctor
import Data.Bitraversable import Data.Bitraversable
import Data.Function
import Data.Text (Text) import Data.Text (Text)
import Data.Traversable import Data.Traversable
import Database.Persist import Database.Persist
@ -35,6 +45,7 @@ import Yesod.Core
import Yesod.Persist.Core import Yesod.Persist.Core
import qualified Data.List.NonEmpty as NE import qualified Data.List.NonEmpty as NE
import qualified Data.List.Ordered as LO
import qualified Database.Esqueleto as E import qualified Database.Esqueleto as E
import Network.FedURI import Network.FedURI
@ -266,3 +277,286 @@ getSharerPatchVersionR shr talkhid ptkhid = do
provideHtmlAndAP versionAP $ redirectToPrettyJSON here provideHtmlAndAP versionAP $ redirectToPrettyJSON here
where where
here = SharerPatchVersionR shr talkhid ptkhid here = SharerPatchVersionR shr talkhid ptkhid
getRepoPatchesR :: ShrIdent -> RpIdent -> Handler TypedContent
getRepoPatchesR shr rp = do
(total, pages, mpage) <- runDB $ do
sid <- getKeyBy404 $ UniqueSharer shr
rid <- getKeyBy404 $ UniqueRepo rp sid
getPageAndNavCount (countPatches rid) (selectPatches rid)
encodeRouteHome <- getEncodeRouteHome
encodeRouteLocal <- getEncodeRouteLocal
encodeRoutePageLocal <- getEncodeRoutePageLocal
let here = RepoPatchesR shr rp
pageUrl = encodeRoutePageLocal here
encodeLT <- getEncodeKeyHashid
encodeTAL <- getEncodeKeyHashid
let patchUrl (Left (E.Value ltid, E.Value mtalid, E.Value mshr, E.Value mtupid)) =
encodeRouteHome $
case (mtalid, mshr, mtupid) of
(Nothing, Nothing, Nothing) -> RepoPatchR shr rp $ encodeLT ltid
(Just talid, Just shrA, Nothing) -> SharerPatchR shrA $ encodeTAL talid
(Just _, Just _, Just _) -> RepoPatchR shr rp $ encodeLT ltid
_ -> error "Impossible"
patchUrl (Right (E.Value h, E.Value lu)) = ObjURI h lu
case mpage of
Nothing -> provide here $ Collection
{ collectionId = encodeRouteLocal here
, collectionType = CollectionTypeOrdered
, collectionTotalItems = Just total
, collectionCurrent = Nothing
, collectionFirst = Just $ pageUrl 1
, collectionLast = Just $ pageUrl pages
, collectionItems = [] :: [Text]
}
Just (patches, navModel) ->
let current = nmCurrent navModel
in provide here $ CollectionPage
{ collectionPageId = pageUrl current
, collectionPageType = CollectionPageTypeOrdered
, collectionPageTotalItems = Nothing
, collectionPageCurrent = Just $ pageUrl current
, collectionPageFirst = Just $ pageUrl 1
, collectionPageLast = Just $ pageUrl pages
, collectionPagePartOf = encodeRouteLocal here
, collectionPagePrev =
if current > 1
then Just $ pageUrl $ current - 1
else Nothing
, collectionPageNext =
if current < pages
then Just $ pageUrl $ current + 1
else Nothing
, collectionPageStartIndex = Nothing
, collectionPageItems = map patchUrl patches
}
where
provide :: ActivityPub a => Route App -> a URIMode -> Handler TypedContent
provide here a = provideHtmlAndAP a $ redirectToPrettyJSON here
countPatches rid = count [TicketRepoLocalRepo ==. rid]
selectPatches rid off lim = do
tids <- E.select $ E.from $ \ (tcl `E.InnerJoin` trl) -> do
E.on $ tcl E.^. TicketContextLocalId E.==. trl E.^. TicketRepoLocalContext
E.where_ $ trl E.^. TicketRepoLocalRepo E.==. E.val rid
E.orderBy [E.desc $ tcl E.^. TicketContextLocalTicket]
E.offset $ fromIntegral off
E.limit $ fromIntegral lim
return $ tcl E.^. TicketContextLocalTicket
let tids' = map E.unValue tids
locals <- E.select $ E.from $ \ (lt `E.LeftOuterJoin` (tal `E.InnerJoin` p `E.InnerJoin` s `E.LeftOuterJoin` tup)) -> do
E.on $ tal E.?. TicketAuthorLocalId E.==. tup E.?. TicketUnderProjectAuthor
E.on $ p E.?. PersonIdent E.==. s E.?. SharerId
E.on $ tal E.?. TicketAuthorLocalAuthor E.==. p E.?. PersonId
E.on $ E.just (lt E.^. LocalTicketId) E.==. tal E.?. TicketAuthorLocalTicket
E.where_ $ lt E.^. LocalTicketTicket `E.in_` E.valList tids'
E.orderBy [E.desc $ lt E.^. LocalTicketTicket]
return
( lt E.^. LocalTicketTicket
, ( lt E.^. LocalTicketId
, tal E.?. TicketAuthorLocalId
, s E.?. SharerIdent
, tup E.?. TicketUnderProjectId
)
)
remotes <- E.select $ E.from $ \ (tcl `E.InnerJoin` tar `E.InnerJoin` rt `E.InnerJoin` ro `E.InnerJoin` i) -> do
E.on $ ro E.^. RemoteObjectInstance E.==. i E.^. InstanceId
E.on $ rt E.^. RemoteTicketIdent E.==. ro E.^. RemoteObjectId
E.on $ tar E.^. TicketAuthorRemoteId E.==. rt E.^. RemoteTicketTicket
E.on $ tcl E.^. TicketContextLocalId E.==. tar E.^. TicketAuthorRemoteTicket
E.where_ $ tcl E.^. TicketContextLocalTicket `E.in_` E.valList tids'
E.orderBy [E.desc $ tcl E.^. TicketContextLocalTicket]
return
( tcl E.^. TicketContextLocalTicket
, ( i E.^. InstanceHost
, ro E.^. RemoteObjectIdent
)
)
return $
map snd $
LO.mergeBy
(flip compare `on` fst)
(map (second Left) locals)
(map (second Right) remotes)
getRepoPatchR
:: ShrIdent -> RpIdent -> KeyHashid LocalTicket -> Handler TypedContent
getRepoPatchR shr rp ltkhid = do
(ticket, ptids, trl, author, massignee) <- runDB $ do
(_, _, Entity tid t, _, _, Entity _ trl, ta, ptids) <- getRepoPatch404 shr rp ltkhid
(,,,,) t ptids trl
<$> bitraverse
(\ (Entity _ tal, _) -> do
p <- getJust $ ticketAuthorLocalAuthor tal
getJust $ personIdent p
)
(\ (Entity _ tar) -> do
ra <- getJust $ ticketAuthorRemoteAuthor tar
ro <- getJust $ remoteActorIdent ra
i <- getJust $ remoteObjectInstance ro
return (i, ro)
)
ta
<*> (for (ticketAssignee t) $ \ pidAssignee -> do
p <- getJust pidAssignee
getJust $ personIdent p
)
hLocal <- getsYesod siteInstanceHost
encodeRouteLocal <- getEncodeRouteLocal
encodeRouteHome <- getEncodeRouteHome
encodePatchId <- getEncodeKeyHashid
let versionUrl = RepoPatchVersionR shr rp ltkhid . encodePatchId
host =
case author of
Left _ -> hLocal
Right (i, _) -> instanceHost i
patchAP = AP.Ticket
{ AP.ticketLocal = Just
( hLocal
, AP.TicketLocal
{ AP.ticketId =
encodeRouteLocal $ RepoPatchR shr rp ltkhid
, AP.ticketReplies =
encodeRouteLocal $ RepoPatchDiscussionR shr rp ltkhid
, AP.ticketParticipants =
encodeRouteLocal $ RepoPatchFollowersR shr rp ltkhid
, AP.ticketTeam = Nothing
, AP.ticketEvents =
encodeRouteLocal $ RepoPatchEventsR shr rp ltkhid
, AP.ticketDeps =
encodeRouteLocal $ RepoPatchDepsR shr rp ltkhid
, AP.ticketReverseDeps =
encodeRouteLocal $ RepoPatchReverseDepsR shr rp ltkhid
}
)
, AP.ticketAttributedTo =
case author of
Left sharer ->
encodeRouteLocal $ SharerR $ sharerIdent sharer
Right (_inztance, object) ->
remoteObjectIdent object
, AP.ticketPublished = Just $ ticketCreated ticket
, AP.ticketUpdated = Nothing
, AP.ticketContext = Just $ encodeRouteHome $ RepoR shr rp
, AP.ticketSummary = TextHtml $ ticketTitle ticket
, AP.ticketContent = TextHtml $ ticketDescription ticket
, AP.ticketSource = TextPandocMarkdown $ ticketSource ticket
, AP.ticketAssignedTo =
encodeRouteHome . SharerR . sharerIdent <$> massignee
, AP.ticketIsResolved = ticketStatus ticket == TSClosed
, AP.ticketAttachment = Just
( hLocal
, MergeRequest
{ mrOrigin = Nothing
, mrTarget =
encodeRouteHome $
case ticketRepoLocalBranch trl of
Nothing -> RepoR shr rp
Just b -> RepoBranchR shr rp b
, mrPatch = NE.map (encodeRouteLocal . versionUrl) ptids
}
)
}
provideHtmlAndAP' host patchAP $ redirectToPrettyJSON here
where
here = RepoPatchR shr rp ltkhid
getRepoPatchDiscussionR
:: ShrIdent -> RpIdent -> KeyHashid LocalTicket -> Handler TypedContent
getRepoPatchDiscussionR shr rp ltkhid =
getRepliesCollection (RepoPatchDiscussionR shr rp ltkhid) $ do
(_, _, _, Entity _ lt, _, _, _, _) <- getRepoPatch404 shr rp ltkhid
return $ localTicketDiscuss lt
getRepoPatchDeps
:: Bool
-> ShrIdent
-> RpIdent
-> KeyHashid LocalTicket
-> Handler TypedContent
getRepoPatchDeps forward shr rp ltkhid =
getDependencyCollection here getTicketId404 forward
where
here =
let route =
if forward then RepoPatchDepsR else RepoPatchReverseDepsR
in route shr rp ltkhid
getTicketId404 = do
(_, _, Entity tid _, _, _, _, _, _) <- getRepoPatch404 shr rp ltkhid
return tid
getRepoPatchDepsR
:: ShrIdent -> RpIdent -> KeyHashid LocalTicket -> Handler TypedContent
getRepoPatchDepsR = getRepoPatchDeps True
getRepoPatchReverseDepsR
:: ShrIdent -> RpIdent -> KeyHashid LocalTicket -> Handler TypedContent
getRepoPatchReverseDepsR = getRepoPatchDeps False
getRepoPatchFollowersR
:: ShrIdent -> RpIdent -> KeyHashid LocalTicket -> Handler TypedContent
getRepoPatchFollowersR shr rp ltkhid = getFollowersCollection here getFsid
where
here = RepoPatchFollowersR shr rp ltkhid
getFsid = do
(_, _, _, Entity _ lt, _, _, _, _) <- getRepoPatch404 shr rp ltkhid
return $ localTicketFollowers lt
getRepoPatchEventsR
:: ShrIdent -> RpIdent -> KeyHashid LocalTicket -> Handler TypedContent
getRepoPatchEventsR shr rp ltkhid = do
_ <- runDB $ getRepoPatch404 shr rp ltkhid
provideEmptyCollection
CollectionTypeOrdered
(RepoPatchEventsR shr rp ltkhid)
getRepoPatchVersionR
:: ShrIdent
-> RpIdent
-> KeyHashid LocalTicket
-> KeyHashid Patch
-> Handler TypedContent
getRepoPatchVersionR shr rp ltkhid ptkhid = do
(vcs, patch, author) <- runDB $ do
(_, Entity _ repo, Entity tid _, _, _, _, ta, _) <- getRepoPatch404 shr rp ltkhid
(repoVcs repo,,)
<$> do ptid <- decodeKeyHashid404 ptkhid
pt <- get404 ptid
unless (patchTicket pt == tid) notFound
return pt
<*> bitraverse
(\ (Entity _ tal, _) -> do
p <- getJust $ ticketAuthorLocalAuthor tal
getJust $ personIdent p
)
(\ (Entity _ tar) -> do
ra <- getJust $ ticketAuthorRemoteAuthor tar
ro <- getJust $ remoteActorIdent ra
i <- getJust $ remoteObjectInstance ro
return (i, ro)
)
ta
encodeRouteLocal <- getEncodeRouteLocal
encodeRouteHome <- getEncodeRouteHome
let versionAP = AP.Patch
{ AP.patchId = encodeRouteLocal here
, AP.patchAttributedTo =
case author of
Left sharer ->
encodeRouteHome $ SharerR $ sharerIdent sharer
Right (inztance, object) ->
ObjURI
(instanceHost inztance)
(remoteObjectIdent object)
, AP.patchPublished = patchCreated patch
, AP.patchContext = encodeRouteLocal $ RepoPatchR shr rp ltkhid
, AP.patchType =
case vcs of
VCSDarcs -> PatchTypeDarcs
VCSGit -> error "TODO add PatchType for git patches"
, AP.patchContent = patchContent patch
}
provideHtmlAndAP versionAP $ redirectToPrettyJSON here
where
here = RepoPatchVersionR shr rp ltkhid ptkhid