1
0
Fork 0
mirror of https://code.sup39.dev/repos/Wqawg synced 2024-12-27 03:34:51 +09:00

UI: Display personal resources using Permit records

This commit is contained in:
Pere Lev 2023-12-09 07:13:34 +02:00
parent 5af2fdd58b
commit 119779b9b3
No known key found for this signature in database
GPG key ID: 5252C5C863E5E57D
6 changed files with 219 additions and 107 deletions

View file

@ -80,6 +80,8 @@ module Vervis.Actor
, sendToLocalActors , sendToLocalActors
, actorIsAddressed , actorIsAddressed
, localActorType
) )
where where
@ -714,3 +716,12 @@ actorIsAddressed recips = isJust . verify
verify (LocalActorProject j) = do verify (LocalActorProject j) = do
routes <- lookup j $ recipProjects recips routes <- lookup j $ recipProjects recips
guard $ routeProject routes guard $ routeProject routes
localActorType :: LocalActorBy f -> AP.ActorType
localActorType = \case
LocalActorPerson _ -> AP.ActorTypePerson
LocalActorRepo _ -> AP.ActorTypeRepo
LocalActorDeck _ -> AP.ActorTypeTicketTracker
LocalActorLoom _ -> AP.ActorTypePatchTracker
LocalActorProject _ -> AP.ActorTypeProject
LocalActorGroup _ -> AP.ActorTypeTeam

View file

@ -53,12 +53,14 @@ import Control.Monad
import Control.Monad.Trans.Except import Control.Monad.Trans.Except
import Data.Bifunctor import Data.Bifunctor
import Data.Bitraversable import Data.Bitraversable
import Data.Function
import Data.List import Data.List
import Data.Text (Text) import Data.Text (Text)
import Data.Time.Clock import Data.Time.Clock
import Data.Traversable import Data.Traversable
import Database.Persist import Database.Persist
import Text.Blaze.Html (preEscapedToHtml) import Text.Blaze.Html (preEscapedToHtml)
import Optics.Core
import Yesod.Auth import Yesod.Auth
import Yesod.Auth.Account import Yesod.Auth.Account
import Yesod.Auth.Account.Message import Yesod.Auth.Account.Message
@ -89,6 +91,7 @@ import Data.EventTime.Local
import Database.Persist.Local import Database.Persist.Local
import Yesod.Form.Local import Yesod.Form.Local
import Vervis.Actor
import Vervis.API import Vervis.API
import Vervis.Client import Vervis.Client
import Vervis.Data.Actor import Vervis.Data.Actor
@ -98,6 +101,7 @@ import Vervis.Form.Ticket
import Vervis.Foundation import Vervis.Foundation
import Vervis.Model import Vervis.Model
import Vervis.Model.Ident import Vervis.Model.Ident
import Vervis.Persist.Actor
import Vervis.Persist.Collab import Vervis.Persist.Collab
import Vervis.Recipient import Vervis.Recipient
import Vervis.Settings import Vervis.Settings
@ -130,64 +134,87 @@ getHomeR = do
where where
personalOverview :: Entity Person -> Handler Html personalOverview :: Entity Person -> Handler Html
personalOverview (Entity pid _person) = do personalOverview (Entity pid _person) = do
(repos, decks, looms, projects, groups) <- runDB $ (,,,,) permits <- runDB $ do
<$> (E.select $ E.from $ \ (recip `E.InnerJoin` collab `E.InnerJoin` topic `E.InnerJoin` enable `E.InnerJoin` repo `E.InnerJoin` actor) -> do locals <- do
E.on $ repo E.^. RepoActor E.==. actor E.^. ActorId ls <- E.select $ E.from $ \ (permit `E.InnerJoin` topic `E.InnerJoin` enable) -> do
E.on $ topic E.^. CollabTopicRepoRepo E.==. repo E.^. RepoId E.on $ topic E.^. PermitTopicLocalId E.==. enable E.^. PermitTopicEnableLocalTopic
E.on $ topic E.^. CollabTopicRepoCollab E.==. enable E.^. CollabEnableCollab E.on $ permit E.^. PermitId E.==. topic E.^. PermitTopicLocalPermit
E.on $ recip E.^. CollabRecipLocalCollab E.==. topic E.^. CollabTopicRepoCollab E.where_ $ permit E.^. PermitPerson E.==. E.val pid
E.on $ recip E.^. CollabRecipLocalCollab E.==. collab E.^. CollabId E.orderBy [E.asc $ enable E.^. PermitTopicEnableLocalId]
E.where_ $ recip E.^. CollabRecipLocalPerson E.==. E.val pid return
E.orderBy [E.asc $ repo E.^. RepoId] ( permit E.^. PermitId
return (repo, actor, collab) , permit E.^. PermitRole
) , topic E.^. PermitTopicLocalId
<*> (E.select $ E.from $ \ (recip `E.InnerJoin` collab `E.InnerJoin` topic `E.InnerJoin` enable `E.InnerJoin` deck `E.InnerJoin` actor) -> do )
E.on $ deck E.^. DeckActor E.==. actor E.^. ActorId for ls $ \ (E.Value permitID, E.Value role, E.Value topicID) -> do
E.on $ topic E.^. CollabTopicDeckDeck E.==. deck E.^. DeckId topic <- getPermitTopicLocal topicID
E.on $ topic E.^. CollabTopicDeckCollab E.==. enable E.^. CollabEnableCollab actorID <- do
E.on $ recip E.^. CollabRecipLocalCollab E.==. topic E.^. CollabTopicDeckCollab ma <- getLocalActorEntity topic
E.on $ recip E.^. CollabRecipLocalCollab E.==. collab E.^. CollabId case ma of
E.where_ $ recip E.^. CollabRecipLocalPerson E.==. E.val pid Nothing -> error "Impossible, we should have found the local actor in DB"
E.orderBy [E.asc $ deck E.^. DeckId] Just a -> pure $ localActorID a
return (deck, actor, collab) actor <- getJust actorID
) return
<*> (E.select $ E.from $ \ (recip `E.InnerJoin` collab `E.InnerJoin` topic `E.InnerJoin` enable `E.InnerJoin` loom `E.InnerJoin` actor) -> do ( permitID
E.on $ loom E.^. LoomActor E.==. actor E.^. ActorId , role
E.on $ topic E.^. CollabTopicLoomLoom E.==. loom E.^. LoomId , localActorType topic
E.on $ topic E.^. CollabTopicLoomCollab E.==. enable E.^. CollabEnableCollab , Left (topic, actor)
E.on $ recip E.^. CollabRecipLocalCollab E.==. topic E.^. CollabTopicLoomCollab )
E.on $ recip E.^. CollabRecipLocalCollab E.==. collab E.^. CollabId remotes <- do
E.where_ $ recip E.^. CollabRecipLocalPerson E.==. E.val pid rs <- E.select $ E.from $ \ (permit `E.InnerJoin` topic `E.InnerJoin` enable) -> do
E.orderBy [E.asc $ loom E.^. LoomId] E.on $ topic E.^. PermitTopicRemoteId E.==. enable E.^. PermitTopicEnableRemoteTopic
return (loom, actor, collab) E.on $ permit E.^. PermitId E.==. topic E.^. PermitTopicRemotePermit
) E.where_ $ permit E.^. PermitPerson E.==. E.val pid
<*> (E.select $ E.from $ \ (recip `E.InnerJoin` collab `E.InnerJoin` topic `E.InnerJoin` enable `E.InnerJoin` project `E.InnerJoin` actor) -> do E.orderBy [E.asc $ enable E.^. PermitTopicEnableRemoteId]
E.on $ project E.^. ProjectActor E.==. actor E.^. ActorId return
E.on $ topic E.^. CollabTopicProjectProject E.==. project E.^. ProjectId ( permit E.^. PermitId
E.on $ topic E.^. CollabTopicProjectCollab E.==. enable E.^. CollabEnableCollab , permit E.^. PermitRole
E.on $ recip E.^. CollabRecipLocalCollab E.==. topic E.^. CollabTopicProjectCollab , topic E.^. PermitTopicRemoteActor
E.on $ recip E.^. CollabRecipLocalCollab E.==. collab E.^. CollabId )
E.where_ $ recip E.^. CollabRecipLocalPerson E.==. E.val pid for rs $ \ (E.Value permitID, E.Value role, E.Value remoteActorID) -> do
E.orderBy [E.asc $ project E.^. ProjectId] remoteActor <- getJust remoteActorID
return (project, actor, collab) remoteObject <- getJust $ remoteActorIdent remoteActor
) inztance <- getJust $ remoteObjectInstance remoteObject
<*> (E.select $ E.from $ \ (recip `E.InnerJoin` collab `E.InnerJoin` topic `E.InnerJoin` enable `E.InnerJoin` group `E.InnerJoin` actor) -> do return
E.on $ group E.^. GroupActor E.==. actor E.^. ActorId ( permitID
E.on $ topic E.^. CollabTopicGroupGroup E.==. group E.^. GroupId , role
E.on $ topic E.^. CollabTopicGroupCollab E.==. enable E.^. CollabEnableCollab , remoteActorType remoteActor
E.on $ recip E.^. CollabRecipLocalCollab E.==. topic E.^. CollabTopicGroupCollab , Right (inztance, remoteObject, remoteActor)
E.on $ recip E.^. CollabRecipLocalCollab E.==. collab E.^. CollabId )
E.where_ $ recip E.^. CollabRecipLocalPerson E.==. E.val pid return $ locals ++ remotes
E.orderBy [E.asc $ group E.^. GroupId] let (people, repos, decks, looms, projects, groups, others) =
return (group, actor, collab) partitionByActorType (view _3) (view _1) permits
) if null people
hashRepo <- getEncodeKeyHashid then pure ()
hashDeck <- getEncodeKeyHashid else error "Bug: Person as a PermitTopic"
hashLoom <- getEncodeKeyHashid
hashProject <- getEncodeKeyHashid
hashGroup <- getEncodeKeyHashid
defaultLayout $(widgetFile "personal-overview") defaultLayout $(widgetFile "personal-overview")
where
partitionByActorType
:: Eq b
=> (a -> AP.ActorType)
-> (a -> b)
-> [a]
-> ([a], [a], [a], [a], [a], [a], [a])
partitionByActorType typ key xs =
let p = filter ((== AP.ActorTypePerson) . typ) xs
r = filter ((== AP.ActorTypeRepo) . typ) xs
d = filter ((== AP.ActorTypeTicketTracker) . typ) xs
l = filter ((== AP.ActorTypePatchTracker) . typ) xs
j = filter ((== AP.ActorTypeProject) . typ) xs
g = filter ((== AP.ActorTypeTeam) . typ) xs
x = deleteFirstsBy ((==) `on` key) xs (p ++ r ++ d ++ l ++ j ++ g)
in (p, r, d, l, j, g, x)
item (_permitID, role, _typ, actor) =
[whamlet|
[
#{show role}
]
^{actorLinkFedW actor}
|]
getBrowseR :: Handler Html getBrowseR :: Handler Html
getBrowseR = do getBrowseR = do
(people, groups, repos, decks, looms, projects) <- runDB $ (people, groups, repos, decks, looms, projects) <- runDB $

View file

@ -17,6 +17,7 @@ module Vervis.Persist.Collab
( getCollabTopic ( getCollabTopic
, getCollabTopic' , getCollabTopic'
, getCollabRecip , getCollabRecip
, getPermitTopicLocal
, getPermitTopic , getPermitTopic
, getStemIdent , getStemIdent
, getStemProject , getStemProject
@ -112,6 +113,29 @@ getCollabRecip collabID =
"Collab without recip" "Collab without recip"
"Collab with both local and remote recip" "Collab with both local and remote recip"
getPermitTopicLocal
:: MonadIO m
=> PermitTopicLocalId
-> ReaderT SqlBackend m (LocalActorBy Key)
getPermitTopicLocal localID = do
options <-
sequence
[ fmap (LocalActorRepo . permitTopicRepoRepo) <$>
getValBy (UniquePermitTopicRepo localID)
, fmap (LocalActorDeck . permitTopicDeckDeck) <$>
getValBy (UniquePermitTopicDeck localID)
, fmap (LocalActorLoom . permitTopicLoomLoom) <$>
getValBy (UniquePermitTopicLoom localID)
, fmap (LocalActorProject . permitTopicProjectProject) <$>
getValBy (UniquePermitTopicProject localID)
, fmap (LocalActorGroup . permitTopicGroupGroup) <$>
getValBy (UniquePermitTopicGroup localID)
]
exactlyOneJust
options
"Found Permit without topic"
"Found Permit with multiple topics"
getPermitTopic getPermitTopic
:: MonadIO m :: MonadIO m
=> PermitId => PermitId
@ -128,25 +152,7 @@ getPermitTopic permitID = do
"Permit without topic" "Permit without topic"
"Permit with both local and remote topic" "Permit with both local and remote topic"
bitraverse bitraverse
(\ localID -> (localID,) <$> do (\ localID -> (localID,) <$> getPermitTopicLocal localID)
options <-
sequence
[ fmap (LocalActorRepo . permitTopicRepoRepo) <$>
getValBy (UniquePermitTopicRepo localID)
, fmap (LocalActorDeck . permitTopicDeckDeck) <$>
getValBy (UniquePermitTopicDeck localID)
, fmap (LocalActorLoom . permitTopicLoomLoom) <$>
getValBy (UniquePermitTopicLoom localID)
, fmap (LocalActorProject . permitTopicProjectProject) <$>
getValBy (UniquePermitTopicProject localID)
, fmap (LocalActorGroup . permitTopicGroupGroup) <$>
getValBy (UniquePermitTopicGroup localID)
]
exactlyOneJust
options
"Found Permit without topic"
"Found Permit with multiple topics"
)
(\ (Entity topicID (PermitTopicRemote _ actorID)) -> (\ (Entity topicID (PermitTopicRemote _ actorID)) ->
return (topicID, actorID) return (topicID, actorID)
) )

View file

@ -1,6 +1,6 @@
{- This file is part of Vervis. {- This file is part of Vervis.
- -
- Written in 2016, 2019, 2022 by fr33domlover <fr33domlover@riseup.net>. - Written in 2016, 2019, 2022, 2023 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.
- -
@ -31,6 +31,8 @@ import Network.FedURI
import Yesod.Auth.Unverified import Yesod.Auth.Unverified
import Yesod.Hashids import Yesod.Hashids
import qualified Web.ActivityPub as AP
import Database.Persist.Local import Database.Persist.Local
import Vervis.Foundation import Vervis.Foundation
@ -54,13 +56,22 @@ personLinkFedW (Left (ep, a)) = personLinkW ep a
personLinkFedW (Right (inztance, object, actor)) = personLinkFedW (Right (inztance, object, actor)) =
[whamlet| [whamlet|
<a href="#{renderObjURI uActor}"> <a href="#{renderObjURI uActor}">
#{marker $ remoteActorType actor} #
$maybe name <- remoteActorName actor $maybe name <- remoteActorName actor
#{name} #{name} @ #{renderAuthority $ instanceHost inztance}
$nothing $nothing
#{renderAuthority $ instanceHost inztance}#{localUriPath $ remoteObjectIdent object} #{renderAuthority $ instanceHost inztance}#{localUriPath $ remoteObjectIdent object}
|] |]
where where
uActor = ObjURI (instanceHost inztance) (remoteObjectIdent object) uActor = ObjURI (instanceHost inztance) (remoteObjectIdent object)
marker = \case
AP.ActorTypePerson -> '~'
AP.ActorTypeRepo -> '^'
AP.ActorTypeTicketTracker -> '='
AP.ActorTypePatchTracker -> '+'
AP.ActorTypeProject -> '$'
AP.ActorTypeTeam -> '&'
AP.ActorTypeOther _ -> '?'
followW :: Route App -> Route App -> FollowerSetId -> Widget followW :: Route App -> Route App -> FollowerSetId -> Widget
followW followRoute unfollowRoute fsid = do followW followRoute unfollowRoute fsid = do

View file

@ -19,19 +19,26 @@ module Vervis.Widget.Tracker
, projectNavW , projectNavW
, componentLinkFedW , componentLinkFedW
, projectLinkFedW , projectLinkFedW
, actorLinkFedW
, groupNavW , groupNavW
) )
where where
import Database.Persist
import Database.Persist.Types import Database.Persist.Types
import Yesod.Core.Widget import Yesod.Core.Widget
import Yesod.Persist.Core
import Network.FedURI import Network.FedURI
import Yesod.Hashids import Yesod.Hashids
import qualified Web.ActivityPub as AP
import Vervis.Actor
import Vervis.Data.Collab import Vervis.Data.Collab
import Vervis.Foundation import Vervis.Foundation
import Vervis.Model import Vervis.Model
import Vervis.Model.Ident
import Vervis.Settings import Vervis.Settings
deckNavW :: Entity Deck -> Actor -> Widget deckNavW :: Entity Deck -> Actor -> Widget
@ -110,3 +117,66 @@ projectLinkFedW (Right (inztance, object, actor)) =
|] |]
where where
uActor = ObjURI (instanceHost inztance) (remoteObjectIdent object) uActor = ObjURI (instanceHost inztance) (remoteObjectIdent object)
actorLinkW :: LocalActorBy Key -> Actor -> Widget
actorLinkW (LocalActorPerson k) actor = do
p <- handlerToWidget $ runDB $ getJust k
h <- encodeKeyHashid k
[whamlet|
<a href=@{PersonR h}>
~#{username2text $ personUsername p} #{actorName actor}
|]
actorLinkW (LocalActorRepo k) actor = do
h <- encodeKeyHashid k
[whamlet|
<a href=@{RepoR h}>
^#{keyHashidText h} #{actorName actor}
|]
actorLinkW (LocalActorDeck k) actor = do
h <- encodeKeyHashid k
[whamlet|
<a href=@{DeckR h}>
=#{keyHashidText h} #{actorName actor}
|]
actorLinkW (LocalActorLoom k) actor = do
h <- encodeKeyHashid k
[whamlet|
<a href=@{LoomR h}>
+#{keyHashidText h} #{actorName actor}
|]
actorLinkW (LocalActorProject k) actor = do
h <- encodeKeyHashid k
[whamlet|
<a href=@{ProjectR h}>
\$#{keyHashidText h} #{actorName actor}
|]
actorLinkW (LocalActorGroup k) actor = do
h <- encodeKeyHashid k
[whamlet|
<a href=@{GroupR h}>
&#{keyHashidText h} #{actorName actor}
|]
actorLinkFedW
:: Either (LocalActorBy Key, Actor) (Instance, RemoteObject, RemoteActor)
-> Widget
actorLinkFedW (Left (c, a)) = actorLinkW c a
actorLinkFedW (Right (inztance, object, actor)) =
[whamlet|
<a href="#{renderObjURI uActor}">
#{marker $ remoteActorType actor} #
$maybe name <- remoteActorName actor
#{name} @ #{renderAuthority $ instanceHost inztance}
$nothing
#{renderAuthority $ instanceHost inztance}#{localUriPath $ remoteObjectIdent object}
|]
where
uActor = ObjURI (instanceHost inztance) (remoteObjectIdent object)
marker = \case
AP.ActorTypePerson -> '~'
AP.ActorTypeRepo -> '^'
AP.ActorTypeTicketTracker -> '='
AP.ActorTypePatchTracker -> '+'
AP.ActorTypeProject -> '$'
AP.ActorTypeTeam -> '&'
AP.ActorTypeOther _ -> '?'

View file

@ -67,54 +67,41 @@ $# Comment on a ticket or merge request
<h2>Your teams <h2>Your teams
<ul> <ul>
$forall (Entity groupID _, Entity _ actor, Entity _ (Collab role)) <- groups $forall i <- groups
<li> <li>
[ ^{item i}
#{show role}
]
<a href=@{GroupR $ hashGroup groupID}>
&#{keyHashidText $ hashGroup groupID} #{actorName actor}
<h2>Your repos <h2>Your repos
<ul> <ul>
$forall (Entity repoID _, Entity _ actor, Entity _ (Collab role)) <- repos $forall i <- repos
<li> <li>
[ ^{item i}
#{show role}
]
<a href=@{RepoR $ hashRepo repoID}>
^#{keyHashidText $ hashRepo repoID} #{actorName actor}
<h2>Your ticket trackers <h2>Your ticket trackers
<ul> <ul>
$forall (Entity deckID _, Entity _ actor, Entity _ (Collab role)) <- decks $forall i <- decks
<li> <li>
[ ^{item i}
#{show role}
]
<a href=@{DeckR $ hashDeck deckID}>
=#{keyHashidText $ hashDeck deckID} #{actorName actor}
<h2>Your patch trackers <h2>Your patch trackers
<ul> <ul>
$forall (Entity loomID _, Entity _ actor, Entity _ (Collab role)) <- looms $forall i <- looms
<li> <li>
[ ^{item i}
#{show role}
]
<a href=@{LoomR $ hashLoom loomID}>
+#{keyHashidText $ hashLoom loomID} #{actorName actor}
<h2>Your projects <h2>Your projects
<ul> <ul>
$forall (Entity projectID _, Entity _ actor, Entity _ (Collab role)) <- projects $forall i <- projects
<li> <li>
[ ^{item i}
#{show role}
] <h2>Your resources of unrecognized type
<a href=@{ProjectR $ hashProject projectID}>
\$#{keyHashidText $ hashProject projectID} #{actorName actor} <ul>
$forall i <- others
<li>
^{item i}