mirror of
https://code.sup39.dev/repos/Wqawg
synced 2024-12-27 17:14:52 +09:00
C2S, UI: Loom creation and Repo linking to a Loom
RepoSourceR, for a repo that doesn't have a loom, lists looms that want to serve that repo with buttons for bidirectionally linking the repo to a loom Once linked, the repo navbar has a Patches/MRs link pointing to the LoomClothsR of the linked Loom
This commit is contained in:
parent
1c8c6d9d24
commit
c495d78d05
15 changed files with 598 additions and 27 deletions
|
@ -1,6 +1,6 @@
|
||||||
{- This file is part of Vervis.
|
{- This file is part of Vervis.
|
||||||
-
|
-
|
||||||
- Written in 2019 by fr33domlover <fr33domlover@riseup.net>.
|
- Written in 2019, 2022 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.
|
||||||
-
|
-
|
||||||
|
@ -21,10 +21,14 @@ module Data.Aeson.Local
|
||||||
, (.:|?)
|
, (.:|?)
|
||||||
, (.:+)
|
, (.:+)
|
||||||
, (.:+?)
|
, (.:+?)
|
||||||
|
, (.:*)
|
||||||
|
, (.:*+)
|
||||||
, (.=?)
|
, (.=?)
|
||||||
, (.=%)
|
, (.=%)
|
||||||
, (.=+)
|
, (.=+)
|
||||||
, (.=+?)
|
, (.=+?)
|
||||||
|
, (.=*)
|
||||||
|
, (.=*+)
|
||||||
, WithValue (..)
|
, WithValue (..)
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
@ -32,6 +36,7 @@ where
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.Aeson.Types (Parser)
|
import Data.Aeson.Types (Parser)
|
||||||
|
import Data.List.NonEmpty (NonEmpty (..))
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Network.URI
|
import Network.URI
|
||||||
|
|
||||||
|
@ -58,7 +63,7 @@ fromEither (Right y) = Right' y
|
||||||
(.:|) :: FromJSON a => Object -> Text -> Parser a
|
(.:|) :: FromJSON a => Object -> Text -> Parser a
|
||||||
o .:| t = o .: t <|> o .: (frg <> t)
|
o .:| t = o .: t <|> o .: (frg <> t)
|
||||||
where
|
where
|
||||||
frg = "https://forgefed.peers.community/ns#"
|
frg = "https://forgefed.org/ns#"
|
||||||
|
|
||||||
(.:|?) :: FromJSON a => Object -> Text -> Parser (Maybe a)
|
(.:|?) :: FromJSON a => Object -> Text -> Parser (Maybe a)
|
||||||
o .:|? t = optional $ o .:| t
|
o .:|? t = optional $ o .:| t
|
||||||
|
@ -71,6 +76,26 @@ o .:+ t = Left <$> o .: t <|> Right <$> o .: t
|
||||||
=> Object -> Text -> Parser (Maybe (Either a b))
|
=> Object -> Text -> Parser (Maybe (Either a b))
|
||||||
o .:+? t = optional $ o .:+ t
|
o .:+? t = optional $ o .:+ t
|
||||||
|
|
||||||
|
-- | For JSON-LD properties that aren't functional, i.e. can have any number of
|
||||||
|
-- values
|
||||||
|
(.:*) :: FromJSON a => Object -> Text -> Parser [a]
|
||||||
|
o .:* t = do
|
||||||
|
maybeOneOrArray <- o .:+? t
|
||||||
|
case maybeOneOrArray of
|
||||||
|
Nothing -> return []
|
||||||
|
Just (Left v) -> return [v]
|
||||||
|
Just (Right vs) -> return vs
|
||||||
|
|
||||||
|
-- | For JSON-LD properties that aren't functional, i.e. can have any number of
|
||||||
|
-- values
|
||||||
|
(.:*+) :: FromJSON a => Object -> Text -> Parser (NonEmpty a)
|
||||||
|
o .:*+ t = do
|
||||||
|
oneOrArray <- o .:+ t
|
||||||
|
case oneOrArray of
|
||||||
|
Left v -> return $ v :| []
|
||||||
|
Right [] -> fail $ "No values for " ++ T.unpack t
|
||||||
|
Right (v:vs) -> return $ v :| vs
|
||||||
|
|
||||||
infixr 8 .=?
|
infixr 8 .=?
|
||||||
(.=?) :: ToJSON v => Text -> Maybe v -> Series
|
(.=?) :: ToJSON v => Text -> Maybe v -> Series
|
||||||
_ .=? Nothing = mempty
|
_ .=? Nothing = mempty
|
||||||
|
@ -93,6 +118,17 @@ infixr 8 .=+?
|
||||||
k .=+? Nothing = mempty
|
k .=+? Nothing = mempty
|
||||||
k .=+? (Just v) = k .=+ v
|
k .=+? (Just v) = k .=+ v
|
||||||
|
|
||||||
|
infixr 8 .=*
|
||||||
|
(.=*) :: ToJSON a => Text -> [a] -> Series
|
||||||
|
_ .=* [] = mempty
|
||||||
|
k .=* [v] = k .= v
|
||||||
|
k .=* vs = k .= vs
|
||||||
|
|
||||||
|
infixr 8 .=*+
|
||||||
|
(.=*+) :: ToJSON a => Text -> NonEmpty a -> Series
|
||||||
|
k .=*+ (v :| []) = k .= v
|
||||||
|
k .=*+ (v :| vs) = k .= (v:vs)
|
||||||
|
|
||||||
data WithValue a = WithValue
|
data WithValue a = WithValue
|
||||||
{ wvRaw :: Object
|
{ wvRaw :: Object
|
||||||
, wvParsed :: a
|
, wvParsed :: a
|
||||||
|
|
|
@ -22,6 +22,7 @@ module Vervis.API
|
||||||
, applyC
|
, applyC
|
||||||
, noteC
|
, noteC
|
||||||
, createNoteC
|
, createNoteC
|
||||||
|
, createPatchTrackerC
|
||||||
, createRepositoryC
|
, createRepositoryC
|
||||||
, createTicketTrackerC
|
, createTicketTrackerC
|
||||||
, followC
|
, followC
|
||||||
|
@ -1277,6 +1278,276 @@ verifyProjectRecip (Left (WITRepo shr rp _ _ _)) localRecips =
|
||||||
guard $ localRecipRepo $ localRecipRepoDirect repoSet
|
guard $ localRecipRepo $ localRecipRepoDirect repoSet
|
||||||
-}
|
-}
|
||||||
|
|
||||||
|
createPatchTrackerC
|
||||||
|
:: Entity Person
|
||||||
|
-> Actor
|
||||||
|
-> Maybe TextHtml
|
||||||
|
-> Audience URIMode
|
||||||
|
-> AP.ActorDetail
|
||||||
|
-> NonEmpty FedURI
|
||||||
|
-> Maybe (Host, AP.ActorLocal URIMode)
|
||||||
|
-> Maybe FedURI
|
||||||
|
-> ExceptT Text Handler OutboxItemId
|
||||||
|
createPatchTrackerC (Entity pidUser personUser) senderActor summary audience detail repos mlocal muTarget = do
|
||||||
|
|
||||||
|
-- Check input
|
||||||
|
verifyNothingE mlocal "'id' not allowed in new PatchTracker to create"
|
||||||
|
(name, msummary) <- parseDetail detail
|
||||||
|
repoID <- parseRepo repos
|
||||||
|
senderHash <- encodeKeyHashid pidUser
|
||||||
|
now <- liftIO getCurrentTime
|
||||||
|
verifyNothingE muTarget "'target' not supported in Create PatchTracker"
|
||||||
|
ParsedAudience localRecips remoteRecips blinded fwdHosts <- do
|
||||||
|
mrecips <- parseAudience audience
|
||||||
|
fromMaybeE mrecips "Create PatchTracker with no recipients"
|
||||||
|
checkFederation remoteRecips
|
||||||
|
|
||||||
|
(obiid, deliverHttpCreate, deliverHttpGrant) <- runDBExcept $ do
|
||||||
|
|
||||||
|
-- Find the specified repo in DB
|
||||||
|
_ <- getE repoID "No such repo in DB"
|
||||||
|
|
||||||
|
-- Make sure the repo has a single, full-access collab, granted to the
|
||||||
|
-- sender of this Create
|
||||||
|
maybeApproved <- lift $ runMaybeT $ do
|
||||||
|
collabs <- lift $ selectList [CollabTopicRepoRepo ==. repoID] []
|
||||||
|
collabID <-
|
||||||
|
case collabs of
|
||||||
|
[Entity _ c] -> return $ collabTopicRepoCollab c
|
||||||
|
_ -> mzero
|
||||||
|
CollabRecipLocal _ recipID <-
|
||||||
|
MaybeT $ getValBy $ UniqueCollabRecipLocal collabID
|
||||||
|
guard $ recipID == pidUser
|
||||||
|
_ <- MaybeT $ getBy $ UniqueCollabEnable collabID
|
||||||
|
_ <- MaybeT $ getBy $ UniqueCollabFulfillsLocalTopicCreation collabID
|
||||||
|
return ()
|
||||||
|
unless (isJust maybeApproved) $
|
||||||
|
throwE "Repo's collabs unexpected state"
|
||||||
|
|
||||||
|
-- Insert new loom to DB
|
||||||
|
obiidCreate <- lift $ insertEmptyOutboxItem (actorOutbox senderActor) now
|
||||||
|
(loomID, Entity loomActorID loomActor) <-
|
||||||
|
lift $ insertLoom now name msummary obiidCreate repoID
|
||||||
|
|
||||||
|
-- Insert the Create activity to author's outbox
|
||||||
|
loomHash <- encodeKeyHashid loomID
|
||||||
|
repoHash <- encodeKeyHashid repoID
|
||||||
|
docCreate <- lift $ insertCreateToOutbox senderHash now blinded name msummary obiidCreate loomHash repoHash
|
||||||
|
|
||||||
|
-- Deliver the Create activity to local recipients, and schedule
|
||||||
|
-- delivery for unavailable remote recipients
|
||||||
|
remoteRecipsHttpCreate <- do
|
||||||
|
let sieve =
|
||||||
|
makeRecipientSet
|
||||||
|
[LocalActorRepo repoHash]
|
||||||
|
[ LocalStagePersonFollowers senderHash
|
||||||
|
, LocalStageRepoFollowers repoHash
|
||||||
|
]
|
||||||
|
moreRemoteRecips <-
|
||||||
|
lift $ deliverLocal' True (LocalActorPerson senderHash) (personActor personUser) obiidCreate $
|
||||||
|
localRecipSieve sieve False localRecips
|
||||||
|
checkFederation moreRemoteRecips
|
||||||
|
lift $ deliverRemoteDB'' fwdHosts obiidCreate remoteRecips moreRemoteRecips
|
||||||
|
|
||||||
|
-- Insert collaboration access for loom's creator
|
||||||
|
let loomOutboxID = actorOutbox loomActor
|
||||||
|
obiidGrant <- lift $ insertEmptyOutboxItem loomOutboxID now
|
||||||
|
lift $ insertCollab loomID obiidGrant
|
||||||
|
|
||||||
|
-- Insert a Grant activity to loom's outbox
|
||||||
|
let grantRecipActors = [LocalActorPerson senderHash]
|
||||||
|
grantRecipStages = [LocalStagePersonFollowers senderHash]
|
||||||
|
docGrant <-
|
||||||
|
lift $ insertGrantToOutbox senderHash loomHash obiidCreate obiidGrant grantRecipActors grantRecipStages
|
||||||
|
|
||||||
|
-- Deliver the Grant activity to local recipients, and schedule
|
||||||
|
-- delivery for unavailable remote recipients
|
||||||
|
remoteRecipsHttpGrant <- do
|
||||||
|
remoteRecips <-
|
||||||
|
lift $ deliverLocal' True (LocalActorLoom loomHash) loomActorID obiidGrant $
|
||||||
|
makeRecipientSet grantRecipActors grantRecipStages
|
||||||
|
checkFederation remoteRecips
|
||||||
|
lift $ deliverRemoteDB'' [] obiidGrant [] remoteRecips
|
||||||
|
|
||||||
|
-- Insert follow record
|
||||||
|
obiidFollow <- lift $ insertEmptyOutboxItem (actorOutbox senderActor) now
|
||||||
|
obiidAccept <- lift $ insertEmptyOutboxItem loomOutboxID now
|
||||||
|
lift $ insert_ $ Follow (personActor personUser) (actorFollowers loomActor) True obiidFollow obiidAccept
|
||||||
|
|
||||||
|
-- Insert a Follow activity to sender's outbox, and an Accept to the
|
||||||
|
-- loom's outbox
|
||||||
|
luFollow <- lift $ insertFollowToOutbox senderHash loomHash obiidFollow
|
||||||
|
lift $ insertAcceptToOutbox senderHash loomHash obiidAccept luFollow
|
||||||
|
|
||||||
|
-- Deliver the Follow and Accept by simply manually inserting them to
|
||||||
|
-- loom and sender inboxes respectively
|
||||||
|
lift $ do
|
||||||
|
ibiidF <- insert $ InboxItem False now
|
||||||
|
insert_ $ InboxItemLocal (actorInbox loomActor) obiidFollow ibiidF
|
||||||
|
ibiidA <- insert $ InboxItem False now
|
||||||
|
insert_ $ InboxItemLocal (actorInbox senderActor) obiidAccept ibiidA
|
||||||
|
|
||||||
|
-- Return instructions for HTTP delivery to remote recipients
|
||||||
|
return
|
||||||
|
( obiidCreate
|
||||||
|
, deliverRemoteHttp' fwdHosts obiidCreate docCreate remoteRecipsHttpCreate
|
||||||
|
, deliverRemoteHttp' [] obiidGrant docGrant remoteRecipsHttpGrant
|
||||||
|
)
|
||||||
|
|
||||||
|
-- Launch asynchronous HTTP delivery of Create and Grant
|
||||||
|
lift $ do
|
||||||
|
forkWorker "createPatchTrackerC: async HTTP Create delivery" deliverHttpCreate
|
||||||
|
forkWorker "createPatchTrackerC: async HTTP Grant delivery" deliverHttpGrant
|
||||||
|
|
||||||
|
return obiid
|
||||||
|
|
||||||
|
where
|
||||||
|
|
||||||
|
parseDetail (AP.ActorDetail typ muser mname msummary) = do
|
||||||
|
unless (typ == AP.ActorTypePatchTracker) $
|
||||||
|
error "createPatchTrackerC: Create object isn't a PatchTracker"
|
||||||
|
verifyNothingE muser "PatchTracker can't have a username"
|
||||||
|
name <- fromMaybeE mname "PatchTracker doesn't specify name"
|
||||||
|
return (name, msummary)
|
||||||
|
|
||||||
|
parseRepo (ObjURI h lu :| us) = do
|
||||||
|
unless (null us) $ throwE "More than one repo is specified"
|
||||||
|
hl <- hostIsLocal h
|
||||||
|
unless hl $ throwE "A remote repo is specified"
|
||||||
|
route <- fromMaybeE (decodeRouteLocal lu) "Not a valid route"
|
||||||
|
case route of
|
||||||
|
RepoR repoHash -> decodeKeyHashidE repoHash "Invalid repo hash"
|
||||||
|
_ -> throwE "Not a repo route"
|
||||||
|
|
||||||
|
insertLoom now name msummary obiidCreate repoID = do
|
||||||
|
actor@(Entity actorID _) <-
|
||||||
|
insertActor now name (fromMaybe "" msummary)
|
||||||
|
loomID <- insert Loom
|
||||||
|
{ loomNextTicket = 1
|
||||||
|
, loomActor = actorID
|
||||||
|
, loomRepo = repoID
|
||||||
|
, loomCreate = obiidCreate
|
||||||
|
}
|
||||||
|
return (loomID, actor)
|
||||||
|
|
||||||
|
insertCreateToOutbox senderHash now blinded name msummary obiidCreate loomHash repoHash = do
|
||||||
|
encodeRouteLocal <- getEncodeRouteLocal
|
||||||
|
encodeRouteHome <- getEncodeRouteHome
|
||||||
|
hLocal <- asksSite siteInstanceHost
|
||||||
|
obikhid <- encodeKeyHashid obiidCreate
|
||||||
|
let ptdetail = AP.ActorDetail
|
||||||
|
{ AP.actorType = AP.ActorTypePatchTracker
|
||||||
|
, AP.actorUsername = Nothing
|
||||||
|
, AP.actorName = Just name
|
||||||
|
, AP.actorSummary = msummary
|
||||||
|
}
|
||||||
|
ptlocal = AP.ActorLocal
|
||||||
|
{ AP.actorId = encodeRouteLocal $ LoomR loomHash
|
||||||
|
, AP.actorInbox = encodeRouteLocal $ LoomInboxR loomHash
|
||||||
|
, AP.actorOutbox = Nothing
|
||||||
|
, AP.actorFollowers = Nothing
|
||||||
|
, AP.actorFollowing = Nothing
|
||||||
|
, AP.actorPublicKeys = []
|
||||||
|
, AP.actorSshKeys = []
|
||||||
|
}
|
||||||
|
repo = encodeRouteHome $ RepoR repoHash
|
||||||
|
create = Doc hLocal Activity
|
||||||
|
{ activityId = Just $ encodeRouteLocal $ PersonOutboxItemR senderHash obikhid
|
||||||
|
, activityActor = encodeRouteLocal $ PersonR senderHash
|
||||||
|
, activityCapability = Nothing
|
||||||
|
, activitySummary = summary
|
||||||
|
, activityAudience = blinded
|
||||||
|
, activityFulfills = []
|
||||||
|
, activitySpecific = CreateActivity Create
|
||||||
|
{ createObject = CreatePatchTracker ptdetail (repo :| []) (Just (hLocal, ptlocal))
|
||||||
|
, createTarget = Nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update obiidCreate [OutboxItemActivity =. persistJSONObjectFromDoc create]
|
||||||
|
return create
|
||||||
|
|
||||||
|
insertCollab loomID obiidGrant = do
|
||||||
|
cid <- insert Collab
|
||||||
|
insert_ $ CollabTopicLoom cid loomID
|
||||||
|
insert_ $ CollabEnable cid obiidGrant
|
||||||
|
insert_ $ CollabRecipLocal cid pidUser
|
||||||
|
insert_ $ CollabFulfillsLocalTopicCreation cid
|
||||||
|
|
||||||
|
insertGrantToOutbox adminHash loomHash obiidCreate obiidGrant actors stages = do
|
||||||
|
encodeRouteLocal <- getEncodeRouteLocal
|
||||||
|
encodeRouteHome <- getEncodeRouteHome
|
||||||
|
hLocal <- asksSite siteInstanceHost
|
||||||
|
obikhidCreate <- encodeKeyHashid obiidCreate
|
||||||
|
obikhidGrant <- encodeKeyHashid obiidGrant
|
||||||
|
let recips =
|
||||||
|
map encodeRouteHome $
|
||||||
|
map renderLocalActor actors ++
|
||||||
|
map renderLocalStage stages
|
||||||
|
grant = Doc hLocal Activity
|
||||||
|
{ activityId =
|
||||||
|
Just $ encodeRouteLocal $
|
||||||
|
LoomOutboxItemR loomHash obikhidGrant
|
||||||
|
, activityActor = encodeRouteLocal $ LoomR loomHash
|
||||||
|
, activityCapability = Nothing
|
||||||
|
, activitySummary = Nothing
|
||||||
|
, activityAudience = Audience recips [] [] [] [] []
|
||||||
|
, activityFulfills =
|
||||||
|
[encodeRouteHome $ PersonOutboxItemR adminHash obikhidCreate]
|
||||||
|
, activitySpecific = GrantActivity Grant
|
||||||
|
{ grantObject = Left RoleAdmin
|
||||||
|
, grantContext = encodeRouteHome $ LoomR loomHash
|
||||||
|
, grantTarget = encodeRouteHome $ PersonR adminHash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update obiidGrant [OutboxItemActivity =. persistJSONObjectFromDoc grant]
|
||||||
|
return grant
|
||||||
|
|
||||||
|
insertFollowToOutbox senderHash loomHash obiidFollow = do
|
||||||
|
encodeRouteLocal <- getEncodeRouteLocal
|
||||||
|
encodeRouteHome <- getEncodeRouteHome
|
||||||
|
hLocal <- asksSite siteInstanceHost
|
||||||
|
|
||||||
|
obikhid <- encodeKeyHashid obiidFollow
|
||||||
|
let luFollow = encodeRouteLocal $ PersonOutboxItemR senderHash obikhid
|
||||||
|
recips = [encodeRouteHome $ LoomR loomHash]
|
||||||
|
doc = Doc hLocal Activity
|
||||||
|
{ activityId = Just luFollow
|
||||||
|
, activityActor = encodeRouteLocal $ PersonR senderHash
|
||||||
|
, activityCapability = Nothing
|
||||||
|
, activitySummary = Nothing
|
||||||
|
, activityAudience = AP.Audience recips [] [] [] [] []
|
||||||
|
, activityFulfills = []
|
||||||
|
, activitySpecific = FollowActivity AP.Follow
|
||||||
|
{ AP.followObject = encodeRouteHome $ LoomR loomHash
|
||||||
|
, AP.followContext = Nothing
|
||||||
|
, AP.followHide = False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update obiidFollow [OutboxItemActivity =. persistJSONObjectFromDoc doc]
|
||||||
|
return luFollow
|
||||||
|
|
||||||
|
insertAcceptToOutbox senderHash loomHash obiidAccept luFollow = do
|
||||||
|
hLocal <- asksSite siteInstanceHost
|
||||||
|
encodeRouteLocal <- getEncodeRouteLocal
|
||||||
|
encodeRouteHome <- getEncodeRouteHome
|
||||||
|
|
||||||
|
obikhid <- encodeKeyHashid obiidAccept
|
||||||
|
|
||||||
|
let recips = [encodeRouteHome $ PersonR senderHash]
|
||||||
|
doc = Doc hLocal Activity
|
||||||
|
{ activityId = Just $ encodeRouteLocal $ LoomOutboxItemR loomHash obikhid
|
||||||
|
, activityActor = encodeRouteLocal $ LoomR loomHash
|
||||||
|
, activityCapability = Nothing
|
||||||
|
, activitySummary = Nothing
|
||||||
|
, activityAudience = Audience recips [] [] [] [] []
|
||||||
|
, activityFulfills = []
|
||||||
|
, activitySpecific = AcceptActivity Accept
|
||||||
|
{ acceptObject = ObjURI hLocal luFollow
|
||||||
|
, acceptResult = Nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update obiidAccept [OutboxItemActivity =. persistJSONObjectFromDoc doc]
|
||||||
|
|
||||||
createRepositoryC
|
createRepositoryC
|
||||||
:: Entity Person
|
:: Entity Person
|
||||||
-> Actor
|
-> Actor
|
||||||
|
@ -1399,6 +1670,7 @@ createRepositoryC (Entity pidUser personUser) senderActor summary audience detai
|
||||||
, repoCollabAnon = Nothing
|
, repoCollabAnon = Nothing
|
||||||
, repoActor = actorID
|
, repoActor = actorID
|
||||||
, repoCreate = createID
|
, repoCreate = createID
|
||||||
|
, repoLoom = Nothing
|
||||||
}
|
}
|
||||||
return (repoID, actor)
|
return (repoID, actor)
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ module Vervis.Client
|
||||||
--, unresolve
|
--, unresolve
|
||||||
--, offerMR
|
--, offerMR
|
||||||
createDeck
|
createDeck
|
||||||
|
, createLoom
|
||||||
, createRepo
|
, createRepo
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
@ -38,6 +39,7 @@ import Control.Monad
|
||||||
import Control.Monad.Trans.Except
|
import Control.Monad.Trans.Except
|
||||||
import Control.Monad.Trans.Reader
|
import Control.Monad.Trans.Reader
|
||||||
import Data.Bitraversable
|
import Data.Bitraversable
|
||||||
|
import Data.List.NonEmpty (NonEmpty (..))
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Database.Persist
|
import Database.Persist
|
||||||
|
@ -621,6 +623,37 @@ createDeck senderHash name desc = do
|
||||||
|
|
||||||
return (Nothing, AP.Audience recips [] [] [] [] [], detail)
|
return (Nothing, AP.Audience recips [] [] [] [] [], detail)
|
||||||
|
|
||||||
|
createLoom
|
||||||
|
:: (MonadHandler m, HandlerSite m ~ App, MonadSite m, SiteEnv m ~ App)
|
||||||
|
=> KeyHashid Person
|
||||||
|
-> Text
|
||||||
|
-> Text
|
||||||
|
-> KeyHashid Repo
|
||||||
|
-> m (Maybe TextHtml, Audience URIMode, AP.ActorDetail, NonEmpty FedURI)
|
||||||
|
createLoom senderHash name desc repoHash = do
|
||||||
|
encodeRouteHome <- getEncodeRouteHome
|
||||||
|
|
||||||
|
let audAuthor =
|
||||||
|
AudLocal [] [LocalStagePersonFollowers senderHash]
|
||||||
|
audRepo =
|
||||||
|
AudLocal
|
||||||
|
[LocalActorRepo repoHash]
|
||||||
|
[LocalStageRepoFollowers repoHash]
|
||||||
|
|
||||||
|
(_, _, _, audLocal, audRemote) = collectAudience [audAuthor, audRepo]
|
||||||
|
|
||||||
|
recips = map encodeRouteHome audLocal ++ audRemote
|
||||||
|
|
||||||
|
detail = AP.ActorDetail
|
||||||
|
{ AP.actorType = AP.ActorTypePatchTracker
|
||||||
|
, AP.actorUsername = Nothing
|
||||||
|
, AP.actorName = Just name
|
||||||
|
, AP.actorSummary = Just desc
|
||||||
|
}
|
||||||
|
repo = encodeRouteHome $ RepoR repoHash
|
||||||
|
|
||||||
|
return (Nothing, AP.Audience recips [] [] [] [] [], detail, repo :| [])
|
||||||
|
|
||||||
createRepo
|
createRepo
|
||||||
:: (MonadHandler m, HandlerSite m ~ App, MonadSite m, SiteEnv m ~ App)
|
:: (MonadHandler m, HandlerSite m ~ App, MonadSite m, SiteEnv m ~ App)
|
||||||
=> KeyHashid Person
|
=> KeyHashid Person
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
module Vervis.Form.Project
|
module Vervis.Form.Project
|
||||||
( NewProject (..)
|
( NewProject (..)
|
||||||
, newProjectForm
|
, newProjectForm
|
||||||
|
, NewLoom (..)
|
||||||
|
, newLoomForm
|
||||||
--, NewProjectCollab (..)
|
--, NewProjectCollab (..)
|
||||||
--, newProjectCollabForm
|
--, newProjectCollabForm
|
||||||
--, editProjectForm
|
--, editProjectForm
|
||||||
|
@ -31,8 +33,11 @@ import Yesod.Form.Functions
|
||||||
import Yesod.Form.Types
|
import Yesod.Form.Types
|
||||||
import Yesod.Persist.Core
|
import Yesod.Persist.Core
|
||||||
|
|
||||||
|
import qualified Data.Text as T
|
||||||
import qualified Database.Esqueleto as E
|
import qualified Database.Esqueleto as E
|
||||||
|
|
||||||
|
import Yesod.Hashids
|
||||||
|
|
||||||
import Vervis.Foundation
|
import Vervis.Foundation
|
||||||
import Vervis.Model
|
import Vervis.Model
|
||||||
|
|
||||||
|
@ -46,6 +51,33 @@ newProjectForm = renderDivs $ NewProject
|
||||||
<$> areq textField "Name*" Nothing
|
<$> areq textField "Name*" Nothing
|
||||||
<*> areq textField "Description" Nothing
|
<*> areq textField "Description" Nothing
|
||||||
|
|
||||||
|
data NewLoom = NewLoom
|
||||||
|
{ nlName :: Text
|
||||||
|
, nlDesc :: Text
|
||||||
|
, nlRepo :: RepoId
|
||||||
|
}
|
||||||
|
|
||||||
|
newLoomForm :: Form NewLoom
|
||||||
|
newLoomForm = renderDivs $ NewLoom
|
||||||
|
<$> areq textField "Name*" Nothing
|
||||||
|
<*> areq textField "Description" Nothing
|
||||||
|
<*> areq selectRepo "Repo*" Nothing
|
||||||
|
where
|
||||||
|
selectRepo = selectField $ do
|
||||||
|
hashRepo <- getEncodeKeyHashid
|
||||||
|
l <- runDB $ E.select $
|
||||||
|
E.from $ \ (repo `E.InnerJoin` actor) -> do
|
||||||
|
E.on $ repo E.^. RepoActor E.==. actor E.^. ActorId
|
||||||
|
E.where_ $ E.isNothing $ repo E.^. RepoLoom
|
||||||
|
E.orderBy [E.desc $ repo E.^. RepoId]
|
||||||
|
return (actor E.^. ActorName, repo E.^. RepoId)
|
||||||
|
optionsPairs $ map (option hashRepo) l
|
||||||
|
where
|
||||||
|
option hashRepo (E.Value name, E.Value repoID) =
|
||||||
|
( T.concat ["^", keyHashidText $ hashRepo repoID, " ", name]
|
||||||
|
, repoID
|
||||||
|
)
|
||||||
|
|
||||||
{-
|
{-
|
||||||
data NewProjectCollab = NewProjectCollab
|
data NewProjectCollab = NewProjectCollab
|
||||||
{ ncPerson :: PersonId
|
{ ncPerson :: PersonId
|
||||||
|
|
|
@ -21,15 +21,21 @@ module Vervis.Handler.Loom
|
||||||
, getLoomOutboxItemR
|
, getLoomOutboxItemR
|
||||||
, getLoomFollowersR
|
, getLoomFollowersR
|
||||||
, getLoomClothsR
|
, getLoomClothsR
|
||||||
|
|
||||||
|
, getLoomNewR
|
||||||
|
, postLoomNewR
|
||||||
|
, postLoomFollowR
|
||||||
|
, postLoomUnfollowR
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Monad.Trans.Except
|
import Control.Monad.Trans.Except
|
||||||
|
import Control.Monad.Trans.Maybe
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
import Data.Foldable
|
import Data.Foldable
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Data.Time.Clock
|
import Data.Time.Clock
|
||||||
import Data.Traversable
|
import Data.Traversable
|
||||||
|
@ -59,6 +65,7 @@ import Control.Monad.Trans.Except.Local
|
||||||
import Data.Either.Local
|
import Data.Either.Local
|
||||||
import Data.Paginate.Local
|
import Data.Paginate.Local
|
||||||
import Database.Persist.Local
|
import Database.Persist.Local
|
||||||
|
import Yesod.Form.Local
|
||||||
import Yesod.Persist.Local
|
import Yesod.Persist.Local
|
||||||
|
|
||||||
import Vervis.Access
|
import Vervis.Access
|
||||||
|
@ -66,6 +73,7 @@ import Vervis.API
|
||||||
import Vervis.Federation.Auth
|
import Vervis.Federation.Auth
|
||||||
import Vervis.Federation.Collab
|
import Vervis.Federation.Collab
|
||||||
import Vervis.FedURI
|
import Vervis.FedURI
|
||||||
|
import Vervis.Form.Project
|
||||||
import Vervis.Foundation
|
import Vervis.Foundation
|
||||||
import Vervis.Model
|
import Vervis.Model
|
||||||
import Vervis.Paginate
|
import Vervis.Paginate
|
||||||
|
@ -73,6 +81,8 @@ import Vervis.Recipient
|
||||||
import Vervis.Settings
|
import Vervis.Settings
|
||||||
import Vervis.Web.Actor
|
import Vervis.Web.Actor
|
||||||
|
|
||||||
|
import qualified Vervis.Client as C
|
||||||
|
|
||||||
getLoomR :: KeyHashid Loom -> Handler TypedContent
|
getLoomR :: KeyHashid Loom -> Handler TypedContent
|
||||||
getLoomR loomHash = do
|
getLoomR loomHash = do
|
||||||
loomID <- decodeKeyHashid404 loomHash
|
loomID <- decodeKeyHashid404 loomHash
|
||||||
|
@ -220,3 +230,71 @@ getLoomClothsR loomHash = selectRep $ do
|
||||||
where
|
where
|
||||||
here = LoomClothsR loomHash
|
here = LoomClothsR loomHash
|
||||||
encodeStrict = BL.toStrict . encode
|
encodeStrict = BL.toStrict . encode
|
||||||
|
|
||||||
|
getLoomNewR :: Handler Html
|
||||||
|
getLoomNewR = do
|
||||||
|
((_result, widget), enctype) <- runFormPost newLoomForm
|
||||||
|
defaultLayout
|
||||||
|
[whamlet|
|
||||||
|
<form method=POST action=@{LoomNewR} enctype=#{enctype}>
|
||||||
|
^{widget}
|
||||||
|
<div class="submit">
|
||||||
|
<input type="submit">
|
||||||
|
|]
|
||||||
|
|
||||||
|
postLoomNewR :: Handler Html
|
||||||
|
postLoomNewR = do
|
||||||
|
(NewLoom name desc repoID, _widget, _enctype) <-
|
||||||
|
runFormPostRedirect LoomNewR newLoomForm
|
||||||
|
|
||||||
|
personEntity@(Entity personID person) <- requireAuth
|
||||||
|
personHash <- encodeKeyHashid personID
|
||||||
|
repoHash <- encodeKeyHashid repoID
|
||||||
|
(maybeSummary, audience, detail, repos) <-
|
||||||
|
C.createLoom personHash name desc repoHash
|
||||||
|
actor <- runDB $ do
|
||||||
|
|
||||||
|
-- Find the specified repo in DB
|
||||||
|
_ <- getJust repoID
|
||||||
|
|
||||||
|
-- Make sure the repo has a single, full-access collab, granted to the
|
||||||
|
-- creator of the loom
|
||||||
|
maybeApproved <- runMaybeT $ do
|
||||||
|
collabs <- lift $ selectList [CollabTopicRepoRepo ==. repoID] []
|
||||||
|
collabID <-
|
||||||
|
case collabs of
|
||||||
|
[Entity _ c] -> return $ collabTopicRepoCollab c
|
||||||
|
_ -> mzero
|
||||||
|
CollabRecipLocal _ recipID <-
|
||||||
|
MaybeT $ getValBy $ UniqueCollabRecipLocal collabID
|
||||||
|
guard $ recipID == personID
|
||||||
|
_ <- MaybeT $ getBy $ UniqueCollabEnable collabID
|
||||||
|
_ <- MaybeT $ getBy $ UniqueCollabFulfillsLocalTopicCreation collabID
|
||||||
|
return ()
|
||||||
|
unless (isJust maybeApproved) $ do
|
||||||
|
setMessage "Can't link with the repo chosen"
|
||||||
|
redirect LoomNewR
|
||||||
|
|
||||||
|
getJust $ personActor person
|
||||||
|
|
||||||
|
result <-
|
||||||
|
runExceptT $ createPatchTrackerC personEntity actor maybeSummary audience detail repos Nothing Nothing
|
||||||
|
|
||||||
|
case result of
|
||||||
|
Left e -> do
|
||||||
|
setMessage $ toHtml e
|
||||||
|
redirect LoomNewR
|
||||||
|
Right createID -> do
|
||||||
|
maybeLoomID <- runDB $ getKeyBy $ UniqueLoomCreate createID
|
||||||
|
case maybeLoomID of
|
||||||
|
Nothing -> error "Can't find the newly created loom"
|
||||||
|
Just loomID -> do
|
||||||
|
loomHash <- encodeKeyHashid loomID
|
||||||
|
setMessage "New patch tracker created"
|
||||||
|
redirect $ LoomR loomHash
|
||||||
|
|
||||||
|
postLoomFollowR :: KeyHashid Loom -> Handler ()
|
||||||
|
postLoomFollowR _ = error "Temporarily disabled"
|
||||||
|
|
||||||
|
postLoomUnfollowR :: KeyHashid Loom -> Handler ()
|
||||||
|
postLoomUnfollowR _ = error "Temporarily disabled"
|
||||||
|
|
|
@ -284,6 +284,8 @@ postPersonOutboxR personHash = do
|
||||||
createTicketTrackerC eperson actorDB summary audience detail mlocal mtarget
|
createTicketTrackerC eperson actorDB summary audience detail mlocal mtarget
|
||||||
AP.CreateRepository detail vcs mlocal ->
|
AP.CreateRepository detail vcs mlocal ->
|
||||||
createRepositoryC eperson actorDB summary audience detail vcs mlocal mtarget
|
createRepositoryC eperson actorDB summary audience detail vcs mlocal mtarget
|
||||||
|
AP.CreatePatchTracker detail repos mlocal ->
|
||||||
|
createPatchTrackerC eperson actorDB summary audience detail repos mlocal mtarget
|
||||||
_ -> throwE "Unsupported Create 'object' type"
|
_ -> throwE "Unsupported Create 'object' type"
|
||||||
AP.InviteActivity invite ->
|
AP.InviteActivity invite ->
|
||||||
inviteC eperson actorDB mcap summary audience invite
|
inviteC eperson actorDB mcap summary audience invite
|
||||||
|
|
|
@ -42,6 +42,8 @@ module Vervis.Handler.Repo
|
||||||
|
|
||||||
, postPostReceiveR
|
, postPostReceiveR
|
||||||
|
|
||||||
|
, postRepoLinkR
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,6 +72,7 @@ import Control.Monad
|
||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad.IO.Class (liftIO)
|
||||||
import Control.Monad.Logger (logWarn)
|
import Control.Monad.Logger (logWarn)
|
||||||
import Control.Monad.Trans.Except
|
import Control.Monad.Trans.Except
|
||||||
|
import Control.Monad.Trans.Maybe
|
||||||
import Data.Bifunctor
|
import Data.Bifunctor
|
||||||
import Data.Binary.Put
|
import Data.Binary.Put
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
|
@ -181,6 +184,7 @@ getRepoR repoHash = do
|
||||||
(r,) <$> getJust (repoActor r)
|
(r,) <$> getJust (repoActor r)
|
||||||
|
|
||||||
encodeRouteLocal <- getEncodeRouteLocal
|
encodeRouteLocal <- getEncodeRouteLocal
|
||||||
|
hashLoom <- getEncodeKeyHashid
|
||||||
let repoAP = AP.Repo
|
let repoAP = AP.Repo
|
||||||
{ AP.repoActor = AP.Actor
|
{ AP.repoActor = AP.Actor
|
||||||
{ AP.actorLocal = AP.ActorLocal
|
{ AP.actorLocal = AP.ActorLocal
|
||||||
|
@ -206,6 +210,8 @@ getRepoR repoHash = do
|
||||||
}
|
}
|
||||||
, AP.repoTeam = Nothing
|
, AP.repoTeam = Nothing
|
||||||
, AP.repoVcs = repoVcs repo
|
, AP.repoVcs = repoVcs repo
|
||||||
|
, AP.repoLoom =
|
||||||
|
encodeRouteLocal . LoomR . hashLoom <$> repoLoom repo
|
||||||
}
|
}
|
||||||
|
|
||||||
next =
|
next =
|
||||||
|
@ -359,22 +365,31 @@ postGitUploadRequestR repoHash = do
|
||||||
getRepoSourceR :: KeyHashid Repo -> [Text] -> Handler Html
|
getRepoSourceR :: KeyHashid Repo -> [Text] -> Handler Html
|
||||||
getRepoSourceR repoHash path = do
|
getRepoSourceR repoHash path = do
|
||||||
repoID <- decodeKeyHashid404 repoHash
|
repoID <- decodeKeyHashid404 repoHash
|
||||||
(repo, actor) <- runDB $ do
|
(repo, looms, actor) <- runDB $ do
|
||||||
r <- get404 repoID
|
r <- get404 repoID
|
||||||
(r,) <$> getJust (repoActor r)
|
ls <-
|
||||||
|
case repoLoom r of
|
||||||
|
Just _ -> pure []
|
||||||
|
Nothing -> selectKeysList [LoomRepo ==. repoID] [Desc LoomId]
|
||||||
|
(r,ls,) <$> getJust (repoActor r)
|
||||||
|
|
||||||
case repoVcs repo of
|
case repoVcs repo of
|
||||||
VCSDarcs -> getDarcsRepoSource repo actor repoHash path
|
VCSDarcs -> getDarcsRepoSource repo actor repoHash path looms
|
||||||
VCSGit -> notFound
|
VCSGit -> notFound
|
||||||
|
|
||||||
getRepoBranchSourceR :: KeyHashid Repo -> Text -> [Text] -> Handler Html
|
getRepoBranchSourceR :: KeyHashid Repo -> Text -> [Text] -> Handler Html
|
||||||
getRepoBranchSourceR repoHash branch path = do
|
getRepoBranchSourceR repoHash branch path = do
|
||||||
repoID <- decodeKeyHashid404 repoHash
|
repoID <- decodeKeyHashid404 repoHash
|
||||||
(repo, actor) <- runDB $ do
|
(repo, looms, actor) <- runDB $ do
|
||||||
r <- get404 repoID
|
r <- get404 repoID
|
||||||
(r,) <$> getJust (repoActor r)
|
ls <-
|
||||||
|
case repoLoom r of
|
||||||
|
Just _ -> pure []
|
||||||
|
Nothing -> selectKeysList [LoomRepo ==. repoID] [Desc LoomId]
|
||||||
|
(r,ls,) <$> getJust (repoActor r)
|
||||||
case repoVcs repo of
|
case repoVcs repo of
|
||||||
VCSDarcs -> notFound
|
VCSDarcs -> notFound
|
||||||
VCSGit -> getGitRepoSource repo actor repoHash branch path
|
VCSGit -> getGitRepoSource repo actor repoHash branch path looms
|
||||||
|
|
||||||
getRepoCommitsR :: KeyHashid Repo -> Handler TypedContent
|
getRepoCommitsR :: KeyHashid Repo -> Handler TypedContent
|
||||||
getRepoCommitsR repoHash = do
|
getRepoCommitsR repoHash = do
|
||||||
|
@ -630,12 +645,62 @@ postPostReceiveR = do
|
||||||
|]
|
|]
|
||||||
-}
|
-}
|
||||||
|
|
||||||
|
postRepoLinkR :: KeyHashid Repo -> KeyHashid Loom -> Handler Html
|
||||||
|
postRepoLinkR repoHash loomHash = do
|
||||||
|
Entity personID person <- requireAuth
|
||||||
|
|
||||||
|
repoID <- decodeKeyHashid404 repoHash
|
||||||
|
|
||||||
|
result <- runExceptT $ runDBExcept $ do
|
||||||
|
repo <- lift $ get404 repoID
|
||||||
|
unless (isNothing $ repoLoom repo) $ throwE "Repo already has a loom"
|
||||||
|
|
||||||
|
loomID <- decodeKeyHashidE loomHash "Invalid loom hash"
|
||||||
|
loom <- getE loomID "No such loom in DB"
|
||||||
|
|
||||||
|
-- Make sure both repo and loom have a single, full-access collab,
|
||||||
|
-- granted to the logged-in person
|
||||||
|
maybeApproved <- lift $ runMaybeT $ do
|
||||||
|
collabs <- lift $ selectList [CollabTopicRepoRepo ==. repoID] []
|
||||||
|
collabID <-
|
||||||
|
case collabs of
|
||||||
|
[Entity _ c] -> return $ collabTopicRepoCollab c
|
||||||
|
_ -> mzero
|
||||||
|
CollabRecipLocal _ recipID <-
|
||||||
|
MaybeT $ getValBy $ UniqueCollabRecipLocal collabID
|
||||||
|
_ <- MaybeT $ getBy $ UniqueCollabEnable collabID
|
||||||
|
_ <- MaybeT $ getBy $ UniqueCollabFulfillsLocalTopicCreation collabID
|
||||||
|
guard $ recipID == personID
|
||||||
|
|
||||||
|
collabs' <- lift $ selectList [CollabTopicLoomLoom ==. loomID] []
|
||||||
|
collabID' <-
|
||||||
|
case collabs' of
|
||||||
|
[Entity _ c] -> return $ collabTopicLoomCollab c
|
||||||
|
_ -> mzero
|
||||||
|
CollabRecipLocal _ recipID' <-
|
||||||
|
MaybeT $ getValBy $ UniqueCollabRecipLocal collabID'
|
||||||
|
_ <- MaybeT $ getBy $ UniqueCollabEnable collabID'
|
||||||
|
_ <- MaybeT $ getBy $ UniqueCollabFulfillsLocalTopicCreation collabID'
|
||||||
|
guard $ recipID' == personID
|
||||||
|
|
||||||
|
return ()
|
||||||
|
|
||||||
|
unless (isJust maybeApproved) $
|
||||||
|
throwE "Repo and loom aren't both yours"
|
||||||
|
|
||||||
|
n <-
|
||||||
|
lift $ updateWhereCount
|
||||||
|
[RepoId ==. repoID, RepoLoom ==. Nothing]
|
||||||
|
[RepoLoom =. Just loomID]
|
||||||
|
case n of
|
||||||
|
0 -> throwE "Couldn't update the repo"
|
||||||
|
1 -> return ()
|
||||||
|
_ -> error $ "Unexpected, " ++ show n ++ " repos were updated"
|
||||||
|
|
||||||
|
case result of
|
||||||
|
Left e -> setMessage $ toHtml e
|
||||||
|
Right () -> setMessage "Repo successfully linked with loom!"
|
||||||
|
redirect $ RepoR repoHash
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2686,6 +2686,8 @@ changes hLocal ctx =
|
||||||
, renameUnique "CollabEnable" "UniqueCollabTopicLocalAcceptAccept" "UniqueCollabEnableGrant"
|
, renameUnique "CollabEnable" "UniqueCollabTopicLocalAcceptAccept" "UniqueCollabEnableGrant"
|
||||||
-- 492
|
-- 492
|
||||||
, removeEntity "CollabTopicLocal"
|
, removeEntity "CollabTopicLocal"
|
||||||
|
-- 493
|
||||||
|
, addFieldRefOptional "Repo" Nothing "loom" "Loom"
|
||||||
]
|
]
|
||||||
|
|
||||||
migrateDB
|
migrateDB
|
||||||
|
|
|
@ -82,8 +82,8 @@ import Vervis.Widget.Repo
|
||||||
import qualified Vervis.Darcs as D
|
import qualified Vervis.Darcs as D
|
||||||
|
|
||||||
getDarcsRepoSource
|
getDarcsRepoSource
|
||||||
:: Repo -> Actor -> KeyHashid Repo -> [Text] -> Handler Html
|
:: Repo -> Actor -> KeyHashid Repo -> [Text] -> [LoomId] -> Handler Html
|
||||||
getDarcsRepoSource repository actor repo dir = do
|
getDarcsRepoSource repository actor repo dir loomIDs = do
|
||||||
path <- askRepoDir repo
|
path <- askRepoDir repo
|
||||||
msv <- liftIO $ D.readSourceView path dir
|
msv <- liftIO $ D.readSourceView path dir
|
||||||
case msv of
|
case msv of
|
||||||
|
@ -91,7 +91,11 @@ getDarcsRepoSource repository actor repo dir = do
|
||||||
Just sv -> do
|
Just sv -> do
|
||||||
let parent = if null dir then [] else init dir
|
let parent = if null dir then [] else init dir
|
||||||
dirs = zip parent (tail $ inits parent)
|
dirs = zip parent (tail $ inits parent)
|
||||||
|
looms <- runDB $ for loomIDs $ \ loomID -> do
|
||||||
|
loom <- getJust loomID
|
||||||
|
(loomID,) <$> getJust (loomActor loom)
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
|
hashLoom <- getEncodeKeyHashid
|
||||||
host <- asksSite siteInstanceHost
|
host <- asksSite siteInstanceHost
|
||||||
ms <- lookupGetParam "style"
|
ms <- lookupGetParam "style"
|
||||||
style <-
|
style <-
|
||||||
|
|
|
@ -97,8 +97,8 @@ import qualified Data.ByteString.Lazy as BL (ByteString)
|
||||||
import qualified Vervis.Git as G
|
import qualified Vervis.Git as G
|
||||||
|
|
||||||
getGitRepoSource
|
getGitRepoSource
|
||||||
:: Repo -> Actor -> KeyHashid Repo -> Text -> [Text] -> Handler Html
|
:: Repo -> Actor -> KeyHashid Repo -> Text -> [Text] -> [LoomId] -> Handler Html
|
||||||
getGitRepoSource repository actor repo ref dir = do
|
getGitRepoSource repository actor repo ref dir loomIDs = do
|
||||||
path <- askRepoDir repo
|
path <- askRepoDir repo
|
||||||
(branches, tags, msv) <- liftIO $ G.readSourceView path ref dir
|
(branches, tags, msv) <- liftIO $ G.readSourceView path ref dir
|
||||||
case msv of
|
case msv of
|
||||||
|
@ -106,7 +106,11 @@ getGitRepoSource repository actor repo ref dir = do
|
||||||
Just sv -> do
|
Just sv -> do
|
||||||
let parent = if null dir then [] else init dir
|
let parent = if null dir then [] else init dir
|
||||||
dirs = zip parent (tail $ inits parent)
|
dirs = zip parent (tail $ inits parent)
|
||||||
|
looms <- runDB $ for loomIDs $ \ loomID -> do
|
||||||
|
loom <- getJust loomID
|
||||||
|
(loomID,) <$> getJust (loomActor loom)
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
|
hashLoom <- getEncodeKeyHashid
|
||||||
host <- asksSite siteInstanceHost
|
host <- asksSite siteInstanceHost
|
||||||
ms <- lookupGetParam "style"
|
ms <- lookupGetParam "style"
|
||||||
style <-
|
style <-
|
||||||
|
|
|
@ -462,6 +462,7 @@ data Repo u = Repo
|
||||||
{ repoActor :: Actor u
|
{ repoActor :: Actor u
|
||||||
, repoTeam :: Maybe LocalURI
|
, repoTeam :: Maybe LocalURI
|
||||||
, repoVcs :: VersionControlSystem
|
, repoVcs :: VersionControlSystem
|
||||||
|
, repoLoom :: Maybe LocalURI
|
||||||
}
|
}
|
||||||
|
|
||||||
instance ActivityPub Repo where
|
instance ActivityPub Repo where
|
||||||
|
@ -474,10 +475,12 @@ instance ActivityPub Repo where
|
||||||
Repo a
|
Repo a
|
||||||
<$> withAuthorityMaybeO h (o .:|? "team")
|
<$> withAuthorityMaybeO h (o .:|? "team")
|
||||||
<*> o .: "versionControlSystem"
|
<*> o .: "versionControlSystem"
|
||||||
toSeries authority (Repo actor team vcs)
|
<*> withAuthorityMaybeO h (o .:? "sendPatchesTo")
|
||||||
|
toSeries authority (Repo actor team vcs loom)
|
||||||
= toSeries authority actor
|
= toSeries authority actor
|
||||||
<> "team" .= (ObjURI authority <$> team)
|
<> "team" .= (ObjURI authority <$> team)
|
||||||
<> "versionControlSystem" .= vcs
|
<> "versionControlSystem" .= vcs
|
||||||
|
<> "sendPatchesTo" .=? (ObjURI authority <$> loom)
|
||||||
|
|
||||||
data TicketTracker u = TicketTracker
|
data TicketTracker u = TicketTracker
|
||||||
{ ticketTrackerActor :: Actor u
|
{ ticketTrackerActor :: Actor u
|
||||||
|
@ -1441,6 +1444,7 @@ data CreateObject u
|
||||||
| CreateTicket (Authority u) (Ticket u)
|
| CreateTicket (Authority u) (Ticket u)
|
||||||
| CreateTicketTracker ActorDetail (Maybe (Authority u, ActorLocal u))
|
| CreateTicketTracker ActorDetail (Maybe (Authority u, ActorLocal u))
|
||||||
| CreateRepository ActorDetail VersionControlSystem (Maybe (Authority u, ActorLocal u))
|
| CreateRepository ActorDetail VersionControlSystem (Maybe (Authority u, ActorLocal u))
|
||||||
|
| CreatePatchTracker ActorDetail (NonEmpty (ObjURI u)) (Maybe (Authority u, ActorLocal u))
|
||||||
|
|
||||||
parseCreateObject :: UriMode u => Object -> Parser (CreateObject u)
|
parseCreateObject :: UriMode u => Object -> Parser (CreateObject u)
|
||||||
parseCreateObject o
|
parseCreateObject o
|
||||||
|
@ -1457,6 +1461,12 @@ parseCreateObject o
|
||||||
vcs <- o .: "versionControlSystem"
|
vcs <- o .: "versionControlSystem"
|
||||||
ml <- parseActorLocal o
|
ml <- parseActorLocal o
|
||||||
return $ CreateRepository d vcs ml
|
return $ CreateRepository d vcs ml
|
||||||
|
<|> do d <- parseActorDetail o
|
||||||
|
unless (actorType d == ActorTypePatchTracker) $
|
||||||
|
fail "type isn't PatchTracker"
|
||||||
|
repos <- o .:*+ "tracksPatchesFor"
|
||||||
|
ml <- parseActorLocal o
|
||||||
|
return $ CreatePatchTracker d repos ml
|
||||||
|
|
||||||
encodeCreateObject :: UriMode u => CreateObject u -> Series
|
encodeCreateObject :: UriMode u => CreateObject u -> Series
|
||||||
encodeCreateObject (CreateNote h note) = toSeries h note
|
encodeCreateObject (CreateNote h note) = toSeries h note
|
||||||
|
@ -1467,6 +1477,10 @@ encodeCreateObject (CreateRepository d vcs ml)
|
||||||
= encodeActorDetail d
|
= encodeActorDetail d
|
||||||
<> "versionControlSystem" .= vcs
|
<> "versionControlSystem" .= vcs
|
||||||
<> maybe mempty (uncurry encodeActorLocal) ml
|
<> maybe mempty (uncurry encodeActorLocal) ml
|
||||||
|
encodeCreateObject (CreatePatchTracker d repos ml)
|
||||||
|
= encodeActorDetail d
|
||||||
|
<> "tracksPatchesFor" .=*+ repos
|
||||||
|
<> maybe mempty (uncurry encodeActorLocal) ml
|
||||||
|
|
||||||
data Create u = Create
|
data Create u = Create
|
||||||
{ createObject :: CreateObject u
|
{ createObject :: CreateObject u
|
||||||
|
@ -1485,6 +1499,7 @@ parseCreate o a luActor = do
|
||||||
fail "Create actor != note attrib"
|
fail "Create actor != note attrib"
|
||||||
CreateTicketTracker _ _ -> return ()
|
CreateTicketTracker _ _ -> return ()
|
||||||
CreateRepository _ _ _ -> return ()
|
CreateRepository _ _ _ -> return ()
|
||||||
|
CreatePatchTracker _ _ _ -> return ()
|
||||||
Create obj <$> o .:? "target"
|
Create obj <$> o .:? "target"
|
||||||
|
|
||||||
encodeCreate :: UriMode u => Create u -> Series
|
encodeCreate :: UriMode u => Create u -> Series
|
||||||
|
|
|
@ -50,11 +50,24 @@ $# ^{personNavW user}
|
||||||
<span>
|
<span>
|
||||||
<a href=@{RepoCommitsR repo}>
|
<a href=@{RepoCommitsR repo}>
|
||||||
[🛠 Changes]
|
[🛠 Changes]
|
||||||
<span>
|
$maybe loomID <- repoLoom repository
|
||||||
[🧩 Patches]
|
<span>
|
||||||
|
<a href=@{LoomClothsR $ hashLoom loomID}>
|
||||||
|
[🧩 Patches]
|
||||||
|
|
||||||
^{followButton}
|
^{followButton}
|
||||||
|
|
||||||
|
$if not $ null looms
|
||||||
|
<h2>Enable patch tracking
|
||||||
|
<ul>
|
||||||
|
$forall (loomID, actor) <- looms
|
||||||
|
<li>
|
||||||
|
Loom
|
||||||
|
<a href=@{LoomR $ hashLoom loomID}>
|
||||||
|
+#{keyHashidText $ hashLoom loomID} #{actorName actor}
|
||||||
|
wants to link with this repo
|
||||||
|
^{buttonW POST "Link" $ RepoLinkR repo $ hashLoom loomID}
|
||||||
|
|
||||||
<h2>Clone
|
<h2>Clone
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -50,11 +50,23 @@ $# ^{personNavW user}
|
||||||
<span>
|
<span>
|
||||||
<a href=@{RepoCommitsR repo}>
|
<a href=@{RepoCommitsR repo}>
|
||||||
[🛠 Commits]
|
[🛠 Commits]
|
||||||
<span>
|
$maybe loomID <- repoLoom repository
|
||||||
[🧩 Merge Requests]
|
<span>
|
||||||
|
<a href=@{LoomClothsR $ hashLoom loomID}>
|
||||||
|
[🧩 Merge Requests]
|
||||||
|
|
||||||
^{followButton}
|
^{followButton}
|
||||||
|
|
||||||
|
$if not $ null looms
|
||||||
|
<h2>Enable patch tracking
|
||||||
|
<ul>
|
||||||
|
$forall (loomID, actor) <- looms
|
||||||
|
Loom
|
||||||
|
@{LoomR $ hashLoom loomID}
|
||||||
|
+#{keyHashidText $ hashLoom loomID} #{actorName actor}
|
||||||
|
wants to link with this repo
|
||||||
|
^{buttonW POST "Link" $ RepoLinkR repo $ hashLoom loomID}
|
||||||
|
|
||||||
<h2>Clone
|
<h2>Clone
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -67,16 +79,16 @@ $# ^{personNavW user}
|
||||||
<h2>Branches
|
<h2>Branches
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
$forall branch <- branches
|
$forall branch <- branches
|
||||||
<li>
|
<li>
|
||||||
<a href=@{RepoBranchSourceR repo branch []}>#{branch}
|
<a href=@{RepoBranchSourceR repo branch []}>#{branch}
|
||||||
|
|
||||||
<h2>Tags
|
<h2>Tags
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
$forall tag <- tags
|
$forall tag <- tags
|
||||||
<li>
|
<li>
|
||||||
<a href=@{RepoBranchSourceR repo tag []}>#{tag}
|
<a href=@{RepoBranchSourceR repo tag []}>#{tag}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<a href=@{RepoBranchSourceR repo ref []}>#{ref}
|
<a href=@{RepoBranchSourceR repo ref []}>#{ref}
|
||||||
|
|
|
@ -347,6 +347,7 @@ Repo
|
||||||
collabAnon RoleId Maybe
|
collabAnon RoleId Maybe
|
||||||
actor ActorId
|
actor ActorId
|
||||||
create OutboxItemId
|
create OutboxItemId
|
||||||
|
loom LoomId Maybe
|
||||||
|
|
||||||
UniqueRepoActor actor
|
UniqueRepoActor actor
|
||||||
UniqueRepoCreate create
|
UniqueRepoCreate create
|
||||||
|
|
|
@ -180,6 +180,8 @@
|
||||||
|
|
||||||
/post-receive PostReceiveR POST
|
/post-receive PostReceiveR POST
|
||||||
|
|
||||||
|
/repos/#RepoKeyHashid/enable-loom/#LoomKeyHashid RepoLinkR POST
|
||||||
|
|
||||||
---- Deck --------------------------------------------------------------------
|
---- Deck --------------------------------------------------------------------
|
||||||
|
|
||||||
/decks/#DeckKeyHashid DeckR GET
|
/decks/#DeckKeyHashid DeckR GET
|
||||||
|
@ -236,11 +238,11 @@
|
||||||
/looms/#LoomKeyHashid/followers LoomFollowersR GET
|
/looms/#LoomKeyHashid/followers LoomFollowersR GET
|
||||||
/looms/#LoomKeyHashid/cloths LoomClothsR GET
|
/looms/#LoomKeyHashid/cloths LoomClothsR GET
|
||||||
|
|
||||||
-- /new-loom LoomNewR GET POST
|
/new-loom LoomNewR GET POST
|
||||||
-- /looms/#LoomKeyHashid/delete LoomDeleteR POST
|
-- /looms/#LoomKeyHashid/delete LoomDeleteR POST
|
||||||
-- /looms/#LoomKeyHashid/edit LoomEditR GET POST
|
-- /looms/#LoomKeyHashid/edit LoomEditR GET POST
|
||||||
-- /looms/#LoomKeyHashid/follow LoomFollowR POST
|
/looms/#LoomKeyHashid/follow LoomFollowR POST
|
||||||
-- /looms/#LoomKeyHashid/unfollow LoomUnfollowR POST
|
/looms/#LoomKeyHashid/unfollow LoomUnfollowR POST
|
||||||
|
|
||||||
---- Cloth -------------------------------------------------------------------
|
---- Cloth -------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue