1
0
Fork 0
mirror of https://code.sup39.dev/repos/Wqawg synced 2025-01-10 16:36:46 +09:00
vervis/src/Vervis/Handler/Ticket.hs

685 lines
27 KiB
Haskell
Raw Normal View History

2016-05-01 07:32:22 +09:00
{- This file is part of Vervis.
-
- Written in 2016 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.Handler.Ticket
( getTicketsR
, postTicketsR
2016-08-04 16:36:24 +09:00
, getTicketTreeR
2016-05-01 07:32:22 +09:00
, getTicketNewR
2016-05-01 08:02:44 +09:00
, getTicketR
, putTicketR
, deleteTicketR
, postTicketR
, getTicketEditR
, postTicketCloseR
, postTicketOpenR
, postTicketClaimR
, postTicketUnclaimR
, getTicketAssignR
, postTicketAssignR
, postTicketUnassignR
, getClaimRequestsPersonR
, getClaimRequestsProjectR
, getClaimRequestsTicketR
2016-06-08 10:28:18 +09:00
, postClaimRequestsTicketR
, getClaimRequestNewR
2016-05-20 01:58:23 +09:00
, getTicketDiscussionR
, postTicketDiscussionR
2016-05-20 07:07:25 +09:00
, getTicketMessageR
, postTicketMessageR
, getTicketTopReplyR
, getTicketReplyR
, getTicketDepsR
, postTicketDepsR
, getTicketDepNewR
, postTicketDepR
, deleteTicketDepR
2016-07-27 17:35:50 +09:00
, getTicketReverseDepsR
2016-05-01 07:32:22 +09:00
)
where
import Prelude
2016-08-04 16:36:24 +09:00
import Control.Applicative (liftA2)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Logger (logWarn)
2016-05-22 23:31:56 +09:00
import Data.Default.Class (def)
2016-05-01 18:58:55 +09:00
import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))
2016-05-01 07:32:22 +09:00
import Data.Text (Text)
import Data.Time.Calendar (Day (..))
import Data.Time.Clock (UTCTime (..), getCurrentTime)
2016-05-01 18:58:55 +09:00
import Data.Time.Format (formatTime, defaultTimeLocale)
2016-06-02 01:20:19 +09:00
import Data.Traversable (for)
import Database.Esqueleto hiding ((==.), (=.), (+=.), update, delete)
2016-05-01 08:02:44 +09:00
import Database.Persist
2016-05-01 07:32:22 +09:00
import Text.Blaze.Html (Html, toHtml)
2016-06-06 19:00:05 +09:00
import Yesod.Auth (requireAuthId, maybeAuthId)
2016-05-01 07:32:22 +09:00
import Yesod.Core (defaultLayout)
import Yesod.Core.Handler (setMessage, redirect, lookupPostParam, notFound)
2016-05-22 23:31:56 +09:00
import Yesod.Form.Functions (runFormGet, runFormPost)
2016-05-01 19:15:38 +09:00
import Yesod.Form.Types (FormResult (..))
2016-05-01 18:58:55 +09:00
import Yesod.Persist.Core (runDB, get404, getBy404)
2016-05-01 07:32:22 +09:00
import qualified Data.Text as T (filter, intercalate, pack)
2016-05-01 18:58:55 +09:00
import qualified Database.Esqueleto as E ((==.))
2016-05-01 07:32:22 +09:00
import Database.Persist.Sql.Graph.TransitiveReduction (trrFix)
2016-05-01 07:32:22 +09:00
import Vervis.Form.Ticket
import Vervis.Foundation
2016-05-20 01:58:23 +09:00
import Vervis.Handler.Discussion
import Vervis.GraphProxy (ticketDepGraph)
import Vervis.MediaType (MediaType (Markdown))
2016-05-01 07:32:22 +09:00
import Vervis.Model
import Vervis.Model.Ident
import Vervis.Model.Workflow
import Vervis.Render (renderSourceT)
2016-05-01 07:32:22 +09:00
import Vervis.Settings (widgetFile)
2016-08-04 16:36:24 +09:00
import Vervis.Ticket
2016-05-22 23:31:56 +09:00
import Vervis.TicketFilter (filterTickets)
2016-06-06 16:26:58 +09:00
import Vervis.Time (showDate)
import Vervis.Widget.Discussion (discussionW)
2016-05-25 06:48:21 +09:00
import Vervis.Widget.Sharer (personLinkW)
import Vervis.Widget.Ticket
2016-05-01 07:32:22 +09:00
getTicketsR :: ShrIdent -> PrjIdent -> Handler Html
2016-05-01 08:02:44 +09:00
getTicketsR shar proj = do
2016-05-22 23:31:56 +09:00
((filtResult, filtWidget), filtEnctype) <- runFormGet ticketFilterForm
let tf =
case filtResult of
FormSuccess filt -> filt
FormMissing -> def
FormFailure l ->
error $ "Ticket filter form failed: " ++ show l
rows <- runDB $ select $ from $ \ (sharer, project, ticket) -> do
2016-05-22 23:31:56 +09:00
where_ $ filterTickets tf ticket $
sharer ^. SharerIdent E.==. val shar &&.
project ^. ProjectSharer E.==. sharer ^. SharerId &&.
project ^. ProjectIdent E.==. val proj &&.
ticket ^. TicketProject E.==. project ^. ProjectId
2016-05-01 18:58:55 +09:00
orderBy [asc $ ticket ^. TicketNumber]
return
( ticket ^. TicketNumber
, sharer
2016-05-01 18:58:55 +09:00
, ticket ^. TicketTitle
, ticket ^. TicketDone
)
defaultLayout $(widgetFile "ticket/list")
2016-05-01 07:32:22 +09:00
postTicketsR :: ShrIdent -> PrjIdent -> Handler Html
2016-05-01 19:15:38 +09:00
postTicketsR shar proj = do
2016-05-20 07:07:25 +09:00
((result, widget), enctype) <- runFormPost newTicketForm
2016-05-01 19:15:38 +09:00
case result of
FormSuccess nt -> do
author <- requireAuthId
now <- liftIO getCurrentTime
tnum <- runDB $ do
Entity pid project <- do
Entity sid _sharer <- getBy404 $ UniqueSharer shar
getBy404 $ UniqueProject proj sid
2016-05-18 18:44:32 +09:00
update pid [ProjectNextTicket +=. 1]
2016-05-20 01:58:23 +09:00
let discussion = Discussion
{ discussionNextMessage = 1
}
did <- insert discussion
let ticket = Ticket
2016-06-02 01:20:19 +09:00
{ ticketProject = pid
, ticketNumber = projectNextTicket project
, ticketCreated = now
, ticketCreator = author
, ticketTitle = ntTitle nt
, ticketDesc = ntDesc nt
, ticketAssignee = Nothing
, ticketDone = False
, ticketClosed = UTCTime (ModifiedJulianDay 0) 0
, ticketCloser = author
, ticketDiscuss = did
}
2016-05-01 19:15:38 +09:00
insert_ ticket
return $ ticketNumber ticket
2016-05-01 19:15:38 +09:00
setMessage "Ticket created."
redirect $ TicketR shar proj tnum
2016-05-01 19:15:38 +09:00
FormMissing -> do
setMessage "Field(s) missing."
defaultLayout $(widgetFile "ticket/new")
FormFailure _l -> do
setMessage "Ticket creation failed, see errors below."
defaultLayout $(widgetFile "ticket/new")
2016-05-01 07:32:22 +09:00
2016-08-04 16:36:24 +09:00
getTicketTreeR :: ShrIdent -> PrjIdent -> Handler Html
getTicketTreeR shr prj = do
(summaries, deps) <- runDB $ do
Entity sid _ <- getBy404 $ UniqueSharer shr
Entity jid _ <- getBy404 $ UniqueProject prj sid
liftA2 (,)
(getTicketSummaries jid)
(getTicketDepEdges jid)
defaultLayout $ ticketTreeDW shr prj summaries deps
getTicketNewR :: ShrIdent -> PrjIdent -> Handler Html
2016-05-01 07:32:22 +09:00
getTicketNewR shar proj = do
((_result, widget), enctype) <- runFormPost newTicketForm
defaultLayout $(widgetFile "ticket/new")
2016-05-01 08:02:44 +09:00
getTicketR :: ShrIdent -> PrjIdent -> Int -> Handler Html
2016-05-01 18:58:55 +09:00
getTicketR shar proj num = do
2016-06-06 19:00:05 +09:00
mpid <- maybeAuthId
(wshr, wfl, author, massignee, closer, ticket, tparams, deps, rdeps) <-
runDB $ do
(jid, wshr, wid, wfl) <- do
Entity s sharer <- getBy404 $ UniqueSharer shar
Entity p project <- getBy404 $ UniqueProject proj s
w <- get404 $ projectWorkflow project
wsharer <-
if workflowSharer w == s
then return sharer
else get404 $ workflowSharer w
return
( p
, sharerIdent wsharer
, projectWorkflow project
, workflowIdent w
)
Entity tid ticket <- getBy404 $ UniqueTicket jid num
author <- do
person <- get404 $ ticketCreator ticket
get404 $ personIdent person
massignee <- for (ticketAssignee ticket) $ \ apid -> do
person <- get404 apid
sharer <- get404 $ personIdent person
return (sharer, fromMaybe False $ (== apid) <$> mpid)
closer <-
if ticketDone ticket
then do
person <- get404 $ ticketCloser ticket
get404 $ personIdent person
else return author
tparams <- select $ from $ \ (f `LeftOuterJoin` p) -> do
on $
just (f ^. WorkflowFieldId) E.==. p ?. TicketParamTextField
&&.
p ?. TicketParamTextTicket E.==. just (val tid)
where_ $
f ^. WorkflowFieldWorkflow E.==. val wid &&.
f ^. WorkflowFieldType E.==. val WFTText
return
( f ^. WorkflowFieldIdent
, f ^. WorkflowFieldName
, f ^. WorkflowFieldRequired
, p ?. TicketParamTextValue
)
deps <- select $ from $ \ (dep `InnerJoin` t) -> do
on $ dep ^. TicketDependencyChild E.==. t ^. TicketId
where_ $ dep ^. TicketDependencyParent E.==. val tid
return t
rdeps <- select $ from $ \ (dep `InnerJoin` t) -> do
on $ dep ^. TicketDependencyParent E.==. t ^. TicketId
where_ $ dep ^. TicketDependencyChild E.==. val tid
return t
return
( wshr, wfl
, author, massignee, closer, ticket, tparams, deps, rdeps
)
let desc = renderSourceT Markdown $ T.filter (/= '\r') $ ticketDesc ticket
discuss =
discussionW
(return $ ticketDiscuss ticket)
(TicketTopReplyR shar proj num)
(TicketReplyR shar proj num)
2016-05-20 01:58:23 +09:00
defaultLayout $(widgetFile "ticket/one")
putTicketR :: ShrIdent -> PrjIdent -> Int -> Handler Html
2016-05-02 18:15:10 +09:00
putTicketR shar proj num = do
Entity tid ticket <- runDB $ do
Entity sid _sharer <- getBy404 $ UniqueSharer shar
2016-05-02 18:15:10 +09:00
Entity pid _project <- getBy404 $ UniqueProject proj sid
getBy404 $ UniqueTicket pid num
((result, widget), enctype) <- runFormPost $ editTicketContentForm ticket
2016-05-02 18:15:10 +09:00
case result of
FormSuccess ticket' -> do
runDB $ replace tid ticket'
2016-05-02 20:33:30 +09:00
setMessage "Ticket updated."
2016-05-02 18:15:10 +09:00
redirect $ TicketR shar proj num
FormMissing -> do
setMessage "Field(s) missing."
defaultLayout $(widgetFile "ticket/edit")
FormFailure _l -> do
setMessage "Ticket update failed, see errors below."
defaultLayout $(widgetFile "ticket/edit")
deleteTicketR :: ShrIdent -> PrjIdent -> Int -> Handler Html
2016-05-02 18:15:10 +09:00
deleteTicketR shar proj num =
--TODO: I can easily implement this, but should it even be possible to
--delete tickets?
error "Not implemented"
postTicketR :: ShrIdent -> PrjIdent -> Int -> Handler Html
postTicketR shar proj num = do
mmethod <- lookupPostParam "_method"
case mmethod of
Just "PUT" -> putTicketR shar proj num
Just "DELETE" -> deleteTicketR shar proj num
_ -> notFound
getTicketEditR :: ShrIdent -> PrjIdent -> Int -> Handler Html
2016-05-02 18:15:10 +09:00
getTicketEditR shar proj num = do
Entity _tid ticket <- runDB $ do
Entity sid _sharer <- getBy404 $ UniqueSharer shar
2016-05-02 18:15:10 +09:00
Entity pid _project <- getBy404 $ UniqueProject proj sid
getBy404 $ UniqueTicket pid num
((_result, widget), enctype) <- runFormPost $ editTicketContentForm ticket
2016-05-20 01:58:23 +09:00
defaultLayout $(widgetFile "ticket/edit")
postTicketCloseR :: ShrIdent -> PrjIdent -> Int -> Handler Html
postTicketCloseR shr prj num = do
pid <- requireAuthId
now <- liftIO getCurrentTime
succ <- runDB $ do
Entity tid ticket <- do
Entity s _ <- getBy404 $ UniqueSharer shr
Entity p _ <- getBy404 $ UniqueProject prj s
getBy404 $ UniqueTicket p num
if ticketDone ticket
then return False
else do
update tid
[ TicketAssignee =. Nothing
, TicketDone =. True
, TicketClosed =. now
, TicketCloser =. pid
]
return True
setMessage $
if succ
then "Ticket closed."
else "Ticket is already closed."
redirect $ TicketR shr prj num
postTicketOpenR :: ShrIdent -> PrjIdent -> Int -> Handler Html
postTicketOpenR shr prj num = do
pid <- requireAuthId
now <- liftIO getCurrentTime
succ <- runDB $ do
Entity tid ticket <- do
Entity s _ <- getBy404 $ UniqueSharer shr
Entity p _ <- getBy404 $ UniqueProject prj s
getBy404 $ UniqueTicket p num
if ticketDone ticket
then do
update tid
[ TicketDone =. False
, TicketCloser =. ticketCreator ticket
]
return True
else return False
setMessage $
if succ
then "Ticket reopened"
else "Ticket is already open."
redirect $ TicketR shr prj num
postTicketClaimR :: ShrIdent -> PrjIdent -> Int -> Handler Html
postTicketClaimR shr prj num = do
pid <- requireAuthId
mmsg <- runDB $ do
Entity tid ticket <- do
Entity s _ <- getBy404 $ UniqueSharer shr
Entity p _ <- getBy404 $ UniqueProject prj s
getBy404 $ UniqueTicket p num
case (ticketDone ticket, ticketAssignee ticket) of
(True, _) ->
return $
Just "The ticket is closed. Cant claim closed tickets."
(False, Just _) ->
return $
Just "The ticket is already assigned to someone."
(False, Nothing) -> do
update tid [TicketAssignee =. Just pid]
return Nothing
setMessage $ fromMaybe "The ticket is now assigned to you." mmsg
redirect $ TicketR shr prj num
postTicketUnclaimR :: ShrIdent -> PrjIdent -> Int -> Handler Html
postTicketUnclaimR shr prj num = do
pid <- requireAuthId
mmsg <- runDB $ do
Entity tid ticket <- do
Entity s _ <- getBy404 $ UniqueSharer shr
Entity p _ <- getBy404 $ UniqueProject prj s
getBy404 $ UniqueTicket p num
case ((== pid) <$> ticketAssignee ticket, ticketDone ticket) of
(Nothing, _) ->
return $ Just "The ticket is already unassigned."
(Just False, _) ->
return $ Just "The ticket is assigned to someone else."
(Just True, True) -> do
$logWarn "Found a closed claimed ticket, this is invalid"
return $
Just "The ticket is closed. Cant unclaim closed tickets."
(Just True, False) -> do
update tid [TicketAssignee =. Nothing]
return Nothing
setMessage $ fromMaybe "The ticket is now unassigned." mmsg
redirect $ TicketR shr prj num
getTicketAssignR :: ShrIdent -> PrjIdent -> Int -> Handler Html
getTicketAssignR shr prj num = do
vpid <- requireAuthId
(jid, Entity tid ticket) <- runDB $ do
Entity s _ <- getBy404 $ UniqueSharer shr
Entity j _ <- getBy404 $ UniqueProject prj s
et <- getBy404 $ UniqueTicket j num
return (j, et)
let msg t = do
setMessage t
redirect $ TicketR shr prj num
case (ticketDone ticket, ticketAssignee ticket) of
(True, _) -> msg "The ticket is closed. Cant assign closed tickets."
(False, Just _) -> msg "The ticket is already assigned to someone."
(False, Nothing) -> do
((_result, widget), enctype) <-
runFormPost $ assignTicketForm vpid jid
defaultLayout $(widgetFile "ticket/assign")
postTicketAssignR :: ShrIdent -> PrjIdent -> Int -> Handler Html
postTicketAssignR shr prj num = do
vpid <- requireAuthId
(jid, Entity tid ticket) <- runDB $ do
Entity s _ <- getBy404 $ UniqueSharer shr
Entity j _ <- getBy404 $ UniqueProject prj s
et <- getBy404 $ UniqueTicket j num
return (j, et)
let msg t = do
setMessage t
redirect $ TicketR shr prj num
case (ticketDone ticket, ticketAssignee ticket) of
(True, _) -> msg "The ticket is closed. Cant assign closed tickets."
(False, Just _) -> msg "The ticket is already assigned to someone."
(False, Nothing) -> do
((result, widget), enctype) <-
runFormPost $ assignTicketForm vpid jid
case result of
FormSuccess pid -> do
sharer <- runDB $ do
update tid [TicketAssignee =. Just pid]
person <- getJust pid
getJust $ personIdent person
let si = sharerIdent sharer
msg $ toHtml $
"The ticket is now assigned to " <> shr2text si <> "."
FormMissing -> do
setMessage "Field(s) missing."
defaultLayout $(widgetFile "ticket/assign")
FormFailure _l -> do
setMessage "Ticket assignment failed, see errors below."
defaultLayout $(widgetFile "ticket/assign")
postTicketUnassignR :: ShrIdent -> PrjIdent -> Int -> Handler Html
postTicketUnassignR shr prj num = do
pid <- requireAuthId
mmsg <- runDB $ do
Entity tid ticket <- do
Entity s _ <- getBy404 $ UniqueSharer shr
Entity p _ <- getBy404 $ UniqueProject prj s
getBy404 $ UniqueTicket p num
case ((== pid) <$> ticketAssignee ticket, ticketDone ticket) of
(Nothing, _) ->
return $ Just "The ticket is already unassigned."
(Just True, _) ->
return $ Just "The ticket is assigned to you, unclaim instead."
(Just False, True) -> do
$logWarn "Found a closed claimed ticket, this is invalid"
return $
Just "The ticket is closed. Cant unclaim closed tickets."
(Just False, False) -> do
update tid [TicketAssignee =. Nothing]
return Nothing
setMessage $ fromMaybe "The ticket is now unassigned." mmsg
redirect $ TicketR shr prj num
-- | The logged-in user gets a list of the ticket claim requests they have
-- opened, in any project.
getClaimRequestsPersonR :: Handler Html
getClaimRequestsPersonR = do
pid <- requireAuthId
rqs <- runDB $ select $ from $
\ (tcr `InnerJoin` ticket `InnerJoin` project `InnerJoin` sharer) -> do
on $ project ^. ProjectSharer E.==. sharer ^. SharerId
on $ ticket ^. TicketProject E.==. project ^. ProjectId
on $ tcr ^. TicketClaimRequestTicket E.==. ticket ^. TicketId
where_ $ tcr ^. TicketClaimRequestPerson E.==. val pid
orderBy [desc $ tcr ^. TicketClaimRequestCreated]
return
( sharer ^. SharerIdent
, project ^. ProjectIdent
, ticket ^. TicketNumber
, ticket ^. TicketTitle
, tcr ^. TicketClaimRequestCreated
)
defaultLayout $(widgetFile "person/claim-requests")
-- | Get a list of ticket claim requests for a given project.
getClaimRequestsProjectR :: ShrIdent -> PrjIdent -> Handler Html
getClaimRequestsProjectR shr prj = do
rqs <- runDB $ do
Entity sid _ <- getBy404 $ UniqueSharer shr
Entity jid _ <- getBy404 $ UniqueProject prj sid
select $ from $
\ ( tcr `InnerJoin`
ticket `InnerJoin`
person `InnerJoin`
sharer
) -> do
on $ person ^. PersonIdent E.==. sharer ^. SharerId
on $ tcr ^. TicketClaimRequestPerson E.==. person ^. PersonId
on $ tcr ^. TicketClaimRequestTicket E.==. ticket ^. TicketId
where_ $ ticket ^. TicketProject E.==. val jid
orderBy [desc $ tcr ^. TicketClaimRequestCreated]
return
( sharer
, ticket ^. TicketNumber
, ticket ^. TicketTitle
, tcr ^. TicketClaimRequestCreated
)
defaultLayout $(widgetFile "project/claim-request/list")
-- | Get a list of ticket claim requests for a given ticket.
getClaimRequestsTicketR :: ShrIdent -> PrjIdent -> Int -> Handler Html
getClaimRequestsTicketR shr prj num = do
rqs <- runDB $ do
Entity sid _ <- getBy404 $ UniqueSharer shr
Entity jid _ <- getBy404 $ UniqueProject prj sid
Entity tid _ <- getBy404 $ UniqueTicket jid num
select $ from $ \ (tcr `InnerJoin` person `InnerJoin` sharer) -> do
on $ person ^. PersonIdent E.==. sharer ^. SharerId
on $ tcr ^. TicketClaimRequestPerson E.==. person ^. PersonId
where_ $ tcr ^. TicketClaimRequestTicket E.==. val tid
orderBy [desc $ tcr ^. TicketClaimRequestCreated]
return (sharer, tcr)
defaultLayout $(widgetFile "ticket/claim-request/list")
2016-06-08 10:28:18 +09:00
getClaimRequestNewR :: ShrIdent -> PrjIdent -> Int -> Handler Html
getClaimRequestNewR shr prj num = do
((_result, widget), etype) <- runFormPost claimRequestForm
defaultLayout $(widgetFile "ticket/claim-request/new")
postClaimRequestsTicketR :: ShrIdent -> PrjIdent -> Int -> Handler Html
postClaimRequestsTicketR shr prj num = do
((result, widget), etype) <- runFormPost claimRequestForm
case result of
FormSuccess msg -> do
now <- liftIO getCurrentTime
pid <- requireAuthId
runDB $ do
tid <- do
Entity s _ <- getBy404 $ UniqueSharer shr
Entity j _ <- getBy404 $ UniqueProject prj s
Entity t _ <- getBy404 $ UniqueTicket j num
return t
let cr = TicketClaimRequest
{ ticketClaimRequestPerson = pid
, ticketClaimRequestTicket = tid
, ticketClaimRequestMessage = msg
, ticketClaimRequestCreated = now
}
insert_ cr
setMessage "Ticket claim request opened."
redirect $ TicketR shr prj num
FormMissing -> do
setMessage "Field(s) missing."
defaultLayout $(widgetFile "ticket/claim-request/new")
FormFailure _l -> do
setMessage "Submission failed, see errors below."
defaultLayout $(widgetFile "ticket/claim-request/new")
selectDiscussionId :: ShrIdent -> PrjIdent -> Int -> AppDB DiscussionId
2016-05-20 07:07:25 +09:00
selectDiscussionId shar proj tnum = do
Entity sid _sharer <- getBy404 $ UniqueSharer shar
2016-05-20 07:07:25 +09:00
Entity pid _project <- getBy404 $ UniqueProject proj sid
Entity _tid ticket <- getBy404 $ UniqueTicket pid tnum
return $ ticketDiscuss ticket
getTicketDiscussionR :: ShrIdent -> PrjIdent -> Int -> Handler Html
getTicketDiscussionR shar proj num =
getDiscussion
(TicketReplyR shar proj num)
(TicketTopReplyR shar proj num)
(selectDiscussionId shar proj num)
2016-05-20 01:58:23 +09:00
postTicketDiscussionR :: ShrIdent -> PrjIdent -> Int -> Handler Html
postTicketDiscussionR shar proj num =
postTopReply
(TicketDiscussionR shar proj num)
(const $ TicketR shar proj num)
(selectDiscussionId shar proj num)
getTicketMessageR :: ShrIdent -> PrjIdent -> Int -> Int -> Handler Html
getTicketMessageR shar proj tnum cnum =
getMessage
(TicketReplyR shar proj tnum)
(selectDiscussionId shar proj tnum)
cnum
2016-05-20 07:07:25 +09:00
postTicketMessageR :: ShrIdent -> PrjIdent -> Int -> Int -> Handler Html
postTicketMessageR shar proj tnum cnum =
2016-05-20 07:07:25 +09:00
postReply
(TicketReplyR shar proj tnum)
(TicketMessageR shar proj tnum)
(const $ TicketR shar proj tnum)
(selectDiscussionId shar proj tnum)
2016-05-20 07:07:25 +09:00
cnum
getTicketTopReplyR :: ShrIdent -> PrjIdent -> Int -> Handler Html
getTicketTopReplyR shar proj num =
getTopReply $ TicketDiscussionR shar proj num
2016-05-20 07:07:25 +09:00
getTicketReplyR :: ShrIdent -> PrjIdent -> Int -> Int -> Handler Html
getTicketReplyR shar proj tnum cnum =
2016-05-20 07:07:25 +09:00
getReply
(TicketReplyR shar proj tnum)
(TicketMessageR shar proj tnum)
(selectDiscussionId shar proj tnum)
2016-05-20 07:07:25 +09:00
cnum
2016-07-27 17:35:50 +09:00
getTicketDeps :: Bool -> ShrIdent -> PrjIdent -> Int -> Handler Html
getTicketDeps forward shr prj num = do
let from' =
if forward then TicketDependencyParent else TicketDependencyChild
to' =
if forward then TicketDependencyChild else TicketDependencyParent
rows <- runDB $ do
Entity sid _ <- getBy404 $ UniqueSharer shr
Entity jid _ <- getBy404 $ UniqueProject prj sid
Entity tid _ <- getBy404 $ UniqueTicket jid num
select $ from $
\ ( td `InnerJoin`
ticket `InnerJoin`
person `InnerJoin`
sharer
) -> do
on $ person ^. PersonIdent E.==. sharer ^. SharerId
on $ ticket ^. TicketCreator E.==. person ^. PersonId
2016-07-27 17:35:50 +09:00
on $ td ^. to' E.==. ticket ^. TicketId
where_ $ td ^. from' E.==. val tid
orderBy [asc $ ticket ^. TicketNumber]
return
( ticket ^. TicketNumber
, sharer
, ticket ^. TicketTitle
, ticket ^. TicketDone
)
defaultLayout $(widgetFile "ticket/dep/list")
2016-07-27 17:35:50 +09:00
getTicketDepsR :: ShrIdent -> PrjIdent -> Int -> Handler Html
getTicketDepsR = getTicketDeps True
postTicketDepsR :: ShrIdent -> PrjIdent -> Int -> Handler Html
postTicketDepsR shr prj num = do
(jid, tid) <- runDB $ do
Entity sid _ <- getBy404 $ UniqueSharer shr
Entity jid _ <- getBy404 $ UniqueProject prj sid
Entity tid _ <- getBy404 $ UniqueTicket jid num
return (jid, tid)
((result, widget), enctype) <- runFormPost $ ticketDepForm jid tid
case result of
FormSuccess ctid -> do
runDB $ do
let td = TicketDependency
{ ticketDependencyParent = tid
, ticketDependencyChild = ctid
}
insert_ td
trrFix td ticketDepGraph
setMessage "Ticket dependency added."
redirect $ TicketR shr prj num
FormMissing -> do
setMessage "Field(s) missing."
defaultLayout $(widgetFile "ticket/dep/new")
FormFailure _l -> do
setMessage "Submission failed, see errors below."
defaultLayout $(widgetFile "ticket/dep/new")
getTicketDepNewR :: ShrIdent -> PrjIdent -> Int -> Handler Html
getTicketDepNewR shr prj num = do
(jid, tid) <- runDB $ do
Entity sid _ <- getBy404 $ UniqueSharer shr
Entity jid _ <- getBy404 $ UniqueProject prj sid
Entity tid _ <- getBy404 $ UniqueTicket jid num
return (jid, tid)
((_result, widget), enctype) <- runFormPost $ ticketDepForm jid tid
defaultLayout $(widgetFile "ticket/dep/new")
postTicketDepR :: ShrIdent -> PrjIdent -> Int -> Int -> Handler Html
postTicketDepR shr prj pnum cnum = do
mmethod <- lookupPostParam "_method"
case mmethod of
Just "DELETE" -> deleteTicketDepR shr prj pnum cnum
_ -> notFound
deleteTicketDepR :: ShrIdent -> PrjIdent -> Int -> Int -> Handler Html
deleteTicketDepR shr prj pnum cnum = do
runDB $ do
Entity sid _ <- getBy404 $ UniqueSharer shr
Entity jid _ <- getBy404 $ UniqueProject prj sid
Entity ptid _ <- getBy404 $ UniqueTicket jid pnum
Entity ctid _ <- getBy404 $ UniqueTicket jid cnum
Entity tdid _ <- getBy404 $ UniqueTicketDependency ptid ctid
delete tdid
setMessage "Ticket dependency removed."
redirect $ TicketDepsR shr prj pnum
2016-07-27 17:35:50 +09:00
getTicketReverseDepsR :: ShrIdent -> PrjIdent -> Int -> Handler Html
getTicketReverseDepsR = getTicketDeps False