Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ changes.

### Fixed

- Fix missing off chain references in DRep details [Issue 3490](https://github.com/IntersectMBO/govtool/issues/3490)

### Changed

### Removed
Expand Down
54 changes: 52 additions & 2 deletions govtool/backend/sql/list-dreps.sql
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,35 @@ DRepData AS (
off_chain_vote_drep_data.motivations,
off_chain_vote_drep_data.qualifications,
off_chain_vote_drep_data.image_url,
off_chain_vote_drep_data.image_hash
off_chain_vote_drep_data.image_hash,
COALESCE(
(
SELECT jsonb_agg(ref)
FROM jsonb_array_elements(
CASE
WHEN (ocvd.json::jsonb)->'body'->'references' IS NOT NULL
THEN (ocvd.json::jsonb)->'body'->'references'
ELSE '[]'::jsonb
END
) AS ref
WHERE ref->>'@type' = 'Identity'
),
'[]'::jsonb
) AS identity_references,
COALESCE(
(
SELECT jsonb_agg(ref)
FROM jsonb_array_elements(
CASE
WHEN (ocvd.json::jsonb)->'body'->'references' IS NOT NULL
THEN (ocvd.json::jsonb)->'body'->'references'
ELSE '[]'::jsonb
END
) AS ref
WHERE ref->>'@type' = 'Link'
),
'[]'::jsonb
) AS link_references
FROM
drep_hash dh
JOIN RankedDRepRegistration ON RankedDRepRegistration.drep_hash_id = dh.id
Expand Down Expand Up @@ -212,7 +240,29 @@ DRepData AS (
off_chain_vote_drep_data.motivations,
off_chain_vote_drep_data.qualifications,
off_chain_vote_drep_data.image_url,
off_chain_vote_drep_data.image_hash
off_chain_vote_drep_data.image_hash,
(
SELECT jsonb_agg(ref)
FROM jsonb_array_elements(
CASE
WHEN (ocvd.json::jsonb)->'body'->'references' IS NOT NULL
THEN (ocvd.json::jsonb)->'body'->'references'
ELSE '[]'::jsonb
END
) AS ref
WHERE ref->>'@type' = 'Identity'
),
(
SELECT jsonb_agg(ref)
FROM jsonb_array_elements(
CASE
WHEN (ocvd.json::jsonb)->'body'->'references' IS NOT NULL
THEN (ocvd.json::jsonb)->'body'->'references'
ELSE '[]'::jsonb
END
) AS ref
WHERE ref->>'@type' = 'Link'
)
)
SELECT * FROM DRepData
WHERE
Expand Down
4 changes: 3 additions & 1 deletion govtool/backend/src/VVA/API.hs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,9 @@ drepRegistrationToDrep Types.DRepRegistration {..} =
dRepMotivations = dRepRegistrationMotivations,
dRepQualifications = dRepRegistrationQualifications,
dRepImageUrl = dRepRegistrationImageUrl,
dRepImageHash = HexText <$> dRepRegistrationImageHash
dRepImageHash = HexText <$> dRepRegistrationImageHash,
dRepIdentityReferences = DRepReferences <$> dRepRegistrationIdentityReferences,
dRepLinkReferences = DRepReferences <$> dRepRegistrationLinkReferences
}

delegationToResponse :: Types.Delegation -> DelegationResponse
Expand Down
30 changes: 27 additions & 3 deletions govtool/backend/src/VVA/API/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ instance ToParamSchema GovernanceActionSortMode where


newtype GovernanceActionDetails
= GovernanceActionDetails { getValue :: Value }
= GovernanceActionDetails { getGovernanceActionValue :: Value }
deriving newtype (Show)

instance FromJSON GovernanceActionDetails where
Expand Down Expand Up @@ -593,6 +593,7 @@ instance ToSchema VoteResponse where
& example
?~ toJSON exampleVoteResponse


data DRepInfoResponse
= DRepInfoResponse
{ dRepInfoResponseIsScriptBased :: Bool
Expand All @@ -612,7 +613,7 @@ data DRepInfoResponse
, dRepInfoResponseGivenName :: Maybe Text
, dRepInfoResponseObjectives :: Maybe Text
, dRepInfoResponseMotivations :: Maybe Text
, dRepInfoResponseQualifications :: Maybe Text
, dRepInfoResponseQualifications :: Maybe Text
, dRepInfoResponseImageUrl :: Maybe Text
, dRepInfoResponseImageHash :: Maybe HexText
}
Expand Down Expand Up @@ -820,6 +821,27 @@ instance ToSchema DRepType where
& description ?~ "DRep Type"
& enum_ ?~ map toJSON [NormalDRep, SoleVoter]

newtype DRepReferences
= DRepReferences { getDRepReferencesValue :: Value }
deriving newtype (Show)

instance FromJSON DRepReferences where
parseJSON v = return $ DRepReferences v

instance ToJSON DRepReferences where
toJSON (DRepReferences d) = d

instance ToSchema DRepReferences where
declareNamedSchema _ = pure $ NamedSchema (Just "DRepReferences") $ mempty
& type_ ?~ OpenApiObject
& description ?~ "A JSON value that can include nested objects and arrays"
& example ?~ toJSON
(Aeson.object
[ "some_key" .= ("some value" :: String)
, "nested_key" .= Aeson.object ["inner_key" .= (1 :: Int)]
, "array_key" .= [1, 2, 3 :: Int]
])

data DRep
= DRep
{ dRepIsScriptBased :: Bool
Expand All @@ -838,9 +860,11 @@ data DRep
, dRepGivenName :: Maybe Text
, dRepObjectives :: Maybe Text
, dRepMotivations :: Maybe Text
, dRepQualifications :: Maybe Text
, dRepQualifications :: Maybe Text
, dRepImageUrl :: Maybe Text
, dRepImageHash :: Maybe HexText
, dRepIdentityReferences :: Maybe DRepReferences
, dRepLinkReferences :: Maybe DRepReferences
}
deriving (Generic, Show)

Expand Down
112 changes: 73 additions & 39 deletions govtool/backend/src/VVA/DRep.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,41 +11,74 @@ import Control.Monad.Reader

import Crypto.Hash

import Data.Aeson (Value)
import Data.ByteString (ByteString)
import qualified Data.ByteString.Base16 as Base16
import qualified Data.ByteString.Char8 as C
import qualified Data.ByteString.Base16 as Base16
import qualified Data.ByteString.Char8 as C
import Data.FileEmbed (embedFile)
import Data.Foldable (Foldable (sum))
import Data.Has (Has)
import qualified Data.Map as M
import qualified Data.Map as M
import Data.Maybe (fromMaybe, isJust, isNothing)
import Data.Scientific
import Data.String (fromString)
import Data.Text (Text, pack, unpack, intercalate)
import qualified Data.Text.Encoding as Text
import qualified Data.Text.Encoding as Text
import Data.Time

import qualified Database.PostgreSQL.Simple as SQL
import qualified Database.PostgreSQL.Simple as SQL
import Database.PostgreSQL.Simple.Types (In(..))
import Database.PostgreSQL.Simple.FromRow

import VVA.Config
import VVA.Pool (ConnectionPool, withPool)
import qualified VVA.Proposal as Proposal
import qualified VVA.Proposal as Proposal
import VVA.Types (AppError, DRepInfo (..), DRepRegistration (..), DRepStatus (..),
DRepType (..), Proposal (..), Vote (..), DRepVotingPowerList (..))

data DRepQueryResult = DRepQueryResult
{ queryDrepHash :: Text
, queryDrepView :: Text
, queryIsScriptBased :: Bool
, queryUrl :: Maybe Text
, queryDataHash :: Maybe Text
, queryDeposit :: Scientific
, queryVotingPower :: Maybe Integer
, queryIsActive :: Bool
, queryTxHash :: Maybe Text
, queryDate :: LocalTime
, queryLatestDeposit :: Scientific
, queryLatestNonDeregisterVotingAnchorWasNotNull :: Bool
, queryMetadataError :: Maybe Text
, queryPaymentAddress :: Maybe Text
, queryGivenName :: Maybe Text
, queryObjectives :: Maybe Text
, queryMotivations :: Maybe Text
, queryQualifications :: Maybe Text
, queryImageUrl :: Maybe Text
, queryImageHash :: Maybe Text
, queryIdentityReferences :: Maybe Value
, queryLinkReferences :: Maybe Value
} deriving (Show)

instance FromRow DRepQueryResult where
fromRow = DRepQueryResult
<$> field <*> field <*> field <*> field <*> field <*> field
<*> field <*> field <*> field <*> field <*> field <*> field
<*> field <*> field <*> field <*> field <*> field <*> field
<*> field <*> field <*> field <*> field

sqlFrom :: ByteString -> SQL.Query
sqlFrom bs = fromString $ unpack $ Text.decodeUtf8 bs

listDRepsSql :: SQL.Query
listDRepsSql = sqlFrom $(embedFile "sql/list-dreps.sql")

listDReps ::
(Has ConnectionPool r, Has VVAConfig r, MonadReader r m, MonadIO m) =>
Maybe Text -> m [DRepRegistration]
listDReps mSearchQuery = withPool $ \conn -> do
let searchParam = fromMaybe "" mSearchQuery
results <- liftIO $ SQL.query conn listDRepsSql
results <- liftIO (SQL.query conn listDRepsSql
( searchParam -- COALESCE(?, '')
, searchParam -- LENGTH(?)
, searchParam -- AND ?
Expand All @@ -56,44 +89,45 @@ listDReps mSearchQuery = withPool $ \conn -> do
, "%" <> searchParam <> "%" -- objectives
, "%" <> searchParam <> "%" -- motivations
, "%" <> searchParam <> "%" -- qualifications
)
) :: IO [DRepQueryResult])

timeZone <- liftIO getCurrentTimeZone
return
[ DRepRegistration drepHash drepView isScriptBased url dataHash (floor @Scientific deposit) votingPower status drepType txHash (localTimeToUTC timeZone date) metadataError paymentAddress givenName objectives motivations qualifications imageUrl imageHash
| ( drepHash
, drepView
, isScriptBased
, url
, dataHash
, deposit
, votingPower
, isActive
, txHash
, date
, latestDeposit
, latestNonDeregisterVotingAnchorWasNotNull
, metadataError
, paymentAddress
, givenName
, objectives
, motivations
, qualifications
, imageUrl
, imageHash
) <- results
, let status = case (isActive, deposit) of
[ DRepRegistration
(queryDrepHash result)
(queryDrepView result)
(queryIsScriptBased result)
(queryUrl result)
(queryDataHash result)
(floor @Scientific $ queryDeposit result)
(queryVotingPower result)
status
drepType
(queryTxHash result)
(localTimeToUTC timeZone $ queryDate result)
(queryMetadataError result)
(queryPaymentAddress result)
(queryGivenName result)
(queryObjectives result)
(queryMotivations result)
(queryQualifications result)
(queryImageUrl result)
(queryImageHash result)
(queryIdentityReferences result)
(queryLinkReferences result)
| result <- results
, let status = case (queryIsActive result, queryDeposit result) of
(_, d) | d < 0 -> Retired
(isActive, d) | d >= 0 && isActive -> Active
| d >= 0 && not isActive -> Inactive
, let latestDeposit' = floor @Scientific latestDeposit :: Integer
, let drepType | latestDeposit' >= 0 && isNothing url = SoleVoter
| latestDeposit' >= 0 && isJust url = DRep
| latestDeposit' < 0 && not latestNonDeregisterVotingAnchorWasNotNull = SoleVoter
| latestDeposit' < 0 && latestNonDeregisterVotingAnchorWasNotNull = DRep
| Data.Maybe.isJust url = DRep
, let latestDeposit' = floor @Scientific (queryLatestDeposit result) :: Integer
, let drepType | latestDeposit' >= 0 && isNothing (queryUrl result) = SoleVoter
| latestDeposit' >= 0 && isJust (queryUrl result) = DRep
| latestDeposit' < 0 && not (queryLatestNonDeregisterVotingAnchorWasNotNull result) = SoleVoter
| latestDeposit' < 0 && queryLatestNonDeregisterVotingAnchorWasNotNull result = DRep
| Data.Maybe.isJust (queryUrl result) = DRep
]

getVotingPowerSql :: SQL.Query
getVotingPowerSql = sqlFrom $(embedFile "sql/get-voting-power.sql")

Expand Down
Loading