Add repo-hosted patch routes and GET handlers
This commit is contained in:
parent
e29233a59f
commit
d9c00cba1f
2 changed files with 306 additions and 1 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue