Ticket un/assign (like un/claim but for other people)

This commit is contained in:
fr33domlover 2016-06-07 07:33:19 +00:00
parent eb6fa307b3
commit ae83a5f3ad
10 changed files with 173 additions and 2 deletions

View file

@ -98,6 +98,8 @@
/s/#ShrIdent/p/#PrjIdent/t/#Int/open TicketOpenR POST /s/#ShrIdent/p/#PrjIdent/t/#Int/open TicketOpenR POST
/s/#ShrIdent/p/#PrjIdent/t/#Int/claim TicketClaimR POST /s/#ShrIdent/p/#PrjIdent/t/#Int/claim TicketClaimR POST
/s/#ShrIdent/p/#PrjIdent/t/#Int/unclaim TicketUnclaimR POST /s/#ShrIdent/p/#PrjIdent/t/#Int/unclaim TicketUnclaimR POST
/s/#ShrIdent/p/#PrjIdent/t/#Int/assign TicketAssignR GET POST
/s/#ShrIdent/p/#PrjIdent/t/#Int/unassign TicketUnassignR POST
/s/#ShrIdent/p/#PrjIdent/t/#Int/d TicketDiscussionR GET POST /s/#ShrIdent/p/#PrjIdent/t/#Int/d TicketDiscussionR GET POST
/s/#ShrIdent/p/#PrjIdent/t/#Int/d/#Int TicketMessageR GET POST /s/#ShrIdent/p/#PrjIdent/t/#Int/d/#Int TicketMessageR GET POST
/s/#ShrIdent/p/#PrjIdent/t/#Int/d/!reply TicketTopReplyR GET /s/#ShrIdent/p/#PrjIdent/t/#Int/d/!reply TicketTopReplyR GET

View file

@ -0,0 +1,46 @@
{- 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.Field.Ticket
( selectAssigneeFromProject
)
where
import Prelude
import Control.Arrow ((***))
import Database.Esqueleto
import Yesod.Form.Fields (selectField, optionsPairs)
import Yesod.Form.Types (Field)
import Yesod.Persist.Core (runDB)
import Vervis.Foundation (Handler)
import Vervis.Model
import Vervis.Model.Ident (shr2text)
-- | Select an assignee for a ticket, from the list of collaborators of
-- the project it belongs to. It can be any collaborator of the project, except
-- for the person doing the assignment.
selectAssigneeFromProject :: PersonId -> ProjectId -> Field Handler PersonId
selectAssigneeFromProject pid jid = selectField $ do
l <- runDB $ select $ from $
\ (pcollab `InnerJoin` person `InnerJoin` sharer) -> do
on $ person ^. PersonIdent ==. sharer ^. SharerId
on $ pcollab ^. ProjectCollabPerson ==. person ^. PersonId
where_ $
pcollab ^. ProjectCollabProject ==. val jid &&.
person ^. PersonId !=. val pid
return (sharer ^. SharerIdent, person ^. PersonId)
optionsPairs $ map (shr2text . unValue *** unValue) l

View file

@ -17,6 +17,7 @@ module Vervis.Form.Ticket
( NewTicket (..) ( NewTicket (..)
, newTicketForm , newTicketForm
, editTicketContentForm , editTicketContentForm
, assignTicketForm
, ticketFilterForm , ticketFilterForm
) )
where where
@ -30,6 +31,7 @@ import Data.Time.Calendar (Day (..))
import Data.Time.Clock (getCurrentTime, UTCTime (..)) import Data.Time.Clock (getCurrentTime, UTCTime (..))
import Yesod.Form import Yesod.Form
import Vervis.Field.Ticket
import Vervis.Foundation (Form, Handler) import Vervis.Foundation (Form, Handler)
import Vervis.Model import Vervis.Model
import Vervis.TicketFilter (TicketFilter (..)) import Vervis.TicketFilter (TicketFilter (..))
@ -79,6 +81,13 @@ editTicketContentAForm ticket = Ticket
editTicketContentForm :: Ticket -> Form Ticket editTicketContentForm :: Ticket -> Form Ticket
editTicketContentForm t = renderDivs $ editTicketContentAForm t editTicketContentForm t = renderDivs $ editTicketContentAForm t
assignTicketAForm :: PersonId -> ProjectId -> AForm Handler PersonId
assignTicketAForm pid jid =
areq (selectAssigneeFromProject pid jid) "Assignee*" Nothing
assignTicketForm :: PersonId -> ProjectId -> Form PersonId
assignTicketForm pid jid = renderDivs $ assignTicketAForm pid jid
ticketFilterAForm :: AForm Handler TicketFilter ticketFilterAForm :: AForm Handler TicketFilter
ticketFilterAForm = TicketFilter ticketFilterAForm = TicketFilter
<$> areq (selectFieldList status) "Status*" (Just Nothing) <$> areq (selectFieldList status) "Status*" (Just Nothing)

View file

@ -166,12 +166,17 @@ instance Yesod App where
(TicketOpenR user _ _ , _ ) -> person user (TicketOpenR user _ _ , _ ) -> person user
(TicketClaimR s j _ , _ ) -> projOp ProjOpClaimTicket s j (TicketClaimR s j _ , _ ) -> projOp ProjOpClaimTicket s j
(TicketUnclaimR s j _ , _ ) -> projOp ProjOpUnclaimTicket s j (TicketUnclaimR s j _ , _ ) -> projOp ProjOpUnclaimTicket s j
(TicketAssignR s j _ , _ ) -> projOp ProjOpAssignTicket s j
(TicketUnassignR s j _ , _ ) -> projOp ProjOpUnassignTicket s j
(TicketDiscussionR _ _ _ , True) -> personAny (TicketDiscussionR _ _ _ , True) -> personAny
(TicketMessageR _ _ _ _ , True) -> personAny (TicketMessageR _ _ _ _ , True) -> personAny
(TicketTopReplyR _ _ _ , _ ) -> personAny (TicketTopReplyR _ _ _ , _ ) -> personAny
(TicketReplyR _ _ _ _ , _ ) -> personAny (TicketReplyR _ _ _ _ , _ ) -> personAny
_ -> return Authorized _ -> return Authorized
where where
nobody :: Handler AuthResult
nobody = return $ Unauthorized "This operation is currently disabled"
personAnd personAnd
:: (Entity Person -> Handler AuthResult) -> Handler AuthResult :: (Entity Person -> Handler AuthResult) -> Handler AuthResult
personAnd f = do personAnd f = do
@ -439,6 +444,10 @@ instance YesodBreadcrumbs App where
TicketOpenR _shar _proj _num -> ("", Nothing) TicketOpenR _shar _proj _num -> ("", Nothing)
TicketClaimR _shar _proj _num -> ("", Nothing) TicketClaimR _shar _proj _num -> ("", Nothing)
TicketUnclaimR _shar _proj _num -> ("", Nothing) TicketUnclaimR _shar _proj _num -> ("", Nothing)
TicketAssignR shr prj num -> ( "Assign"
, Just $ TicketR shr prj num
)
TicketUnassignR _shr _prj _num -> ("", Nothing)
TicketDiscussionR shar proj num -> ( "Discussion" TicketDiscussionR shar proj num -> ( "Discussion"
, Just $ TicketR shar proj num , Just $ TicketR shar proj num
) )

View file

@ -26,6 +26,9 @@ module Vervis.Handler.Ticket
, postTicketOpenR , postTicketOpenR
, postTicketClaimR , postTicketClaimR
, postTicketUnclaimR , postTicketUnclaimR
, getTicketAssignR
, postTicketAssignR
, postTicketUnassignR
, getTicketDiscussionR , getTicketDiscussionR
, postTicketDiscussionR , postTicketDiscussionR
, getTicketMessageR , getTicketMessageR
@ -41,6 +44,7 @@ import Control.Monad.IO.Class (liftIO)
import Control.Monad.Logger (logWarn) import Control.Monad.Logger (logWarn)
import Data.Default.Class (def) import Data.Default.Class (def)
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))
import Data.Text (Text) import Data.Text (Text)
import Data.Time.Calendar (Day (..)) import Data.Time.Calendar (Day (..))
import Data.Time.Clock (UTCTime (..), getCurrentTime) import Data.Time.Clock (UTCTime (..), getCurrentTime)
@ -306,6 +310,81 @@ postTicketUnclaimR shr prj num = do
setMessage $ fromMaybe "The ticket is now unassigned." mmsg setMessage $ fromMaybe "The ticket is now unassigned." mmsg
redirect $ TicketR shr prj num 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
selectDiscussionId :: ShrIdent -> PrjIdent -> Int -> AppDB DiscussionId selectDiscussionId :: ShrIdent -> PrjIdent -> Int -> AppDB DiscussionId
selectDiscussionId shar proj tnum = do selectDiscussionId shar proj tnum = do
Entity sid _sharer <- getBy404 $ UniqueSharer shar Entity sid _sharer <- getBy404 $ UniqueSharer shar

View file

@ -30,6 +30,8 @@ derivePersistField "RepoOperation"
data ProjectOperation data ProjectOperation
= ProjOpClaimTicket = ProjOpClaimTicket
| ProjOpUnclaimTicket | ProjOpUnclaimTicket
| ProjOpAssignTicket
| ProjOpUnassignTicket
deriving (Eq, Show, Read, Enum, Bounded) deriving (Eq, Show, Read, Enum, Bounded)
derivePersistField "ProjectOperation" derivePersistField "ProjectOperation"

View file

@ -0,0 +1,17 @@
$# 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/>.
<form method=POST action=@{TicketAssignR shr prj num} enctype=#{enctype}>
^{widget}
<input type=submit>

View file

@ -12,8 +12,6 @@ $# You should have received a copy of the CC0 Public Domain Dedication along
$# with this software. If not, see $# with this software. If not, see
$# <http://creativecommons.org/publicdomain/zero/1.0/>. $# <http://creativecommons.org/publicdomain/zero/1.0/>.
Enter the details and click "Submit" to update the ticket.
<form method=POST action=@{TicketR shar proj num} enctype=#{enctype}> <form method=POST action=@{TicketR shar proj num} enctype=#{enctype}>
<input type=hidden name=_method value=PUT> <input type=hidden name=_method value=PUT>
^{widget} ^{widget}

View file

@ -33,12 +33,20 @@ $if not $ ticketDone ticket
<input type=submit value="Unclaim this ticket"> <input type=submit value="Unclaim this ticket">
$else $else
Assigned to ^{personLinkW assignee}. Assigned to ^{personLinkW assignee}.
<form method=POST action=@{TicketUnassignR shar proj num}>
<input type=submit value="Unassign this ticket">
$nothing $nothing
Not assigned. Not assigned.
<form method=POST action=@{TicketClaimR shar proj num}> <form method=POST action=@{TicketClaimR shar proj num}>
<input type=submit value="Claim this ticket"> <input type=submit value="Claim this ticket">
or
<a href=@{TicketAssignR shar proj num}>Assign to someone else
.
<p> <p>
Status: # Status: #
$if ticketDone ticket $if ticketDone ticket

View file

@ -87,6 +87,7 @@ library
Vervis.Field.Repo Vervis.Field.Repo
Vervis.Field.Role Vervis.Field.Role
Vervis.Field.Sharer Vervis.Field.Sharer
Vervis.Field.Ticket
Vervis.Form.Discussion Vervis.Form.Discussion
Vervis.Form.Group Vervis.Form.Group
Vervis.Form.Key Vervis.Form.Key