Implement sharer ticket JSON view, including discussion, followers, deps etc.
This commit is contained in:
parent
00e0f7c14f
commit
0de98a9cdd
2 changed files with 247 additions and 3 deletions
|
@ -1,6 +1,6 @@
|
||||||
-- This file is part of Vervis.
|
-- This file is part of Vervis.
|
||||||
--
|
--
|
||||||
-- Written in 2016, 2018, 2019 by fr33domlover <fr33domlover@riseup.net>.
|
-- Written in 2016, 2018, 2019, 2020 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.
|
||||||
--
|
--
|
||||||
|
@ -184,5 +184,11 @@
|
||||||
/s/#ShrIdent/t SharerTicketsR GET
|
/s/#ShrIdent/t SharerTicketsR GET
|
||||||
|
|
||||||
/s/#ShrIdent/t/#TicketAuthorLocalKeyHashid SharerTicketR GET
|
/s/#ShrIdent/t/#TicketAuthorLocalKeyHashid SharerTicketR GET
|
||||||
|
/s/#ShrIdent/t/#TicketAuthorLocalKeyHashid/d SharerTicketDiscussionR GET
|
||||||
|
/s/#ShrIdent/t/#TicketAuthorLocalKeyHashid/deps SharerTicketDepsR GET
|
||||||
|
/s/#ShrIdent/t/#TicketAuthorLocalKeyHashid/rdeps SharerTicketReverseDepsR GET
|
||||||
|
/s/#ShrIdent/t/#TicketAuthorLocalKeyHashid/followers SharerTicketFollowersR GET
|
||||||
|
/s/#ShrIdent/t/#TicketAuthorLocalKeyHashid/team SharerTicketTeamR GET
|
||||||
|
/s/#ShrIdent/t/#TicketAuthorLocalKeyHashid/events SharerTicketEventsR GET
|
||||||
|
|
||||||
/s/#ShrIdent/p/#PrjIdent/w/+Texts WikiPageR GET
|
/s/#ShrIdent/p/#PrjIdent/w/+Texts WikiPageR GET
|
||||||
|
|
|
@ -54,6 +54,12 @@ module Vervis.Handler.Ticket
|
||||||
|
|
||||||
, getSharerTicketsR
|
, getSharerTicketsR
|
||||||
, getSharerTicketR
|
, getSharerTicketR
|
||||||
|
, getSharerTicketDiscussionR
|
||||||
|
, getSharerTicketDepsR
|
||||||
|
, getSharerTicketReverseDepsR
|
||||||
|
, getSharerTicketFollowersR
|
||||||
|
, getSharerTicketTeamR
|
||||||
|
, getSharerTicketEventsR
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
|
@ -64,10 +70,11 @@ import Control.Monad.Logger.CallStack
|
||||||
import Control.Monad.Trans.Except
|
import Control.Monad.Trans.Except
|
||||||
import Data.Aeson (encode)
|
import Data.Aeson (encode)
|
||||||
import Data.Bifunctor
|
import Data.Bifunctor
|
||||||
|
import Data.Bitraversable
|
||||||
import Data.Bool (bool)
|
import Data.Bool (bool)
|
||||||
import Data.Default.Class (def)
|
import Data.Default.Class (def)
|
||||||
import Data.Foldable (traverse_)
|
import Data.Foldable (traverse_)
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe
|
||||||
import Data.Monoid ((<>))
|
import Data.Monoid ((<>))
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Data.Time.Calendar (Day (..))
|
import Data.Time.Calendar (Day (..))
|
||||||
|
@ -1225,6 +1232,43 @@ getTicketEventsR
|
||||||
:: ShrIdent -> PrjIdent -> KeyHashid LocalTicket -> Handler TypedContent
|
:: ShrIdent -> PrjIdent -> KeyHashid LocalTicket -> Handler TypedContent
|
||||||
getTicketEventsR _shr _prj _ltkhid = error "TODO not implemented"
|
getTicketEventsR _shr _prj _ltkhid = error "TODO not implemented"
|
||||||
|
|
||||||
|
getSharerTicket
|
||||||
|
:: ShrIdent
|
||||||
|
-> KeyHashid TicketAuthorLocal
|
||||||
|
-> AppDB
|
||||||
|
( Entity TicketAuthorLocal
|
||||||
|
, Entity LocalTicket
|
||||||
|
, Entity Ticket
|
||||||
|
, Either (Entity TicketProjectLocal) ()
|
||||||
|
)
|
||||||
|
getSharerTicket shr talkhid = do
|
||||||
|
pid <- do
|
||||||
|
sid <- getKeyBy404 $ UniqueSharer shr
|
||||||
|
getKeyBy404 $ UniquePersonIdent sid
|
||||||
|
talid <- decodeKeyHashid404 talkhid
|
||||||
|
tal <- get404 talid
|
||||||
|
unless (ticketAuthorLocalAuthor tal == pid) notFound
|
||||||
|
let ltid = ticketAuthorLocalTicket tal
|
||||||
|
lt <- getJust ltid
|
||||||
|
let tid = localTicketTicket lt
|
||||||
|
t <- getJust tid
|
||||||
|
project <-
|
||||||
|
requireEitherAlt
|
||||||
|
(do mtpl <- getBy $ UniqueTicketProjectLocal tid
|
||||||
|
for mtpl $ \ etpl@(Entity tplid tpl) -> do
|
||||||
|
mtup1 <- getBy $ UniqueTicketUnderProjectProject tplid
|
||||||
|
mtup2 <- getBy $ UniqueTicketUnderProjectAuthor talid
|
||||||
|
unless (isJust mtup1 == isJust mtup2) $
|
||||||
|
error "TUP points to unrelated TAL and TPL!"
|
||||||
|
unless (isNothing mtup1) notFound
|
||||||
|
return etpl
|
||||||
|
)
|
||||||
|
(return Nothing
|
||||||
|
)
|
||||||
|
"Ticket doesn't have project"
|
||||||
|
"Ticket has both local and remote project"
|
||||||
|
return (Entity talid tal, Entity ltid lt, Entity tid t, project)
|
||||||
|
|
||||||
getSharerTicketsR :: ShrIdent -> Handler TypedContent
|
getSharerTicketsR :: ShrIdent -> Handler TypedContent
|
||||||
getSharerTicketsR shr = do
|
getSharerTicketsR shr = do
|
||||||
(total, pages, mpage) <- runDB $ do
|
(total, pages, mpage) <- runDB $ do
|
||||||
|
@ -1298,4 +1342,198 @@ getSharerTicketsR shr = do
|
||||||
|
|
||||||
getSharerTicketR
|
getSharerTicketR
|
||||||
:: ShrIdent -> KeyHashid TicketAuthorLocal -> Handler TypedContent
|
:: ShrIdent -> KeyHashid TicketAuthorLocal -> Handler TypedContent
|
||||||
getSharerTicketR shr talkhid = error "Not implemented yet"
|
getSharerTicketR shr talkhid = do
|
||||||
|
(ticket, project, massignee) <- runDB $ do
|
||||||
|
(_, _, Entity _ t, tp) <- getSharerTicket shr talkhid
|
||||||
|
(,,) t
|
||||||
|
<$> bitraverse
|
||||||
|
(\ (Entity _ tpl) -> do
|
||||||
|
j <- getJust $ ticketProjectLocalProject tpl
|
||||||
|
s <- getJust $ projectSharer j
|
||||||
|
return (s, j)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
tp
|
||||||
|
<*> (for (ticketAssignee t) $ \ pidAssignee -> do
|
||||||
|
p <- getJust pidAssignee
|
||||||
|
getJust $ personIdent p
|
||||||
|
)
|
||||||
|
hLocal <- getsYesod siteInstanceHost
|
||||||
|
encodeRouteLocal <- getEncodeRouteLocal
|
||||||
|
encodeRouteHome <- getEncodeRouteHome
|
||||||
|
let ticketAP = AP.Ticket
|
||||||
|
{ AP.ticketLocal = Just
|
||||||
|
( hLocal
|
||||||
|
, AP.TicketLocal
|
||||||
|
{ AP.ticketId =
|
||||||
|
encodeRouteLocal $ SharerTicketR shr talkhid
|
||||||
|
, AP.ticketContext =
|
||||||
|
encodeRouteLocal $
|
||||||
|
case project of
|
||||||
|
Left (s, j) ->
|
||||||
|
ProjectR (sharerIdent s) (projectIdent j)
|
||||||
|
Right () -> error "No TPR yet!"
|
||||||
|
, AP.ticketReplies =
|
||||||
|
encodeRouteLocal $ SharerTicketDiscussionR shr talkhid
|
||||||
|
, AP.ticketParticipants =
|
||||||
|
encodeRouteLocal $ SharerTicketFollowersR shr talkhid
|
||||||
|
, AP.ticketTeam =
|
||||||
|
encodeRouteLocal $ SharerTicketTeamR shr talkhid
|
||||||
|
, AP.ticketEvents =
|
||||||
|
encodeRouteLocal $ SharerTicketEventsR shr talkhid
|
||||||
|
, AP.ticketDeps =
|
||||||
|
encodeRouteLocal $ SharerTicketDepsR shr talkhid
|
||||||
|
, AP.ticketReverseDeps =
|
||||||
|
encodeRouteLocal $ SharerTicketReverseDepsR shr talkhid
|
||||||
|
}
|
||||||
|
)
|
||||||
|
, AP.ticketAttributedTo = encodeRouteLocal $ SharerR shr
|
||||||
|
, AP.ticketPublished = Just $ ticketCreated ticket
|
||||||
|
, AP.ticketUpdated = Nothing
|
||||||
|
, 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
|
||||||
|
}
|
||||||
|
provideHtmlAndAP ticketAP $ redirectToPrettyJSON here
|
||||||
|
where
|
||||||
|
here = SharerTicketR shr talkhid
|
||||||
|
|
||||||
|
getSharerTicketDiscussionR
|
||||||
|
:: ShrIdent -> KeyHashid TicketAuthorLocal -> Handler TypedContent
|
||||||
|
getSharerTicketDiscussionR shr talkhid = do
|
||||||
|
(locals, remotes) <- runDB $ do
|
||||||
|
(_, Entity _ lt, _, _) <- getSharerTicket shr talkhid
|
||||||
|
let did = localTicketDiscuss lt
|
||||||
|
(,) <$> selectLocals did <*> selectRemotes did
|
||||||
|
encodeRouteLocal <- getEncodeRouteLocal
|
||||||
|
encodeRouteHome <- getEncodeRouteHome
|
||||||
|
encodeHid <- getEncodeKeyHashid
|
||||||
|
let localUri' = localUri encodeRouteHome encodeHid
|
||||||
|
replies = Collection
|
||||||
|
{ collectionId = encodeRouteLocal here
|
||||||
|
, collectionType = CollectionTypeUnordered
|
||||||
|
, collectionTotalItems = Just $ length locals + length remotes
|
||||||
|
, collectionCurrent = Nothing
|
||||||
|
, collectionFirst = Nothing
|
||||||
|
, collectionLast = Nothing
|
||||||
|
, collectionItems =
|
||||||
|
map localUri' locals ++ map remoteUri remotes
|
||||||
|
}
|
||||||
|
provideHtmlAndAP replies $ redirectToPrettyJSON here
|
||||||
|
where
|
||||||
|
here = SharerTicketDiscussionR shr talkhid
|
||||||
|
selectLocals did =
|
||||||
|
E.select $ E.from $
|
||||||
|
\ (m `E.InnerJoin` lm `E.InnerJoin` p `E.InnerJoin` s) -> do
|
||||||
|
E.on $ p E.^. PersonIdent E.==. s E.^. SharerId
|
||||||
|
E.on $ lm E.^. LocalMessageAuthor E.==. p E.^. PersonId
|
||||||
|
E.on $ m E.^. MessageId E.==. lm E.^. LocalMessageRest
|
||||||
|
E.where_ $
|
||||||
|
m E.^. MessageRoot E.==. E.val did E.&&.
|
||||||
|
E.isNothing (m E.^. MessageParent) E.&&.
|
||||||
|
E.isNothing (lm E.^. LocalMessageUnlinkedParent)
|
||||||
|
return (s E.^. SharerIdent, lm E.^. LocalMessageId)
|
||||||
|
selectRemotes did =
|
||||||
|
E.select $ E.from $
|
||||||
|
\ (m `E.InnerJoin` rm `E.InnerJoin` ro `E.InnerJoin` i) -> do
|
||||||
|
E.on $ ro E.^. RemoteObjectInstance E.==. i E.^. InstanceId
|
||||||
|
E.on $ rm E.^. RemoteMessageIdent E.==. ro E.^. RemoteObjectId
|
||||||
|
E.on $ m E.^. MessageId E.==. rm E.^. RemoteMessageRest
|
||||||
|
E.where_ $
|
||||||
|
m E.^. MessageRoot E.==. E.val did E.&&.
|
||||||
|
E.isNothing (m E.^. MessageParent) E.&&.
|
||||||
|
E.isNothing (rm E.^. RemoteMessageLostParent)
|
||||||
|
return (i E.^. InstanceHost, ro E.^. RemoteObjectIdent)
|
||||||
|
localUri encR encH (E.Value shrAuthor, E.Value lmid) =
|
||||||
|
encR $ MessageR shrAuthor (encH lmid)
|
||||||
|
remoteUri (E.Value h, E.Value lu) = ObjURI h lu
|
||||||
|
|
||||||
|
getSharerTicketDeps
|
||||||
|
:: Bool -> ShrIdent -> KeyHashid TicketAuthorLocal -> Handler TypedContent
|
||||||
|
getSharerTicketDeps forward shr talkhid = do
|
||||||
|
tdids <- runDB $ do
|
||||||
|
(_, _, Entity tid _, _) <- getSharerTicket shr talkhid
|
||||||
|
let (from, to) =
|
||||||
|
if forward
|
||||||
|
then (TicketDependencyParent, TicketDependencyChild)
|
||||||
|
else (TicketDependencyChild, TicketDependencyParent)
|
||||||
|
E.select $ E.from $ \ (td `E.InnerJoin` t) -> do
|
||||||
|
E.on $ td E.^. to E.==. t E.^. TicketId
|
||||||
|
E.where_ $ td E.^. from E.==. E.val tid
|
||||||
|
return $ td E.^. TicketDependencyId
|
||||||
|
encodeRouteLocal <- getEncodeRouteLocal
|
||||||
|
encodeRouteHome <- getEncodeRouteHome
|
||||||
|
encodeHid <- getEncodeKeyHashid
|
||||||
|
let deps = Collection
|
||||||
|
{ collectionId = encodeRouteLocal here
|
||||||
|
, collectionType = CollectionTypeUnordered
|
||||||
|
, collectionTotalItems = Just $ length tdids
|
||||||
|
, collectionCurrent = Nothing
|
||||||
|
, collectionFirst = Nothing
|
||||||
|
, collectionLast = Nothing
|
||||||
|
, collectionItems =
|
||||||
|
map (encodeRouteHome . TicketDepR . encodeHid . E.unValue)
|
||||||
|
tdids
|
||||||
|
}
|
||||||
|
provideHtmlAndAP deps $ redirectToPrettyJSON here
|
||||||
|
where
|
||||||
|
here =
|
||||||
|
let route =
|
||||||
|
if forward then SharerTicketDepsR else SharerTicketReverseDepsR
|
||||||
|
in route shr talkhid
|
||||||
|
|
||||||
|
getSharerTicketDepsR
|
||||||
|
:: ShrIdent -> KeyHashid TicketAuthorLocal -> Handler TypedContent
|
||||||
|
getSharerTicketDepsR = getSharerTicketDeps True
|
||||||
|
|
||||||
|
getSharerTicketReverseDepsR
|
||||||
|
:: ShrIdent -> KeyHashid TicketAuthorLocal -> Handler TypedContent
|
||||||
|
getSharerTicketReverseDepsR = getSharerTicketDeps False
|
||||||
|
|
||||||
|
getSharerTicketFollowersR
|
||||||
|
:: ShrIdent -> KeyHashid TicketAuthorLocal -> Handler TypedContent
|
||||||
|
getSharerTicketFollowersR shr talkhid = getFollowersCollection here getFsid
|
||||||
|
where
|
||||||
|
here = SharerTicketFollowersR shr talkhid
|
||||||
|
getFsid = do
|
||||||
|
(_, Entity _ lt, _, _) <- getSharerTicket shr talkhid
|
||||||
|
return $ localTicketFollowers lt
|
||||||
|
|
||||||
|
getSharerTicketTeamR
|
||||||
|
:: ShrIdent -> KeyHashid TicketAuthorLocal -> Handler TypedContent
|
||||||
|
getSharerTicketTeamR shr talkhid = do
|
||||||
|
_ <- runDB $ getSharerTicket shr talkhid
|
||||||
|
encodeRouteLocal <- getEncodeRouteLocal
|
||||||
|
let team = Collection
|
||||||
|
{ collectionId = encodeRouteLocal here
|
||||||
|
, collectionType = CollectionTypeUnordered
|
||||||
|
, collectionTotalItems = Just 0
|
||||||
|
, collectionCurrent = Nothing
|
||||||
|
, collectionFirst = Nothing
|
||||||
|
, collectionLast = Nothing
|
||||||
|
, collectionItems = [] :: [Text]
|
||||||
|
}
|
||||||
|
provideHtmlAndAP team $ redirectToPrettyJSON here
|
||||||
|
where
|
||||||
|
here = SharerTicketTeamR shr talkhid
|
||||||
|
|
||||||
|
getSharerTicketEventsR
|
||||||
|
:: ShrIdent -> KeyHashid TicketAuthorLocal -> Handler TypedContent
|
||||||
|
getSharerTicketEventsR shr talkhid = do
|
||||||
|
_ <- runDB $ getSharerTicket shr talkhid
|
||||||
|
encodeRouteLocal <- getEncodeRouteLocal
|
||||||
|
let team = Collection
|
||||||
|
{ collectionId = encodeRouteLocal here
|
||||||
|
, collectionType = CollectionTypeOrdered
|
||||||
|
, collectionTotalItems = Just 0
|
||||||
|
, collectionCurrent = Nothing
|
||||||
|
, collectionFirst = Nothing
|
||||||
|
, collectionLast = Nothing
|
||||||
|
, collectionItems = [] :: [Text]
|
||||||
|
}
|
||||||
|
provideHtmlAndAP team $ redirectToPrettyJSON here
|
||||||
|
where
|
||||||
|
here = SharerTicketEventsR shr talkhid
|
||||||
|
|
Loading…
Reference in a new issue