Commit 178d4434 authored by Alexandre Delanoë's avatar Alexandre Delanoë
parents e62237a1 e42e053f
...@@ -30,6 +30,8 @@ Thanks @yannEsposito for this. ...@@ -30,6 +30,8 @@ Thanks @yannEsposito for this.
{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeOperators #-}
{-# LANGUAGE KindSignatures #-} {-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE UndecidableInstances #-}
...@@ -45,14 +47,16 @@ import GHC.TypeLits (AppendSymbol, Symbol) ...@@ -45,14 +47,16 @@ import GHC.TypeLits (AppendSymbol, Symbol)
import Control.Lens import Control.Lens
import Control.Exception (finally) import Control.Exception (finally)
import Control.Monad.Except (withExceptT, ExceptT)
import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Class (liftIO)
import Control.Monad.Reader (runReaderT) import Control.Monad.Reader (ReaderT, runReaderT)
import Data.Aeson.Encode.Pretty (encodePretty) import Data.Aeson.Encode.Pretty (encodePretty)
import qualified Data.ByteString.Lazy.Char8 as BL8 import qualified Data.ByteString.Lazy.Char8 as BL8
import Data.Swagger import Data.Swagger
import Data.Text (Text) import Data.Text (Text)
import qualified Data.Text.IO as T import qualified Data.Text.IO as T
--import qualified Data.Set as Set --import qualified Data.Set as Set
import Data.Validity
import Network.Wai import Network.Wai
import Network.Wai.Handler.Warp hiding (defaultSettings) import Network.Wai.Handler.Warp hiding (defaultSettings)
...@@ -70,6 +74,7 @@ import Text.Blaze.Html (Html) ...@@ -70,6 +74,7 @@ import Text.Blaze.Html (Html)
--import Gargantext.API.Swagger --import Gargantext.API.Swagger
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Core.Types (HasInvalidError(..))
import Gargantext.API.FrontEnd (FrontEndAPI, frontEndServer) import Gargantext.API.FrontEnd (FrontEndAPI, frontEndServer)
import Gargantext.API.Auth (AuthRequest, AuthResponse, auth) import Gargantext.API.Auth (AuthRequest, AuthResponse, auth)
...@@ -84,8 +89,10 @@ import Gargantext.API.Node ( GargServer ...@@ -84,8 +89,10 @@ import Gargantext.API.Node ( GargServer
, HyperdataCorpus , HyperdataCorpus
, HyperdataAnnuaire , HyperdataAnnuaire
) )
import Gargantext.Database.Schema.Node (HasNodeError(..), NodeError)
--import Gargantext.Database.Node.Contact (HyperdataContact) --import Gargantext.Database.Node.Contact (HyperdataContact)
import Gargantext.Database.Utils (HasConnection) import Gargantext.Database.Utils (HasConnection)
import Gargantext.Database.Tree (HasTreeError(..), TreeError)
import Gargantext.Database.Types.Node (NodeId, CorpusId, AnnuaireId) import Gargantext.Database.Types.Node (NodeId, CorpusId, AnnuaireId)
import Gargantext.API.Count ( CountAPI, count, Query) import Gargantext.API.Count ( CountAPI, count, Query)
import Gargantext.API.Search ( SearchAPI, search, SearchQuery) import Gargantext.API.Search ( SearchAPI, search, SearchQuery)
...@@ -115,6 +122,26 @@ import Network.HTTP.Types hiding (Query) ...@@ -115,6 +122,26 @@ import Network.HTTP.Types hiding (Query)
import Gargantext.API.Settings import Gargantext.API.Settings
data GargError
= GargNodeError NodeError
| GargTreeError TreeError
| GargInvalidError Validation
deriving (Show)
makePrisms ''GargError
instance HasNodeError GargError where
_NodeError = _GargNodeError
instance HasInvalidError GargError where
_InvalidError = _GargInvalidError
instance HasTreeError GargError where
_TreeError = _GargTreeError
showAsServantErr :: Show a => a -> ServantErr
showAsServantErr a = err500 { errBody = BL8.pack $ show a }
fireWall :: Applicative f => Request -> FireWall -> f Bool fireWall :: Applicative f => Request -> FireWall -> f Bool
fireWall req fw = do fireWall req fw = do
let origin = lookup "Origin" (requestHeaders req) let origin = lookup "Origin" (requestHeaders req)
...@@ -278,13 +305,16 @@ type API = SwaggerFrontAPI :<|> GargAPI :<|> Get '[HTML] Html ...@@ -278,13 +305,16 @@ type API = SwaggerFrontAPI :<|> GargAPI :<|> Get '[HTML] Html
--------------------------------------------------------------------- ---------------------------------------------------------------------
-- | Server declarations -- | Server declarations
server :: (HasConnection env, HasRepo env, HasSettings env) server :: forall env. (HasConnection env, HasRepo env, HasSettings env)
=> env -> IO (Server API) => env -> IO (Server API)
server env = do server env = do
-- orchestrator <- scrapyOrchestrator env -- orchestrator <- scrapyOrchestrator env
pure $ swaggerFront pure $ swaggerFront
:<|> hoistServer (Proxy :: Proxy GargAPI) (`runReaderT` env) serverGargAPI :<|> hoistServer (Proxy :: Proxy GargAPI) transform serverGargAPI
:<|> serverStatic :<|> serverStatic
where
transform :: forall a. ReaderT env (ExceptT GargError IO) a -> Handler a
transform = Handler . withExceptT showAsServantErr . (`runReaderT` env)
serverGargAPI :: GargServer GargAPI serverGargAPI :: GargServer GargAPI
serverGargAPI -- orchestrator serverGargAPI -- orchestrator
......
...@@ -37,7 +37,6 @@ module Gargantext.API.Ngrams ...@@ -37,7 +37,6 @@ module Gargantext.API.Ngrams
-- import Debug.Trace (trace) -- import Debug.Trace (trace)
import Prelude (Enum, Bounded, Semigroup(..), minBound, maxBound {-, round-}, error) import Prelude (Enum, Bounded, Semigroup(..), minBound, maxBound {-, round-}, error)
-- import Gargantext.Database.Schema.User (UserId) -- import Gargantext.Database.Schema.User (UserId)
import Data.Functor (($>))
import Data.Patch.Class (Replace, replace, Action(act), Applicable(..), import Data.Patch.Class (Replace, replace, Action(act), Applicable(..),
Composable(..), Transformable(..), Composable(..), Transformable(..),
PairPatch(..), Patched, ConflictResolution, PairPatch(..), Patched, ConflictResolution,
...@@ -55,9 +54,8 @@ import Data.Map.Strict (Map) ...@@ -55,9 +54,8 @@ import Data.Map.Strict (Map)
import qualified Data.Set as Set import qualified Data.Set as Set
import Control.Category ((>>>)) import Control.Category ((>>>))
import Control.Concurrent import Control.Concurrent
import Control.Lens (makeLenses, makePrisms, Getter, Prism', prism', Iso', iso, from, (.~), (?=), (#), to, folded, {-withIndex, ifolded,-} view, use, (^.), (^..), (^?), (+~), (%~), (%=), sumOf, at, _Just, Each(..), itraverse_, both, mapped, forOf_) import Control.Lens (makeLenses, makePrisms, Getter, Iso', iso, from, (.~), (?=), (#), to, folded, {-withIndex, ifolded,-} view, use, (^.), (^..), (^?), (+~), (%~), (%=), sumOf, at, _Just, Each(..), itraverse_, both, mapped, forOf_)
import Control.Monad (guard) import Control.Monad.Error.Class (MonadError)
import Control.Monad.Error.Class (MonadError, throwError)
import Control.Monad.Reader import Control.Monad.Reader
import Control.Monad.State import Control.Monad.State
import Data.Aeson hiding ((.=)) import Data.Aeson hiding ((.=))
...@@ -82,7 +80,7 @@ import qualified Gargantext.Database.Schema.Ngrams as Ngrams ...@@ -82,7 +80,7 @@ import qualified Gargantext.Database.Schema.Ngrams as Ngrams
-- import Gargantext.Database.Schema.NodeNgram hiding (Action) -- import Gargantext.Database.Schema.NodeNgram hiding (Action)
import Gargantext.Prelude import Gargantext.Prelude
-- import Gargantext.Core.Types (ListTypeId, listTypeId) -- import Gargantext.Core.Types (ListTypeId, listTypeId)
import Gargantext.Core.Types (ListType(..), NodeId, ListId, CorpusId, Limit, Offset) import Gargantext.Core.Types (ListType(..), NodeId, ListId, CorpusId, Limit, Offset, HasInvalidError, assertValid)
import Servant hiding (Patch) import Servant hiding (Patch)
import System.FileLock (FileLock) import System.FileLock (FileLock)
import Test.QuickCheck (elements) import Test.QuickCheck (elements)
...@@ -622,22 +620,6 @@ type TableNgramsApi = Summary " Table Ngrams API Change" ...@@ -622,22 +620,6 @@ type TableNgramsApi = Summary " Table Ngrams API Change"
:> ReqBody '[JSON] (Versioned NgramsTablePatch) :> ReqBody '[JSON] (Versioned NgramsTablePatch)
:> Put '[JSON] (Versioned NgramsTablePatch) :> Put '[JSON] (Versioned NgramsTablePatch)
data NgramError = UnsupportedVersion
deriving (Show)
class HasNgramError e where
_NgramError :: Prism' e NgramError
instance HasNgramError ServantErr where
_NgramError = prism' make match
where
err = err500 { errBody = "NgramError: Unsupported version" }
make UnsupportedVersion = err
match e = guard (e == err) $> UnsupportedVersion
ngramError :: (MonadError e m, HasNgramError e) => NgramError -> m a
ngramError nne = throwError $ _NgramError # nne
{- {-
-- TODO: Replace.old is ignored which means that if the current list -- TODO: Replace.old is ignored which means that if the current list
-- `GraphTerm` and that the patch is `Replace CandidateTerm StopTerm` then -- `GraphTerm` and that the patch is `Replace CandidateTerm StopTerm` then
...@@ -670,6 +652,7 @@ ngramsTypeFromTabType tabType = ...@@ -670,6 +652,7 @@ ngramsTypeFromTabType tabType =
Institutes -> Ngrams.Institutes Institutes -> Ngrams.Institutes
Terms -> Ngrams.NgramsTerms Terms -> Ngrams.NgramsTerms
_ -> panic $ lieu <> "No Ngrams for this tab" _ -> panic $ lieu <> "No Ngrams for this tab"
-- ^ TODO: This `panic` would disapear with custom NgramsType.
------------------------------------------------------------------------ ------------------------------------------------------------------------
data Repo s p = Repo data Repo s p = Repo
...@@ -756,22 +739,6 @@ ngramsStatePatchConflictResolution _ngramsType _nodeId _ngramsTerm ...@@ -756,22 +739,6 @@ ngramsStatePatchConflictResolution _ngramsType _nodeId _ngramsTerm
= (const ours, ours) = (const ours, ours)
-- undefined {- TODO think this through -}, listTypeConflictResolution) -- undefined {- TODO think this through -}, listTypeConflictResolution)
class HasInvalidError e where
_InvalidError :: Prism' e Validation
instance HasInvalidError ServantErr where
_InvalidError = panic "error" {-prism' make match
where
err = err500 { errBody = "InvalidError" }
make _ = err
match e = guard (e == err) $> UnsupportedVersion-}
-- assertValid :: (MonadError e m, HasInvalidError e) => Validation -> m ()
-- assertValid v = when (not $ validationIsValid v) $ throwError $ _InvalidError # v
assertValid :: MonadIO m => Validation -> m ()
assertValid v = when (not $ validationIsValid v) $ fail $ show v
-- Current state: -- Current state:
-- Insertions are not considered as patches, -- Insertions are not considered as patches,
-- they do not extend history, -- they do not extend history,
...@@ -828,8 +795,7 @@ putListNgrams listId ngramsType nes = do ...@@ -828,8 +795,7 @@ putListNgrams listId ngramsType nes = do
-- Apply the given patch to the DB and returns the patch to be applied on the -- Apply the given patch to the DB and returns the patch to be applied on the
-- client. -- client.
tableNgramsPatch :: (HasNgramError err, HasInvalidError err, tableNgramsPatch :: (HasInvalidError err, RepoCmdM env err m)
RepoCmdM env err m)
=> CorpusId -> TabType -> ListId => CorpusId -> TabType -> ListId
-> Versioned NgramsTablePatch -> Versioned NgramsTablePatch
-> m (Versioned NgramsTablePatch) -> m (Versioned NgramsTablePatch)
...@@ -863,8 +829,17 @@ tableNgramsPatch _corpusId tabType listId (Versioned p_version p_table) ...@@ -863,8 +829,17 @@ tableNgramsPatch _corpusId tabType listId (Versioned p_version p_table)
& r_state %~ act p' & r_state %~ act p'
& r_history %~ (p' :) & r_history %~ (p' :)
q'_table = q' ^. _PatchMap . at ngramsType . _Just . _PatchMap . at listId . _Just q'_table = q' ^. _PatchMap . at ngramsType . _Just . _PatchMap . at listId . _Just
{-
-- Ideally we would like to check these properties. However:
-- * They should be checked only to debug the code. The client data
-- should be able to trigger these.
-- * What kind of error should they throw (we are in IO here)?
-- * Should we keep modifyMVar?
-- * Should we throw the validation in an Exception, catch it around
-- modifyMVar and throw it back as an Error?
assertValid $ transformable p q assertValid $ transformable p q
assertValid $ applicable p' (r ^. r_state) assertValid $ applicable p' (r ^. r_state)
-}
pure (r', Versioned (r' ^. r_version) q'_table) pure (r', Versioned (r' ^. r_version) q'_table)
saveRepo saveRepo
......
...@@ -44,7 +44,7 @@ import Gargantext.API.Metrics ...@@ -44,7 +44,7 @@ import Gargantext.API.Metrics
import Gargantext.API.Ngrams (TabType(..), TableNgramsApi, TableNgramsApiGet, tableNgramsPatch, getTableNgrams, HasRepo, QueryParamR) import Gargantext.API.Ngrams (TabType(..), TableNgramsApi, TableNgramsApiGet, tableNgramsPatch, getTableNgrams, HasRepo, QueryParamR)
import Gargantext.API.Ngrams.Tools import Gargantext.API.Ngrams.Tools
import Gargantext.API.Search ( SearchAPI, searchIn, SearchInQuery) import Gargantext.API.Search ( SearchAPI, searchIn, SearchInQuery)
import Gargantext.Core.Types (Offset, Limit, ListType(..)) import Gargantext.Core.Types (Offset, Limit, ListType(..), HasInvalidError)
import Gargantext.Core.Types.Main (Tree, NodeTree) import Gargantext.Core.Types.Main (Tree, NodeTree)
import Gargantext.Database.Facet (FacetDoc , runViewDocuments, OrderBy(..),FacetChart,runViewAuthorsDoc) import Gargantext.Database.Facet (FacetDoc , runViewDocuments, OrderBy(..),FacetChart,runViewAuthorsDoc)
import qualified Gargantext.Database.Metrics as Metrics import qualified Gargantext.Database.Metrics as Metrics
...@@ -74,11 +74,16 @@ import qualified Gargantext.Text.List.Learn as Learn ...@@ -74,11 +74,16 @@ import qualified Gargantext.Text.List.Learn as Learn
import qualified Data.Vector as Vec import qualified Data.Vector as Vec
--} --}
type GargServer api = forall env m. type GargServer api =
( CmdM env ServantErr m forall env err m.
, HasRepo env ( CmdM env err m
, HasNodeError err
, HasInvalidError err
, HasTreeError err
, HasRepo env
, HasSettings env , HasSettings env
) => ServerT api m )
=> ServerT api m
------------------------------------------------------------------- -------------------------------------------------------------------
-- TODO-ACCESS: access by admin only. -- TODO-ACCESS: access by admin only.
......
...@@ -20,9 +20,12 @@ module Gargantext.Core.Types ( module Gargantext.Core.Types.Main ...@@ -20,9 +20,12 @@ module Gargantext.Core.Types ( module Gargantext.Core.Types.Main
, Term, Terms(..) , Term, Terms(..)
, TokenTag(..), POS(..), NER(..) , TokenTag(..), POS(..), NER(..)
, Label, Stems , Label, Stems
, HasInvalidError(..), assertValid
) where ) where
import GHC.Generics import Control.Lens (Prism', (#))
import Control.Monad.Error.Class (MonadError, throwError)
import Data.Aeson import Data.Aeson
import Data.Semigroup import Data.Semigroup
import Data.Monoid import Data.Monoid
...@@ -30,11 +33,13 @@ import Data.Set (Set, empty) ...@@ -30,11 +33,13 @@ import Data.Set (Set, empty)
--import qualified Data.Set as S --import qualified Data.Set as S
import Data.Text (Text, unpack) import Data.Text (Text, unpack)
import Data.Validity
import Gargantext.Core.Types.Main import Gargantext.Core.Types.Main
import Gargantext.Database.Types.Node import Gargantext.Database.Types.Node
import Gargantext.Prelude import Gargantext.Prelude
import GHC.Generics
------------------------------------------------------------------------ ------------------------------------------------------------------------
type Term = Text type Term = Text
...@@ -120,3 +125,11 @@ instance Monoid TokenTag where ...@@ -120,3 +125,11 @@ instance Monoid TokenTag where
mconcat = foldl mappend mempty mconcat = foldl mappend mempty
class HasInvalidError e where
_InvalidError :: Prism' e Validation
assertValid :: (MonadError e m, HasInvalidError e) => Validation -> m ()
assertValid v = when (not $ validationIsValid v) $ throwError $ _InvalidError # v
-- assertValid :: MonadIO m => Validation -> m ()
-- assertValid v = when (not $ validationIsValid v) $ fail $ show v
...@@ -31,12 +31,11 @@ import Gargantext.Database.Flow (getOrMkRootWithCorpus) ...@@ -31,12 +31,11 @@ import Gargantext.Database.Flow (getOrMkRootWithCorpus)
import Gargantext.Database.Config (userMaster) import Gargantext.Database.Config (userMaster)
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Text.Metrics (scored, Scored(..), localMetrics, toScored) import Gargantext.Text.Metrics (scored, Scored(..), localMetrics, toScored)
import Servant (ServantErr)
import qualified Data.Map as Map import qualified Data.Map as Map
import qualified Data.Vector.Storable as Vec import qualified Data.Vector.Storable as Vec
getMetrics' :: FlowCmdM env ServantErr m getMetrics' :: FlowCmdM env err m
=> CorpusId -> Maybe ListId -> TabType -> Maybe Limit => CorpusId -> Maybe ListId -> TabType -> Maybe Limit
-> m (Map Text (ListType, Maybe Text), [Scored Text]) -> m (Map Text (ListType, Maybe Text), [Scored Text])
getMetrics' cId maybeListId tabType maybeLimit = do getMetrics' cId maybeListId tabType maybeLimit = do
...@@ -44,7 +43,7 @@ getMetrics' cId maybeListId tabType maybeLimit = do ...@@ -44,7 +43,7 @@ getMetrics' cId maybeListId tabType maybeLimit = do
pure (ngs, scored myCooc) pure (ngs, scored myCooc)
getMetrics :: FlowCmdM env ServantErr m getMetrics :: FlowCmdM env err m
=> CorpusId -> Maybe ListId -> TabType -> Maybe Limit => CorpusId -> Maybe ListId -> TabType -> Maybe Limit
-> m (Map Text (ListType, Maybe Text), [Scored Text]) -> m (Map Text (ListType, Maybe Text), [Scored Text])
getMetrics cId maybeListId tabType maybeLimit = do getMetrics cId maybeListId tabType maybeLimit = do
...@@ -57,7 +56,7 @@ getMetrics cId maybeListId tabType maybeLimit = do ...@@ -57,7 +56,7 @@ getMetrics cId maybeListId tabType maybeLimit = do
pure (ngs , toScored [metrics, Map.fromList $ map (\(a,b) -> (a, Vec.fromList [fst b])) $ Map.toList metrics']) pure (ngs , toScored [metrics, Map.fromList $ map (\(a,b) -> (a, Vec.fromList [fst b])) $ Map.toList metrics'])
getLocalMetrics :: (FlowCmdM env ServantErr m) getLocalMetrics :: (FlowCmdM env err m)
=> CorpusId -> Maybe ListId -> TabType -> Maybe Limit => CorpusId -> Maybe ListId -> TabType -> Maybe Limit
-> m ( Map Text (ListType, Maybe Text) -> m ( Map Text (ListType, Maybe Text)
, Map Text (Maybe RootTerm) , Map Text (Maybe RootTerm)
...@@ -68,7 +67,7 @@ getLocalMetrics cId maybeListId tabType maybeLimit = do ...@@ -68,7 +67,7 @@ getLocalMetrics cId maybeListId tabType maybeLimit = do
pure (ngs, ngs', localMetrics myCooc) pure (ngs, ngs', localMetrics myCooc)
getNgramsCooc :: (FlowCmdM env ServantErr m) getNgramsCooc :: (FlowCmdM env err m)
=> CorpusId -> Maybe ListId -> TabType -> Maybe Limit => CorpusId -> Maybe ListId -> TabType -> Maybe Limit
-> m ( Map Text (ListType, Maybe Text) -> m ( Map Text (ListType, Maybe Text)
, Map Text (Maybe RootTerm) , Map Text (Maybe RootTerm)
...@@ -89,7 +88,7 @@ getNgramsCooc cId maybeListId tabType maybeLimit = do ...@@ -89,7 +88,7 @@ getNgramsCooc cId maybeListId tabType maybeLimit = do
getNgrams :: (FlowCmdM env ServantErr m) getNgrams :: (FlowCmdM env err m)
=> CorpusId -> Maybe ListId -> TabType => CorpusId -> Maybe ListId -> TabType
-> m (Map Text (ListType, Maybe Text), Map Text (Maybe RootTerm)) -> m (Map Text (ListType, Maybe Text), Map Text (Maybe RootTerm))
getNgrams cId maybeListId tabType = do getNgrams cId maybeListId tabType = do
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment