diff --git a/govtool/backend/app/Main.hs b/govtool/backend/app/Main.hs index 8de817ea3..f4df1c03c 100644 --- a/govtool/backend/app/Main.hs +++ b/govtool/backend/app/Main.hs @@ -1,90 +1,77 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE OverloadedLabels #-} -{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeOperators #-} -{-# LANGUAGE OverloadedLabels #-} -{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeOperators #-} module Main where -import Control.Exception - ( Exception, - SomeException, - fromException, - throw, - ) -import Control.Lens.Operators ((.~)) -import Control.Monad -import Control.Monad.IO.Class -import Control.Monad.Trans.Except -import Control.Monad.Trans.Reader -import Data.Aeson hiding (Error) -import Data.ByteString.Char8 (unpack) -import qualified Data.ByteString as BS -import Data.Function ((&)) -import Data.Monoid (mempty) -import Data.OpenApi (OpenApi, Server (Server), servers, _openApiServers, _serverDescription, _serverUrl, _serverVariables) -import Data.Proxy -import Data.String (fromString) -import Data.String.Conversions - ( cs, - ) -import qualified Data.Text as Text -import qualified Data.Text.IO as Text -import qualified Data.Text.Lazy as LazyText -import qualified Data.Text.Lazy.Encoding as LazyText -import Network.Wai -import Network.Wai - ( Request, - rawPathInfo, - requestHeaderHost, - ) -import Network.Wai.Handler.Warp -import Network.Wai.Handler.Warp - ( defaultOnException, - defaultSettings, - runSettings, - setOnException, - setPort, - ) -import Network.Wai.Middleware.Cors -import Options.Applicative (execParser) -import Servant -import Servant.API.ContentTypes -import Servant.OpenApi (toOpenApi) -import qualified Servant.Server as Servant -import Servant.Swagger.UI - ( SwaggerSchemaUI, - swaggerSchemaUIServer, - ) -import System.IO (stderr) -import System.Log.Raven - ( initRaven, - register, - silentFallback, - ) -import System.Log.Raven.Transport.HttpConduit (sendRecord) -import System.Log.Raven.Types - ( SentryLevel (Error), - SentryRecord (..), - ) -import VVA.API -import VVA.CommandLine -import VVA.Config -import Data.Function ((&)) -import Control.Lens.Operators ((.~)) -import Data.Monoid (mempty) -import qualified Data.Cache as Cache -import VVA.API.Types -import System.Clock (TimeSpec(TimeSpec)) -import Data.Pool (createPool) -import Database.PostgreSQL.Simple (connectPostgreSQL, close) -import Data.Text.Encoding (encodeUtf8) -import Data.Has (getter) -import VVA.Types (AppError(ValidationError, NotFoundError, CriticalError), CacheEnv(..), AppEnv(..)) +import Control.Exception (Exception, + SomeException, + fromException, throw) +import Control.Lens.Operators ((.~)) +import Control.Monad +import Control.Monad.IO.Class +import Control.Monad.Trans.Except +import Control.Monad.Trans.Reader + +import Data.Aeson hiding (Error) +import qualified Data.ByteString as BS +import Data.ByteString.Char8 (unpack) +import qualified Data.Cache as Cache +import Data.Function ((&)) +import Data.Has (getter) +import Data.Monoid (mempty) +import Data.OpenApi (OpenApi, + Server (Server), + _openApiServers, + _serverDescription, + _serverUrl, + _serverVariables, + servers) +import Data.Pool (createPool) +import Data.Proxy +import Data.String (fromString) +import Data.String.Conversions (cs) +import qualified Data.Text as Text +import Data.Text.Encoding (encodeUtf8) +import qualified Data.Text.IO as Text +import qualified Data.Text.Lazy as LazyText +import qualified Data.Text.Lazy.Encoding as LazyText + +import Database.PostgreSQL.Simple (close, + connectPostgreSQL) + +import Network.Wai +import Network.Wai.Handler.Warp +import Network.Wai.Middleware.Cors + +import Options.Applicative (execParser) + +import Servant +import Servant.API.ContentTypes +import Servant.OpenApi (toOpenApi) +import qualified Servant.Server as Servant +import Servant.Swagger.UI (SwaggerSchemaUI, + swaggerSchemaUIServer) + +import System.Clock (TimeSpec (TimeSpec)) +import System.IO (stderr) +import System.Log.Raven (initRaven, register, + silentFallback) +import System.Log.Raven.Transport.HttpConduit (sendRecord) +import System.Log.Raven.Types (SentryLevel (Error), + SentryRecord (..)) + +import VVA.API +import VVA.API.Types +import VVA.CommandLine +import VVA.Config +import VVA.Types (AppEnv (..), + AppError (CriticalError, NotFoundError, ValidationError), + CacheEnv (..)) proxyAPI :: Proxy (VVAApi :<|> SwaggerAPI) proxyAPI = Proxy @@ -94,7 +81,7 @@ main = do commandLineConfig <- execParser cmdParser vvaConfig <- loadVVAConfig (clcConfigPath commandLineConfig) case clcCommand commandLineConfig of - StartApp -> startApp vvaConfig + StartApp -> startApp vvaConfig ShowConfig -> Text.putStrLn $ vvaConfigToText vvaConfig startApp :: VVAConfig -> IO () @@ -172,7 +159,7 @@ recordUpdate Nothing exception record = record recordUpdate (Just request) exception record = record { srCulprit = Just $ unpack $ rawPathInfo request, - srServerName = fmap unpack $ requestHeaderHost request + srServerName = unpack <$> requestHeaderHost request } shouldDisplayException :: SomeException -> Bool @@ -243,7 +230,8 @@ mkVVAServer appEnv = do (liftServer appEnv :<|> swagger) ) -newtype TextException = TextException Text.Text +newtype TextException + = TextException Text.Text instance Show TextException where show (TextException e) = show e diff --git a/govtool/backend/src/VVA/API.hs b/govtool/backend/src/VVA/API.hs index 27909a5d3..3796b52d3 100644 --- a/govtool/backend/src/VVA/API.hs +++ b/govtool/backend/src/VVA/API.hs @@ -1,38 +1,46 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ViewPatterns #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE ViewPatterns #-} module VVA.API where -import Control.Monad.Reader -import Control.Monad.Except (throwError) -import Data.List (sortOn) -import Data.Maybe (fromMaybe, Maybe (Nothing)) -import Data.Ord (Down (..)) -import Data.Text hiding (elem, filter, map, null, take, drop, length) -import Servant.API -import Servant.Server -import Text.Read (readMaybe) -import VVA.API.Types -import qualified VVA.AdaHolder as AdaHolder -import VVA.Config -import qualified VVA.DRep as DRep -import qualified VVA.Proposal as Proposal -import qualified VVA.Epoch as Epoch -import qualified VVA.Transaction as Transaction -import Data.Bool (Bool) -import qualified Data.Map as Map -import VVA.Cache (cacheRequest) -import Control.Exception (throw) -import VVA.Types (CacheEnv(..), AppError(ValidationError, CriticalError), App, AppEnv(..)) -import qualified VVA.Types as Types -import qualified Data.Text as Text -import VVA.Network as Network -import Numeric.Natural (Natural) +import Control.Exception (throw) +import Control.Monad.Except (throwError) +import Control.Monad.Reader + +import Data.Bool (Bool) +import Data.List (sortOn) +import qualified Data.Map as Map +import Data.Maybe (Maybe (Nothing), fromMaybe) +import Data.Ord (Down (..)) +import Data.Text hiding (drop, elem, filter, length, map, + null, take) +import qualified Data.Text as Text + +import Numeric.Natural (Natural) + +import Servant.API +import Servant.Server + +import Text.Read (readMaybe) + +import qualified VVA.AdaHolder as AdaHolder +import VVA.API.Types +import VVA.Cache (cacheRequest) +import VVA.Config +import qualified VVA.DRep as DRep +import qualified VVA.Epoch as Epoch +import VVA.Network as Network +import qualified VVA.Proposal as Proposal +import qualified VVA.Transaction as Transaction +import qualified VVA.Types as Types +import VVA.Types (App, AppEnv (..), + AppError (CriticalError, ValidationError), + CacheEnv (..)) type VVAApi = "drep" :> "list" :> QueryParam "drepView" Text :> Get '[JSON] [DRep] @@ -71,12 +79,12 @@ server = drepList mapDRepType :: Types.DRepType -> DRepType -mapDRepType Types.DRep = NormalDRep +mapDRepType Types.DRep = NormalDRep mapDRepType Types.SoleVoter = SoleVoter mapDRepStatus :: Types.DRepStatus -> DRepStatus -mapDRepStatus Types.Retired = Retired -mapDRepStatus Types.Active = Active +mapDRepStatus Types.Retired = Retired +mapDRepStatus Types.Active = Active mapDRepStatus Types.Inactive = Inactive drepRegistrationToDrep :: Types.DRepRegistration -> DRep @@ -99,9 +107,9 @@ drepList mDRepView = do let filtered = flip filter dreps $ \Types.DRepRegistration {..} -> case (dRepRegistrationType, mDRepView) of (Types.SoleVoter, Just x) -> x == dRepRegistrationView - (Types.DRep, Just x) -> isInfixOf x dRepRegistrationView - (Types.DRep, Nothing) -> True - _ -> False + (Types.DRep, Just x) -> x `isInfixOf` dRepRegistrationView + (Types.DRep, Nothing) -> True + _ -> False return $ map drepRegistrationToDrep filtered getVotingPower :: App m => HexText -> m Integer @@ -165,10 +173,10 @@ mapSortAndFilterProposals selectedTypes sortMode proposals = ) mappedProposals sortedProposals = case sortMode of - Nothing -> filteredProposals - Just NewestCreated -> sortOn (Down . proposalResponseCreatedDate) filteredProposals + Nothing -> filteredProposals + Just NewestCreated -> sortOn (Down . proposalResponseCreatedDate) filteredProposals Just SoonestToExpire -> sortOn proposalResponseExpiryDate filteredProposals - Just MostYesVotes -> sortOn (Down . proposalResponseYesVotes) filteredProposals + Just MostYesVotes -> sortOn (Down . proposalResponseYesVotes) filteredProposals in sortedProposals getVotes :: App m => HexText -> [GovernanceActionType] -> Maybe GovernanceActionSortMode -> m [VoteResponse] @@ -179,7 +187,7 @@ getVotes (unHexText -> dRepId) selectedTypes sortMode = do let processedProposals = mapSortAndFilterProposals selectedTypes sortMode proposals return $ [ VoteResponse - { voteResponseVote = voteToResponse (voteMap Map.! (read $ unpack proposalResponseId)) + { voteResponseVote = voteToResponse (voteMap Map.! read (unpack proposalResponseId)) , voteResponseProposal = proposalResponse } | proposalResponse@ProposalResponse{proposalResponseId} <- processedProposals @@ -209,7 +217,7 @@ getCurrentDelegation (unHexText -> stakeKey) = do getStakeKeyVotingPower :: App m => HexText -> m Integer getStakeKeyVotingPower (unHexText -> stakeKey) = do CacheEnv {adaHolderVotingPowerCache} <- asks vvaCache - cacheRequest adaHolderVotingPowerCache stakeKey $ AdaHolder.getStakeKeyVotingPower $ stakeKey + cacheRequest adaHolderVotingPowerCache stakeKey $ AdaHolder.getStakeKeyVotingPower stakeKey listProposals @@ -255,10 +263,7 @@ listProposals selectedTypes sortMode mPage mPageSize mDrepRaw mSearchQuery = do ( \p@ProposalResponse {proposalResponseId} -> proposalResponseId `notElem` proposalsToRemove && filterF p - ) - <$> - mapSortAndFilterProposals selectedTypes sortMode - <$> cacheRequest proposalListCache () Proposal.listProposals + ) . mapSortAndFilterProposals selectedTypes sortMode <$> cacheRequest proposalListCache () Proposal.listProposals let total = length mappedAndSortedProposals :: Int @@ -271,7 +276,7 @@ listProposals selectedTypes sortMode mPage mPageSize mDrepRaw mSearchQuery = do , listProposalsResponseElements = elements } -getProposal :: App m => GovActionId -> Maybe (HexText) -> m GetProposalResponse +getProposal :: App m => GovActionId -> Maybe HexText -> m GetProposalResponse getProposal g@(GovActionId govActionTxHash govActionIndex) mDrepId' = do let mDrepId = unHexText <$> mDrepId' CacheEnv {getProposalCache} <- asks vvaCache @@ -300,7 +305,7 @@ getTransactionStatus :: App m => HexText -> m GetTransactionStatusResponse getTransactionStatus (unHexText -> transactionId) = do x <- Transaction.getTransactionStatus transactionId case x of - Types.TransactionConfirmed -> return $ GetTransactionStatusResponse True + Types.TransactionConfirmed -> return $ GetTransactionStatusResponse True Types.TransactionUnconfirmed -> return $ GetTransactionStatusResponse False throw500 :: App m => m () diff --git a/govtool/backend/src/VVA/API/Types.hs b/govtool/backend/src/VVA/API/Types.hs index 1f49b5f23..83352c56e 100644 --- a/govtool/backend/src/VVA/API/Types.hs +++ b/govtool/backend/src/VVA/API/Types.hs @@ -1,60 +1,68 @@ -{-# LANGUAGE ConstraintKinds #-} -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE DerivingStrategies #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE ConstraintKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} module VVA.API.Types where -import Control.Lens ((?~), (.~)) -import Control.Monad.Except -import Control.Monad.Reader -import Data.Aeson -import qualified Data.Aeson as Aeson -import qualified Data.Text.Lazy.Encoding as Text +import Control.Exception (throw) +import Control.Lens ((.~), (?~)) +import Control.Monad (guard) +import Control.Monad.Except +import Control.Monad.Reader + +import Data.Aeson +import qualified Data.Aeson as Aeson +import qualified Data.Aeson.KeyMap as Aeson (toList) +import Data.Aeson.TH (deriveJSON) import qualified Data.ByteString.Lazy.Char8 as Char8 -import qualified Data.Aeson.KeyMap as Aeson (toList) -import Data.Aeson.TH (deriveJSON) -import Data.Function ((&)) -import Data.Maybe (fromJust, fromMaybe) -import Data.OpenApi hiding (Info) -import Data.Text hiding (map) -import qualified Data.Text as Text -import Data.Time -import GHC.Generics -import Servant.API (FromHttpApiData, parseUrlPiece, parseQueryParam) -import Text.Read (readMaybe) -import VVA.API.Utils -import VVA.Config -import GHC.Exts (toList) -import qualified Data.Cache as Cache -import qualified VVA.Proposal as Proposal -import Data.Hashable (Hashable) -import Data.Has (Has, getter, modifier) -import Data.Pool (Pool) -import Database.PostgreSQL.Simple (Connection) -import Data.Char (isHexDigit) -import VVA.Types (AppError(ValidationError)) -import Data.Proxy (Proxy(Proxy)) -import Control.Exception (throw) -import Data.Swagger.Internal (SwaggerType(SwaggerString)) -import Control.Monad (guard) - -newtype HexText = HexText { unHexText :: Text } - deriving newtype (Show, Eq) +import qualified Data.Cache as Cache +import Data.Char (isHexDigit) +import Data.Function ((&)) +import Data.Has (Has, getter, modifier) +import Data.Hashable (Hashable) +import Data.Maybe (fromJust, fromMaybe) +import Data.OpenApi hiding (Info) +import Data.Pool (Pool) +import Data.Proxy (Proxy (Proxy)) +import Data.Swagger.Internal (SwaggerType (SwaggerString)) +import Data.Text hiding (map) +import qualified Data.Text as Text +import qualified Data.Text.Lazy.Encoding as Text +import Data.Time + +import Database.PostgreSQL.Simple (Connection) + +import GHC.Exts (toList) +import GHC.Generics + +import Servant.API (FromHttpApiData, parseQueryParam, + parseUrlPiece) + +import Text.Read (readMaybe) + +import VVA.API.Utils +import VVA.Config +import qualified VVA.Proposal as Proposal +import VVA.Types (AppError (ValidationError)) + +newtype HexText + = HexText { unHexText :: Text } + deriving newtype (Eq, Show) instance FromJSON HexText where parseJSON (Aeson.String t) = do - if (Text.length t `mod` 2 == 1 || Text.any (not . isHexDigit) t) + if Text.length t `mod` 2 == 1 || Text.any (not . isHexDigit) t then mzero else pure $ HexText t @@ -64,7 +72,7 @@ instance ToJSON HexText where -- To use it in routes, we need to be able to parse it from Text: instance FromHttpApiData HexText where parseUrlPiece txt - | Text.all isHexDigit txt && (Text.length txt `mod` 2 == 0) = Right (HexText txt) + | Text.all isHexDigit txt && even (Text.length txt) = Right (HexText txt) | otherwise = Left "Not a valid hex value" @@ -82,10 +90,11 @@ instance ToSchema HexText where & schema . format ?~ "hex" & schema . example ?~ toJSON (HexText "a1b2c3") -data GovActionId = GovActionId - { govActionIdTxHash :: HexText - , govActionIdIndex :: Integer - } +data GovActionId + = GovActionId + { govActionIdTxHash :: HexText + , govActionIdIndex :: Integer + } deriving (Eq) instance Show GovActionId where @@ -135,15 +144,14 @@ instance ToSchema GovActionId where & schema . example ?~ Aeson.String exampleGovActionId -data GovernanceActionType - = ParameterChange - | HardForkInitiation - | TreasuryWithdrawals - | NoConfidence - | NewCommittee - | NewConstitution - | InfoAction - deriving (Eq, Show, Read, Enum, Bounded, Generic) +data GovernanceActionType = ParameterChange | HardForkInitiation | TreasuryWithdrawals | NoConfidence | NewCommittee | NewConstitution | InfoAction deriving + ( Bounded + , Enum + , Eq + , Generic + , Read + , Show + ) instance FromJSON GovernanceActionType where parseJSON (Aeson.String governanceActionType) = pure $ fromMaybe InfoAction $ readMaybe (Text.unpack governanceActionType) @@ -163,7 +171,7 @@ instance ToSchema GovernanceActionType where instance FromHttpApiData GovernanceActionType where parseQueryParam t = case readMaybe $ Text.unpack t of - Just x -> Right x + Just x -> Right x Nothing -> Left ("incorrect governance action type: " <> t) instance ToParamSchema GovernanceActionType where @@ -172,11 +180,14 @@ instance ToParamSchema GovernanceActionType where & type_ ?~ OpenApiString & enum_ ?~ map toJSON (enumFromTo minBound maxBound :: [GovernanceActionType]) -data GovernanceActionSortMode - = SoonestToExpire - | NewestCreated - | MostYesVotes - deriving (Eq, Show, Read, Enum, Bounded, Generic) +data GovernanceActionSortMode = SoonestToExpire | NewestCreated | MostYesVotes deriving + ( Bounded + , Enum + , Eq + , Generic + , Read + , Show + ) instance FromJSON GovernanceActionSortMode where parseJSON (Aeson.String governanceActionSortMode) = pure $ fromJust $ readMaybe (Text.unpack governanceActionSortMode) @@ -196,7 +207,7 @@ instance ToSchema GovernanceActionSortMode where instance FromHttpApiData GovernanceActionSortMode where parseQueryParam t = case readMaybe $ Text.unpack t of - Just x -> Right x + Just x -> Right x Nothing -> Left ("incorrect governance action sort mode: " <> t) instance ToParamSchema GovernanceActionSortMode where @@ -206,7 +217,8 @@ instance ToParamSchema GovernanceActionSortMode where & enum_ ?~ map toJSON (enumFromTo minBound maxBound :: [GovernanceActionSortMode]) -newtype GovernanceActionDetails = GovernanceActionDetails { getValue :: Value } +newtype GovernanceActionDetails + = GovernanceActionDetails { getValue :: Value } deriving newtype (Show) instance FromJSON GovernanceActionDetails where @@ -216,8 +228,8 @@ instance FromJSON GovernanceActionDetails where (Aeson.Object _) -> fail "GovernanceActionDetails cannot have nested objects" (Aeson.Array a) -> forM_ (toList a) $ \case (Aeson.Object _) -> fail "GovernanceActionDetails cannot have nested objects" - (Aeson.Array _) -> fail "GovernanceActionDetails cannot have nested arrays" - _ -> pure () + (Aeson.Array _) -> fail "GovernanceActionDetails cannot have nested arrays" + _ -> pure () _ -> pure () return $ GovernanceActionDetails v parseJSON _ = fail "GovernanceActionDetails has to be an object" @@ -234,12 +246,13 @@ instance ToSchema GovernanceActionDetails where ("{\"some_key\": \"some value\", \"some_key2\": [1,2,3]}" :: Text) -newtype GovernanceActionMetadata = GovernanceActionMetadata Value +newtype GovernanceActionMetadata + = GovernanceActionMetadata Value deriving newtype (Show) instance FromJSON GovernanceActionMetadata where parseJSON v@(Aeson.Object o) = pure (GovernanceActionMetadata v) - parseJSON _ = fail "GovernanceActionMetadata has to be an object" + parseJSON _ = fail "GovernanceActionMetadata has to be an object" instance ToJSON GovernanceActionMetadata where toJSON (GovernanceActionMetadata g) = g @@ -254,27 +267,28 @@ instance ToSchema GovernanceActionMetadata where -data ProposalResponse = ProposalResponse - { proposalResponseId :: Text, - proposalResponseTxHash :: HexText, - proposalResponseIndex :: Integer, - proposalResponseType :: GovernanceActionType, - proposalResponseDetails :: Maybe GovernanceActionDetails, - proposalResponseExpiryDate :: Maybe UTCTime, - proposalResponseExpiryEpochNo :: Maybe Integer, - proposalResponseCreatedDate :: UTCTime, - proposalResponseCreatedEpochNo :: Integer, - proposalResponseUrl :: Text, - proposalResponseMetadataHash :: HexText, - proposalResponseTitle :: Maybe Text, - proposalResponseAbout :: Maybe Text, - proposalResponseMotivation :: Maybe Text, - proposalResponseRationale :: Maybe Text, - proposalResponseMetadata :: Maybe GovernanceActionMetadata, - proposalResponseYesVotes :: Integer, - proposalResponseNoVotes :: Integer, - proposalResponseAbstainVotes :: Integer - } +data ProposalResponse + = ProposalResponse + { proposalResponseId :: Text + , proposalResponseTxHash :: HexText + , proposalResponseIndex :: Integer + , proposalResponseType :: GovernanceActionType + , proposalResponseDetails :: Maybe GovernanceActionDetails + , proposalResponseExpiryDate :: Maybe UTCTime + , proposalResponseExpiryEpochNo :: Maybe Integer + , proposalResponseCreatedDate :: UTCTime + , proposalResponseCreatedEpochNo :: Integer + , proposalResponseUrl :: Text + , proposalResponseMetadataHash :: HexText + , proposalResponseTitle :: Maybe Text + , proposalResponseAbout :: Maybe Text + , proposalResponseMotivation :: Maybe Text + , proposalResponseRationale :: Maybe Text + , proposalResponseMetadata :: Maybe GovernanceActionMetadata + , proposalResponseYesVotes :: Integer + , proposalResponseNoVotes :: Integer + , proposalResponseAbstainVotes :: Integer + } deriving (Generic, Show) deriveJSON (jsonOptions "proposalResponse") ''ProposalResponse @@ -323,12 +337,14 @@ exampleListProposalsResponse = <> "\"elements\": [" <> exampleProposalResponse <> "]}" -data ListProposalsResponse = ListProposalsResponse - { listProposalsResponsePage :: Integer - , listProposalsResponsePageSize :: Integer - , listProposalsResponseTotal :: Integer - , listProposalsResponseElements :: [ProposalResponse] - } deriving (Generic, Show) +data ListProposalsResponse + = ListProposalsResponse + { listProposalsResponsePage :: Integer + , listProposalsResponsePageSize :: Integer + , listProposalsResponseTotal :: Integer + , listProposalsResponseElements :: [ProposalResponse] + } + deriving (Generic, Show) deriveJSON (jsonOptions "listProposalsResponse") ''ListProposalsResponse @@ -347,13 +363,14 @@ instance ToSchema ListProposalsResponse where & example ?~ toJSON exampleListProposalsResponse -data VoteParams = VoteParams - { voteParamsProposalId :: Text, - voteParamsDrepId :: HexText, - voteParamsVote :: Text, - voteParamsUrl :: Maybe Text, - voteParamsMetadataHash :: Maybe HexText - } +data VoteParams + = VoteParams + { voteParamsProposalId :: Text + , voteParamsDrepId :: HexText + , voteParamsVote :: Text + , voteParamsUrl :: Maybe Text + , voteParamsMetadataHash :: Maybe HexText + } deriving (Generic, Show) deriveJSON (jsonOptions "voteParams") ''VoteParams @@ -381,10 +398,11 @@ instance ToSchema VoteParams where & example ?~ toJSON exampleVoteParams -data VoteResponse = VoteResponse - { voteResponseVote :: VoteParams, - voteResponseProposal :: ProposalResponse - } +data VoteResponse + = VoteResponse + { voteResponseVote :: VoteParams + , voteResponseProposal :: ProposalResponse + } deriving (Generic, Show) deriveJSON (jsonOptions "voteResponse") ''VoteResponse @@ -409,16 +427,18 @@ instance ToSchema VoteResponse where & example ?~ toJSON exampleVoteResponse -data DRepInfoResponse = DRepInfoResponse - { dRepInfoResponseIsRegisteredAsDRep :: Bool - , dRepInfoResponseWasRegisteredAsDRep :: Bool - , dRepInfoResponseIsRegisteredAsSoleVoter :: Bool - , dRepInfoResponseWasRegisteredAsSoleVoter :: Bool - , dRepInfoResponseDeposit :: Maybe Integer - , dRepInfoResponseUrl :: Maybe Text - , dRepInfoResponseDataHash :: Maybe HexText - , dRepInfoResponseVotingPower :: Maybe Integer - } deriving (Generic, Show) +data DRepInfoResponse + = DRepInfoResponse + { dRepInfoResponseIsRegisteredAsDRep :: Bool + , dRepInfoResponseWasRegisteredAsDRep :: Bool + , dRepInfoResponseIsRegisteredAsSoleVoter :: Bool + , dRepInfoResponseWasRegisteredAsSoleVoter :: Bool + , dRepInfoResponseDeposit :: Maybe Integer + , dRepInfoResponseUrl :: Maybe Text + , dRepInfoResponseDataHash :: Maybe HexText + , dRepInfoResponseVotingPower :: Maybe Integer + } + deriving (Generic, Show) deriveJSON (jsonOptions "dRepInfoResponse") ''DRepInfoResponse @@ -447,10 +467,11 @@ instance ToSchema DRepInfoResponse where ?~ toJSON exampleDRepInfoResponse -data GetProposalResponse = GetProposalResponse - { getProposalResponseVote :: Maybe VoteParams, - getProposalResponseProposal :: ProposalResponse - } +data GetProposalResponse + = GetProposalResponse + { getProposalResponseVote :: Maybe VoteParams + , getProposalResponseProposal :: ProposalResponse + } deriving (Generic, Show) exampleGetProposalResponse :: Text @@ -477,14 +498,15 @@ instance ToSchema GetProposalResponse where ?~ toJSON exampleGetProposalResponse -newtype GetCurrentEpochParamsResponse = GetCurrentEpochParamsResponse { getCurrentEpochParamsResponse :: Maybe Value } +newtype GetCurrentEpochParamsResponse + = GetCurrentEpochParamsResponse { getCurrentEpochParamsResponse :: Maybe Value } deriving newtype (Show) instance FromJSON GetCurrentEpochParamsResponse where parseJSON = pure . GetCurrentEpochParamsResponse . Just instance ToJSON GetCurrentEpochParamsResponse where - toJSON (GetCurrentEpochParamsResponse Nothing) = Null + toJSON (GetCurrentEpochParamsResponse Nothing) = Null toJSON (GetCurrentEpochParamsResponse (Just params)) = toJSON params exampleGetCurrentEpochParamsResponse :: Text @@ -499,9 +521,8 @@ instance ToSchema GetCurrentEpochParamsResponse where ?~ toJSON exampleGetCurrentEpochParamsResponse newtype GetTransactionStatusResponse - = GetTransactionStatusResponse - { getTransactionstatusResponseTransactionConfirmed :: Bool - } deriving (Generic, Show) + = GetTransactionStatusResponse { getTransactionstatusResponseTransactionConfirmed :: Bool } + deriving (Generic, Show) deriveJSON (jsonOptions "getTransactionstatusResponse") ''GetTransactionStatusResponse @@ -524,12 +545,13 @@ instance ToSchema GetTransactionStatusResponse where & example ?~ toJSON exampleGetTransactionStatusResponse -newtype DRepHash = DRepHash Text +newtype DRepHash + = DRepHash Text deriving (Generic, Show) instance FromJSON DRepHash where parseJSON (Aeson.String s) = pure $ DRepHash s - parseJSON x = fail ("expected DRepHash to be a string but got: " <> Char8.unpack (encode x)) + parseJSON x = fail ("expected DRepHash to be a string but got: " <> Char8.unpack (encode x)) instance ToJSON DRepHash where toJSON (DRepHash raw) = toJSON raw @@ -546,22 +568,21 @@ instance ToSchema DRepHash where ?~ toJSON exampleDrepHash -data DRepStatus = Retired | Active | Inactive - deriving (Generic, Show) +data DRepStatus = Retired | Active | Inactive deriving (Generic, Show) -- ToJSON instance for DRepStatus instance ToJSON DRepStatus where - toJSON Retired = "Retired" - toJSON Active = "Active" + toJSON Retired = "Retired" + toJSON Active = "Active" toJSON Inactive = "Inactive" -- FromJSON instance for DRepStatus instance FromJSON DRepStatus where parseJSON = withText "DRepStatus" $ \case - "Retired" -> pure Retired - "Active" -> pure Active + "Retired" -> pure Retired + "Active" -> pure Active "Inactive" -> pure Inactive - _ -> fail "Invalid DRepStatus" + _ -> fail "Invalid DRepStatus" -- ToSchema instance for DRepStatus instance ToSchema DRepStatus where @@ -576,19 +597,19 @@ data DRepType = NormalDRep | SoleVoter instance Show DRepType where show NormalDRep = "DRep" - show SoleVoter = "SoleVoter" + show SoleVoter = "SoleVoter" -- ToJSON instance for DRepType instance ToJSON DRepType where toJSON NormalDRep = "DRep" - toJSON SoleVoter = "SoleVoter" + toJSON SoleVoter = "SoleVoter" -- FromJSON instance for DRepType instance FromJSON DRepType where parseJSON = withText "DRepType" $ \case - "DRep" -> pure NormalDRep + "DRep" -> pure NormalDRep "SoleVoter" -> pure SoleVoter - _ -> fail "Invalid DRepType" + _ -> fail "Invalid DRepType" -- ToSchema instance for DRepType instance ToSchema DRepType where @@ -597,16 +618,18 @@ instance ToSchema DRepType where & description ?~ "DRep Type" & enum_ ?~ map toJSON [NormalDRep, SoleVoter] -data DRep = DRep - { dRepDrepId :: DRepHash - , dRepView :: Text - , dRepUrl :: Maybe Text - , dRepMetadataHash :: Maybe Text - , dRepDeposit :: Integer - , dRepVotingPower :: Maybe Integer - , dRepStatus :: DRepStatus - , dRepType :: DRepType - } deriving (Generic, Show) +data DRep + = DRep + { dRepDrepId :: DRepHash + , dRepView :: Text + , dRepUrl :: Maybe Text + , dRepMetadataHash :: Maybe Text + , dRepDeposit :: Integer + , dRepVotingPower :: Maybe Integer + , dRepStatus :: DRepStatus + , dRepType :: DRepType + } + deriving (Generic, Show) deriveJSON (jsonOptions "dRep") ''DRep @@ -639,18 +662,19 @@ instance ToSchema DRep where -data GetNetworkMetricsResponse = GetNetworkMetricsResponse - { getNetworkMetricsResponseCurrentTime :: UTCTime - , getNetworkMetricsResponseCurrentEpoch :: Integer - , getNetworkMetricsResponseCurrentBlock :: Integer - , getNetworkMetricsResponseUniqueDelegators :: Integer - , getNetworkMetricsResponseTotalDelegations :: Integer - , getNetworkMetricsResponseTotalGovernanceActions :: Integer - , getNetworkMetricsResponseTotalDRepVotes :: Integer - , getNetworkMetricsResponseTotalRegisteredDReps :: Integer - , getNetworkMetricsResponseAlwaysAbstainVotingPower :: Integer - , getNetworkMetricsResponseAlwaysNoConfidenceVotingPower :: Integer - } +data GetNetworkMetricsResponse + = GetNetworkMetricsResponse + { getNetworkMetricsResponseCurrentTime :: UTCTime + , getNetworkMetricsResponseCurrentEpoch :: Integer + , getNetworkMetricsResponseCurrentBlock :: Integer + , getNetworkMetricsResponseUniqueDelegators :: Integer + , getNetworkMetricsResponseTotalDelegations :: Integer + , getNetworkMetricsResponseTotalGovernanceActions :: Integer + , getNetworkMetricsResponseTotalDRepVotes :: Integer + , getNetworkMetricsResponseTotalRegisteredDReps :: Integer + , getNetworkMetricsResponseAlwaysAbstainVotingPower :: Integer + , getNetworkMetricsResponseAlwaysNoConfidenceVotingPower :: Integer + } deriveJSON (jsonOptions "getNetworkMetricsResponse") ''GetNetworkMetricsResponse diff --git a/govtool/backend/src/VVA/API/Utils.hs b/govtool/backend/src/VVA/API/Utils.hs index 49a47f672..9ba8f26f8 100644 --- a/govtool/backend/src/VVA/API/Utils.hs +++ b/govtool/backend/src/VVA/API/Utils.hs @@ -1,13 +1,14 @@ module VVA.API.Utils where -import Data.Aeson (Options (..), defaultOptions) -import Data.Char -import Foreign (pooledMalloc) +import Data.Aeson (Options (..), defaultOptions) +import Data.Char + +import Foreign (pooledMalloc) -- | Apply function to first element in the list. applyFirst :: (a -> a) -> [a] -> [a] -applyFirst _ [] = [] -applyFirst f [x] = [f x] +applyFirst _ [] = [] +applyFirst f [x] = [f x] applyFirst f (x : xs) = f x : xs jsonOptions :: String -> Options diff --git a/govtool/backend/src/VVA/AdaHolder.hs b/govtool/backend/src/VVA/AdaHolder.hs index b6ea49412..1e177235f 100644 --- a/govtool/backend/src/VVA/AdaHolder.hs +++ b/govtool/backend/src/VVA/AdaHolder.hs @@ -1,25 +1,29 @@ -{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} module VVA.AdaHolder where -import Control.Monad.Except -import Control.Monad.Reader -import Crypto.Hash -import Data.ByteString (ByteString) -import qualified Data.ByteString.Char8 as C -import Data.FileEmbed (embedFile) -import Data.Scientific -import Data.String (fromString) -import Data.Text (Text, unpack) -import qualified Data.Text.Encoding as Text -import qualified Data.Text.IO as Text +import Control.Monad.Except +import Control.Monad.Reader + +import Crypto.Hash + +import Data.ByteString (ByteString) +import qualified Data.ByteString.Char8 as C +import Data.FileEmbed (embedFile) +import Data.Has (Has) +import Data.Scientific +import Data.String (fromString) +import Data.Text (Text, unpack) +import qualified Data.Text.Encoding as Text +import qualified Data.Text.IO as Text + import qualified Database.PostgreSQL.Simple as SQL -import VVA.Config -import Data.Has (Has) -import VVA.Pool (withPool, ConnectionPool) + +import VVA.Config +import VVA.Pool (ConnectionPool, withPool) sqlFrom :: ByteString -> SQL.Query sqlFrom bs = fromString $ unpack $ Text.decodeUtf8 bs @@ -37,9 +41,9 @@ getCurrentDelegation :: getCurrentDelegation stakeKey = withPool $ \conn -> do result <- liftIO $ SQL.query conn getCurrentDelegationSql (SQL.Only stakeKey) case result of - [] -> return Nothing + [] -> return Nothing [SQL.Only delegation] -> return $ Just delegation - _ -> error ("multiple delegations for stake key: " <> unpack stakeKey) + _ -> error ("multiple delegations for stake key: " <> unpack stakeKey) getVotingPowerSql :: SQL.Query getVotingPowerSql = sqlFrom $(embedFile "sql/get-stake-key-voting-power.sql") diff --git a/govtool/backend/src/VVA/Cache.hs b/govtool/backend/src/VVA/Cache.hs index 548755615..f3cfe3299 100644 --- a/govtool/backend/src/VVA/Cache.hs +++ b/govtool/backend/src/VVA/Cache.hs @@ -1,10 +1,11 @@ module VVA.Cache where -import qualified Data.Cache as Cache -import Data.Hashable (Hashable) -import Control.Monad.IO.Class (MonadIO, liftIO) -import Data.Text (Text) -import Data.Aeson (Value) +import Control.Monad.IO.Class (MonadIO, liftIO) + +import Data.Aeson (Value) +import qualified Data.Cache as Cache +import Data.Hashable (Hashable) +import Data.Text (Text) cacheRequest :: (Monad m, MonadIO m, Hashable k) => Cache.Cache k v -> k -> m v -> m v diff --git a/govtool/backend/src/VVA/CommandLine.hs b/govtool/backend/src/VVA/CommandLine.hs index 82d28082a..49e9ab94f 100644 --- a/govtool/backend/src/VVA/CommandLine.hs +++ b/govtool/backend/src/VVA/CommandLine.hs @@ -1,18 +1,18 @@ module VVA.CommandLine - ( cmdParser, - CommandLineConfig (..), - Command (..), - ) -where + ( Command (..) + , CommandLineConfig (..) + , cmdParser + ) where -import Options.Applicative +import Options.Applicative data Command = StartApp | ShowConfig deriving (Show) -data CommandLineConfig = CommandLineConfig - { clcConfigPath :: Maybe FilePath, - clcCommand :: Command - } +data CommandLineConfig + = CommandLineConfig + { clcConfigPath :: Maybe FilePath + , clcCommand :: Command + } deriving (Show) cmdParser :: ParserInfo CommandLineConfig diff --git a/govtool/backend/src/VVA/Config.hs b/govtool/backend/src/VVA/Config.hs index 03d0bdd48..7055c33ed 100644 --- a/govtool/backend/src/VVA/Config.hs +++ b/govtool/backend/src/VVA/Config.hs @@ -1,15 +1,12 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE GADTs #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE PolyKinds #-} -{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE PolyKinds #-} +{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeOperators #-} -- | Module : VVA.Config -- Description : Configuration interface @@ -19,65 +16,70 @@ -- configuration backend (Conferer) and ensures that the provided configuration -- is valid and satisfies required invariants. module VVA.Config - ( -- * Data types and basic functions - VVAConfig (..), - loadVVAConfig, - - -- * Data type conversions - vvaConfigToText, - getDbSyncConnectionString, - getServerPort, - getServerHost, - ) -where - -import Conferer -import qualified Conferer.Source.Aeson as JSON -import qualified Conferer.Source.Env as Env -import Control.Monad.Reader -import Data.Aeson + ( -- * Data types and basic functions + VVAConfig (..) + , loadVVAConfig + -- * Data type conversions + , getDbSyncConnectionString + , getServerHost + , getServerPort + , vvaConfigToText + ) where + +import Conferer +import qualified Conferer.Source.Aeson as JSON +import qualified Conferer.Source.Env as Env + +import Control.Monad.Reader + +import Data.Aeson import qualified Data.Aeson.Encode.Pretty as AP -import Data.ByteString (ByteString, toStrict) -import Data.Maybe (fromMaybe) -import Data.Text (Text) -import qualified Data.Text as Text -import Data.Text.Encoding (decodeUtf8, encodeUtf8) -import GHC.Generics -import VVA.CommandLine (CommandLineConfig (..), clcConfigPath) -import Data.Has (Has, getter) +import Data.ByteString (ByteString, toStrict) +import Data.Has (Has, getter) +import Data.Maybe (fromMaybe) +import Data.Text (Text) +import qualified Data.Text as Text +import Data.Text.Encoding (decodeUtf8, encodeUtf8) + +import GHC.Generics + +import VVA.CommandLine (CommandLineConfig (..), + clcConfigPath) -- | PostgreSQL database access information. -data DBConfig = DBConfig - { -- | URL of host running the database - dBConfigHost :: Text, - -- | Database name - dBConfigDbname :: Text, - -- | User name - dBConfigUser :: Text, - -- | Database password - dBConfigPassword :: Text, - -- | Port - dBConfigPort :: Int - } - deriving (Generic, Show, FromConfig) +data DBConfig + = DBConfig + { -- | URL of host running the database + dBConfigHost :: Text + -- | Database name + , dBConfigDbname :: Text + -- | User name + , dBConfigUser :: Text + -- | Database password + , dBConfigPassword :: Text + -- | Port + , dBConfigPort :: Int + } + deriving (FromConfig, Generic, Show) instance DefaultConfig DBConfig where configDef = DBConfig "localhost" "cexplorer" "postgres" "test" 9903 -- | Internal, backend-dependent representation of configuration for DEX. This -- data type should not be exported from this module. -data VVAConfigInternal = VVAConfigInternal - { -- | db-sync database access. - vVAConfigInternalDbsyncconfig :: DBConfig, - -- | Server port. - vVAConfigInternalPort :: Int, - -- | Server host. - vVAConfigInternalHost :: Text, - -- | Request cache duration - vVaConfigInternalCacheDurationSeconds :: Int, - -- | Sentry DSN - vVAConfigInternalSentrydsn :: String - } - deriving (Generic, Show, FromConfig) +data VVAConfigInternal + = VVAConfigInternal + { -- | db-sync database access. + vVAConfigInternalDbsyncconfig :: DBConfig + -- | Server port. + , vVAConfigInternalPort :: Int + -- | Server host. + , vVAConfigInternalHost :: Text + -- | Request cache duration + , vVaConfigInternalCacheDurationSeconds :: Int + -- | Sentry DSN + , vVAConfigInternalSentrydsn :: String + } + deriving (FromConfig, Generic, Show) instance DefaultConfig VVAConfigInternal where configDef = @@ -90,19 +92,20 @@ instance DefaultConfig VVAConfigInternal where } -- | DEX configuration. -data VVAConfig = VVAConfig - { -- | db-sync database credentials. - dbSyncConnectionString :: Text, - -- | Server port. - serverPort :: Int, - -- | Server host. - serverHost :: Text, - -- | Request cache duration - cacheDurationSeconds :: Int, - -- | Sentry DSN - sentryDSN :: String - } - deriving (Generic, ToJSON, Show) +data VVAConfig + = VVAConfig + { -- | db-sync database credentials. + dbSyncConnectionString :: Text + -- | Server port. + , serverPort :: Int + -- | Server host. + , serverHost :: Text + -- | Request cache duration + , cacheDurationSeconds :: Int + -- | Sentry DSN + , sentryDSN :: String + } + deriving (Generic, Show, ToJSON) -- | Convert 'DBConfig' to a string required by PostgreSQL backend. dbConfigToText :: DBConfig -> Text @@ -165,7 +168,7 @@ loadVVAConfig configFile = do getDbSyncConnectionString :: (Has VVAConfig r, MonadReader r m) => m ByteString -getDbSyncConnectionString = encodeUtf8 <$> asks (dbSyncConnectionString . getter) +getDbSyncConnectionString = asks (encodeUtf8 . dbSyncConnectionString . getter) -- | Access server port. getServerPort :: diff --git a/govtool/backend/src/VVA/DRep.hs b/govtool/backend/src/VVA/DRep.hs index eba8dd9cc..52008a2cd 100644 --- a/govtool/backend/src/VVA/DRep.hs +++ b/govtool/backend/src/VVA/DRep.hs @@ -1,42 +1,38 @@ -{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} module VVA.DRep where -import Control.Monad.Except (MonadError) -import Control.Monad.Reader -import Crypto.Hash -import Data.Maybe (fromMaybe) -import Data.ByteString (ByteString) -import qualified Data.ByteString.Base16 as Base16 -import qualified Data.ByteString.Char8 as C -import Data.FileEmbed (embedFile) -import qualified Data.Map as M -import Data.Scientific -import Data.String (fromString) -import Data.Text (Text, unpack, pack) -import qualified Data.Text.Encoding as Text -import qualified Database.PostgreSQL.Simple as SQL -import VVA.Config -import qualified VVA.Proposal as Proposal -import Data.Foldable (Foldable(sum)) -import Data.Has (Has) -import VVA.Pool (ConnectionPool, withPool) -import VVA.Types - ( AppError - , DRepRegistration(..) - , Proposal(..) - , Vote(..) - , DRepInfo(..) - , DRepType(..) - , DRepStatus(..) - ) +import Control.Monad.Except (MonadError) +import Control.Monad.Reader + +import Crypto.Hash +import Data.ByteString (ByteString) +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 Data.Maybe (fromMaybe, isJust, isNothing) +import Data.Scientific +import Data.String (fromString) +import Data.Text (Text, pack, unpack) +import qualified Data.Text.Encoding as Text +import qualified Database.PostgreSQL.Simple as SQL +import VVA.Config +import VVA.Pool (ConnectionPool, withPool) +import qualified VVA.Proposal as Proposal +import VVA.Types (AppError, DRepInfo (..), + DRepRegistration (..), + DRepStatus (..), DRepType (..), + Proposal (..), Vote (..)) sqlFrom :: ByteString -> SQL.Query sqlFrom bs = fromString $ unpack $ Text.decodeUtf8 bs @@ -69,9 +65,9 @@ listDReps = withPool $ \conn -> do (_, d) | d < 0 -> Retired (isActive, d) | d >= 0 && isActive -> Active | d >= 0 && not isActive -> Inactive - , let drepType | url == Nothing && wasDRep = DRep - | url == Nothing && not wasDRep = SoleVoter - | url /= Nothing = DRep + , let drepType | isNothing url && wasDRep = DRep + | isNothing url && not wasDRep = SoleVoter + | Data.Maybe.isJust url = DRep ] getVotesSql :: SQL.Query diff --git a/govtool/backend/src/VVA/Epoch.hs b/govtool/backend/src/VVA/Epoch.hs index f29819038..9c48db028 100644 --- a/govtool/backend/src/VVA/Epoch.hs +++ b/govtool/backend/src/VVA/Epoch.hs @@ -1,22 +1,24 @@ +{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE TemplateHaskell #-} module VVA.Epoch where +import Control.Monad.Except (MonadError, throwError) +import Control.Monad.Reader + +import Data.Aeson (Value) +import Data.ByteString (ByteString) +import Data.FileEmbed (embedFile) +import Data.Has (Has) +import Data.String (fromString) +import Data.Text (Text, unpack) +import qualified Data.Text.Encoding as Text -import Data.ByteString (ByteString) -import Control.Monad.Except (MonadError, throwError) -import Control.Monad.Reader -import Data.FileEmbed (embedFile) -import Data.Text (Text, unpack) -import Data.String (fromString) -import qualified Data.Text.Encoding as Text import qualified Database.PostgreSQL.Simple as SQL -import VVA.Config -import Data.Aeson (Value) -import Data.Has (Has) -import VVA.Pool (ConnectionPool, withPool) + +import VVA.Config +import VVA.Pool (ConnectionPool, withPool) sqlFrom :: ByteString -> SQL.Query sqlFrom bs = fromString $ unpack $ Text.decodeUtf8 bs @@ -30,5 +32,5 @@ getCurrentEpochParams :: getCurrentEpochParams = withPool $ \conn -> do result <- liftIO $ SQL.query_ conn getCurrentEpochParamsSql case result of - [] -> return Nothing + [] -> return Nothing (SQL.Only params:_) -> return $ Just params diff --git a/govtool/backend/src/VVA/Network.hs b/govtool/backend/src/VVA/Network.hs index a76be9452..2329c689e 100644 --- a/govtool/backend/src/VVA/Network.hs +++ b/govtool/backend/src/VVA/Network.hs @@ -1,24 +1,26 @@ +{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE TemplateHaskell #-} module VVA.Network where +import Control.Monad.Except (MonadError, throwError) +import Control.Monad.Reader + +import Data.Aeson (Value) +import Data.ByteString (ByteString) +import Data.FileEmbed (embedFile) +import Data.Has (Has) +import Data.String (fromString) +import Data.Text (Text, unpack) +import qualified Data.Text.Encoding as Text +import Data.Time.Clock -import Data.ByteString (ByteString) -import Control.Monad.Except (MonadError, throwError) -import Control.Monad.Reader -import Data.FileEmbed (embedFile) -import Data.Text (Text, unpack) -import Data.String (fromString) -import qualified Data.Text.Encoding as Text import qualified Database.PostgreSQL.Simple as SQL -import VVA.Config -import Data.Aeson (Value) -import Data.Has (Has) -import VVA.Pool (ConnectionPool, withPool) -import VVA.Types -import Data.Time.Clock + +import VVA.Config +import VVA.Pool (ConnectionPool, withPool) +import VVA.Types sqlFrom :: ByteString -> SQL.Query sqlFrom bs = fromString $ unpack $ Text.decodeUtf8 bs @@ -31,7 +33,7 @@ networkMetrics :: m NetworkMetrics networkMetrics = withPool $ \conn -> do result <- liftIO $ SQL.query_ conn networkMetricsSql - current_time <- liftIO $ getCurrentTime + current_time <- liftIO getCurrentTime case result of [( epoch_no , block_no diff --git a/govtool/backend/src/VVA/Pool.hs b/govtool/backend/src/VVA/Pool.hs index 78da9a14e..0431d596b 100644 --- a/govtool/backend/src/VVA/Pool.hs +++ b/govtool/backend/src/VVA/Pool.hs @@ -1,11 +1,14 @@ {-# LANGUAGE FlexibleContexts #-} + module VVA.Pool where -import Data.Has (Has, getter) -import Data.Pool (Pool, takeResource, putResource) -import Database.PostgreSQL.Simple (Connection) -import Control.Monad.Reader (MonadReader, asks) -import Control.Monad.IO.Class (MonadIO, liftIO) +import Control.Monad.IO.Class (MonadIO, liftIO) +import Control.Monad.Reader (MonadReader, asks) + +import Data.Has (Has, getter) +import Data.Pool (Pool, putResource, takeResource) + +import Database.PostgreSQL.Simple (Connection) type ConnectionPool = Pool Connection diff --git a/govtool/backend/src/VVA/Proposal.hs b/govtool/backend/src/VVA/Proposal.hs index 9ba29ea25..e2c949992 100644 --- a/govtool/backend/src/VVA/Proposal.hs +++ b/govtool/backend/src/VVA/Proposal.hs @@ -1,39 +1,41 @@ -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} module VVA.Proposal where -import Control.Monad.Except (MonadError, throwError) -import Control.Monad.Reader -import Data.ByteString (ByteString) -import Data.FileEmbed (embedFile) -import Data.Foldable (fold) -import qualified Data.Map as Map -import Data.Maybe (fromMaybe) -import Data.Monoid (Sum (..), getSum) -import Data.Scientific -import Data.String (fromString) -import Data.Text (Text, unpack, pack) -import qualified Data.Text.Encoding as Text -import qualified Data.Text.IO as Text -import Data.Time +import Control.Exception (throw) +import Control.Monad.Except (MonadError, throwError) +import Control.Monad.Reader + +import Data.Aeson +import Data.Aeson.Types (Parser, parseMaybe) +import Data.ByteString (ByteString) +import Data.FileEmbed (embedFile) +import Data.Foldable (fold) +import Data.Has (Has) +import qualified Data.Map as Map +import Data.Maybe (fromMaybe) +import Data.Monoid (Sum (..), getSum) +import Data.Scientific +import Data.String (fromString) +import Data.Text (Text, pack, unpack) +import qualified Data.Text.Encoding as Text +import qualified Data.Text.IO as Text +import Data.Time + import qualified Database.PostgreSQL.Simple as SQL -import qualified GHC.Generics as SQL -import VVA.Config -import Data.Aeson (Value) -import Text.Read (readMaybe) -import Data.Has (Has) -import VVA.Pool (ConnectionPool, withPool) -import Control.Exception (throw) -import VVA.Types (Proposal(..), AppError(..)) -import Data.Aeson -import Data.Aeson.Types (parseMaybe, Parser) -import Data.Text (Text) +import qualified GHC.Generics as SQL + +import Text.Read (readMaybe) + +import VVA.Config +import VVA.Pool (ConnectionPool, withPool) +import VVA.Types (AppError (..), Proposal (..)) sqlFrom :: ByteString -> SQL.Query sqlFrom bs = fromString $ unpack $ Text.decodeUtf8 bs @@ -58,7 +60,6 @@ getProposal txHash index = do [a] -> return a _ -> throwError $ CriticalError ("Multiple proposal found for id: " <> txHash <> "#" <> pack (show index) <> ". This should never happen") - getProposals :: (Has ConnectionPool r, Has VVAConfig r, MonadReader r m, MonadIO m, MonadFail m, MonadError AppError m) => Maybe [Text] -> diff --git a/govtool/backend/src/VVA/Transaction.hs b/govtool/backend/src/VVA/Transaction.hs index fda9c4c35..73ebc594a 100644 --- a/govtool/backend/src/VVA/Transaction.hs +++ b/govtool/backend/src/VVA/Transaction.hs @@ -1,29 +1,31 @@ +{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE TemplateHaskell #-} module VVA.Transaction where +import Control.Exception (throw) +import Control.Monad.Except (MonadError, throwError) +import Control.Monad.Reader + +import Data.Aeson (Value) +import Data.ByteString (ByteString) +import Data.FileEmbed (embedFile) +import Data.Has (Has) +import Data.String (fromString) +import Data.Text (Text, pack, unpack) +import qualified Data.Text.Encoding as Text -import Data.ByteString (ByteString) -import Control.Monad.Except (MonadError, throwError) -import Control.Monad.Reader -import Data.FileEmbed (embedFile) -import Data.Text (Text, unpack, pack) -import Data.String (fromString) -import qualified Data.Text.Encoding as Text import qualified Database.PostgreSQL.Simple as SQL -import VVA.Config -import Data.Aeson (Value) -import Data.Has (Has) -import VVA.Pool (ConnectionPool, withPool) -import VVA.Types (TransactionStatus(..), AppError(..)) -import Control.Exception (throw) + +import VVA.Config +import VVA.Pool (ConnectionPool, withPool) +import VVA.Types (AppError (..), + TransactionStatus (..)) sqlFrom :: ByteString -> SQL.Query sqlFrom bs = fromString $ unpack $ Text.decodeUtf8 bs - getTransactionStatusSql :: SQL.Query getTransactionStatusSql = sqlFrom $(embedFile "sql/get-transaction-status.sql") diff --git a/govtool/backend/src/VVA/Types.hs b/govtool/backend/src/VVA/Types.hs index 37d522b67..a741489be 100644 --- a/govtool/backend/src/VVA/Types.hs +++ b/govtool/backend/src/VVA/Types.hs @@ -1,33 +1,37 @@ -{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE ConstraintKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE ConstraintKinds #-} -{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NamedFieldPuns #-} module VVA.Types where -import Data.Text (Text) -import Control.Exception -import Control.Monad.IO.Class (MonadIO) -import Control.Monad.Reader (MonadReader) -import Control.Monad.Fail (MonadFail) -import Control.Monad.Except (MonadError) -import VVA.Config -import VVA.Cache -import Data.Has -import Data.Pool (Pool) -import Database.PostgreSQL.Simple (Connection) -import Data.Aeson (Value) -import Data.Time (UTCTime) -import qualified Data.Cache as Cache +import Control.Exception +import Control.Monad.Except (MonadError) +import Control.Monad.Fail (MonadFail) +import Control.Monad.IO.Class (MonadIO) +import Control.Monad.Reader (MonadReader) + +import Data.Aeson (Value) +import qualified Data.Cache as Cache +import Data.Has +import Data.Pool (Pool) +import Data.Text (Text) +import Data.Time (UTCTime) + +import Database.PostgreSQL.Simple (Connection) + +import VVA.Cache +import VVA.Config type App m = (MonadReader AppEnv m, MonadIO m, MonadFail m, MonadError AppError m) -data AppEnv = AppEnv - { vvaConfig :: VVAConfig - , vvaCache :: CacheEnv - , vvaConnectionPool :: Pool Connection - } +data AppEnv + = AppEnv + { vvaConfig :: VVAConfig + , vvaCache :: CacheEnv + , vvaConnectionPool :: Pool Connection + } instance Has VVAConfig AppEnv where getter AppEnv {vvaConfig} = vvaConfig @@ -42,103 +46,100 @@ instance Has (Pool Connection) AppEnv where modifier f a@AppEnv {vvaConnectionPool} = a {vvaConnectionPool = f vvaConnectionPool} data AppError - = ValidationError Text - | NotFoundError Text - | CriticalError Text - deriving Show - + = ValidationError Text + | NotFoundError Text + | CriticalError Text + deriving (Show) instance Exception AppError -data Vote = Vote - { voteProposalId :: Integer, - voteDrepId :: Text, - voteVote :: Text, - voteUrl :: Maybe Text, - voteDocHash :: Maybe Text - } - -data DRepInfo = DRepInfo - { dRepInfoIsRegisteredAsDRep :: Bool - , dRepInfoWasRegisteredAsDRep :: Bool - , dRepInfoIsRegisteredAsSoleVoter :: Bool - , dRepInfoWasRegisteredAsSoleVoter :: Bool - , dRepInfoDeposit :: Maybe Integer - , dRepInfoUrl :: Maybe Text - , dRepInfoDataHash :: Maybe Text - , dRepInfoVotingPower :: Maybe Integer - } - -data DRepStatus - = Retired - | Active - | Inactive - -data DRepType - = DRep - | SoleVoter - -data DRepRegistration = DRepRegistration - { dRepRegistrationDRepHash :: Text - , dRepRegistrationView :: Text - , dRepRegistrationUrl :: Maybe Text - , dRepRegistrationDataHash :: Maybe Text - , dRepRegistrationDeposit :: Integer - , dRepRegistrationVotingPower :: Maybe Integer - , dRepRegistrationStatus :: DRepStatus - , dRepRegistrationType :: DRepType - } - -data Proposal = Proposal - { proposalId :: Integer, - proposalTxHash :: Text, - proposalIndex :: Integer, - proposalType :: Text, - proposalDetails :: Maybe Value, - proposalExpiryDate :: Maybe UTCTime, - proposalExpiryEpochNo :: Maybe Integer, - proposalCreatedDate :: UTCTime, - proposalCreatedEpochNo :: Integer, - proposalUrl :: Text, - proposalDocHash :: Text, - proposalTitle :: Maybe Text, - proposalAbout :: Maybe Text, - proposalMotivaiton :: Maybe Text, - proposalRationale :: Maybe Text, - proposalMetadata :: Maybe Value, - proposalYesVotes :: Integer, - proposalNoVotes :: Integer, - proposalAbstainVotes :: Integer - } deriving (Show) - - - -data TransactionStatus - = TransactionConfirmed - | TransactionUnconfirmed - -data CacheEnv = CacheEnv - { proposalListCache :: Cache.Cache () [Proposal] - , getProposalCache :: Cache.Cache (Text, Integer) Proposal - , currentEpochCache :: Cache.Cache () (Maybe Value) - , adaHolderVotingPowerCache :: Cache.Cache Text Integer - , adaHolderGetCurrentDelegationCache :: Cache.Cache Text (Maybe Text) - , dRepGetVotesCache :: Cache.Cache Text ([Vote], [Proposal]) - , dRepInfoCache :: Cache.Cache Text DRepInfo - , dRepVotingPowerCache :: Cache.Cache Text Integer - , dRepListCache :: Cache.Cache () [DRepRegistration] - , networkMetricsCache :: Cache.Cache () NetworkMetrics - } - -data NetworkMetrics = NetworkMetrics - { networkMetricsCurrentTime :: UTCTime - , networkMetricsCurrentEpoch :: Integer - , networkMetricsCurrentBlock :: Integer - , networkMetricsUniqueDelegators :: Integer - , networkMetricsTotalDelegations :: Integer - , networkMetricsTotalGovernanceActions :: Integer - , networkMetricsTotalDRepVotes :: Integer - , networkMetricsTotalRegisteredDReps :: Integer - , networkMetricsAlwaysAbstainVotingPower :: Integer - , networkMetricsAlwaysNoConfidenceVotingPower :: Integer - } +data Vote + = Vote + { voteProposalId :: Integer + , voteDrepId :: Text + , voteVote :: Text + , voteUrl :: Maybe Text + , voteDocHash :: Maybe Text + } + +data DRepInfo + = DRepInfo + { dRepInfoIsRegisteredAsDRep :: Bool + , dRepInfoWasRegisteredAsDRep :: Bool + , dRepInfoIsRegisteredAsSoleVoter :: Bool + , dRepInfoWasRegisteredAsSoleVoter :: Bool + , dRepInfoDeposit :: Maybe Integer + , dRepInfoUrl :: Maybe Text + , dRepInfoDataHash :: Maybe Text + , dRepInfoVotingPower :: Maybe Integer + } + +data DRepStatus = Retired | Active | Inactive + +data DRepType = DRep | SoleVoter + +data DRepRegistration + = DRepRegistration + { dRepRegistrationDRepHash :: Text + , dRepRegistrationView :: Text + , dRepRegistrationUrl :: Maybe Text + , dRepRegistrationDataHash :: Maybe Text + , dRepRegistrationDeposit :: Integer + , dRepRegistrationVotingPower :: Maybe Integer + , dRepRegistrationStatus :: DRepStatus + , dRepRegistrationType :: DRepType + } + +data Proposal + = Proposal + { proposalId :: Integer + , proposalTxHash :: Text + , proposalIndex :: Integer + , proposalType :: Text + , proposalDetails :: Maybe Value + , proposalExpiryDate :: Maybe UTCTime + , proposalExpiryEpochNo :: Maybe Integer + , proposalCreatedDate :: UTCTime + , proposalCreatedEpochNo :: Integer + , proposalUrl :: Text + , proposalDocHash :: Text + , proposalTitle :: Maybe Text + , proposalAbout :: Maybe Text + , proposalMotivaiton :: Maybe Text + , proposalRationale :: Maybe Text + , proposalMetadata :: Maybe Value + , proposalYesVotes :: Integer + , proposalNoVotes :: Integer + , proposalAbstainVotes :: Integer + } + deriving (Show) + +data TransactionStatus = TransactionConfirmed | TransactionUnconfirmed + +data CacheEnv + = CacheEnv + { proposalListCache :: Cache.Cache () [Proposal] + , getProposalCache :: Cache.Cache (Text, Integer) Proposal + , currentEpochCache :: Cache.Cache () (Maybe Value) + , adaHolderVotingPowerCache :: Cache.Cache Text Integer + , adaHolderGetCurrentDelegationCache :: Cache.Cache Text (Maybe Text) + , dRepGetVotesCache :: Cache.Cache Text ([Vote], [Proposal]) + , dRepInfoCache :: Cache.Cache Text DRepInfo + , dRepVotingPowerCache :: Cache.Cache Text Integer + , dRepListCache :: Cache.Cache () [DRepRegistration] + , networkMetricsCache :: Cache.Cache () NetworkMetrics + } + +data NetworkMetrics + = NetworkMetrics + { networkMetricsCurrentTime :: UTCTime + , networkMetricsCurrentEpoch :: Integer + , networkMetricsCurrentBlock :: Integer + , networkMetricsUniqueDelegators :: Integer + , networkMetricsTotalDelegations :: Integer + , networkMetricsTotalGovernanceActions :: Integer + , networkMetricsTotalDRepVotes :: Integer + , networkMetricsTotalRegisteredDReps :: Integer + , networkMetricsAlwaysAbstainVotingPower :: Integer + , networkMetricsAlwaysNoConfidenceVotingPower :: Integer + }