Allow ticket author to be a remote actor

This commit is contained in:
fr33domlover 2019-06-07 04:26:32 +00:00
parent d73b113b4f
commit b1897a20c0
26 changed files with 281 additions and 149 deletions

View file

@ -281,14 +281,13 @@ Ticket
project ProjectId
number Int
created UTCTime
creator PersonId
title Text
source Text -- Pandoc Markdown
description Text -- HTML
assignee PersonId Maybe
status TicketStatus
closed UTCTime
closer PersonId
closer PersonId Maybe
discuss DiscussionId
followers FollowerSetId
@ -296,6 +295,18 @@ Ticket
UniqueTicketDiscussion discuss
UniqueTicketFollowers followers
TicketAuthorLocal
ticket TicketId
author PersonId
UniqueTicketAuthorLocal ticket
TicketAuthorRemote
ticket TicketId
author RemoteActorId
UniqueTicketAuthorRemote ticket
TicketDependency
parent TicketId
child TicketId

View file

@ -0,0 +1,11 @@
TicketAuthorLocal
ticket TicketId
author PersonId
UniqueTicketAuthorLocal ticket
TicketAuthorRemote
ticket TicketId
author RemoteActorId
UniqueTicketAuthorRemote ticket

View file

@ -0,0 +1,24 @@
TicketAuthorLocal
ticket TicketId
author Int64
UniqueTicketAuthorLocal ticket
Ticket
project Int64
number Int
created UTCTime
creator Int64
title Text
source Text -- Pandoc Markdown
description Text -- HTML
assignee Int64 Maybe
status Text
closed UTCTime
closer Int64
discuss Int64
followers Int64
UniqueTicket project number
UniqueTicketDiscussion discuss
UniqueTicketFollowers followers

View file

@ -17,11 +17,14 @@ module Data.Either.Local
( maybeRight
, maybeLeft
, requireEither
, requireEitherAlt
)
where
import Prelude
import Control.Applicative
maybeRight :: Either a b -> Maybe b
maybeRight (Left _) = Nothing
maybeRight (Right b) = Just b
@ -35,3 +38,13 @@ requireEither Nothing Nothing = Left False
requireEither (Just _) (Just _) = Left True
requireEither (Just x) Nothing = Right $ Left x
requireEither Nothing (Just y) = Right $ Right y
requireEitherAlt
:: Applicative f
=> f (Maybe a) -> f (Maybe b) -> String -> String -> f (Either a b)
requireEitherAlt get1 get2 errNone errBoth = liftA2 mk get1 get2
where
mk Nothing Nothing = error errNone
mk (Just _) (Just _) = error errBoth
mk (Just x) Nothing = Left x
mk Nothing (Just y) = Right y

View file

@ -123,7 +123,6 @@ editTicketContentAForm ticket = Ticket
<$> pure (ticketProject ticket)
<*> pure (ticketNumber ticket)
<*> pure (ticketCreated ticket)
<*> pure (ticketCreator ticket)
<*> areq textField "Title*" (Just $ ticketTitle ticket)
<*> ( maybe "" (T.filter (/= '\r') . unTextarea) <$>
aopt

View file

@ -52,7 +52,7 @@ import Vervis.Model.Group
import Vervis.Model.Ident (ShrIdent, shr2text)
import Vervis.Settings (widgetFile)
import Vervis.Time (showDate)
import Vervis.Widget.Sharer (groupLinkW, personLinkW)
import Vervis.Widget.Sharer
getGroupsR :: Handler Html
getGroupsR = do

View file

@ -78,7 +78,7 @@ import Vervis.Style
import Vervis.Time (showDate)
import Vervis.Widget (buttonW)
import Vervis.Widget.Repo
import Vervis.Widget.Sharer (personLinkW)
import Vervis.Widget.Sharer
import qualified Data.ByteString.Lazy as BL (ByteString)
import qualified Data.Git.Local as G (createRepo)

View file

@ -96,6 +96,7 @@ import Yesod.Hashids
import qualified Web.ActivityPub as AP
import Data.Either.Local
import Data.Maybe.Local (partitionMaybePairs)
import Database.Persist.Local
import Yesod.Persist.Local
@ -117,7 +118,7 @@ import Vervis.TicketFilter (filterTickets)
import Vervis.Time (showDate)
import Vervis.Widget (buttonW)
import Vervis.Widget.Discussion (discussionW)
import Vervis.Widget.Sharer (personLinkW)
import Vervis.Widget.Sharer
import Vervis.Widget.Ticket
getTicketsR :: ShrIdent -> PrjIdent -> Handler Html
@ -164,18 +165,18 @@ postTicketsR shar proj = do
{ ticketProject = pid
, ticketNumber = projectNextTicket project
, ticketCreated = now
, ticketCreator = author
, ticketTitle = ntTitle nt
, ticketSource = source
, ticketDescription = descHtml
, ticketAssignee = Nothing
, ticketStatus = TSNew
, ticketClosed = UTCTime (ModifiedJulianDay 0) 0
, ticketCloser = author
, ticketCloser = Nothing
, ticketDiscuss = did
, ticketFollowers = fsid
}
tid <- insert ticket
insert_ $ TicketAuthorLocal tid author
let mktparam (fid, v) = TicketParamText
{ ticketParamTextTicket = tid
, ticketParamTextField = fid
@ -221,7 +222,7 @@ getTicketR :: ShrIdent -> PrjIdent -> Int -> Handler TypedContent
getTicketR shar proj num = do
mpid <- maybeAuthId
( wshr, wfl,
author, massignee, closer, ticket, tparams, eparams, deps, rdeps) <-
author, massignee, mcloser, ticket, tparams, eparams, deps, rdeps) <-
runDB $ do
(jid, wshr, wid, wfl) <- do
Entity s sharer <- getBy404 $ UniqueSharer shar
@ -238,19 +239,37 @@ getTicketR shar proj num = do
, workflowIdent w
)
Entity tid ticket <- getBy404 $ UniqueTicket jid num
author <- do
person <- get404 $ ticketCreator ticket
get404 $ personIdent person
author <-
requireEitherAlt
(do mtal <- getValBy $ UniqueTicketAuthorLocal tid
for mtal $ \ tal -> do
p <- getJust $ ticketAuthorLocalAuthor tal
getJust $ personIdent p
)
(do mtar <- getValBy $ UniqueTicketAuthorRemote tid
for mtar $ \ tar -> do
ra <- getJust $ ticketAuthorRemoteAuthor tar
i <- getJust $ remoteActorInstance ra
return (i, ra)
)
"Ticket doesn't have author"
"Ticket has both local and remote author"
massignee <- for (ticketAssignee ticket) $ \ apid -> do
person <- get404 apid
sharer <- get404 $ personIdent person
return (sharer, fromMaybe False $ (== apid) <$> mpid)
closer <-
mcloser <-
case ticketStatus ticket of
TSClosed -> do
person <- get404 $ ticketCloser ticket
get404 $ personIdent person
_ -> return author
TSClosed ->
case ticketCloser ticket of
Just pidCloser -> Just <$> do
person <- getJust pidCloser
getJust $ personIdent person
Nothing -> error "Closer not set for closed ticket"
_ ->
case ticketCloser ticket of
Just _ -> error "Closer set for open ticket"
Nothing -> return Nothing
tparams <- getTicketTextParams tid wid
eparams <- getTicketEnumParams tid wid
deps <- E.select $ E.from $ \ (dep `E.InnerJoin` t) -> do
@ -263,7 +282,7 @@ getTicketR shar proj num = do
return t
return
( wshr, wfl
, author, massignee, closer, ticket, tparams, eparams
, author, massignee, mcloser, ticket, tparams, eparams
, deps, rdeps
)
encodeHid <- getEncodeKeyHashid
@ -287,6 +306,10 @@ getTicketR shar proj num = do
encodeRouteHome <- getEncodeRouteHome
let siblingUri =
encodeRouteHome . TicketR shar proj . ticketNumber . entityVal
host =
case author of
Left _ -> hLocal
Right (i, _) -> instanceHost i
ticketAP = AP.Ticket
{ AP.ticketLocal = Just
( hLocal
@ -307,7 +330,11 @@ getTicketR shar proj num = do
)
, AP.ticketAttributedTo =
encodeRouteLocal $ SharerR $ sharerIdent author
case author of
Left sharer ->
encodeRouteLocal $ SharerR $ sharerIdent sharer
Right (_inztance, actor) ->
remoteActorIdent actor
, AP.ticketPublished = Just $ ticketCreated ticket
, AP.ticketUpdated = Nothing
, AP.ticketName = Just $ "#" <> T.pack (show num)
@ -322,7 +349,7 @@ getTicketR shar proj num = do
, AP.ticketDependsOn = map siblingUri deps
, AP.ticketDependedBy = map siblingUri rdeps
}
provideHtmlAndAP ticketAP $(widgetFile "ticket/one")
provideHtmlAndAP' host ticketAP $(widgetFile "ticket/one")
putTicketR :: ShrIdent -> PrjIdent -> Int -> Handler Html
putTicketR shar proj num = do
@ -438,7 +465,7 @@ postTicketCloseR shr prj num = do
[ TicketAssignee =. Nothing
, TicketStatus =. TSClosed
, TicketClosed =. now
, TicketCloser =. pid
, TicketCloser =. Just pid
]
return True
setMessage $
@ -460,7 +487,7 @@ postTicketOpenR shr prj num = do
TSClosed -> do
update tid
[ TicketStatus =. TSTodo
, TicketCloser =. ticketCreator ticket
, TicketCloser =. Nothing
]
return True
_ -> return False
@ -768,24 +795,42 @@ getTicketDeps forward shr prj num = do
Entity sid _ <- getBy404 $ UniqueSharer shr
Entity jid _ <- getBy404 $ UniqueProject prj sid
Entity tid _ <- getBy404 $ UniqueTicket jid num
E.select $ E.from $
\ ( td `E.InnerJoin`
ticket `E.InnerJoin`
person `E.InnerJoin`
sharer
fmap (map toRow) $ E.select $ E.from $
\ ( td
`E.InnerJoin` t
`E.LeftOuterJoin` (tal `E.InnerJoin` p `E.InnerJoin` s)
`E.LeftOuterJoin` (tar `E.InnerJoin` ra `E.InnerJoin` i)
) -> do
E.on $ person E.^. PersonIdent E.==. sharer E.^. SharerId
E.on $ ticket E.^. TicketCreator E.==. person E.^. PersonId
E.on $ td E.^. to' E.==. ticket E.^. TicketId
E.on $ ra E.?. RemoteActorInstance E.==. i E.?. InstanceId
E.on $ tar E.?. TicketAuthorRemoteAuthor E.==. ra E.?. RemoteActorId
E.on $ E.just (t E.^. TicketId) E.==. tar E.?. TicketAuthorRemoteTicket
E.on $ p E.?. PersonIdent E.==. s E.?. SharerId
E.on $ tal E.?. TicketAuthorLocalAuthor E.==. p E.?. PersonId
E.on $ E.just (t E.^. TicketId) E.==. tal E.?. TicketAuthorLocalTicket
E.on $ td E.^. to' E.==. t E.^. TicketId
E.where_ $ td E.^. from' E.==. E.val tid
E.orderBy [E.asc $ ticket E.^. TicketNumber]
E.orderBy [E.asc $ t E.^. TicketNumber]
return
( ticket E.^. TicketNumber
, sharer
, ticket E.^. TicketTitle
, ticket E.^. TicketStatus
( t E.^. TicketNumber
, s
, i
, ra
, t E.^. TicketTitle
, t E.^. TicketStatus
)
defaultLayout $(widgetFile "ticket/dep/list")
where
toRow (E.Value number, ms, mi, mra, E.Value title, E.Value status) =
( number
, case (ms, mi, mra) of
(Just s, Nothing, Nothing) ->
Left $ entityVal s
(Nothing, Just i, Just ra) ->
Right (entityVal i, entityVal ra)
_ -> error "Ticket author DB invalid state"
, title
, status
)
getTicketDepsR :: ShrIdent -> PrjIdent -> Int -> Handler Html
getTicketDepsR = getTicketDeps True
@ -934,16 +979,6 @@ getTicketTeamR shr prj num = do
[whamlet|
<div><pre>#{encodePrettyToLazyText doc}
|]
where
requireEitherAlt
:: Applicative f
=> f (Maybe a) -> f (Maybe b) -> String -> String -> f (Either a b)
requireEitherAlt get1 get2 errNone errBoth = liftA2 mk get1 get2
where
mk Nothing Nothing = error errNone
mk (Just _) (Just _) = error errBoth
mk (Just x) Nothing = Left x
mk Nothing (Just y) = Right y
getTicketEventsR :: ShrIdent -> PrjIdent -> Int -> Handler TypedContent
getTicketEventsR shr prj num = error "TODO not implemented"

View file

@ -527,6 +527,18 @@ changes hLocal ctx =
[ Ticket201906Source =. source
, Ticket201906Description =. content
]
-- 91
, addEntities model_2019_06_06
-- 92
, unchecked $ lift $ do
tickets <- selectList ([] :: [Filter Ticket20190606]) []
let mklocal (Entity tid t) =
TicketAuthorLocal20190606 tid $ ticket20190606Creator t
insertMany_ $ map mklocal tickets
-- 93
, setFieldMaybe "Ticket" "closer"
-- 94
, removeField "Ticket" "creator"
]
migrateDB :: MonadIO m => Text -> HashidsContext -> ReaderT SqlBackend m (Either Text (Int, Int))

View file

@ -57,6 +57,10 @@ module Vervis.Migration.Model
, Message201906
, Ticket201906Generic (..)
, Ticket201906
, model_2019_06_06
, Ticket20190606Generic (..)
, Ticket20190606
, TicketAuthorLocal20190606Generic (..)
)
where
@ -146,3 +150,9 @@ makeEntitiesMigration "201906"
makeEntitiesMigration "201906"
$(modelFile "migrations/2019_06_03.model")
model_2019_06_06 :: [Entity SqlBackend]
model_2019_06_06 = $(schema "2019_06_06")
makeEntitiesMigration "20190606"
$(modelFile "migrations/2019_06_06_mig.model")

View file

@ -47,34 +47,51 @@ getTicketSummaries
-> Maybe (SqlExpr (Entity Ticket) -> [SqlExpr OrderBy])
-> ProjectId
-> AppDB [TicketSummary]
getTicketSummaries mfilt morder jid = do
let toSummary (Value n, Entity _ s, Value c, Value t, Value d, Value r) =
TicketSummary
{ tsNumber = n
, tsCreatedBy = s
, tsCreatedAt = c
, tsTitle = t
, tsStatus = d
, tsComments = r
}
fmap (map toSummary) $ select $ from $
\ (t `InnerJoin` p `InnerJoin` s `InnerJoin` d `LeftOuterJoin` m) -> do
on $ just (d ^. DiscussionId) ==. m ?. MessageRoot
on $ t ^. TicketDiscuss ==. d ^. DiscussionId
on $ p ^. PersonIdent ==. s ^. SharerId
on $ t ^. TicketCreator ==. p ^. PersonId
where_ $ t ^. TicketProject ==. val jid
groupBy (t ^. TicketId, s ^. SharerId)
for_ mfilt $ \ filt -> where_ $ filt t
for_ morder $ \ order -> orderBy $ order t
return
( t ^. TicketNumber
, s
, t ^. TicketCreated
, t ^. TicketTitle
, t ^. TicketStatus
, count $ m ?. MessageId
)
getTicketSummaries mfilt morder jid = fmap (map toSummary) $ select $ from $
\ ( t
`LeftOuterJoin` (tal `InnerJoin` p `InnerJoin` s)
`LeftOuterJoin` (tar `InnerJoin` ra `InnerJoin` i)
`InnerJoin` d
`LeftOuterJoin` m
) -> do
on $ just (d ^. DiscussionId) ==. m ?. MessageRoot
on $ t ^. TicketDiscuss ==. d ^. DiscussionId
on $ ra ?. RemoteActorInstance ==. i ?. InstanceId
on $ tar ?. TicketAuthorRemoteAuthor ==. ra ?. RemoteActorId
on $ just (t ^. TicketId) ==. tar ?. TicketAuthorRemoteTicket
on $ p ?. PersonIdent ==. s ?. SharerId
on $ tal ?. TicketAuthorLocalAuthor ==. p ?. PersonId
on $ just (t ^. TicketId) ==. tal ?. TicketAuthorLocalTicket
where_ $ t ^. TicketProject ==. val jid
groupBy $ t ^. TicketId
for_ mfilt $ \ filt -> where_ $ filt t
for_ morder $ \ order -> orderBy $ order t
return
( t ^. TicketNumber
, s
, i
, ra
, t ^. TicketCreated
, t ^. TicketTitle
, t ^. TicketStatus
, count $ m ?. MessageId
)
where
toSummary (Value n, ms, mi, mra, Value c, Value t, Value d, Value r) =
TicketSummary
{ tsNumber = n
, tsCreatedBy =
case (ms, mi, mra) of
(Just s, Nothing, Nothing) ->
Left $ entityVal s
(Nothing, Just i, Just ra) ->
Right (entityVal i, entityVal ra)
_ -> error "Ticket author DB invalid state"
, tsCreatedAt = c
, tsTitle = t
, tsStatus = d
, tsComments = r
}
-- | Get the child-parent ticket number pairs of all the ticket dependencies
-- in the given project, in ascending order by child, and then ascending order

View file

@ -45,7 +45,7 @@ import Vervis.Model
import Vervis.Model.Ident
import Vervis.Render (renderSourceT)
import Vervis.Settings (widgetFile)
import Vervis.Widget.Sharer (personLinkW)
import Vervis.Widget.Sharer
actorLinkW :: MessageTreeNodeAuthor -> Widget
actorLinkW actor = $(widgetFile "widget/actor-link")

View file

@ -15,28 +15,40 @@
module Vervis.Widget.Sharer
( sharerLinkW
, personLinkW
, groupLinkW
, sharerLinkFedW
)
where
import Prelude
import Yesod.Core (Route)
import Yesod.Core
import Network.FedURI
import Vervis.Foundation
import Vervis.Model
import Vervis.Model.Ident (ShrIdent, shr2text)
import Vervis.Settings (widgetFile)
link :: (ShrIdent -> Route App) -> Sharer -> Widget
link route sharer = $(widgetFile "sharer-link")
sharerLinkW :: Sharer -> Widget
sharerLinkW = link SharerR
sharerLinkW sharer =
[whamlet|
<a href=@{SharerR $ sharerIdent sharer}>
$maybe name <- sharerName sharer
#{name}
$nothing
#{shr2text $ sharerIdent sharer}
|]
personLinkW :: Sharer -> Widget
personLinkW = link SharerR
groupLinkW :: Sharer -> Widget
groupLinkW = link SharerR
sharerLinkFedW :: Either Sharer (Instance, RemoteActor) -> Widget
sharerLinkFedW (Left sharer) = sharerLinkW sharer
sharerLinkFedW (Right (inztance, actor)) =
[whamlet|
<a href="#{renderFedURI uActor}">
$maybe name <- remoteActorName actor
#{name}
$nothing
(?)
|]
where
uActor = l2f (instanceHost inztance) (remoteActorIdent actor)

View file

@ -1,6 +1,6 @@
{- This file is part of Vervis.
-
- Written in 2016 by fr33domlover <fr33domlover@riseup.net>.
- Written in 2016, 2019 by fr33domlover <fr33domlover@riseup.net>.
-
- Copying is an act of love. Please copy, reuse and share.
-
@ -45,11 +45,11 @@ import Vervis.Model.Ticket
import Vervis.Settings (widgetFile)
import Vervis.Style
import Vervis.Time (showDate)
import Vervis.Widget.Sharer (personLinkW)
import Vervis.Widget.Sharer
data TicketSummary = TicketSummary
{ tsNumber :: Int
, tsCreatedBy :: Sharer
, tsCreatedBy :: Either Sharer (Instance, RemoteActor)
, tsCreatedAt :: UTCTime
, tsTitle :: Text
, tsStatus :: TicketStatus

View file

@ -18,6 +18,7 @@ module Yesod.ActivityPub
, deliverActivity
, forwardActivity
, provideHtmlAndAP
, provideHtmlAndAP'
)
where
@ -121,25 +122,30 @@ provideHtmlAndAP
=> a -> WidgetFor site () -> HandlerFor site TypedContent
provideHtmlAndAP object widget = do
host <- getsYesod siteInstanceHost
provideHtmlAndAP' host object widget
provideHtmlAndAP'
:: (YesodActivityPub site, ActivityPub a)
=> Text -> a -> WidgetFor site () -> HandlerFor site TypedContent
provideHtmlAndAP' host object widget = selectRep $ do
let doc = Doc host object
selectRep $ do
provideAP $ pure doc
provideRep $ do
mval <- lookupGetParam "prettyjson"
defaultLayout $
case mval of
Just "true" ->
provideAP $ pure doc
provideRep $ do
mval <- lookupGetParam "prettyjson"
defaultLayout $
case mval of
Just "true" ->
[whamlet|
<div><pre>#{encodePrettyToLazyText doc}
|]
_ -> do
widget
mroute <- getCurrentRoute
for_ mroute $ \ route -> do
params <- reqGetParams <$> getRequest
let pj = ("prettyjson", "true")
[whamlet|
<div><pre>#{encodePrettyToLazyText doc}
<div>
<a href=@?{(route, pj : params)}>
[See JSON]
|]
_ -> do
widget
mroute <- getCurrentRoute
for_ mroute $ \ route -> do
params <- reqGetParams <$> getRequest
let pj = ("prettyjson", "true")
[whamlet|
<div>
<a href=@?{(route, pj : params)}>
[See JSON]
|]

View file

@ -1,6 +1,6 @@
$# This file is part of Vervis.
$#
$# Written in 2016 by fr33domlover <fr33domlover@riseup.net>.
$# Written in 2016, 2019 by fr33domlover <fr33domlover@riseup.net>.
$#
$# ♡ Copying is an act of love. Please copy, reuse and share.
$#
@ -18,4 +18,4 @@ $# <http://creativecommons.org/publicdomain/zero/1.0/>.
<ul>
$forall Entity _sid sharer <- groups
<li>
^{groupLinkW sharer}
^{sharerLinkW sharer}

View file

@ -1,6 +1,6 @@
$# This file is part of Vervis.
$#
$# Written in 2016 by fr33domlover <fr33domlover@riseup.net>.
$# Written in 2016, 2019 by fr33domlover <fr33domlover@riseup.net>.
$#
$# ♡ Copying is an act of love. Please copy, reuse and share.
$#
@ -24,4 +24,4 @@ $# <http://creativecommons.org/publicdomain/zero/1.0/>.
<ul>
$forall Entity _sid s <- members
<li>
^{personLinkW s}
^{sharerLinkW s}

View file

@ -1,6 +1,6 @@
$# This file is part of Vervis.
$#
$# Written in 2016 by fr33domlover <fr33domlover@riseup.net>.
$# Written in 2016, 2019 by fr33domlover <fr33domlover@riseup.net>.
$#
$# ♡ Copying is an act of love. Please copy, reuse and share.
$#
@ -23,7 +23,7 @@ $# <http://creativecommons.org/publicdomain/zero/1.0/>.
<td>
#{showDate time}
<td>
^{personLinkW sharer}
^{sharerLinkW sharer}
<td>
<a href=@{TicketR shr prj num}>#{num}
<td>

View file

@ -18,7 +18,7 @@ $# <http://creativecommons.org/publicdomain/zero/1.0/>.
<th>Role
$forall (Entity _sid sharer, Value mrl) <- devs
<tr>
<td>^{personLinkW sharer}
<td>^{sharerLinkW sharer}
<td>
$maybe rl <- mrl
#{rl2text rl}

View file

@ -18,7 +18,7 @@ $# <http://creativecommons.org/publicdomain/zero/1.0/>.
<th>Role
$forall (Entity _sid sharer, Value mrl) <- devs
<tr>
<td>^{personLinkW sharer}
<td>^{sharerLinkW sharer}
<td>
$maybe rl <- mrl
#{rl2text rl}

View file

@ -1,6 +1,6 @@
$# This file is part of Vervis.
$#
$# Written in 2018 by fr33domlover <fr33domlover@riseup.net>.
$# Written in 2018, 2019 by fr33domlover <fr33domlover@riseup.net>.
$#
$# ♡ Copying is an act of love. Please copy, reuse and share.
$#
@ -17,7 +17,7 @@ $# <http://creativecommons.org/publicdomain/zero/1.0/>.
<td>By
<td>
$maybe sharer <- msharer
^{personLinkW sharer}
^{sharerLinkW sharer}
$nothing
#{patchAuthorName patch}
<tr>

View file

@ -1,19 +0,0 @@
$# 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/>.
<a href=@{route $ sharerIdent sharer}>
$maybe name <- sharerName sharer
#{name}
$nothing
#{shr2text $ sharerIdent sharer}

View file

@ -1,6 +1,6 @@
$# This file is part of Vervis.
$#
$# Written in 2016 by fr33domlover <fr33domlover@riseup.net>.
$# Written in 2016, 2019 by fr33domlover <fr33domlover@riseup.net>.
$#
$# ♡ Copying is an act of love. Please copy, reuse and share.
$#
@ -22,6 +22,6 @@ $# <http://creativecommons.org/publicdomain/zero/1.0/>.
<td>
#{showDate $ ticketClaimRequestCreated tcr}
<td>
^{personLinkW sharer}
^{sharerLinkW sharer}
<td>
^{renderSourceT Markdown $ ticketClaimRequestMessage tcr}

View file

@ -1,6 +1,6 @@
$# This file is part of Vervis.
$#
$# Written in 2016, 2018 by fr33domlover <fr33domlover@riseup.net>.
$# Written in 2016, 2018, 2019 by fr33domlover <fr33domlover@riseup.net>.
$#
$# ♡ Copying is an act of love. Please copy, reuse and share.
$#
@ -20,12 +20,12 @@ $# <http://creativecommons.org/publicdomain/zero/1.0/>.
<th>Status
$if forward
<th>Remove dependency
$forall (E.Value number, Entity _ author, E.Value title, E.Value status) <- rows
$forall (number, author, title, status) <- rows
<tr>
<td>
<a href=@{TicketR shr prj number}>#{number}
<td>
^{personLinkW author}
^{sharerLinkFedW author}
<td>
<a href=@{TicketR shr prj number}>#{title}
<td>

View file

@ -1,6 +1,6 @@
$# This file is part of Vervis.
$#
$# Written in 2016, 2018 by fr33domlover <fr33domlover@riseup.net>.
$# Written in 2016, 2018, 2019 by fr33domlover <fr33domlover@riseup.net>.
$#
$# ♡ Copying is an act of love. Please copy, reuse and share.
$#
@ -41,7 +41,7 @@ $# <http://creativecommons.org/publicdomain/zero/1.0/>.
<p>
Created on #{showDate $ ticketCreated ticket} by
^{personLinkW author}
^{sharerLinkFedW author}
$if ticketStatus ticket /= TSClosed
<p>
@ -51,7 +51,7 @@ $if ticketStatus ticket /= TSClosed
^{buttonW POST "Unclaim this ticket" (TicketUnclaimR shar proj num)}
$else
Assigned to ^{personLinkW assignee}.
Assigned to ^{sharerLinkW assignee}.
^{buttonW POST "Unassign this ticket" (TicketUnassignR shar proj num)}
$nothing
@ -90,8 +90,9 @@ $if ticketStatus ticket /= TSClosed
^{buttonW POST "Close this ticket" (TicketCloseR shar proj num)}
$of TSClosed
Closed on #{showDate $ ticketClosed ticket} by
^{personLinkW closer}.
Closed on #{showDate $ ticketClosed ticket}
$maybe closer <- mcloser
by ^{sharerLinkW closer}.
^{buttonW POST "Reopen this ticket" (TicketOpenR shar proj num)}

View file

@ -1,6 +1,6 @@
$# This file is part of Vervis.
$#
$# Written in 2016 by fr33domlover <fr33domlover@riseup.net>.
$# Written in 2016, 2019 by fr33domlover <fr33domlover@riseup.net>.
$#
$# ♡ Copying is an act of love. Please copy, reuse and share.
$#
@ -30,7 +30,7 @@ $# <http://creativecommons.org/publicdomain/zero/1.0/>.
<span>
#{showDate $ tsCreatedAt ts}
^{personLinkW $ tsCreatedBy ts}
^{sharerLinkFedW $ tsCreatedBy ts}
<a href=@{TicketR shr prj $ tsNumber ts}>
#{tsTitle ts}