Commit 4e20502b authored by Karen Konou's avatar Karen Konou

Merge branch 'dev' into 548-dev-node-url-share

parents 31abed19 f64be6b0
Pipeline #5993 failed with stages
in 120 minutes and 50 seconds
## Version 0.0.7.1 [RELEASE CANDIDATE 007]
* [FRONT][FIX][Fix breadcrumbs (#648)](https://gitlab.iscpif.fr/gargantext/purescript-gargantext/issues/648)
## Version 0.0.7
- [BACK/FRONT][RELEASE] OO7 Version
## Version 0.0.6.9.9.9.9.1 [RELEASE CANDIDATE 007]
* [FRONT][FIX][In Document View: show Institute field of the document (#629)](https://gitlab.iscpif.fr/gargantext/purescript-gargantext/issues/629)
* [BACK][FIX] Cabal optim
* [BACK][FIX][duckling fork (#319)](https://gitlab.iscpif.fr/gargantext/haskell-gargantext/issues/319)
* [BACK][FIX][haskell-opaleye fork (#317)](https://gitlab.iscpif.fr/gargantext/haskell-gargantext/issues/317)
* [BACK][FIX][[Node type/API GQL] Extend a little the node GQL query to have an extra "node_type" (or similar) so that we can extend the Purescript Node type with the value form the backend (#336)](https://gitlab.iscpif.fr/gargantext/haskell-gargantext/issues/336)
* [BACK][DOC][Welcome: Door To enter the project (#177)](https://gitlab.iscpif.fr/gargantext/haskell-gargantext/issues/177)
## Version 0.0.6.9.9.9.9 [RELEASE CANDIDATE 007]
* [FRONT][FIX][[Node Documents] In the settings popin, remove the upload button (and also delete button) (#634)](https://gitlab.iscpif.fr/gargantext/purescript-gargantext/issues/634)
* [FRONT][FIX] NoList Serialization
* [FRONT][FIX][[Fonts & CSS] Internalise external calls (initiated by alternative themes) (#626)](https://gitlab.iscpif.fr/gargantext/purescript-gargantext/issues/626)
* [BACK][FIX] Dev Prelude Refactoring
* [BACK][FIX][Test, file missing (#338)](https://gitlab.iscpif.fr/gargantext/haskell-gargantext/issues/338)
* [BACK][FIX][boolexpr has been fixed upstream (#315)](https://gitlab.iscpif.fr/gargantext/haskell-gargantext/issues/315)
* [BACK][FIX][[Node Corpus] Creating a corpus from an empty Notes node make a big document with HTML code instead of simple text (#333)](https://gitlab.iscpif.fr/gargantext/haskell-gargantext/issues/333)
* [BACK][FIX][Export Data as zip for all exports (#312)](https://gitlab.iscpif.fr/gargantext/haskell-gargantext/issues/312)
* [BACK][FIX][Sort by terms is not language-aware (#331)](https://gitlab.iscpif.fr/gargantext/haskell-gargantext/issues/331)
* [BACK][FIX][[API search] When an external service is down (HAL or other), display a message with a more explicit text (#335)](https://gitlab.iscpif.fr/gargantext/haskell-gargantext/issues/335)
## Version 0.0.6.9.9.9.8.1 [RELEASE CANDIDATE 007]
* [FRONT][FEAT][Make `esc` key close current popup window (#640)](https://gitlab.iscpif.fr/gargantext/purescript-gargantext/issues/640)
......
......@@ -11,15 +11,12 @@ Main specifications to index a corpus with a term list
-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE Strict #-}
module Main where
import Control.Concurrent.Async as CCA (mapConcurrently)
import Control.Monad.IO.Class
import Data.Aeson
import Data.Aeson ( ToJSON, encode )
import Data.List.Split (chunksOf)
import Data.Map.Strict qualified as DM
import Data.Text (pack)
......@@ -28,14 +25,12 @@ import Data.Text.Lazy qualified as DTL
import Data.Text.Lazy.Encoding qualified as TLE
import Data.Tuple.Extra (both)
import Data.Vector qualified as DV
import GHC.Generics
import Gargantext.Core.Text.Context
import Gargantext.Core.Text.Context (TermList)
import Gargantext.Core.Text.Corpus.Parsers.CSV (readCSVFile, csv_title, csv_abstract, csv_publication_year, fromMIntOrDec, defaultYear)
import Gargantext.Core.Text.List.Formats.CSV (csvMapTermList)
import Gargantext.Core.Text.Metrics.Count (coocOnContexts, Coocs)
import Gargantext.Core.Text.Terms.WithList
import Gargantext.Prelude hiding (show)
import Protolude
import Gargantext.Core.Text.Terms.WithList ( Patterns, buildPatterns, extractTermsWithList )
import Gargantext.Prelude
import System.IO (hFlush)
------------------------------------------------------------------------
......
......@@ -18,8 +18,8 @@ fi
# with the `sha256sum` result calculated on the `cabal.project` and
# `cabal.project.freeze`. This ensures the files stay deterministic so that CI
# cache can kick in.
expected_cabal_project_hash="96be39a29bab66851278db07974dc3c61e7f807aefc3a3e9d50a9eb269706ef0"
expected_cabal_project_freeze_hash="a88c2d091ee6223b64fb5dd38e71ab8379710a2aa716d2467f318789e4d75589"
expected_cabal_project_hash="0d3f7f5beed88c1afe95e0df8a91080440ba59049f3610bf2343132635038d22"
expected_cabal_project_freeze_hash="9b2cac3a02e9b129bd80253fc407782bf10c7ed62ed21be41c720d30ed17ef53"
cabal --store-dir=$STORE_DIR v2-build --dry-run
cabal2stack --system-ghc --allow-newer --resolver lts-21.17 --resolver-file devops/stack/lts-21.17.yaml -o stack.yaml
......
......@@ -3,6 +3,7 @@
index-state: 2023-12-10T10:34:46Z
with-compiler: ghc-9.4.7
optimization: 2
packages:
./
......@@ -19,20 +20,16 @@ source-repository-package
subdir: accelerate-llvm-native/
accelerate-llvm/
-- Patch for "Allow NOT to backtrack"
source-repository-package
type: git
location: https://github.com/adinapoli/boolexpr.git
tag: 91928b5d7f9342e9865dde0d94862792d2b88779
location: https://github.com/boolexpr/boolexpr.git
tag: bcd7cb20a1b1bc3b58c4ba1b6ae1bccfe62f67ae
source-repository-package
type: git
location: https://github.com/adinapoli/duckling.git
tag: 23603a832117e5352d5b0fb9bb1110228324b35a
source-repository-package
type: git
location: https://github.com/garganscript/haskell-opaleye.git
tag: 6cf1bcfe215143efac17919cfd0abdd60e0f717c
location: https://gitlab.iscpif.fr/gargantext/opaleye-textsearch.git
tag: cb07b604bfb7a22aa21dd8918de5cb65c8a4bdf1
source-repository-package
type: git
......@@ -41,11 +38,6 @@ source-repository-package
subdir: llvm-hs
llvm-hs-pure
source-repository-package
type: git
location: https://github.com/adinapoli/text16-compat.git
tag: 85533b5d597e6fc5498411b4bcfc76380ec80d71
source-repository-package
type: git
location: https://github.com/alpmestan/accelerate-arithmetic.git
......@@ -131,7 +123,8 @@ source-repository-package
source-repository-package
type: git
location: https://gitlab.iscpif.fr/gargantext/haskell-gargantext-prelude
tag: 618f711a530df56caefbb1577c4bf3d5ff45e214
-- tag: 618f711a530df56caefbb1577c4bf3d5ff45e214
tag: d4f9bee483d41bbdf8ab4e09efb5a5a8216edff4
source-repository-package
type: git
......@@ -172,7 +165,7 @@ source-repository-package
type: git
location: https://github.com/robstewart57/rdf4h.git
tag: 4fd2edf30c141600ffad6d730cc4c1c08a6dbce4
allow-older: *
allow-newer: *
......
......@@ -126,8 +126,6 @@ constraints: any.Cabal ==3.8.1.0,
any.conduit-zstd ==0.0.2.0,
any.connection ==0.3.1,
any.constraints ==0.13.4,
any.constraints-extras ==0.4.0.0,
constraints-extras +build-readme,
any.containers ==0.6.7,
any.contravariant ==1.5.5,
contravariant +semigroups +statevar +tagged,
......@@ -169,7 +167,6 @@ constraints: any.Cabal ==3.8.1.0,
any.dec ==0.0.5,
any.deepseq ==1.4.8.0,
any.dense-linear-algebra ==0.1.0.0,
any.dependent-sum ==0.7.1.0,
any.deriving-aeson ==0.2.9,
any.digest ==0.0.1.7,
digest +pkg-config,
......@@ -183,7 +180,6 @@ constraints: any.Cabal ==3.8.1.0,
any.doctemplates ==0.11,
any.double-conversion ==2.0.4.2,
double-conversion -developer +embedded_double_conversion,
any.duckling ==0.2.0.0,
any.easy-file ==0.2.5,
any.eigen ==3.3.7.0,
any.either ==5.0.2,
......@@ -196,7 +192,6 @@ constraints: any.Cabal ==3.8.1.0,
any.epo-api-client ==0.1.0.0,
any.erf ==2.0.0.0,
any.exceptions ==0.10.5,
any.extensible-exceptions ==0.1.1.4,
any.extra ==1.7.14,
any.fail ==4.9.0.0,
any.fast-logger ==3.2.2,
......@@ -219,8 +214,6 @@ constraints: any.Cabal ==3.8.1.0,
any.fullstop ==0.1.4,
any.gargantext-graph ==0.1.0.0,
any.gargantext-prelude ==0.1.0.0,
any.generic-deriving ==1.14.5,
generic-deriving +base-4-9,
any.generic-monoid ==0.1.0.1,
any.generically ==0.1.1,
any.generics-sop ==0.5.1.3,
......@@ -311,9 +304,6 @@ constraints: any.Cabal ==3.8.1.0,
any.integer-logarithms ==1.0.3.1,
integer-logarithms -check-bounds +integer-gmp,
any.invariant ==0.6.2,
any.io-streams ==1.5.2.2,
io-streams +network -nointeractivetests +zlib,
any.io-streams-haproxy ==1.0.1.0,
any.iproute ==1.7.12,
any.ipynb ==0.2,
any.ipython-kernel ==0.11.0.0,
......@@ -393,6 +383,7 @@ constraints: any.Cabal ==3.8.1.0,
any.old-locale ==1.0.0.7,
any.old-time ==1.1.0.3,
any.opaleye ==0.9.6.1,
any.opaleye-textsearch ==0.1.0.0,
any.openalex ==0.1.0.0,
any.optics-core ==0.4.1.1,
optics-core -explicit-generic-labels,
......@@ -457,7 +448,6 @@ constraints: any.Cabal ==3.8.1.0,
any.random-shuffle ==0.0.4,
any.raw-strings-qq ==1.1,
any.rdf4h ==3.1.1,
any.readable ==0.3.1,
any.recover-rtti ==0.4.3,
any.recv ==0.1.0,
any.refact ==0.3.0.2,
......@@ -465,8 +455,6 @@ constraints: any.Cabal ==3.8.1.0,
reflection -slow +template-haskell,
any.regex-base ==0.94.0.2,
any.regex-compat ==0.95.2.1,
any.regex-pcre ==0.95.0.0,
regex-pcre +pkg-config,
any.regex-posix ==0.96.0.1,
regex-posix -_regex-posix-clib,
any.regex-tdfa ==1.3.2.2,
......@@ -534,10 +522,6 @@ constraints: any.Cabal ==3.8.1.0,
any.skylighting-format-latex ==0.1,
any.smallcheck ==1.2.1.1,
any.smtp-mail ==0.3.0.0,
any.snap-core ==1.0.5.1,
snap-core -debug +network-uri -portable,
any.snap-server ==1.1.2.1,
snap-server -build-pong -build-testserver -debug -openssl -portable,
any.socks ==0.6.1,
any.some ==1.0.4.1,
some +newtype-unsafe,
......@@ -589,10 +573,6 @@ constraints: any.Cabal ==3.8.1.0,
text-metrics -dev,
any.text-short ==0.1.5,
text-short -asserts,
any.text-show ==3.10.4,
text-show +base-4-9 +integer-gmp +new-functor-classes +template-haskell-2-11,
any.text16-compat ==0.1.0.0,
text16-compat -enable-golden-test-generation,
any.tf-random ==0.5,
any.th-abstraction ==0.4.5.0,
any.th-compat ==0.1.4,
......@@ -609,7 +589,6 @@ constraints: any.Cabal ==3.8.1.0,
any.time-locale-compat ==0.1.1.5,
time-locale-compat -old-locale,
any.time-manager ==0.0.1,
any.timezone-olson ==0.2.1,
any.timezone-series ==0.1.13,
any.tls ==1.6.0,
tls +compat -hans +network,
......@@ -700,7 +679,6 @@ constraints: any.Cabal ==3.8.1.0,
zip-archive -executable,
any.zlib ==0.6.3.0,
zlib -bundled-c-zlib -non-blocking-ffi -pkg-config,
any.zlib-bindings ==0.1.1.5,
any.zstd ==0.1.3.0,
zstd +standalone
index-state: hackage.haskell.org 2023-12-10T10:34:46Z
......@@ -29,7 +29,7 @@ USER 1000
RUN stack install aeson aeson-lens aeson-pretty array \
blaze-html blaze-markup bytestring \
conduit conduit-extra containers \
deepseq directory duckling \
deepseq directory \
ekg-core ekg-json exceptions \
fgl filepath formatting \
hashable hsparql http-api-data http-client http-client-tls http-conduit \
......
......@@ -5,7 +5,7 @@ cabal-version: 3.4
-- see: https://github.com/sol/hpack
name: gargantext
version: 0.0.6.9.9.9.8.1
version: 0.0.7.1
synopsis: Search, map, share
description: Please see README.md
category: Data
......@@ -38,15 +38,13 @@ data-files:
test-data/phylo/bpa_phylo_test.json
test-data/phylo/cleopatre.golden.json
test-data/phylo/nadal.golden.json
test-data/phylo/nadal_docslist.golden.json
test-data/phylo/nadal_ngramslist.golden.json
test-data/phylo/nadal_docslist.golden.csv
test-data/phylo/nadal_ngramslist.golden.csv
test-data/phylo/issue-290-small.golden.json
test-data/phylo/open_science.json
test-data/phylo/small-phylo.golden.json
test-data/phylo/small_phylo_docslist.csv
test-data/phylo/small_phylo_ngramslist.csv
test-data/phylo/GarganText_DocsList-nodeId-187481.csv
test-data/phylo/GarganText_NgramsList-nodeId-187482.csv
test-data/phylo/187481.json
test-data/phylo/phylo2dot2json.golden.json
test-data/stemming/lancaster.txt
......@@ -76,7 +74,6 @@ common defaults
build-depends:
base >=4.7 && <5
optimization: 2
common optimized
ghc-options:
-O2
......@@ -231,6 +228,7 @@ library
Gargantext.System.Logging
Gargantext.Utils.Dict
Gargantext.Utils.Jobs
Gargantext.Utils.Jobs.Error
Gargantext.Utils.Jobs.Internal
Gargantext.Utils.Jobs.Map
Gargantext.Utils.Jobs.Monad
......@@ -498,7 +496,6 @@ library
, deepseq ^>= 1.4.4.0
, directory ^>= 1.3.6.0
, discrimination >= 0.5
, duckling ^>= 0.2.0.0
, ekg-core ^>= 0.1.1.7
, ekg-json ^>= 0.1.0.7
, epo-api-client
......@@ -560,6 +557,7 @@ library
, natural-transformation ^>= 0.4
, network-uri ^>= 2.6.4.1
, opaleye ^>= 0.9.6.1
, opaleye-textsearch >= 0.1.0.0
, openalex
, pandoc ^>= 2.14.0.3
, parallel ^>= 3.2.2.0
......@@ -629,6 +627,7 @@ library
, tomland >= 1.3.3.2
, tuple ^>= 0.3.0.2
, unordered-containers ^>= 0.2.16.0
, unicode-collation >= 0.1.3.6
, uri-encode ^>= 1.5.0.7
, utf8-string ^>= 1.0.2
, uuid ^>= 1.3.15
......@@ -829,7 +828,6 @@ executable gargantext-server
, text ^>= 1.2.4.1
, unordered-containers ^>= 0.2.16.0
, vector ^>= 0.7.3
optimization: 2
executable gargantext-upgrade
import:
......@@ -907,7 +905,6 @@ test-suite garg-test-tasty
, crawlerArxiv
, cryptohash
, directory
, duckling ^>= 0.2.0.0
, extra ^>= 1.7.9
, fast-logger ^>= 3.0.5
, fmt
......@@ -960,6 +957,7 @@ test-suite garg-test-tasty
, tmp-postgres >= 1.34.1 && < 1.35
, tree-diff
, unordered-containers ^>= 0.2.16.0
, unicode-collation >= 0.1.3.6
, validity ^>= 0.11.0.1
, vector ^>= 0.12.3.0
, wai
......@@ -1002,7 +1000,6 @@ test-suite garg-test-hspec
, conduit ^>= 1.3.4.2
, containers ^>= 0.6.5.1
, crawlerArxiv
, duckling ^>= 0.2.0.0
, extra ^>= 1.7.9
, fast-logger ^>= 3.0.5
, fmt
......@@ -1048,6 +1045,7 @@ test-suite garg-test-hspec
, text ^>= 1.2.4.1
, time ^>= 1.9.3
, tmp-postgres >= 1.34.1 && < 1.35
, tree-diff
, unordered-containers ^>= 0.2.16.0
, validity ^>= 0.11.0.1
, wai
......@@ -1077,7 +1075,6 @@ executable gargantext-phylo-profile
Common
hs-source-dirs:
bin/gargantext-phylo-profile bin/gargantext-phylo/Phylo
default-extensions: GHC2021
ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N -O2 -Wmissing-signatures
build-depends:
base
......@@ -1092,7 +1089,7 @@ executable gargantext-phylo-profile
, split
, vector
, directory
default-language: Haskell2010
default-language: GHC2021
executable garg-golden-file-diff
import:
......
......@@ -85,9 +85,13 @@ startGargantext mode port file = withLoggerHoisted mode $ \logger -> do
portRouteInfo :: PortNumber -> IO ()
portRouteInfo port = do
putStrLn " ----Main Routes----- "
putStrLn $ "http://localhost:" <> toUrlPiece port <> "/index.html"
putStrLn $ "http://localhost:" <> toUrlPiece port <> "/swagger-ui"
putStrLn "=========================================================================================================="
putStrLn " GarganText Main Routes"
putStrLn "=========================================================================================================="
putStrLn $ " - Web GarganText Frontend..................: " <> "http://localhost:" <> toUrlPiece port <> "/index.html"
putStrLn $ " - Swagger UI (API documentation)...........: " <> "http://localhost:" <> toUrlPiece port <> "/swagger-ui"
putStrLn $ " - Playground GraphQL (API documentation)...: " <> "http://localhost:" <> toUrlPiece port <> "/gql"
putStrLn "=========================================================================================================="
-- | Stops the gargantext server and cancels all the periodic actions
-- scheduled to run up to that point.
......
......@@ -13,11 +13,9 @@ Portability : POSIX
module Gargantext.API.Admin.Auth.Types
where
import Control.Lens hiding (elements, to)
import Data.Aeson.TH (deriveJSON)
import qualified Data.Aeson.TH as JSON
import Data.List (tail)
import Data.Swagger
import Data.Swagger ( ToSchema(..), genericDeclareNamedSchema )
import Gargantext.Core.Types.Individu (Username, GargPassword(..), arbitraryUsername, arbitraryPassword)
import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
import Gargantext.Database.Admin.Types.Node (NodeId(..), ListId, DocId, UserId (..))
......
......@@ -19,16 +19,13 @@ Count API part of Gargantext.
module Gargantext.API.Count
where
import Data.Aeson hiding (Error)
import Data.Aeson.TH (deriveJSON)
import Data.Either
import Data.Swagger
import Data.Swagger ( ToSchema(..), genericDeclareNamedSchema )
import Data.Text (pack)
import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
import Gargantext.Prelude
import Servant
import Servant (JSON, Post)
import Test.QuickCheck (elements)
import Test.QuickCheck.Arbitrary
import Test.QuickCheck.Arbitrary (Arbitrary(..))
-----------------------------------------------------------------------
-- TODO-ACCESS: CanCount
......
{-|
Module : Gargantext.API.Errors.Types
Description :
Copyright : (c) CNRS, 2017-Present
License : AGPL + CECILL v3
Maintainer : team@gargantext.org
Stability : experimental
Portability : POSIX
-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RecordWildCards #-}
......@@ -8,7 +18,6 @@
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# OPTIONS_GHC -Wno-unused-top-binds #-}
{-# OPTIONS_GHC -Wno-orphans #-} -- instance IsFrontendErrorData and stage restriction
......@@ -36,32 +45,28 @@ module Gargantext.API.Errors.Types (
, genFrontendErr
) where
import Control.Exception
import Control.Lens (makePrisms)
import Control.Monad.Fail (fail)
import Data.Aeson (FromJSON(..), ToJSON(..), Value(..), (.:), (.=), object, withObject, toJSON)
import Data.Aeson (Value(..), (.:), (.=), object, withObject)
import Data.Aeson.Types (typeMismatch, emptyArray)
import Data.List.NonEmpty qualified as NE
import Data.Singletons.TH
import Data.Singletons.TH ( SingI(sing), SingKind(fromSing) )
import Data.Text qualified as T
import Data.Typeable
import Data.Validity (Validation(..), ValidationChain (..), prettyValidation)
import GHC.Generics
import GHC.Stack
import Gargantext.API.Admin.Auth.Types (AuthenticationError)
import Gargantext.API.Errors.Class
import Gargantext.API.Errors.TH
import Gargantext.API.Errors.Class (HasAuthenticationError(..))
import Gargantext.API.Errors.TH ( deriveIsFrontendErrorData )
import Gargantext.API.Errors.Types.Backend
import Gargantext.Core.Types (HasValidationError(..))
import Gargantext.Core.Types.Individu
import Gargantext.Core.Types.Individu (Username)
import Gargantext.Database.Admin.Types.Node
import Gargantext.Database.Query.Table.Node.Error
import Gargantext.Database.Query.Tree.Error
import Gargantext.Database.Query.Table.Node.Error (HasNodeError(..), NodeError)
import Gargantext.Database.Query.Tree.Error (HasTreeError(..), TreeError)
import Gargantext.Prelude hiding (Location, WithStacktrace)
import Gargantext.Utils.Dict
import Gargantext.Utils.Dict (Dict(..))
import Gargantext.Utils.Jobs.Monad qualified as Jobs
import Servant (ServerError)
import Servant.Job.Core
import Servant.Job.Core ( HasServerError(..) )
import Servant.Job.Types qualified as SJ
import Test.QuickCheck
import Test.QuickCheck.Instances.Text ()
......
......@@ -70,6 +70,7 @@ data Query m
, languages :: m [GQLNLP.LanguageTuple]
, nodes :: GQLNode.NodeArgs -> m [GQLNode.Node]
, nodes_corpus :: GQLNode.CorpusArgs -> m [GQLNode.Corpus]
, node_children :: GQLNode.NodeChildrenArgs -> m [GQLNode.Node]
, node_parent :: GQLNode.NodeParentArgs -> m [GQLNode.Node]
, user_infos :: GQLUserInfo.UserInfoArgs -> m [GQLUserInfo.UserInfo]
, users :: GQLUser.UserArgs -> m [GQLUser.User m]
......@@ -121,6 +122,7 @@ rootResolver authenticatedUser policyManager =
, languages = GQLNLP.resolveLanguages
, nodes = GQLNode.resolveNodes authenticatedUser policyManager
, nodes_corpus = GQLNode.resolveNodesCorpus
, node_children = GQLNode.resolveNodeChildren
, node_parent = GQLNode.resolveNodeParent
, user_infos = GQLUserInfo.resolveUserInfos authenticatedUser policyManager
, users = GQLUser.resolveUsers authenticatedUser policyManager
......
......@@ -14,22 +14,21 @@ Portability : POSIX
module Gargantext.API.GraphQL.Node where
import Data.Aeson
import Data.Aeson ( Result(..), Value(..) )
import Data.Aeson.KeyMap qualified as KM
import Data.Morpheus.Types ( GQLType )
import Data.Text qualified as T
import Gargantext.API.Admin.Auth.Types
import Gargantext.API.Auth.PolicyCheck
import Gargantext.API.Admin.Auth.Types ( AuthenticatedUser )
import Gargantext.API.Auth.PolicyCheck ( nodeChecks, AccessPolicyManager )
import Gargantext.API.GraphQL.PolicyCheck (withPolicy)
import Gargantext.API.GraphQL.Types
import Gargantext.API.GraphQL.Types ( GqlM )
import Gargantext.Core ( HasDBid(lookupDBid) )
import Gargantext.Database.Admin.Types.Node (NodeType)
import Gargantext.Database.Admin.Types.Node qualified as NN
import Gargantext.Database.Prelude (CmdCommon) -- , JSONB)
import Gargantext.Database.Query.Table.Node (getClosestParentIdByType, getNode)
import Gargantext.Database.Query.Table.Node (getClosestChildrenByType, getClosestParentIdByType, getNode)
import Gargantext.Database.Schema.Node qualified as N
import Gargantext.Prelude
import PUBMED.Types qualified as PUBMED
import Prelude qualified
data Corpus = Corpus
{ id :: Int
......@@ -43,6 +42,7 @@ data Node = Node
, name :: Text
, parent_id :: Maybe Int
, type_id :: Int
, node_type :: Maybe NodeType
} deriving (Show, Generic, GQLType)
data CorpusArgs
......@@ -87,7 +87,13 @@ dbNodesCorpus corpus_id = do
data NodeParentArgs
= NodeParentArgs
{ node_id :: Int
, parent_type :: Text
, parent_type :: NodeType
} deriving (Generic, GQLType)
data NodeChildrenArgs
= NodeChildrenArgs
{ node_id :: Int
, child_type :: NodeType
} deriving (Generic, GQLType)
resolveNodeParent
......@@ -95,16 +101,21 @@ resolveNodeParent
=> NodeParentArgs -> GqlM e env [Node]
resolveNodeParent NodeParentArgs { node_id, parent_type } = dbParentNodes node_id parent_type
resolveNodeChildren
:: (CmdCommon env)
=> NodeChildrenArgs -> GqlM e env [Node]
resolveNodeChildren NodeChildrenArgs { node_id, child_type } = dbChildNodes node_id child_type
dbParentNodes
:: (CmdCommon env)
=> Int -> Text -> GqlM e env [Node]
dbParentNodes node_id parent_type = do
let mParentType = readEither (T.unpack parent_type) :: Either Prelude.String NodeType
case mParentType of
Left err -> do
lift $ printDebug "[dbParentNodes] error reading parent type" (T.pack err)
pure []
Right parentType -> do
=> Int -> NodeType -> GqlM e env [Node]
dbParentNodes node_id parentType = do
-- let mParentType = readEither (T.unpack parent_type) :: Either Prelude.String NodeType
-- case mParentType of
-- Left err -> do
-- lift $ printDebug "[dbParentNodes] error reading parent type" (T.pack err)
-- pure []
-- Right parentType -> do
mNodeId <- lift $ getClosestParentIdByType (NN.UnsafeMkNodeId node_id) parentType -- (fromNodeTypeId parent_type_id)
case mNodeId of
Nothing -> pure []
......@@ -112,11 +123,22 @@ dbParentNodes node_id parent_type = do
node <- lift $ getNode id
pure [toNode node]
dbChildNodes :: (CmdCommon env)
=> Int -> NodeType -> GqlM e env [Node]
dbChildNodes node_id childType = do
childIds <- lift $ getClosestChildrenByType (NN.UnsafeMkNodeId node_id) childType -- (fromNodeTypeId parent_type_id)
children <- lift $ mapM getNode childIds
pure $ toNode <$> children
toNode :: NN.Node json -> Node
toNode N.Node { .. } = Node { id = NN.unNodeId _node_id
toNode N.Node { .. } = Node { id = nid
, name = _node_name
, parent_id = NN.unNodeId <$> _node_parent_id
, type_id = _node_typename }
, type_id = _node_typename
, node_type = lookupDBid _node_typename
}
where
nid = NN.unNodeId _node_id
toCorpus :: NN.Node Value -> Corpus
toCorpus N.Node { .. } = Corpus { id = NN.unNodeId _node_id
......
......@@ -3,11 +3,11 @@ module Gargantext.API.GraphQL.PolicyCheck where
import Prelude
import Control.Monad.Except
import Gargantext.API.Admin.Auth.Types
import Gargantext.API.Auth.PolicyCheck
import Gargantext.API.Errors.Types
import Gargantext.API.GraphQL.Types
import Control.Monad.Except (MonadError(..), MonadTrans(..))
import Gargantext.API.Admin.Auth.Types ( AuthenticatedUser )
import Gargantext.API.Auth.PolicyCheck ( BoolExpr, AccessCheck, AccessPolicyManager(..), AccessResult(..))
import Gargantext.API.Errors.Types ( BackendInternalError(..) )
import Gargantext.API.GraphQL.Types (GqlM)
import Gargantext.Database.Prelude (HasConnectionPool, HasConfig)
withPolicy :: (HasConnectionPool env, HasConfig env)
......
......@@ -15,15 +15,15 @@ Portability : POSIX
module Gargantext.API.GraphQL.TreeFirstLevel where
import Data.Morpheus.Types (GQLType)
import Gargantext.API.Admin.Auth.Types
import Gargantext.API.Auth.PolicyCheck
import Gargantext.API.GraphQL.PolicyCheck
import Gargantext.API.GraphQL.Types
import Gargantext.API.Admin.Auth.Types ( AuthenticatedUser )
import Gargantext.API.Auth.PolicyCheck (AccessPolicyManager, nodeChecks)
import Gargantext.API.GraphQL.PolicyCheck (withPolicy)
import Gargantext.API.GraphQL.Types ( GqlM )
import Gargantext.Core (fromDBid)
import Gargantext.Core.Types (Tree, NodeTree, NodeType)
import Gargantext.Core.Types.Main ( Tree(TreeN), _tn_node, _tn_children, NodeTree(NodeTree, _nt_id, _nt_type), _nt_name )
-- import Gargantext.Core.Types (ContextId, CorpusId, ListId)
import Gargantext.Core.Types.Main ( Tree(..), _tn_node, _tn_children, NodeTree(..), _nt_name )
import Gargantext.Database.Admin.Config ()
import Gargantext.Database.Admin.Types.Node (allNodeTypes, NodeId (UnsafeMkNodeId))
import Gargantext.Database.Admin.Types.Node (allNodeTypes, NodeId(..), NodeType)
import Gargantext.Database.Admin.Types.Node qualified as NN
import Gargantext.Database.Prelude (CmdCommon)
import Gargantext.Database.Query.Table.Node (getNode)
......@@ -51,7 +51,8 @@ data TreeFirstLevel m = TreeFirstLevel
, parent :: m (Maybe TreeNode)
, children :: [TreeNode]
} deriving (Generic, GQLType)
data BreadcrumbArgs = BreadcrumbArgs
{
node_id :: Int
......@@ -105,31 +106,33 @@ resolveParent Nothing = pure Nothing
nodeToTreeNode :: HasCallStack => NN.Node json -> Maybe TreeNode
nodeToTreeNode N.Node {..} = if (fromDBid _node_typename /= NN.NodeFolderShared) && (fromDBid _node_typename /= NN.NodeTeam)
then
Just TreeNode { id = NN.unNodeId _node_id
, name = _node_name
, node_type = fromDBid _node_typename
, parent_id = NN.unNodeId <$> _node_parent_id
}
else
Nothing
resolveBreadcrumb :: (CmdCommon env) => BreadcrumbArgs -> GqlM e env (BreadcrumbInfo)
nodeToTreeNode N.Node {..} =
if (fromDBid _node_typename /= NN.NodeFolderShared) && (fromDBid _node_typename /= NN.NodeTeam)
then
Just TreeNode { id = NN.unNodeId _node_id
, name = _node_name
, node_type = fromDBid _node_typename
, parent_id = NN.unNodeId <$> _node_parent_id
}
else
Nothing
resolveBreadcrumb :: (CmdCommon env) => BreadcrumbArgs -> GqlM e env BreadcrumbInfo
resolveBreadcrumb BreadcrumbArgs { node_id } = dbRecursiveParents node_id
convertDbTreeToTreeNode :: HasCallStack => T.DbTreeNode -> TreeNode
convertDbTreeToTreeNode T.DbTreeNode { _dt_name, _dt_nodeId, _dt_typeId, _dt_parentId } = TreeNode
{ name = _dt_name
, id = NN.unNodeId _dt_nodeId
, node_type = fromDBid _dt_typeId
, parent_id = NN.unNodeId <$> _dt_parentId
}
dbRecursiveParents :: (CmdCommon env) => Int -> GqlM e env (BreadcrumbInfo)
dbRecursiveParents node_id = do
let nId = UnsafeMkNodeId node_id
convertDbTreeToTreeNode T.DbTreeNode { _dt_name, _dt_nodeId, _dt_typeId, _dt_parentId } =
TreeNode
{ name = _dt_name
, id = NN.unNodeId _dt_nodeId
, node_type = fromDBid _dt_typeId
, parent_id = NN.unNodeId <$> _dt_parentId
}
dbRecursiveParents :: (CmdCommon env) => Int -> GqlM e env BreadcrumbInfo
dbRecursiveParents nodeId = do
let nId = UnsafeMkNodeId nodeId
dbParents <- lift $ T.recursiveParents nId allNodeTypes
let treeNodes = map convertDbTreeToTreeNode dbParents
let breadcrumbInfo = BreadcrumbInfo { parents = treeNodes }
pure breadcrumbInfo
pure $ BreadcrumbInfo { parents = treeNodes }
......@@ -12,8 +12,7 @@ Portability : POSIX
module Gargantext.API.GraphQL.Utils where
import Control.Lens ((^.))
import Control.Lens.Getter (view)
import Control.Lens (view)
import Data.Morpheus.Types (GQLTypeOptions, fieldLabelModifier)
import Data.Text qualified as T
import Gargantext.API.Admin.Auth.Types (AuthenticatedUser (..), auth_node_id)
......
......@@ -9,12 +9,24 @@ Portability : POSIX
-}
module Gargantext.API.Job where
module Gargantext.API.Job (
jobLogStart
, jobLogProgress
, jobLogComplete
, jobLogAddMore
, jobLogFailures
, jobLogFailTotal
, jobLogEvt
, jobLogFailTotalWithMessage
, RemainingSteps(..)
, addErrorEvent
) where
import Control.Lens (over, _Just)
import Data.Text qualified as T
import Gargantext.API.Admin.Orchestrator.Types
import Gargantext.Prelude
import Gargantext.Utils.Jobs.Error
newtype RemainingSteps = RemainingSteps { _RemainingSteps :: Int }
deriving (Show, Eq, Num)
......@@ -34,8 +46,8 @@ addEvent level message (JobLog { _scst_events = mEvts, .. }) = JobLog { _scst_ev
, _scev_level = Just level
, _scev_date = Nothing }
addErrorEvent :: T.Text -> JobLog -> JobLog
addErrorEvent message = addEvent "ERROR" message
addErrorEvent :: ToHumanFriendlyError e => e -> JobLog -> JobLog
addErrorEvent message = addEvent "ERROR" (mkHumanFriendly message)
jobLogProgress :: Int -> JobLog -> JobLog
jobLogProgress n jl = over (scst_succeeded . _Just) (+ n) $
......@@ -70,7 +82,7 @@ jobLogFailTotal (JobLog { _scst_succeeded = mSucc
Nothing -> (Nothing, mFail)
Just rem' -> (Just 0, (+ rem') <$> mFail)
jobLogFailTotalWithMessage :: T.Text -> JobLog -> JobLog
jobLogFailTotalWithMessage :: ToHumanFriendlyError e => e -> JobLog -> JobLog
jobLogFailTotalWithMessage message jl = addErrorEvent message $ jobLogFailTotal jl
jobLogEvt :: JobLog -> ScraperEvent -> JobLog
......
......@@ -86,7 +86,7 @@ module Gargantext.API.Ngrams
)
where
import Control.Lens ((.~), view, (^.), (^..), (+~), (%~), (.~), msumOf, at, ix, _Just, Each(..), (%%~), ifolded, to, withIndex, over)
import Control.Lens (view, (^..), (+~), (%~), msumOf, at, ix, _Just, Each(..), (%%~), ifolded, to, withIndex, over)
import Data.Aeson.Text qualified as DAT
import Data.List qualified as List
import Data.Map.Strict qualified as Map
......@@ -119,7 +119,9 @@ import Gargantext.Database.Schema.Node (node_id, node_parent_id, node_user_id)
import Gargantext.Prelude hiding (log, to, toLower, (%), isInfixOf)
import Gargantext.Prelude.Clock (hasTime, getTime)
import Gargantext.Utils.Jobs (serveJobsAPI, MonadJobStatus(..))
import Gargantext.Utils.Jobs.Monad (markFailedNoErr)
import Servant hiding (Patch)
import Text.Collate qualified as Unicode
{-
-- TODO sequences of modifications (Patchs)
......@@ -429,7 +431,7 @@ tableNgramsPostChartsAsync utn jobHandle = do
Nothing -> do
-- printDebug "[tableNgramsPostChartsAsync] can't update charts, no parent, nId" nId
markStarted 1 jobHandle
markFailed Nothing jobHandle
markFailedNoErr jobHandle
Just cId -> do
case tabType of
Authors -> do
......@@ -474,7 +476,7 @@ tableNgramsPostChartsAsync utn jobHandle = do
_otherTabType -> do
-- printDebug "[tableNgramsPostChartsAsync] no update for tabType = " tabType
markStarted 1 jobHandle
markFailed Nothing jobHandle
markFailedNoErr jobHandle
{-
{ _ne_list :: ListType
......@@ -556,13 +558,21 @@ searchTableNgrams versionedTableMap NgramsSearchQuery{..} =
&& _nsq_searchQuery (inputNode ^. ne_ngrams)
&& matchesListType (inputNode ^. ne_list)
-- Sorts the input 'NgramsElement' list.
-- /IMPORTANT/: As we might be sorting ngrams in all sorts of language,
-- some of them might include letters with accents and other unicode symbols,
-- but we need to filter those /diacritics/ out so that the sorting would
-- happen in the way users would expect. See ticket #331.
sortOnOrder :: Maybe OrderBy -> ([NgramsElement] -> [NgramsElement])
sortOnOrder Nothing = sortOnOrder (Just ScoreDesc)
sortOnOrder (Just TermAsc) = List.sortOn $ view ne_ngrams
sortOnOrder (Just TermDesc) = List.sortOn $ Down . view ne_ngrams
sortOnOrder (Just TermAsc) = List.sortBy ngramTermsAscSorter
sortOnOrder (Just TermDesc) = List.sortBy ngramTermsDescSorter
sortOnOrder (Just ScoreAsc) = List.sortOn $ view (ne_occurrences . to Set.size)
sortOnOrder (Just ScoreDesc) = List.sortOn $ Down . view (ne_occurrences . to Set.size)
ngramTermsAscSorter = on unicodeDUCETSorter (unNgramsTerm . view ne_ngrams)
ngramTermsDescSorter = on (\n1 n2 -> unicodeDUCETSorter n2 n1) (unNgramsTerm . view ne_ngrams)
-- | Filters the given `tableMap` with the search criteria. It returns
-- a set of 'NgramsElement' all matching the input 'NGramsSearchQuery'.
filterNodes :: Map NgramsTerm NgramsElement -> Set NgramsElement
......@@ -595,6 +605,13 @@ searchTableNgrams versionedTableMap NgramsSearchQuery{..} =
. Set.toList
$ xs
-- | This function allows sorting two texts via their unicode sorting
-- (as opposed as the standard lexicographical sorting) by relying on
-- the DUCET table, a table that specifies the ordering of all unicode
-- characters. This is enough for mimicking the \"natural sort\" effect
-- that users would expect.
unicodeDUCETSorter :: Text -> Text -> Ordering
unicodeDUCETSorter = Unicode.collate Unicode.rootCollator
getTableNgrams :: forall env err m.
( HasNodeStory env err m
......
......@@ -14,18 +14,18 @@ Portability : POSIX
module Gargantext.API.Ngrams.NgramsTree
where
import Data.Aeson.TH (deriveJSON)
import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HashMap
import Data.List qualified as List
import Data.Set qualified as Set
import Data.Swagger
import Data.Tree
import Data.Swagger ( ToSchema(..), genericDeclareNamedSchema )
import Data.Tree ( Tree(Node), unfoldForest )
import Gargantext.API.Ngrams.Types
import Gargantext.Core.Types (ListType(..), NodeId)
import Gargantext.Core.Types.Main ( ListType(..) )
import Gargantext.Database.Admin.Types.Node ( NodeId )
import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
import Gargantext.Prelude
import Test.QuickCheck
import Test.QuickCheck ( Arbitrary(arbitrary) )
type Children = Text
type Root = Text
......
......@@ -17,7 +17,7 @@ module Gargantext.API.Ngrams.Tools
where
-- import Gargantext.Core.NodeStoryFile qualified as NSF
import Control.Lens (_Just, (^.), at, ix, view, At, Index, IxValue)
import Control.Lens (_Just, at, ix, view, At, Index, IxValue)
import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HM
import Data.Map.Strict qualified as Map
......
......@@ -8,20 +8,21 @@ Stability : experimental
Portability : POSIX
-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# OPTIONS -fno-warn-orphans #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# OPTIONS -fno-warn-orphans #-}
module Gargantext.API.Ngrams.Types where
import Codec.Serialise (Serialise())
import Control.Category ((>>>))
import Control.Lens (makeLenses, makePrisms, Iso', iso, from, (.~), (.=), (?=), (#), to, folded, {-withIndex, ifolded,-} view, use, (^.), (^?), (%~), (.~), (%=), at, _Just, Each(..), itraverse_, both, forOf_, (?~), over)
import Control.Lens (makePrisms, Iso', iso, from, (.=), (?=), (#), to, folded, {-withIndex, ifolded,-} view, use, (^?), (%~), (%=), at, _Just, Each(..), itraverse_, both, forOf_, (?~), over)
import Data.Aeson hiding ((.=))
import Data.Aeson.TH (deriveJSON)
import Data.Csv (defaultEncodeOptions, encodeByNameWith, header, namedRecord, EncodeOptions(..), NamedRecord, Quoting(QuoteNone))
import Data.Csv qualified as Csv
import Data.HashMap.Strict.InsOrd qualified as InsOrdHashMap
......@@ -33,6 +34,7 @@ import Data.Set qualified as Set
import Data.String (IsString(..))
import Data.Swagger ( NamedSchema(NamedSchema), declareSchemaRef, genericDeclareNamedSchema, SwaggerType(SwaggerObject), ToParamSchema, ToSchema(..), HasProperties(properties), HasRequired(required), HasType(type_) )
import Data.Text qualified as T
import Data.TreeDiff
import Data.Validity ( Validity(..) )
import Database.PostgreSQL.Simple.FromField (FromField, fromField, fromJSONField)
import Database.PostgreSQL.Simple.ToField (ToField, toJSONField, toField)
......@@ -92,7 +94,9 @@ instance ToJSONKey TabType where
toJSONKey = genericToJSONKey defaultJSONKeyOptions
newtype MSet a = MSet (Map a ())
deriving (Eq, Ord, Show, Generic, Arbitrary, Semigroup, Monoid)
deriving stock (Eq, Ord, Show, Generic)
deriving newtype (Arbitrary, Semigroup, Monoid)
deriving anyclass (ToExpr)
instance ToJSON a => ToJSON (MSet a) where
toJSON (MSet m) = toJSON (Map.keys m)
......@@ -124,7 +128,9 @@ instance (ToJSONKey a, ToSchema a) => ToSchema (MSet a) where
------------------------------------------------------------------------
newtype NgramsTerm = NgramsTerm { unNgramsTerm :: Text }
deriving (Ord, Eq, Show, Generic, ToJSONKey, ToJSON, FromJSON, Semigroup, Arbitrary, Serialise, ToSchema, Hashable, NFData, FromField, ToField)
deriving (Ord, Eq, Show, Generic)
deriving newtype (ToJSONKey, ToJSON, FromJSON, Semigroup, Arbitrary, Serialise, ToSchema, Hashable, NFData, FromField, ToField)
deriving anyclass (ToExpr)
instance IsHashable NgramsTerm where
hash (NgramsTerm t) = hash t
instance Monoid NgramsTerm where
......@@ -175,7 +181,8 @@ data NgramsElement =
, _ne_parent :: Maybe NgramsTerm
, _ne_children :: MSet NgramsTerm
}
deriving (Ord, Eq, Show, Generic)
deriving stock (Ord, Eq, Show, Generic)
deriving anyclass (ToExpr)
deriveJSON (unPrefix "_ne_") ''NgramsElement
makeLenses ''NgramsElement
......@@ -197,7 +204,9 @@ instance ToSchema NgramsElement where
------------------------------------------------------------------------
newtype NgramsTable = NgramsTable [NgramsElement]
deriving (Ord, Eq, Generic, ToJSON, FromJSON, Show)
deriving stock (Ord, Eq, Generic, Show)
deriving newtype (ToJSON, FromJSON)
deriving anyclass (ToExpr)
-- type NgramsList = NgramsTable
......@@ -385,8 +394,8 @@ isRem = (== remPatch)
type PatchMap = PM.PatchMap
newtype PatchMSet a = PatchMSet (PatchMap a AddRem)
deriving (Eq, Show, Generic, Validity, Semigroup, Monoid, Group,
Transformable, Composable)
deriving stock (Eq, Show, Generic)
deriving newtype (Validity, Semigroup, Monoid, Group, Transformable, Composable)
unPatchMSet :: PatchMSet a -> PatchMap a AddRem
unPatchMSet (PatchMSet a) = a
......@@ -538,7 +547,8 @@ instance Action (Replace ListType) NgramsRepoElement where
act replaceP = over nre_list (act replaceP)
newtype NgramsTablePatch = NgramsTablePatch (PatchMap NgramsTerm NgramsPatch)
deriving (Eq, Show, Generic, ToJSON, FromJSON, Semigroup, Monoid, Validity, Transformable)
deriving stock (Eq, Show, Generic)
deriving newtype (ToJSON, FromJSON, Semigroup, Monoid, Validity, Transformable)
mkNgramsTablePatch :: Map NgramsTerm NgramsPatch -> NgramsTablePatch
mkNgramsTablePatch = NgramsTablePatch . PM.fromMap
......@@ -699,7 +709,8 @@ data VersionedWithCount a = VersionedWithCount
, _vc_count :: Count
, _vc_data :: a
}
deriving (Generic, Show, Eq)
deriving stock (Generic, Show, Eq)
deriving anyclass ToExpr
deriveJSON (unPrefix "_vc_") ''VersionedWithCount
makeLenses ''VersionedWithCount
instance (Typeable a, ToSchema a) => ToSchema (VersionedWithCount a) where
......
......@@ -28,27 +28,25 @@ Node API
module Gargantext.API.Node
where
import Control.Lens ((^.))
import Data.Aeson (FromJSON, ToJSON)
import Data.Aeson.TH (deriveJSON)
import Data.Swagger
import Data.Swagger (ToSchema)
import Gargantext.API.Admin.Auth (withAccess, withPolicy)
import Gargantext.API.Admin.Auth.Types (PathId(..), AuthenticatedUser (..), auth_node_id)
import Gargantext.API.Admin.EnvTypes
import Gargantext.API.Auth.PolicyCheck
import Gargantext.API.Errors.Types
import Gargantext.API.Admin.EnvTypes (Env)
import Gargantext.API.Auth.PolicyCheck ( PolicyChecked, nodeChecks )
import Gargantext.API.Errors.Types (BackendInternalError)
import Gargantext.API.Metrics
import Gargantext.API.Ngrams (TableNgramsApi, apiNgramsTableCorpus)
import Gargantext.API.Ngrams.Types (TabType(..))
import Gargantext.API.Node.DocumentUpload qualified as DocumentUpload
import Gargantext.API.Node.File
import Gargantext.API.Node.DocumentsFromWriteNodes qualified as DFWN
import Gargantext.API.Node.File ( FileAsyncApi, FileApi, fileApi, fileAsyncApi )
import Gargantext.API.Node.FrameCalcUpload qualified as FrameCalcUpload
import Gargantext.API.Node.New
import Gargantext.API.Node.New ( PostNodeAsync, PostNode, postNode, postNodeAsyncAPI )
import Gargantext.API.Node.Share qualified as Share
import Gargantext.API.Node.Update qualified as Update
import Gargantext.API.Prelude
import Gargantext.API.Prelude ( GargM, GargServer )
import Gargantext.API.Search qualified as Search
import Gargantext.API.Table
import Gargantext.API.Table ( TableApi, tableApi, getPair )
import Gargantext.Core.Types (NodeTableResult)
import Gargantext.Core.Types.Individu (User(..))
import Gargantext.Core.Types.Main (Tree, NodeTree)
......@@ -57,10 +55,11 @@ import Gargantext.Core.Utils.Prefix (unPrefix)
import Gargantext.Core.Viz.Phylo.API (PhyloAPI, phyloAPI)
import Gargantext.Database.Action.Delete qualified as Action (deleteNode)
import Gargantext.Database.Action.Flow.Pairing (pairing)
import Gargantext.Database.Admin.Types.Hyperdata
import Gargantext.Database.Admin.Types.Hyperdata.Prelude ( HyperdataC )
import Gargantext.Database.Admin.Types.Hyperdata.User ( HyperdataUser )
import Gargantext.Database.Admin.Types.Node
import Gargantext.Database.Prelude (Cmd, JSONB)
import Gargantext.Database.Query.Facet (FacetDoc, OrderBy(..))
import Gargantext.Database.Query.Facet.Types ( FacetDoc, OrderBy(..) )
import Gargantext.Database.Query.Table.Node
import Gargantext.Database.Query.Table.Node.Children (getChildren)
import Gargantext.Database.Query.Table.Node.Error (HasNodeError(..))
......@@ -74,7 +73,6 @@ import Gargantext.Prelude
import Servant
import Test.QuickCheck (elements)
import Test.QuickCheck.Arbitrary (Arbitrary, arbitrary)
import qualified Gargantext.API.Node.DocumentsFromWriteNodes as DFWN
-- | Admin NodesAPI
......
......@@ -21,27 +21,27 @@ module Gargantext.API.Node.Corpus.New
import Conduit
import Control.Lens hiding (elements, Empty)
import Data.Aeson
import Data.Aeson.TH (deriveJSON)
import Control.Lens ( view, non )
import Data.Aeson ( genericParseJSON, genericToJSON )
import Data.ByteString.Base64 qualified as BSB64
import Data.Conduit.Internal (zipSources)
import Data.Swagger
import Data.Swagger ( ToSchema(..), genericDeclareNamedSchema )
import Data.Text qualified as T
import Data.Text.Encoding qualified as TE
import EPO.API.Client.Types qualified as EPO
import Gargantext.API.Admin.Orchestrator.Types (JobLog(..), AsyncJobs)
import Gargantext.API.Admin.Types (HasSettings)
import Gargantext.API.Ngrams (commitStatePatch, Versioned(..))
import Gargantext.API.Node.Corpus.New.Types
import Gargantext.API.Node.Corpus.Searx
import Gargantext.API.Node.Corpus.Types
import Gargantext.API.Node.Corpus.New.Types ( FileFormat(..), FileType(..) )
import Gargantext.API.Node.Corpus.Searx ( triggerSearxSearch )
import Gargantext.API.Node.Corpus.Types ( Database, Datafield(Web), database2origin )
import Gargantext.API.Node.Corpus.Update (addLanguageToCorpus)
import Gargantext.API.Node.Types
import Gargantext.Core (Lang(..), withDefaultLanguage, defaultLanguage)
import Gargantext.Core.NodeStory (HasNodeStoryImmediateSaver, HasNodeArchiveStoryImmediateSaver, currentVersion, NgramsStatePatch')
import Gargantext.Core.Text.Corpus.API qualified as API
import Gargantext.Core.Text.Corpus.Parsers qualified as Parser (FileType(..), parseFormatC)
import Gargantext.API.Admin.Orchestrator.Types qualified as API
import Gargantext.Core.Text.Corpus.Query qualified as API
import Gargantext.Core.Text.Corpus.Parsers qualified as Parser (FileType(..), parseFormatC, _ParseFormatError)
import Gargantext.Core.Text.List.Social (FlowSocialListWith(..))
import Gargantext.Core.Types.Individu (User(..))
import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
......@@ -50,7 +50,8 @@ import Gargantext.Database.Action.Flow.Types (FlowCmdM)
import Gargantext.Database.Action.Mail (sendMail)
import Gargantext.Database.Action.Node (mkNodeWithParent)
import Gargantext.Database.Action.User (getUserId)
import Gargantext.Database.Admin.Types.Hyperdata
import Gargantext.Database.Admin.Types.Hyperdata.Document ( ToHyperdataDocument(..) )
import Gargantext.Database.Admin.Types.Hyperdata.File ( HyperdataFile(..) )
import Gargantext.Database.Admin.Types.Node (CorpusId, NodeType(..), ParentId)
import Gargantext.Database.GargDB qualified as GargDB
import Gargantext.Database.Prelude (hasConfig)
......@@ -60,11 +61,11 @@ import Gargantext.Database.Query.Tree.Root (MkCorpusUser(MkCorpusUserNormalCorpu
import Gargantext.Database.Schema.Node (node_hyperdata)
import Gargantext.Prelude
import Gargantext.Prelude.Config (gc_max_docs_parsers)
import Gargantext.System.Logging
import Gargantext.Utils.Jobs (JobHandle, MonadJobStatus(..))
import Servant
import Gargantext.System.Logging ( logLocM, LogLevel(..) )
import Gargantext.Utils.Jobs.Monad (JobHandle, MonadJobStatus(..))
import Servant ( JSON, type (:>), FormUrlEncoded, Capture, Summary )
import Servant.Job.Utils (jsonOptions)
import Test.QuickCheck.Arbitrary
import Test.QuickCheck.Arbitrary (Arbitrary(..))
------------------------------------------------------------------------
{-
......@@ -254,7 +255,7 @@ addToCorpusWithQuery user cid (WithQuery { _wq_query = q
$(logLocM) DEBUG $ T.pack $ "corpus id " <> show corpusId
_ <- commitCorpus cid user
-- printDebug "sending email" ("xxxxxxxxxxxxxxxxxxxxx" :: Text)
sendMail user
-- TODO ...
......@@ -262,8 +263,8 @@ addToCorpusWithQuery user cid (WithQuery { _wq_query = q
Left err -> do
-- printDebug "Error: " err
$(logLocM) ERROR (T.pack $ show err)
markFailed (Just $ T.pack (show err)) jobHandle
$(logLocM) ERROR (T.pack $ show err) -- log the full error
markFailed (Just err) jobHandle
type AddWithForm = Summary "Add with FormUrlEncoded to corpus endpoint"
:> "corpus"
......@@ -352,9 +353,9 @@ addToCorpusWithForm user cid nwf jobHandle = do
--sendMail user
markComplete jobHandle
Left e -> do
printDebug "[addToCorpusWithForm] parse error" e
markFailed (Just e) jobHandle
Left parseErr -> do
$(logLocM) ERROR $ "parse error: " <> (Parser._ParseFormatError parseErr)
markFailed (Just parseErr) jobHandle
{-
addToCorpusWithFile :: FlowCmdM env err m
......
......@@ -12,24 +12,22 @@ Portability : POSIX
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
module Gargantext.API.Node.Corpus.New.File
where
import Control.Lens ((.~), (?~))
import Data.Maybe
import Control.Lens ((?~))
import Data.Swagger
import Gargantext.API.Node.Corpus.New.Types
import Gargantext.API.Node.Corpus.New.Types (FileFormat, FileType)
import Gargantext.Core.Types (TODO)
import Gargantext.Database.Admin.Types.Node
import Gargantext.Database.Admin.Types.Node (NodeId)
import Gargantext.Database.Prelude (Cmd)
import Gargantext.Prelude hiding (hash)
import Gargantext.Prelude.Crypto.Hash (hash)
import Servant
import Servant.Multipart
import Servant.Swagger.Internal
import Servant ( JSON, type (:>), Post, QueryParam, Summary )
import Servant.Multipart ( Input(iName), Mem, MultipartData(inputs), MultipartForm )
import Servant.Swagger.Internal ( addParam, HasSwagger(..) )
-------------------------------------------------------------
type Hash = Text
......
......@@ -15,7 +15,6 @@ module Gargantext.API.Node.Corpus.Searx where
import Control.Lens (view)
import Data.Aeson qualified as Aeson
import Data.Aeson.TH (deriveJSON)
import Data.HashMap.Strict qualified as HashMap
import Data.Text qualified as T
import Data.Text qualified as Text
......@@ -25,7 +24,7 @@ import Data.Tuple.Select (sel1, sel2, sel3)
import Gargantext.Core (Lang(..))
import Gargantext.Core.NLP (HasNLPServer, nlpServerGet)
import Gargantext.Core.NodeStory.Types ( HasNodeStory )
import Gargantext.Core.Text.Corpus.API qualified as API
import Gargantext.Core.Text.Corpus.Query qualified as Query
import Gargantext.Core.Text.List (buildNgramsLists)
import Gargantext.Core.Text.List.Group.WithStem ({-StopSize(..),-} GroupParams(..))
import Gargantext.Core.Text.Terms (TermType(..))
......@@ -44,10 +43,10 @@ import Gargantext.Database.Query.Table.Node.Error (HasNodeError)
import Gargantext.Database.Query.Tree.Error (HasTreeError)
import Gargantext.Database.Query.Tree.Root (getOrMkRootWithCorpus, MkCorpusUser (MkCorpusUserMaster))
import Gargantext.Prelude hiding (All)
import Gargantext.Prelude.Config
import Gargantext.Utils.Jobs (JobHandle, MonadJobStatus(..))
import Gargantext.Prelude.Config (GargConfig(..))
import Gargantext.Utils.Jobs.Monad (JobHandle, MonadJobStatus(..))
import Network.HTTP.Client
import Network.HTTP.Client.TLS
import Network.HTTP.Client.TLS (tlsManagerSettings)
import Prelude qualified
langToSearx :: Lang -> Text
......@@ -167,7 +166,7 @@ triggerSearxSearch :: ( MonadBase IO m
, MonadJobStatus m )
=> User
-> CorpusId
-> API.RawQuery
-> Query.RawQuery
-> Lang
-> JobHandle m
-> m ()
......@@ -195,7 +194,7 @@ triggerSearxSearch user cId q l jobHandle = do
res <- liftBase $ fetchSearxPage $ FetchSearxParams { _fsp_language = l
, _fsp_manager = manager
, _fsp_pageno = page
, _fsp_query = API.getRawQuery q
, _fsp_query = Query.getRawQuery q
, _fsp_url = surl }
insertSearxResponse user cId listId l res
......
......@@ -13,17 +13,16 @@ Portability : POSIX
module Gargantext.API.Node.Corpus.Types where
import Control.Lens hiding (elements, Empty)
import Control.Lens ( (?~) )
import Control.Monad.Fail (fail)
import Data.Aeson
import Data.Aeson.TH (deriveJSON)
import Data.Aeson ( Value(..), (.:), withText, object )
import Data.Swagger
import Data.Text qualified as T
import Gargantext.API.Admin.Orchestrator.Types qualified as Types
import Gargantext.Core.Utils.Prefix (unPrefix)
import Gargantext.Database.Action.Flow (DataOrigin(..))
import Gargantext.Database.Action.Flow.Types (DataOrigin(..))
import Gargantext.Prelude
import Test.QuickCheck
import Test.QuickCheck (Arbitrary(..), oneof, arbitraryBoundedEnum)
data Database = Empty
| OpenAlex
......
......@@ -16,6 +16,7 @@ import Data.ByteString.Lazy.Char8 qualified as BSC
import Data.Csv (encodeDefaultOrderedByName)
import Data.Text qualified as T
import Data.Text.Encoding qualified as TE
import Data.Time.Clock.System (getSystemTime, systemSeconds)
import Data.Version (showVersion)
import Gargantext.API.Node.Document.Export.Types
import Gargantext.API.Prelude (GargNoServer, GargServer)
......@@ -28,6 +29,7 @@ import Gargantext.Database.Schema.Node (NodePoly(..), node_user_id)
import Gargantext.Prelude
import Paths_gargantext qualified as PG -- cabal magic build module
import Servant ( addHeader, (:<|>)((:<|>)), Header, Headers(getResponse) )
import Data.Time.LocalTime (getCurrentTimeZone, TimeZone (timeZoneMinutes))
api :: NodeId
-- ^ The ID of the target user
......@@ -79,8 +81,14 @@ getDocumentsJSONZip :: NodeId
-> GargNoServer (Headers '[Header "Content-Disposition" T.Text] DocumentExportZIP) -- [Document]
getDocumentsJSONZip userNodeId pId = do
dJSON <- getDocumentsJSON userNodeId pId
systime <- liftBase getSystemTime
tz <- liftBase getCurrentTimeZone
let dexp = getResponse dJSON
let dexpz = DocumentExportZIP { _dez_dexp = dexp, _dez_doc_id = pId }
let dexpz = DocumentExportZIP { _dez_dexp = dexp
, _dez_doc_id = pId
-- see https://github.com/jgm/zip-archive/commit/efe4423a9a2b1dc2a4d413917a933828d3f8dc0f
, _dez_last_modified = fromIntegral (systemSeconds systime) +
fromIntegral (timeZoneMinutes tz * 60) }
pure $ addHeader (T.concat [ "attachment; filename="
, dezFileName dexpz
, ".zip" ]) dexpz
......
......@@ -25,7 +25,7 @@ import Gargantext.Database.Admin.Types.Hyperdata.Document ( HyperdataDocument(..
import Gargantext.Database.Admin.Types.Node (DocId)
import Gargantext.Database.Schema.Node (NodePoly(..))
import Gargantext.Utils.Servant (ZIP)
import Gargantext.Utils.Zip (zipContentsPure)
import Gargantext.Utils.Zip (zipContentsPureWithLastModified)
import Protolude
import Servant ((:>), (:<|>), Get, Header, Headers(..), JSON, MimeRender(..), PlainText, Summary)
......@@ -38,8 +38,9 @@ data DocumentExport =
-- | This is to represent a zipped document export. We want to have doc_id in zipped file name.
data DocumentExportZIP =
DocumentExportZIP { _dez_dexp :: DocumentExport
, _dez_doc_id :: DocId } deriving (Generic)
DocumentExportZIP { _dez_dexp :: DocumentExport
, _dez_doc_id :: DocId
, _dez_last_modified :: Integer } deriving (Generic)
data Document =
......@@ -125,4 +126,4 @@ dezFileName (DocumentExportZIP { .. }) = "GarganText_DocsList-" <> show _dez_doc
instance MimeRender ZIP DocumentExportZIP where
mimeRender _ dexpz@(DocumentExportZIP { .. }) =
zipContentsPure (T.unpack $ dezFileName dexpz) (encode _dez_dexp)
zipContentsPureWithLastModified (T.unpack $ dezFileName dexpz) (encode _dez_dexp) _dez_last_modified
......@@ -16,8 +16,8 @@ Portability : POSIX
module Gargantext.API.Node.DocumentUpload where
import Control.Lens (makeLenses, view)
import Data.Aeson
import Control.Lens (view)
import Data.Aeson ( Options(..), genericParseJSON, defaultOptions, genericToJSON, SumEncoding(..) )
import Data.Swagger (ToSchema)
import Data.Text qualified as T
import Gargantext.API.Admin.EnvTypes (GargJob(..), Env)
......
......@@ -10,14 +10,14 @@ Portability : POSIX
-}
{-# LANGUAGE MonoLocalBinds #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
module Gargantext.API.Node.DocumentsFromWriteNodes
where
import Conduit ( yieldMany )
import Control.Lens ((^.))
import Data.Aeson ( genericParseJSON, defaultOptions, genericToJSON, FromJSON(parseJSON), ToJSON(toJSON) )
import Data.Aeson ( genericParseJSON, defaultOptions, genericToJSON )
import Data.List qualified as List
import Data.Swagger ( ToSchema )
import Data.Text qualified as T
......@@ -43,7 +43,9 @@ import Gargantext.Database.Admin.Types.Node ( NodeId, Node, NodeType(..) )
import Gargantext.Database.Query.Table.Node (getChildrenByType, getClosestParentIdByType', getNodeWith, getOrMkList)
import Gargantext.Database.Schema.Node (node_hyperdata, node_name, node_date)
import Gargantext.Prelude
import Gargantext.System.Logging
import Gargantext.Utils.Jobs (serveJobsAPI, MonadJobStatus(..))
import Gargantext.Utils.Jobs.Error
import Servant ( JSON, Summary, type (:>), HasServer(ServerT) )
------------------------------------------------------------------------
......@@ -90,8 +92,9 @@ documentsFromWriteNodes authenticatedUser nId Params { selection, lang, paragrap
cId <- case mcId of
Just cId -> pure cId
Nothing -> do
let msg = T.pack $ "[G.A.N.DFWN] Node has no corpus parent: " <> show nId
markFailed (Just msg) jobHandle
let msg = T.pack $ "Node has no corpus parent: " <> show nId
$(logLocM) ERROR msg
markFailed (Just $ UnsafeMkHumanFriendlyErrorText "The requested node has no corpus parent.") jobHandle
panicTrace msg
frameWriteIds <- getChildrenByType nId Notes
......
......@@ -17,35 +17,31 @@ Portability : POSIX
module Gargantext.API.Node.File where
import Control.Lens ((^.))
import Data.ByteString qualified as BS
import Data.ByteString.Lazy qualified as BSL
import Data.MIME.Types qualified as DMT
import Data.Swagger
import Data.Swagger (ToSchema(..))
import Data.Text qualified as T
import Data.Text
import Servant
import qualified Gargantext.Database.GargDB as GargDB
import qualified Network.HTTP.Media as M
import Data.Either
import Gargantext.API.Admin.Auth.Types
import Gargantext.API.Admin.Auth.Types ( AuthenticatedUser, auth_user_id )
import Gargantext.API.Admin.EnvTypes (GargJob(..), Env)
import Gargantext.API.Admin.Orchestrator.Types (JobLog(..), AsyncJobs)
import Gargantext.API.Admin.Types (HasSettings)
import Gargantext.API.Errors.Types
import Gargantext.API.Node.Types
import Gargantext.API.Prelude
import Gargantext.API.Errors.Types ( BackendInternalError )
import Gargantext.API.Node.Types ( NewWithFile(NewWithFile) )
import Gargantext.API.Prelude ( GargM, GargServer )
import Gargantext.Core.Types (TODO)
import Gargantext.Database.Action.Flow.Types
import Gargantext.Database.Action.Flow.Types ( FlowCmdM )
import Gargantext.Database.Action.Node (mkNodeWithParent)
import Gargantext.Database.Admin.Types.Hyperdata.File
import Gargantext.Database.Admin.Types.Node
import Gargantext.Database.Admin.Types.Hyperdata.File ( HyperdataFile(..) )
import Gargantext.Database.Admin.Types.Node ( NodeId, NodeType(..) )
import Gargantext.Database.GargDB qualified as GargDB
import Gargantext.Database.Query.Table.Node (getNodeWith)
import Gargantext.Database.Query.Table.Node.UpdateOpaleye (updateHyperdata)
import Gargantext.Database.Schema.Node (node_hyperdata)
import Gargantext.Prelude
import Gargantext.Utils.Jobs (serveJobsAPI, MonadJobStatus(..))
import Network.HTTP.Media qualified as M
import Servant
data RESPONSE deriving Typeable
......
......@@ -15,8 +15,6 @@ Portability : POSIX
module Gargantext.API.Node.FrameCalcUpload where
import Control.Lens ((^.))
import Data.Aeson ( FromJSON, ToJSON )
import Data.ByteString.Lazy qualified as BSL
import Data.ByteString.UTF8 qualified as BSU8
import Data.Swagger ( ToSchema )
......@@ -40,7 +38,7 @@ import Gargantext.Database.Prelude (HasConfig)
import Gargantext.Database.Query.Table.Node (getClosestParentIdByType, getNodeWith)
import Gargantext.Database.Schema.Node (node_hyperdata)
import Gargantext.Prelude
import Gargantext.Utils.Jobs (serveJobsAPI, MonadJobStatus(..))
import Gargantext.Utils.Jobs (serveJobsAPI, MonadJobStatus(..), markFailureNoErr)
import Network.HTTP.Client (newManager, httpLbs, parseRequest, responseBody)
import Network.HTTP.Client.TLS (tlsManagerSettings)
import Servant ( type (:>), JSON, Summary, HasServer(ServerT) )
......@@ -105,7 +103,7 @@ frameCalcUploadAsync authenticatedUser nId (FrameCalcUpload _wf_lang _wf_selecti
-- printDebug "[frameCalcUploadAsync] mCId" mCId
case mCId of
Nothing -> markFailure 1 Nothing jobHandle
Nothing -> markFailureNoErr 1 jobHandle
Just cId ->
-- FIXME(adn) Audit this conversion.
addToCorpusWithForm (RootId userNodeId)
......
......@@ -63,8 +63,8 @@ api :: (HasNodeError err, HasNLPServer env, CmdRandom env err m)
api userInviting nId (ShareTeamParams user') = do
let user'' = Text.toLower user'
user <- case guessUserName user'' of
Nothing -> pure user''
Just (u,_) -> do
Nothing -> pure user''
Just (u, _) -> do
isRegistered <- getUserId' (UserName u)
case isRegistered of
Right _ -> do
......@@ -72,7 +72,7 @@ api userInviting nId (ShareTeamParams user') = do
pure u
Left _err -> do
username' <- getUsername userInviting
_ <- case List.elem username' arbitraryUsername of
_ <- case username' `List.elem` arbitraryUsername of
True -> do
-- printDebug "[G.A.N.Share.api]" ("Demo users are not allowed to invite" :: Text)
pure ()
......
......@@ -15,27 +15,28 @@ Portability : POSIX
module Gargantext.API.Public
where
import Control.Lens ((^?), (^.), _Just)
import Data.Aeson
import Control.Lens ((^?), _Just)
import Data.Aeson ( Options(sumEncoding), genericParseJSON, defaultOptions, genericToJSON )
import Data.List qualified as List
import Data.Map.Strict qualified as Map
import Data.Set qualified as Set
import Data.Swagger hiding (title, url)
import Gargantext.API.Node.File
import Gargantext.API.Prelude
import Data.Swagger (ToSchema)
import Gargantext.API.Node.File (FileApi, fileApi)
import Gargantext.API.Prelude (serverError, GargServer)
import Gargantext.Core.Utils.DateUtils (utc2year)
import Gargantext.Database.Admin.Types.Hyperdata
import Gargantext.Database.Admin.Types.Hyperdata.Corpus ( hc_fields )
import Gargantext.Database.Admin.Types.Hyperdata.Folder ( HyperdataFolder )
import Gargantext.Database.Admin.Types.Hyperdata.CorpusField
import Gargantext.Database.Admin.Types.Node
import Gargantext.Database.Admin.Types.Node ( NodeId(..), Node, unNodeId )
import Gargantext.Database.Prelude (Cmd, DBCmd)
import Gargantext.Database.Query.Table.Node.Error (HasNodeError(..))
import Gargantext.Database.Query.Table.NodeNode (selectPublicNodes)
import Gargantext.Database.Schema.Node -- (NodePoly(..))
import Gargantext.Database.Schema.Node ( NodePoly(..), node_date, node_hyperdata ) -- (NodePoly(..))
import Gargantext.Prelude
import Gargantext.Utils.Aeson qualified as GUA
import Servant
import Test.QuickCheck (elements)
import Test.QuickCheck.Arbitrary
import Test.QuickCheck.Arbitrary ( Arbitrary(arbitrary) )
------------------------------------------------------------------------
type API = API_Home
......
......@@ -13,9 +13,10 @@ Portability : POSIX
module Gargantext.API.Server where
import Control.Lens ((^.))
import Control.Monad.Catch (catch, throwM)
import Data.ByteString.Lazy qualified as BL
import Data.Text qualified as T
import Data.Text.Encoding qualified as TE
import Data.Version (showVersion)
import Gargantext.API.Admin.Auth (auth, forgotPassword, forgotPasswordAsync)
import Gargantext.API.Admin.Auth.Types (AuthContext)
......@@ -24,20 +25,18 @@ import Gargantext.API.Admin.FrontEnd (frontEndServer)
import Gargantext.API.Auth.PolicyCheck ()
import Gargantext.API.Errors
import Gargantext.API.GraphQL qualified as GraphQL
import Gargantext.API.Prelude
import Gargantext.API.Prelude (GargM, GargServer)
import Gargantext.API.Public qualified as Public
import Gargantext.API.Routes
import Gargantext.API.Routes (API, GargVersion, GargAPI)
import Gargantext.API.Swagger (swaggerDoc)
import Gargantext.API.ThrowAll (serverPrivateGargAPI)
import Gargantext.Database.Prelude (hasConfig)
import Gargantext.Prelude hiding (Handler, catch)
import Gargantext.Prelude.Config (gc_url_backend_api)
import Gargantext.System.Logging
import Gargantext.System.Logging (logLocM, LogLevel(..))
import Paths_gargantext qualified as PG -- cabal magic build module
import Servant
import Servant.Swagger.UI (swaggerSchemaUIServer)
import qualified Data.ByteString.Lazy as BL
import qualified Data.Text.Encoding as TE
serverGargAPI :: Text -> ServerT GargAPI (GargM Env BackendInternalError)
......
......@@ -31,9 +31,7 @@ Node API
module Gargantext.API.Table
where
import Data.Aeson.TH (deriveJSON)
import Data.Maybe
import Data.Swagger
import Data.Swagger (ToSchema(..), genericDeclareNamedSchema)
import Data.Text qualified as T
import Gargantext.API.HashedResponse
import Gargantext.API.Ngrams.Types (TabType(..))
......
......@@ -63,7 +63,7 @@ module Gargantext.Core.NodeStory
, getParentsChildren )
where
import Control.Lens ((^.), (.~), (%~), non, _Just, at, over, view)
import Control.Lens ((%~), non, _Just, at, over, view)
import Data.Map.Strict qualified as Map
import Data.Pool (Pool, withResource)
import Data.Set qualified as Set
......
......@@ -25,7 +25,6 @@ module Gargantext.Core.NodeStory.DB
, updateNodeStoryVersion )
where
import Control.Lens ((^.))
import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HashMap
import Data.Map.Strict qualified as Map
......@@ -41,7 +40,7 @@ import Gargantext.Database.Admin.Types.Node ( NodeId(..), NodeType )
import Gargantext.Database.Admin.Config ()
import Gargantext.Database.Schema.Ngrams ()
import Gargantext.Prelude hiding (to)
import Gargantext.Prelude.Database
import Gargantext.Prelude.Database ( runPGSExecute, runPGSExecuteMany, runPGSQuery, runPGSReturning )
nodeExists :: PGS.Connection -> NodeId -> IO Bool
......
......@@ -48,7 +48,7 @@ module Gargantext.Core.NodeStory.Types
where
import Codec.Serialise.Class ( Serialise )
import Control.Lens (makeLenses, Getter, (^.))
import Control.Lens (Getter)
import Data.Aeson hiding ((.=), decode)
import Data.Map.Strict qualified as Map
import Data.Profunctor.Product.TH (makeAdaptorAndInstance)
......
......@@ -9,6 +9,8 @@ Portability : POSIX
-}
{-# LANGUAGE LambdaCase #-}
module Gargantext.Core.Text.Corpus.API
( ExternalAPIs(..)
, Corpus.RawQuery(..)
......@@ -33,6 +35,7 @@ import Gargantext.Core.Text.Corpus.API.Pubmed qualified as PUBMED
import Gargantext.Core.Text.Corpus.Query qualified as Corpus
import Gargantext.Database.Admin.Types.Hyperdata.Document (HyperdataDocument(..))
import Gargantext.Prelude hiding (get)
import Gargantext.Utils.Jobs.Error
import PUBMED.Types qualified as PUBMED
import Servant.Client (ClientError)
......@@ -40,9 +43,16 @@ data GetCorpusError
= -- | We couldn't parse the user input query into something meaningful.
InvalidInputQuery !Corpus.RawQuery !T.Text
-- | The external service returned an error.
| ExternalAPIError !ClientError
| ExternalAPIError !ExternalAPIs !ClientError
deriving (Show, Eq)
instance ToHumanFriendlyError GetCorpusError where
mkHumanFriendly = \case
InvalidInputQuery rq txt ->
"Invalid input query (" <> Corpus.getRawQuery rq <> ") for corpus search: " <> txt
ExternalAPIError api _ ->
"There was a network problem while contacting the " <> T.pack (show api) <> " API provider. Please try again later or contact your network administrator."
-- | Get External API metadata main function
get :: ExternalAPIs
-> Lang
......@@ -61,14 +71,14 @@ get externalAPI lang q mPubmedAPIKey epoAuthKey epoAPIUrl limit = do
-- For Arxiv we parse the query into a structured boolean query we submit over.
case externalAPI of
PubMed ->
first ExternalAPIError <$> PUBMED.get (fromMaybe "" mPubmedAPIKey) q limit
first (ExternalAPIError externalAPI) <$> PUBMED.get (fromMaybe "" mPubmedAPIKey) q limit
OpenAlex ->
first ExternalAPIError <$> OpenAlex.get (fromMaybe "" Nothing {- email -}) q (Just $ toISO639 lang) limit
first (ExternalAPIError externalAPI) <$> OpenAlex.get (fromMaybe "" Nothing {- email -}) q (Just $ toISO639 lang) limit
Arxiv -> runExceptT $ do
corpusQuery <- ExceptT (pure parse_query)
ExceptT $ fmap Right (Arxiv.get lang corpusQuery limit)
HAL ->
first ExternalAPIError <$> HAL.getC (Just $ toISO639 lang) (Corpus.getRawQuery q) (Corpus.getLimit <$> limit)
first (ExternalAPIError externalAPI) <$> HAL.getC (Just $ toISO639 lang) (Corpus.getRawQuery q) (Corpus.getLimit <$> limit)
IsTex -> do
docs <- ISTEX.get lang (Corpus.getRawQuery q) (Corpus.getLimit <$> limit)
pure $ Right (Just $ fromIntegral $ length docs, yieldMany docs)
......@@ -76,7 +86,7 @@ get externalAPI lang q mPubmedAPIKey epoAuthKey epoAPIUrl limit = do
docs <- ISIDORE.get lang (Corpus.getLimit <$> limit) (Just $ Corpus.getRawQuery q) Nothing
pure $ Right (Just $ fromIntegral $ length docs, yieldMany docs)
EPO -> do
first ExternalAPIError <$> EPO.get epoAuthKey epoAPIUrl q (toISO639 lang) limit
first (ExternalAPIError externalAPI) <$> EPO.get epoAuthKey epoAPIUrl q (toISO639 lang) limit
where
parse_query = first (InvalidInputQuery q . T.pack) $ Corpus.parseQuery q
......
......@@ -20,8 +20,17 @@ please follow the types.
{-# LANGUAGE PackageImports #-}
module Gargantext.Core.Text.Corpus.Parsers (FileFormat(..), FileType(..), clean, parseFile, cleanText, parseFormatC, splitOn, etale)
where
module Gargantext.Core.Text.Corpus.Parsers (
FileFormat(..)
, FileType(..)
, ParseFormatError(..)
, clean
, parseFile
, cleanText
, parseFormatC
, splitOn
, etale
) where
-- import Gargantext.Core.Text.Learn (detectLangDefault)
import "zip" Codec.Archive.Zip (EntrySelector, withArchive, getEntry, getEntries, unEntrySelector)
......@@ -49,6 +58,7 @@ import Gargantext.Core.Text.Corpus.Parsers.WOS qualified as WOS
import Gargantext.Core.Text.Ngrams (NgramsType(..))
import Gargantext.Database.Admin.Types.Hyperdata.Document ( HyperdataDocument(..) )
import Gargantext.Prelude hiding (show, undefined)
import Gargantext.Utils.Jobs.Error
import Gargantext.Utils.Zip qualified as UZip
import Protolude ( show )
import System.FilePath (takeExtension)
......@@ -81,73 +91,85 @@ data FileType = WOS
-- | PDF -- Not Implemented / pdftotext and import Pandoc ?
-- | XML -- Not Implemented / see :
parseFormatC :: MonadBaseControl IO m
newtype ParseFormatError = ParseFormatError { _ParseFormatError :: DT.Text }
deriving (Show, Eq, Ord, IsString)
instance ToHumanFriendlyError ParseFormatError where
mkHumanFriendly = _ParseFormatError -- nothing sensitive that cannot be shown.
parseFormatC :: forall m. MonadBaseControl IO m
=> FileType
-> FileFormat
-> DB.ByteString
-> m (Either ParseFormatError (Integer, ConduitT () HyperdataDocument IO ()))
parseFormatC ft ff bs0 = first ParseFormatError <$> do_parse ft ff bs0
where
do_parse :: MonadBaseControl IO m
=> FileType
-> FileFormat
-> DB.ByteString
-> m (Either Text (Integer, ConduitT () HyperdataDocument IO ()))
parseFormatC CsvGargV3 Plain bs = do
let eParsedC = parseCsvC $ DBL.fromStrict bs
pure (second (transPipe (pure . runIdentity)) <$> eParsedC)
parseFormatC CsvHal Plain bs = do
let eParsedC = parseCsvC $ DBL.fromStrict bs
pure (second (transPipe (pure . runIdentity)) <$> eParsedC)
parseFormatC Istex Plain bs = do
ep <- liftBase $ parseIstex EN $ DBL.fromStrict bs
pure $ (\p -> (1, yieldMany [p])) <$> ep
parseFormatC RisPresse Plain bs = do
--docs <- enrichWith RisPresse
let eDocs = runParser' RisPresse bs
pure $ (\docs ->
( fromIntegral $ length docs
, yieldMany docs
.| mapC presseEnrich
.| mapC (map $ both decodeUtf8)
.| mapMC (toDoc RIS)) ) <$> eDocs
parseFormatC WOS Plain bs = do
let eDocs = runParser' WOS bs
pure $ (\docs ->
( fromIntegral $ length docs
, yieldMany docs
.| mapC (map $ first WOS.keys)
.| mapC (map $ both decodeUtf8)
.| mapMC (toDoc WOS)) ) <$> eDocs
parseFormatC Iramuteq Plain bs = do
let eDocs = runParser' Iramuteq bs
pure $ (\docs ->
( fromIntegral $ length docs
, yieldMany docs
.| mapC (map $ first Iramuteq.keys)
.| mapC (map $ both decodeUtf8)
.| mapMC (toDoc Iramuteq . map (second (DT.replace "_" " ")))
)
)
<$> eDocs
parseFormatC JSON Plain bs = do
let eParsedC = parseJSONC $ DBL.fromStrict bs
pure (second (transPipe (pure . runIdentity)) <$> eParsedC)
parseFormatC ft ZIP bs = liftBase $ UZip.withZipFileBS bs $ do
fileNames <- filter (filterZIPFileNameP ft) . DM.keys <$> getEntries
printDebug "[parseFormatC] fileNames" fileNames
fileContents <- mapM getEntry fileNames
--printDebug "[parseFormatC] fileContents" fileContents
eContents <- mapM (parseFormatC ft Plain) fileContents
--printDebug "[parseFormatC] contents" contents
--pure $ Left $ "Not implemented for ZIP"
let (errs, contents) = partitionEithers eContents
case errs of
[] ->
case contents of
[] -> pure $ Left "No files in zip"
_ -> do
let lenghts = fst <$> contents
let contents' = snd <$> contents
let totalLength = sum lenghts
pure $ Right ( totalLength
, void (sequenceConduits contents') ) -- .| mapM_C (printDebug "[parseFormatC] doc")
_ -> pure $ Left $ DT.intercalate "\n" errs
parseFormatC _ _ _ = pure $ Left "Not implemented"
-> m (Either DT.Text (Integer, ConduitT () HyperdataDocument IO ()))
do_parse CsvGargV3 Plain bs = do
let eParsedC = parseCsvC $ DBL.fromStrict bs
pure (second (transPipe (pure . runIdentity)) <$> eParsedC)
do_parse CsvHal Plain bs = do
let eParsedC = parseCsvC $ DBL.fromStrict bs
pure (second (transPipe (pure . runIdentity)) <$> eParsedC)
do_parse Istex Plain bs = do
ep <- liftBase $ parseIstex EN $ DBL.fromStrict bs
pure $ (\p -> (1, yieldMany [p])) <$> ep
do_parse RisPresse Plain bs = do
--docs <- enrichWith RisPresse
let eDocs = runParser' RisPresse bs
pure $ (\docs ->
( fromIntegral $ length docs
, yieldMany docs
.| mapC presseEnrich
.| mapC (map $ both decodeUtf8)
.| mapMC (toDoc RIS)) ) <$> eDocs
do_parse WOS Plain bs = do
let eDocs = runParser' WOS bs
pure $ (\docs ->
( fromIntegral $ length docs
, yieldMany docs
.| mapC (map $ first WOS.keys)
.| mapC (map $ both decodeUtf8)
.| mapMC (toDoc WOS)) ) <$> eDocs
do_parse Iramuteq Plain bs = do
let eDocs = runParser' Iramuteq bs
pure $ (\docs ->
( fromIntegral $ length docs
, yieldMany docs
.| mapC (map $ first Iramuteq.keys)
.| mapC (map $ both decodeUtf8)
.| mapMC (toDoc Iramuteq . map (second (DT.replace "_" " ")))
)
)
<$> eDocs
do_parse JSON Plain bs = do
let eParsedC = parseJSONC $ DBL.fromStrict bs
pure (second (transPipe (pure . runIdentity)) <$> eParsedC)
do_parse fty ZIP bs = liftBase $ UZip.withZipFileBS bs $ do
fileNames <- filter (filterZIPFileNameP ft) . DM.keys <$> getEntries
printDebug "[do_parse] fileNames" fileNames
fileContents <- mapM getEntry fileNames
--printDebug "[do_parse] fileContents" fileContents
eContents <- mapM (do_parse fty Plain) fileContents
--printDebug "[do_parse] contents" contents
--pure $ Left $ "Not implemented for ZIP"
let (errs, contents) = partitionEithers eContents
case errs of
[] ->
case contents of
[] -> pure $ Left "No files in zip"
_ -> do
let lenghts = fst <$> contents
let contents' = snd <$> contents
let totalLength = sum lenghts
pure $ Right ( totalLength
, void (sequenceConduits contents') ) -- .| mapM_C (printDebug "[do_parse] doc")
_ -> pure $ Left $ DT.intercalate "\n" errs
do_parse _ _ _ = pure $ Left "Not implemented"
filterZIPFileNameP :: FileType -> EntrySelector -> Bool
......
......@@ -18,32 +18,21 @@ DGP.parseDateRaw DGP.FR "12 avril 2010" == "2010-04-12T00:00:00.000+00:00"
{-# LANGUAGE TypeFamilies #-}
module Gargantext.Core.Text.Corpus.Parsers.Date
{-(parse, parseRaw, dateSplit, Year, Month, Day)-}
where
module Gargantext.Core.Text.Corpus.Parsers.Date (
dateSplit
, mDateSplit
, defaultDay
, defaultUTCTime
, split'
) where
import Data.Aeson (toJSON, Value)
import Data.Aeson qualified as Json
import Data.Aeson.KeyMap as KM hiding (map)
import Data.HashSet qualified as HashSet
import Data.List qualified as List
import Data.Text (unpack, splitOn, replace)
import Data.Time (defaultTimeLocale, iso8601DateFormat, parseTimeM, toGregorian)
import Data.Time.Calendar qualified as DTC
import Data.Time.Clock ( secondsToDiffTime)
import Data.Time.Clock (UTCTime(..)) -- , getCurrentTime)
import Data.Time.LocalTime (utc)
import Data.Time.LocalTime.TimeZone.Series (zonedTimeToZoneSeriesTime)
import Duckling.Api (analyze)
import Duckling.Core (makeLocale, Dimension(Time))
import Duckling.Core qualified as DC
import Duckling.Resolve (fromUTC, Context(Context, referenceTime, locale), DucklingTime(DucklingTime), Options(..))
import Duckling.Types (ResolvedToken(..), ResolvedVal(..))
import Duckling.Types (Seal(..))
import Gargantext.Core (Lang(FR,EN))
-- import Gargantext.Core.Types (DebugMode(..), withDebugMode)
import Data.Time.Clock (UTCTime(..), secondsToDiffTime)
import Gargantext.Prelude hiding (replace)
import System.Environment (getEnv)
------------------------------------------------------------------------
-- | Parse date to Ints
-- TODO add hours, minutes and seconds
......@@ -91,13 +80,6 @@ parse s = do
-- $ getCurrentTime)
_ -> Left "[G.C.T.C.Parsers.Date] parse: Should not happen"
defaultDate :: Text
defaultDate = "0-0-0T0:0:0"
type DateFormat = Text
type DateDefault = Text
data DateFlow = DucklingSuccess { ds_result :: Text }
| DucklingFailure { df_result :: Text }
| ReadFailure1 { rf1_result :: Text }
......@@ -133,83 +115,9 @@ readDate txt = do
parseTimeM True defaultTimeLocale (unpack format) (cs txt)
-- TODO add Paris at Duckling.Locale Region datatype
-- | To get Homogeinity of the languages
-- TODO : put this in a more generic place in the source code
parserLang :: Lang -> DC.Lang
parserLang FR = DC.FR
parserLang EN = DC.EN
parserLang lang = panic $ "[G.C.T.C.P.Date] Lang not implemented" <> (show lang)
-- | Final Date parser API
-- IO can be avoided here:
-- currentContext :: Lang -> IO Context
-- currentContext lang = localContext lang <$> utcToDucklingTime <$> getCurrentTime
-- parseRaw :: Context -> Text -> SomeErrorHandling Text
parseRawSafe :: Lang -> Text -> IO DateFlow
parseRawSafe lang text = do
let triedParseRaw = parseRaw lang text
dateStr' <- case triedParseRaw of
--Left (CE.SomeException err) -> do
Left _err -> do
_envLang <- getEnv "LANG"
-- printDebug "[G.C.T.C.P.Date] Exception: " (err, envLang, lang, text)
pure $ DucklingFailure text
Right res -> pure $ DucklingSuccess res
pure dateStr'
--tryParseRaw :: CE.Exception e => Lang -> Text -> IO (Either e Text)
--tryParseRaw lang text = CE.try (parseRaw lang text)
parseRaw :: Lang -> Text -> Either Text Text
parseRaw lang text = do -- case result
let maybeResult = extractValue $ getTimeValue
$ parseDateWithDuckling lang text (Options True)
case maybeResult of
Just result -> Right result
Nothing -> do
-- printDebug ("[G.C.T.C.P.D.parseRaw] ERROR " <> (cs . show) lang) text
Left $ "[G.C.T.C.P.D.parseRaw ERROR] " <> show lang <> " :: " <> text
getTimeValue :: [ResolvedToken] -> Maybe Value
getTimeValue rt = case head rt of
Nothing -> do
Nothing
Just x -> case rval x of
RVal Time t -> Just $ toJSON t
_ -> do
Nothing
extractValue :: Maybe Value -> Maybe Text
extractValue (Just (Json.Object object)) =
case KM.lookup "value" object of
Just (Json.String date) -> Just date
_ -> Nothing
extractValue _ = Nothing
-- | Current Time in DucklingTime format
-- TODO : get local Time in a more generic way
utcToDucklingTime :: UTCTime -> DucklingTime
utcToDucklingTime time = DucklingTime . zonedTimeToZoneSeriesTime $ fromUTC time utc
-- | Local Context which depends on Lang and Time
localContext :: Lang -> DucklingTime -> Context
localContext lang dt = Context { referenceTime = dt
, locale = makeLocale (parserLang lang) Nothing }
defaultDay :: DTC.Day
defaultDay = DTC.fromGregorian 1 1 1
defaultUTCTime :: UTCTime
defaultUTCTime = UTCTime { utctDay = defaultDay
, utctDayTime = secondsToDiffTime 0 }
-- | Date parser with Duckling
parseDateWithDuckling :: Lang -> Text -> Options -> [ResolvedToken]
parseDateWithDuckling lang input options = do
let contxt = localContext lang $ utcToDucklingTime defaultUTCTime
--pure $ parseAndResolve (rulesFor (locale ctx) (HashSet.fromList [(This Time)])) input ctx
-- TODO check/test Options False or True
analyze input contxt options $ HashSet.fromList [(Seal Time)]
......@@ -13,7 +13,7 @@ module Gargantext.Core.Text.Corpus.Parsers.Gitlab (
Issue(..), gitlabIssue2hyperdataDocument, readFile_Issues, readFile_IssuesAsDocs
) where
import Data.Aeson ( FromJSON(parseJSON), decode, (.:), (.:?), withObject )
import Data.Aeson ( decode, (.:), (.:?), withObject )
import Data.ByteString.Lazy qualified as DBL
import Data.Text qualified as DT
import Data.Time
......
......@@ -26,7 +26,6 @@ _flowCorpusDebat u n l fp = do
module Gargantext.Core.Text.Corpus.Parsers.GrandDebat
where
import Data.Aeson (ToJSON, FromJSON)
import Data.ByteString.Lazy qualified as DBL
import Data.JsonStream.Parser qualified as P
import Data.Text qualified as Text
......
......@@ -20,7 +20,6 @@ TODO:
module Gargantext.Core.Text.Corpus.Parsers.Isidore where
import Control.Lens ( (^.), (.~) )
import Data.ByteString.Lazy (ByteString)
import Data.RDF ( Node(LNode, UNode), LValue(PlainLL, TypedL, PlainL) )
import Data.Text qualified as T
......
......@@ -17,8 +17,7 @@ Json parser to export towoard CSV GargV3 format.
module Gargantext.Core.Text.Corpus.Parsers.Json2Csv (json2csv, readPatents)
where
import Data.Aeson
import Data.Aeson.TH (deriveJSON)
import Data.Aeson ( decode )
import Data.ByteString.Lazy (readFile)
import Data.Text (unpack)
import Data.Vector (fromList)
......
......@@ -18,7 +18,6 @@ Portability : POSIX
module Gargantext.Core.Text.Corpus.Parsers.Wikidata where
import Control.Lens (makeLenses, (^.) )
import Data.List qualified as List
import Data.Text (concat)
import Database.HSparql.Connection ( BindingValue, EndPoint, selectQueryRaw )
......
......@@ -16,11 +16,10 @@ Portability : POSIX
module Gargantext.Core.Text.List.Group.Prelude
where
import Control.Lens (makeLenses, view, set, over)
import Control.Lens (view, set, over)
import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HashMap
import Data.List qualified as List
import Data.Monoid
import Data.Semigroup
import Data.Set qualified as Set
import Gargantext.API.Ngrams.Types (NgramsElement, mkNgramsElement, NgramsTerm(..), RootParent(..), mSetFromList)
......
......@@ -17,7 +17,6 @@ Portability : POSIX
module Gargantext.Core.Text.List.Group.WithStem
where
import Control.Lens (makeLenses)
import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HashMap
import Data.HashSet (HashSet)
......
......@@ -16,7 +16,6 @@ Mainly reexport functions in @Data.Text.Metrics@
module Gargantext.Core.Text.Metrics
where
import Control.Lens (makeLenses)
import Data.Array.Accelerate qualified as DAA
import Data.Array.Accelerate.Interpreter qualified as DAA
import Data.HashMap.Strict (HashMap)
......
......@@ -32,7 +32,7 @@ import Data.List qualified as List
import Data.Map.Strict ( empty, singleton , insertWith, unionWith, unionsWith , mapKeys )
import Data.Map.Strict qualified as DMS
import Data.Text (pack)
import Gargantext.Core.Types
import Gargantext.Core.Types (Terms(..), Stems)
import Gargantext.Prelude hiding (empty)
------------------------------------------------------------------------
......
......@@ -20,7 +20,7 @@ module Gargantext.Core.Text.Ngrams
import Codec.Serialise (Serialise())
import Control.Lens (over)
import Data.Aeson ( ToJSON(..), FromJSON(..), FromJSONKey(..), FromJSONKeyFunction(..), Value(String), ToJSONKey(..) )
import Data.Aeson ( FromJSONKey(..), FromJSONKeyFunction(..), Value(String), ToJSONKey(..) )
import Data.Aeson.Types (toJSONKeyText)
import Data.Text (pack)
import Database.PostgreSQL.Simple qualified as PGS
......
......@@ -37,7 +37,7 @@ compute graph
module Gargantext.Core.Text.Terms
where
import Control.Lens ( (^.), view, over, makeLenses )
import Control.Lens ( view, over )
import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HashMap
import Data.List qualified as List
......
......@@ -15,8 +15,7 @@ Portability : POSIX
module Gargantext.Core.Text.Terms.Multi.PosTagging.Types where
import Data.Aeson.TH (deriveJSON)
import Gargantext.Core.Types
import Gargantext.Core.Types ( NER, POS )
import Gargantext.Core.Utils.Prefix (unPrefix)
import Gargantext.Prelude
......
......@@ -31,19 +31,12 @@ module Gargantext.Core.Types ( module Gargantext.Core.Types.Main
, TODO(..)
) where
import Control.Lens (Prism', (#), makeLenses, over)
import Data.Aeson
import Data.Aeson.TH (deriveJSON)
import Data.Maybe
import Data.Monoid
import Data.Semigroup
import Control.Lens (Prism', (#), over)
import Data.Aeson ( withText )
import Data.Set (empty)
import Data.String
import Data.Swagger (ToParamSchema)
import Data.Swagger (ToSchema(..))
import Data.Swagger (ToParamSchema, ToSchema(..))
import Data.Text (unpack)
import Data.Validity
import GHC.Generics
import Data.Validity ( validationIsValid, Validation )
import Gargantext.Core.Types.Main
import Gargantext.Core.Utils.Prefix (unPrefix, wellNamedSchema)
import Gargantext.Database.Admin.Types.Node
......
......@@ -12,16 +12,16 @@ Portability : POSIX
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveAnyClass #-}
-----------------------------------------------------------------------
module Gargantext.Core.Types.Main where
------------------------------------------------------------------------
import Data.Aeson (FromJSON, ToJSON)
import Data.Aeson.TH (deriveJSON)
import Data.Bimap (Bimap)
import Data.Swagger
import Data.Swagger ( ToSchema(..), ToParamSchema, genericDeclareNamedSchema )
import Data.Text (unpack, pack)
import Data.TreeDiff
import Gargantext.Core
import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger, wellNamedSchema)
import Gargantext.Database.Admin.Types.Node -- (NodeType(..), Node, Hyperdata(..))
......@@ -49,7 +49,7 @@ type TypeId = Int
-- TODO multiple ListType declaration, remove it
-- data ListType = CandidateTerm | StopTerm | MapTerm
data ListType = CandidateTerm | StopTerm | MapTerm
deriving (Generic, Eq, Ord, Show, Read, Enum, Bounded)
deriving (Generic, Eq, Ord, Show, Read, Enum, Bounded, ToExpr)
instance ToJSON ListType
instance FromJSON ListType
......
......@@ -27,22 +27,17 @@ Phylomemy was first described in Chavalarias, D., Cointet, J.-P., 2013. Phylomem
module Gargantext.Core.Types.Phylo where
import Control.DeepSeq
import Control.Lens (makeLenses)
import Control.Monad.Fail (fail)
import Data.Aeson
import Data.Aeson.TH (deriveJSON)
import Data.Aeson.Types
import Data.Maybe
import Data.Monoid
import Data.Swagger
import Data.Aeson ( Value(..), (.:), (.:?), withObject, object, KeyValue((.=)) )
import Data.Aeson.Types ( parseMaybe )
import Data.Swagger ( NamedSchema(..), ToSchema(..), genericDeclareNamedSchema, defaultSchemaOptions )
import Data.Text qualified as T
import Data.Time.Clock.POSIX (POSIXTime)
import Data.TreeDiff ( ToExpr )
import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
import Gargantext.Prelude
import Test.QuickCheck
import Test.QuickCheck ( Arbitrary(arbitrary), oneof, vectorOf )
import Test.QuickCheck.Instances.Text()
import Data.TreeDiff
------------------------------------------------------------------------
-- | Phylo datatype descriptor of a phylomemy
......
......@@ -18,8 +18,7 @@ Portability : POSIX
module Gargantext.Core.Viz.Graph.API
where
import Control.Lens (set, (^.), _Just, (^?), at)
import Data.Aeson ( ToJSON, FromJSON )
import Control.Lens (set, _Just, (^?), at)
import Data.HashMap.Strict qualified as HashMap
import Data.Swagger ( ToSchema )
import Gargantext.API.Admin.EnvTypes (GargJob(..), Env)
......
......@@ -17,7 +17,6 @@ Portability : POSIX
module Gargantext.Core.Viz.Graph.Tools
where
import Data.Aeson ( ToJSON, FromJSON )
import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HashMap
import Data.HashSet qualified as HashSet
......
......@@ -14,9 +14,6 @@ Portability : POSIX
module Gargantext.Core.Viz.Graph.Types
where
import Control.Lens (makeLenses)
import Data.Aeson (FromJSON, ToJSON)
import Data.Aeson.TH (deriveJSON)
import Data.HashSet (HashSet)
import Data.HashSet qualified as HashSet
import Data.Swagger (ToSchema(..), genericDeclareNamedSchema)
......
......@@ -27,9 +27,7 @@ one 8, e54847.
module Gargantext.Core.Viz.LegacyPhylo where
import Control.DeepSeq
import Control.Lens (makeLenses)
import Data.Aeson.TH (deriveJSON,defaultOptions)
import Data.Aeson.TH (defaultOptions)
import Data.Swagger
import Data.Vector (Vector)
import Gargantext.Core.Text.Context (TermList)
......
......@@ -26,17 +26,12 @@ one 8, e54847.
module Gargantext.Core.Viz.Phylo where
import Control.DeepSeq
import Control.Lens (makeLenses)
import Data.Aeson
import Data.Aeson.TH (deriveJSON)
import Data.Swagger
import Data.Text (pack)
import Data.Text.Lazy qualified as TextLazy
import Data.TreeDiff
import Data.TreeDiff (ToExpr)
import Data.Vector (Vector)
import Gargantext.Core.Utils.Prefix (unPrefix)
import Gargantext.Core.Utils.Prefix (unPrefixSwagger)
import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
import Gargantext.Prelude
import Test.QuickCheck
import Test.QuickCheck.Instances.Text()
......
......@@ -17,23 +17,21 @@ TODO: NodeError
module Gargantext.Database.Action.Delete
where
import Control.Lens (view, (^.))
import Data.Text
import Servant
import Gargantext.Core
import Control.Lens (view)
import Data.Text (unpack)
import Gargantext.Core (HasDBid(..))
import Gargantext.Core.Types.Individu (User(..))
import Gargantext.Database.Action.Share (delFolderTeam)
import Gargantext.Database.Action.User (getUserId)
import Gargantext.Database.Admin.Types.Hyperdata.File
import Gargantext.Database.Admin.Types.Node -- (NodeType(..))
import Gargantext.Database.Admin.Types.Hyperdata.File ( HyperdataFile(..) )
import Gargantext.Database.Admin.Types.Node ( NodeId, NodeType(..) ) -- (NodeType(..))
import Gargantext.Database.GargDB qualified as GargDB
import Gargantext.Database.Prelude (Cmd', CmdCommon)
import Gargantext.Database.Query.Table.Node (getNodeWith)
import Gargantext.Database.Query.Table.Node qualified as N (getNode, deleteNode)
import Gargantext.Database.Query.Table.Node.Error (HasNodeError)
import Gargantext.Database.Schema.Node
import Gargantext.Prelude
import qualified Gargantext.Database.GargDB as GargDB
import qualified Gargantext.Database.Query.Table.Node as N (getNode, deleteNode)
------------------------------------------------------------------------
-- TODO
......
......@@ -51,7 +51,7 @@ module Gargantext.Database.Action.Flow -- (flowDatabase, ngrams2list)
where
import Conduit
import Control.Lens ( (^.), to, view, over )
import Control.Lens ( to, view, over )
import Data.Bifunctor qualified as B
import Data.Conduit qualified as C
import Data.Conduit.Internal (zipSources)
......
......@@ -17,7 +17,7 @@ Portability : POSIX
module Gargantext.Database.Action.Flow.Extract
where
import Control.Lens ((^.), _Just, view)
import Control.Lens (_Just, view)
import Data.HashMap.Strict qualified as HashMap
import Data.Map.Strict qualified as DM
import Gargantext.Core (Lang, NLPServerConfig(server))
......
......@@ -15,8 +15,7 @@ Portability : POSIX
module Gargantext.Database.Action.Flow.List
where
import Control.Lens ((^.), (+~), (%~), at, (.~))
import Control.Monad.Reader
import Control.Lens ((+~), (%~), at)
import Data.List qualified as List
import Data.Map.Strict (toList)
import Data.Map.Strict qualified as Map
......@@ -28,7 +27,7 @@ import Gargantext.Core.NodeStory (HasNodeStory, a_history, a_state, a_version)
import Gargantext.Core.Text.Ngrams (NgramsType(..))
import Gargantext.Core.Types (HasValidationError(..), assertValid)
import Gargantext.Core.Types.Main (ListType(CandidateTerm))
import Gargantext.Database.Admin.Types.Node
import Gargantext.Database.Admin.Types.Node (ListId, NodeId)
import Gargantext.Database.Query.Table.NodeNgrams (NodeNgramsPoly(..), NodeNgramsW, listInsertDb,{- getCgramsId -})
import Gargantext.Prelude hiding (toList)
......
......@@ -17,7 +17,7 @@ module Gargantext.Database.Action.Flow.Pairing
-- (pairing)
where
import Control.Lens (_Just, (^.), view)
import Control.Lens (_Just, view)
import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HM
import Data.HashMap.Strict qualified as HashMap
......
......@@ -18,9 +18,6 @@ module Gargantext.Database.Action.Flow.Types
where
import Conduit (ConduitT)
import Control.Lens (makeLenses)
import Data.Aeson (ToJSON)
import Data.Aeson.TH (deriveJSON)
import Data.HashMap.Strict (HashMap)
import Data.Swagger (ToSchema(..), genericDeclareNamedSchema)
import Gargantext.Core.Flow.Types ( UniqId )
......
......@@ -19,7 +19,6 @@ module Gargantext.Database.Action.Flow.Utils
, mapNodeIdNgrams )
where
import Control.Lens ((^.))
import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HashMap
import Data.List qualified as List
......@@ -37,7 +36,7 @@ import Gargantext.Database.Action.Flow.Types (DocumentIdWithNgrams(..), FlowInse
import Gargantext.Database.Admin.Types.Hyperdata.Document ( HyperdataDocument, hd_abstract, hd_title )
import Gargantext.Database.Admin.Types.Node
import Gargantext.Database.Prelude (DBCmd, DbCmd')
import Gargantext.Database.Query.Table.ContextNodeNgrams
import Gargantext.Database.Query.Table.ContextNodeNgrams ( ContextNodeNgramsPoly(..), insertContextNodeNgrams )
import Gargantext.Database.Query.Table.Node.Document.Add qualified as Doc (add)
import Gargantext.Database.Query.Table.Node.Document.Insert (ReturnId, addUniqId, insertDb, reId, reInserted, reUniqId)
import Gargantext.Database.Query.Table.Node.Error (HasNodeError(..))
......
......@@ -22,7 +22,7 @@ module Gargantext.Database.Action.Search (
) where
import Control.Arrow (returnA)
import Control.Lens ((^.), view)
import Control.Lens (view)
import Data.BoolExpr ( BoolExpr(..), Signed(Negative, Positive) )
import Data.List qualified as List
import Data.Map.Strict qualified as Map
......@@ -54,6 +54,7 @@ import Gargantext.Database.Schema.Node ( NodePolySearch(_ns_hyperdata, _ns_searc
import Gargantext.Prelude hiding (groupBy)
import Opaleye hiding (Order)
import Opaleye qualified as O hiding (Order)
import Opaleye.TextSearch
--
-- Interpreting a query into a Postgres' TSQuery
......
......@@ -17,12 +17,12 @@ module Gargantext.Database.Action.Share
where
import Control.Arrow (returnA)
import Control.Lens (view, (^.))
import Control.Lens (view)
import Gargantext.Core.Types.Individu (User(..))
import Gargantext.Database
import Gargantext.Database.Action.User (getUserId)
import Gargantext.Database.Admin.Config (hasNodeType, isInNodeTypes)
import Gargantext.Database.Admin.Types.Hyperdata (HyperdataAny(..))
import Gargantext.Database.Admin.Types.Hyperdata.Any (HyperdataAny(..))
import Gargantext.Database.Admin.Types.Node
import Gargantext.Database.Query.Table.Node (getNode, getNodesWith)
import Gargantext.Database.Query.Table.Node.Error (HasNodeError, errorWith)
......
......@@ -96,15 +96,15 @@ mkNewUser emailAddress pass' =
let username = case guessUserName emailAddress of
Just (u', _m) -> u'
Nothing -> panic "[G.D.A.U.N.newUserQuick]: Email invalid"
in (NewUser username (Text.toLower emailAddress) pass')
in NewUser username (Text.toLower emailAddress) pass'
------------------------------------------------------------------------
-- | guessUserName
-- guess username and normalize it (Text.toLower)
guessUserName :: Text -> Maybe (Text,Text)
guessUserName n = case splitOn "@" n of
[u',m'] -> if m' /= "" then Just (Text.toLower u',m')
else Nothing
[_u', ""] -> Nothing
[u', m'] -> Just (Text.toLower u', m')
_ -> Nothing
------------------------------------------------------------------------
......
......@@ -14,11 +14,10 @@ Portability : POSIX
module Gargantext.Database.Admin.Types.Hyperdata.Frame
where
import Control.Lens
import Data.ByteString.Lazy (toStrict)
import Data.Text qualified as T
import Gargantext.Database.Admin.Types.Hyperdata.Prelude
import Gargantext.Prelude hiding (toStrict)
import Gargantext.Prelude ( ($), Show, Applicative(pure), IO, (.), (&), decodeUtf8 )
import Network.Wreq qualified as Wreq
------------------------------------------------------------------------
......@@ -62,7 +61,12 @@ instance ToSchema HyperdataFrame where
getHyperdataFrameContents :: HyperdataFrame -> IO Text
getHyperdataFrameContents (HyperdataFrame { _hf_base, _hf_frame_id }) = do
let path = T.concat [_hf_base, "/", _hf_frame_id, "/download"]
let path = T.intercalate "/" [_hf_base, _hf_frame_id, "download"]
-- We need to issue a request to this frame, because it might not
-- have been fetched yet and in that case codimd returns some ugly
-- HTML
-- See issue https://gitlab.iscpif.fr/gargantext/haskell-gargantext/issues/333
_ <- Wreq.headWith Wreq.defaults $ T.unpack path
r <- Wreq.get $ T.unpack path
pure $ decodeUtf8 $ toStrict $ r ^. Wreq.responseBody
......
......@@ -11,11 +11,13 @@ Portability : POSIX
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
-- {-# LANGUAGE DuplicateRecordFields #-}
......@@ -23,30 +25,31 @@ module Gargantext.Database.Admin.Types.Node
where
import Codec.Serialise (Serialise())
import Data.Aeson
import Data.Aeson.TH (deriveJSON)
import Data.Aeson as JSON
import Data.Aeson.Types
import Data.Csv qualified as Csv
import Data.Either
import Data.Morpheus.Kind (SCALAR)
import Data.Morpheus.Types
import Data.Morpheus.Types ( DecodeScalar(..), EncodeScalar(..), GQLType(KIND) )
import Data.Swagger
import Data.Text (unpack, pack)
import Data.Text (pack, unpack)
import Data.Time (UTCTime)
import Data.TreeDiff
import Database.PostgreSQL.Simple.FromField (FromField, fromField, fromJSONField)
import Database.PostgreSQL.Simple.ToField (ToField, toField, toJSONField)
import Database.PostgreSQL.Simple.ToRow (ToRow, toRow)
import Fmt
import Fmt ( Buildable(..) )
import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger, wellNamedSchema)
import Gargantext.Database.Schema.Context
import Gargantext.Database.Schema.Node
import Gargantext.Database.Schema.Node ( NodePoly(Node), NodePolySearch(NodeSearch) )
import Gargantext.Prelude
import Gargantext.Prelude.Crypto.Hash (Hash)
import Opaleye (DefaultFromField, defaultFromField, SqlInt4, SqlText, SqlTSVector, Nullable, fromPGSFromField)
import Opaleye (DefaultFromField, defaultFromField, SqlInt4, SqlText, Nullable, fromPGSFromField)
import Opaleye.TextSearch (SqlTSVector)
import Opaleye qualified as O
import Prelude qualified
import Servant hiding (Context)
import Test.QuickCheck (elements, Positive (getPositive))
import Test.QuickCheck.Arbitrary
import Test.QuickCheck.Arbitrary ( Arbitrary(arbitrary), arbitraryBoundedEnum)
import Test.QuickCheck.Instances.Text ()
import Test.QuickCheck.Instances.Time ()
import Text.Read (read)
......@@ -246,7 +249,9 @@ pgContextId = pgResourceId _ContextId
-- to a tree, and each node has its unique identifier. Note how nodes might
-- have also /other/ identifiers, to better qualify them.
newtype NodeId = UnsafeMkNodeId { _NodeId :: Int }
deriving (Read, Generic, Num, Eq, Ord, Enum, ToJSONKey, FromJSONKey, ToJSON, FromJSON, Hashable, Csv.ToField)
deriving stock (Read, Generic, Eq, Ord)
deriving newtype (Num, Enum, ToJSONKey, FromJSONKey, ToJSON, FromJSON, Hashable, Csv.ToField)
deriving anyclass (ToExpr)
instance ResourceId NodeId where
isPositive = (> 0) . _NodeId
......@@ -275,6 +280,7 @@ instance ToSchema NodeId
newtype ContextId = UnsafeMkContextId { _ContextId :: Int }
deriving stock (Show, Eq, Ord, Generic)
deriving newtype (Csv.ToField, ToJSONKey, FromJSONKey, ToJSON, FromJSON, ToField, ToSchema)
deriving anyclass ToExpr
deriving FromField via NodeId
instance ToParamSchema ContextId
......@@ -288,7 +294,9 @@ instance ToHttpApiData ContextId where
toUrlPiece (UnsafeMkContextId n) = toUrlPiece n
newtype NodeContextId = UnsafeMkNodeContextId { _NodeContextId :: Int }
deriving (Read, Generic, Num, Eq, Ord, Enum, ToJSONKey, FromJSONKey, ToJSON, FromJSON, Hashable, Csv.ToField)
deriving stock (Read, Generic, Eq, Ord)
deriving newtype (Num, Enum, ToJSONKey, FromJSONKey, ToJSON, FromJSON, Hashable, Csv.ToField)
deriving anyclass (ToExpr)
--instance Csv.ToField NodeId where
......@@ -400,37 +408,142 @@ instance ToSchema Resource where
------------------------------------------------------------------------
-- | Then a Node can be either a Folder or a Corpus or a Document
data NodeType = NodeUser
| NodeFolderPrivate
| NodeFolderShared | NodeTeam
| NodeFolderPublic
| NodeFolder
-- | NodeAnalysis | NodeCommunity
| NodeCorpus | NodeCorpusV3 | NodeTexts | NodeDocument
| NodeAnnuaire | NodeContact
| NodeGraph | NodePhylo
| NodeDashboard -- | NodeChart | NodeNoteBook
| NodeList | NodeModel
| NodeListCooc
{-
-- | Metrics
-- | NodeOccurrences
-- | Classification
-}
-- Optional Nodes
| Notes | Calc | NodeFrameVisio | NodeFrameNotebook
| NodeFile
data NodeType
= NodeUser
| NodeFolderPrivate
| NodeFolderShared
| NodeTeam
| NodeFolderPublic
| NodeFolder
| NodeCorpus
| NodeCorpusV3
| NodeTexts
| NodeDocument
| NodeAnnuaire
| NodeContact
| NodeGraph
| NodePhylo
| NodeDashboard
| NodeList
| NodeModel
| NodeListCooc
-- Optional Nodes
| Notes
| Calc
| NodeFrameVisio
| NodeFrameNotebook
| NodeFile
deriving (Show, Read, Eq, Ord, Generic, Bounded, Enum)
instance GQLType NodeType
instance FromJSON NodeType
instance ToJSON NodeType
-- /NOTE/ (adn) For backward-compatibility reasons, we keep the format for ToJSON/FromJSON similar
-- to what 'Show/Read' would generate, but we otherwise generate \"by hand\" the mapping between a
-- NodeType and its JSON representation, because this way we reduce the odds of /breaking the frontend/
-- in case we change the Show/Read instances in the future.
instance ToJSON NodeType where
toJSON = JSON.String . \case
NodeUser
-> "NodeUser"
NodeFolderPrivate
-> "NodeFolderPrivate"
NodeFolderShared
-> "NodeFolderShared"
NodeTeam
-> "NodeTeam"
NodeFolderPublic
-> "NodeFolderPublic"
NodeFolder
-> "NodeFolder"
NodeCorpus
-> "NodeCorpus"
NodeCorpusV3
-> "NodeCorpusV3"
NodeTexts
-> "NodeTexts"
NodeDocument
-> "NodeDocument"
NodeAnnuaire
-> "NodeAnnuaire"
NodeContact
-> "NodeContact"
NodeGraph
-> "NodeGraph"
NodePhylo
-> "NodePhylo"
NodeDashboard
-> "NodeDashboard"
NodeList
-> "NodeList"
NodeModel
-> "NodeModel"
NodeListCooc
-> "NodeListCooc"
Notes
-> "Notes"
Calc
-> "Calc"
NodeFrameVisio
-> "NodeFrameVisio"
NodeFrameNotebook
-> "NodeFrameNotebook"
NodeFile
-> "NodeFile"
instance FromJSON NodeType where
parseJSON = withText "NodeType" $ \t -> case t of
"NodeUser"
-> pure NodeUser
"NodeFolderPrivate"
-> pure NodeFolderPrivate
"NodeFolderShared"
-> pure NodeFolderShared
"NodeTeam"
-> pure NodeTeam
"NodeFolderPublic"
-> pure NodeFolderPublic
"NodeFolder"
-> pure NodeFolder
"NodeCorpus"
-> pure NodeCorpus
"NodeCorpusV3"
-> pure NodeCorpusV3
"NodeTexts"
-> pure NodeTexts
"NodeDocument"
-> pure NodeDocument
"NodeAnnuaire"
-> pure NodeAnnuaire
"NodeContact"
-> pure NodeContact
"NodeGraph"
-> pure NodeGraph
"NodePhylo"
-> pure NodePhylo
"NodeDashboard"
-> pure NodeDashboard
"NodeList"
-> pure NodeList
"NodeModel"
-> pure NodeModel
"NodeListCooc"
-> pure NodeListCooc
"Notes"
-> pure Notes
"Calc"
-> pure Calc
"NodeFrameVisio"
-> pure NodeFrameVisio
"NodeFrameNotebook"
-> pure NodeFrameNotebook
"NodeFile"
-> pure NodeFile
unhandled
-> typeMismatch "NodeType" (JSON.String unhandled)
-- | FIXME(adn) these instances could reuse the fromJSON/toJSON instances,
-- but for some reason this broke the frontend:
-- https://gitlab.iscpif.fr/gargantext/haskell-gargantext/merge_requests/277#note_10388
instance FromHttpApiData NodeType where
parseUrlPiece = Right . read . unpack
instance ToHttpApiData NodeType where
......@@ -438,7 +551,7 @@ instance ToHttpApiData NodeType where
instance ToParamSchema NodeType
instance ToSchema NodeType
instance Arbitrary NodeType where
arbitrary = elements allNodeTypes
arbitrary = arbitraryBoundedEnum
instance FromField NodeType where
fromField = fromJSONField
instance ToField NodeType where
......
......@@ -12,23 +12,20 @@ TODO_2: quantitative tests (coded)
-}
{-# LANGUAGE QuasiQuotes #-}
module Gargantext.Database.GargDB
where
import Control.Lens (view)
import Data.Aeson (ToJSON, toJSON)
import Data.Text qualified as Text
import Data.Tuple.Extra (both)
import Gargantext.Database.Prelude (HasConfig(..))
import Gargantext.Prelude hiding (hash)
import Gargantext.Prelude.Config
import Gargantext.Prelude.Crypto.Hash
import Gargantext.Prelude.Config ( gc_datafilepath )
import Gargantext.Prelude.Crypto.Hash ( IsHashable(hash) )
import Prelude qualified
import System.Directory (createDirectoryIfMissing)
import System.Directory qualified as SD
import System.IO.Error
import System.IO.Error ( isDoesNotExistError )
import System.Random (newStdGen)
-------------------------------------------------------------------
......
......@@ -9,19 +9,16 @@ Portability : POSIX
-}
{-# LANGUAGE Arrows #-}
{-# LANGUAGE ConstraintKinds, ScopedTypeVariables #-}
{-# LANGUAGE LambdaCase #-}
module Gargantext.Database.Prelude where
import Control.Exception
import Control.Exception (throw)
import Control.Lens (Getter, view)
import Control.Monad.Except
import Control.Monad.Random
import Control.Monad.Reader
import Control.Monad.Random ( MonadRandom )
import Control.Monad.Trans.Control (MonadBaseControl)
import Data.Aeson (Result(Error,Success), fromJSON, FromJSON)
import Data.Aeson (Result(..))
import Data.ByteString qualified as DB
import Data.List qualified as DL
import Data.Pool (Pool, withResource)
......
......@@ -23,7 +23,6 @@ module Gargantext.Database.Query.Table.Ngrams
)
where
import Control.Lens ((^.))
import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HashMap
import Data.List qualified as List
......
......@@ -18,7 +18,7 @@ TODO use Opaleye for the queries.
module Gargantext.Database.Query.Table.NgramsPostag
where
import Control.Lens (view, (^.))
import Control.Lens (view)
import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HashMap
import Data.List qualified as List
......
......@@ -22,7 +22,7 @@ module Gargantext.Database.Query.Table.Node
import Control.Arrow (returnA)
import Control.Lens (set, view)
import Data.Aeson ( encode, Value, ToJSON )
import Data.Aeson ( encode, Value )
import Database.PostgreSQL.Simple qualified as PGS
import Database.PostgreSQL.Simple.SqlQQ (sql)
import Gargantext.Core ( HasDBid(toDBid) )
......@@ -173,15 +173,26 @@ getChildrenByType :: HasDBid NodeType
-> NodeType
-> DBCmd err [NodeId]
getChildrenByType nId nType = do
result <- runPGSQuery query (PGS.Only nId)
children_lst <- mapM (\(id, _) -> getChildrenByType id nType) result
pure $ concat $ [fst <$> filter (\(_, pTypename) -> pTypename == toDBid nType) result] ++ children_lst
childrenFirstLevel <- getClosestChildrenByType nId nType
childrenLst <- mapM (\id -> getChildrenByType id nType) childrenFirstLevel
pure $ childrenFirstLevel ++ concat childrenLst
-- | Given a node id, find all it's children (only first level) of
-- given node type.
getClosestChildrenByType :: HasDBid NodeType
=> NodeId
-> NodeType
-> DBCmd err [NodeId]
getClosestChildrenByType nId nType = do
results <- runPGSQuery query (nId, toDBid nType)
pure $ (\(PGS.Only nodeId) -> nodeId) <$> results
where
query :: PGS.Query
query = [sql|
SELECT n.id, n.typename
SELECT n.id
FROM nodes n
WHERE n.parent_id = ?;
WHERE n.parent_id = ?
AND n.typename = ?;
|]
------------------------------------------------------------------------
......
......@@ -57,7 +57,6 @@ the concatenation of the parameters defined by @shaParameters@.
module Gargantext.Database.Query.Table.Node.Document.Insert
where
import Data.Aeson (toJSON, ToJSON)
import Data.Text qualified as DT (pack, concat, take, filter, toLower)
import Data.Time.Segment (jour)
import Database.PostgreSQL.Simple (FromRow, Query, Only(..))
......
......@@ -27,7 +27,7 @@ module Gargantext.Database.Query.Table.Node.Error (
) where
import Control.Lens (Prism', (#), (^?))
import Data.Aeson ( object, ToJSON(toJSON) )
import Data.Aeson (object)
import Data.Text qualified as T
import Gargantext.Core.Types.Individu ( renderUser, User, Username )
import Gargantext.Database.Admin.Types.Node (ListId, NodeId(..), ContextId, UserId, ParentId)
......
......@@ -44,7 +44,7 @@ module Gargantext.Database.Query.Table.NodeContext
where
import Control.Arrow (returnA)
import Control.Lens (view, (^.))
import Control.Lens (view)
import Data.Text (splitOn)
import Data.Time (UTCTime)
import Database.PostgreSQL.Simple qualified as PGS (In(..), Query, Only(..))
......
......@@ -33,7 +33,7 @@ module Gargantext.Database.Query.Table.NodeNode
where
import Control.Arrow (returnA)
import Control.Lens ((^.), view)
import Control.Lens (view)
import Data.Text (splitOn)
import Database.PostgreSQL.Simple qualified as PGS
import Database.PostgreSQL.Simple.SqlQQ (sql)
......
......@@ -48,7 +48,7 @@ module Gargantext.Database.Query.Table.User
where
import Control.Arrow (returnA)
import Control.Lens ((^.), (?~))
import Control.Lens ((?~))
import Data.List.NonEmpty qualified as NE
import Data.Time (UTCTime)
import Data.UUID qualified as UUID
......
......@@ -43,15 +43,14 @@ module Gargantext.Database.Query.Tree
)
where
import Control.Lens (view, toListOf, at, each, _Just, to, set, makeLenses)
import Control.Lens (view, toListOf, at, each, _Just, to, set)
import Data.List (tail, nub)
import Data.List qualified as List
import Data.Map.Strict (fromListWith, lookup)
import Data.Proxy
import Data.Text qualified as Text
import Database.PostgreSQL.Simple
import Database.PostgreSQL.Simple.SqlQQ
import Gargantext.Core
import Database.PostgreSQL.Simple ( Only(Only), In(In) )
import Database.PostgreSQL.Simple.SqlQQ ( sql )
import Gargantext.Core ( fromDBid, HasDBid(toDBid) )
import Gargantext.Core.Types.Main (NodeTree(..), Tree(..))
import Gargantext.Database.Admin.Config ()
import Gargantext.Database.Admin.Types.Hyperdata.Any (HyperdataAny)
......
......@@ -20,7 +20,6 @@ ngrams in NgramsTerm Lists.
module Gargantext.Database.Schema.NgramsPostag
where
import Control.Lens ( makeLenses )
import Database.PostgreSQL.Simple qualified as PGS
import Gargantext.Database.Schema.Prelude ( Column, SqlInt4, SqlText, ToField(toField), toRow )
import Gargantext.Prelude
......
......@@ -27,6 +27,7 @@ module Gargantext.Database.Schema.Prelude
, module Opaleye
, module Opaleye.Internal.Table
, module Opaleye.Internal.QueryArr
, module Opaleye.TextSearch
, module Test.QuickCheck.Arbitrary
)
where
......@@ -41,6 +42,7 @@ import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
import Opaleye hiding (FromField)
import Opaleye.Internal.QueryArr (Query)
import Opaleye.Internal.Table (Table(..))
import Opaleye.TextSearch
import Test.QuickCheck.Arbitrary hiding (vector)
import Database.PostgreSQL.Simple.FromField (FromField, fromField)
......
......@@ -21,7 +21,6 @@ Functions to deal with users, database side.
module Gargantext.Database.Schema.User where
import Data.Aeson.TH (deriveJSON)
import Data.Morpheus.Types (GQLType(typeOptions))
import Data.Time (UTCTime)
import Database.PostgreSQL.Simple.FromField (FromField, fromField)
......
......@@ -18,6 +18,8 @@ module Gargantext.Utils.Jobs (
, readPrios
-- * Handy re-exports
, MonadJobStatus(..)
, markFailureNoErr
, markFailedNoErr
) where
import Control.Monad.Except ( runExceptT )
......@@ -32,7 +34,7 @@ import Gargantext.API.Admin.EnvTypes ( mkJobHandle, Env, GargJob(..) )
import Gargantext.API.Errors.Types ( BackendInternalError(InternalJobError) )
import Gargantext.API.Prelude ( GargM )
import qualified Gargantext.Utils.Jobs.Internal as Internal
import Gargantext.Utils.Jobs.Monad ( JobError, MonadJobStatus(..) )
import Gargantext.Utils.Jobs.Monad ( JobError, MonadJobStatus(..), markFailureNoErr, markFailedNoErr )
import Gargantext.System.Logging
import qualified Servant.Job.Async as SJ
......
{-# LANGUAGE LambdaCase #-}
module Gargantext.Utils.Jobs.Error
( ToHumanFriendlyError(..)
, HumanFriendlyErrorText(..)
) where
import Prelude
import Data.Void
import qualified Data.Text as T
-- | This class represents the concept of \"human friendly strings\", by which we mean
-- error messages and/or diagnostics which needs to be displayed to the end users, and, as such:
--
-- 1. They should be easy to understand for end users, not developers (developers would access
-- the full debug logs on the server machine). As such, they don't have to include implementation
-- details and/or technicalities;
-- 2. They /MUST NOT/ include any sensitive data. Please be very careful when writing these instances
-- because just calling \"T.pack . show\" on the input data is immediately wrong; things like Servant's
-- 'ClientError' or any HTTP exception might include api keys in the form of HTTP headers, so leaking
-- that is /BAD/.
class ToHumanFriendlyError e where
mkHumanFriendly :: e -> T.Text
-- | A newtype to wrap a 'Text' to be displayed to the end user.
-- /IMPORTANT/: You need to be very careful when using this newtype; please ensure that the text
-- you are wrapping with this newtype doesn't contain sentitive information.
newtype HumanFriendlyErrorText = UnsafeMkHumanFriendlyErrorText { _HumanFriendlyErrorText :: T.Text }
deriving (Show, Eq, Ord)
instance ToHumanFriendlyError HumanFriendlyErrorText where
mkHumanFriendly = _HumanFriendlyErrorText
-- /N.B/ Don't get fooled by this instance, it's just to help inference in case we use \"markFailed Nothing\".
instance ToHumanFriendlyError Void where
mkHumanFriendly = absurd
{-# LANGUAGE MultiWayIf, FunctionalDependencies, MultiParamTypeClasses, TypeFamilies #-}
{-# LANGUAGE MultiWayIf, FunctionalDependencies, MultiParamTypeClasses, TypeFamilies, ScopedTypeVariables #-}
module Gargantext.Utils.Jobs.Monad (
-- * Types and classes
JobEnv(..)
......@@ -7,6 +7,9 @@ module Gargantext.Utils.Jobs.Monad (
, MonadJob(..)
-- * Reporting errors to users in a friendly way
, ToHumanFriendlyError(..)
-- * Tracking jobs status
, MonadJobStatus(..)
......@@ -24,11 +27,14 @@ module Gargantext.Utils.Jobs.Monad (
, withJob
, handleIDError
, removeJob
, markFailedNoErr
, markFailureNoErr
) where
import Gargantext.Utils.Jobs.Settings
import Gargantext.Utils.Jobs.Error
import Gargantext.Utils.Jobs.Map
import Gargantext.Utils.Jobs.Queue
import Gargantext.Utils.Jobs.Settings
import Gargantext.Utils.Jobs.State
import Control.Concurrent.STM
......@@ -38,6 +44,7 @@ import Control.Monad.Reader
import Data.Kind (Type)
import Data.Map.Strict (Map)
import Data.Time.Clock
import Data.Void (Void)
import qualified Data.Text as T
import Network.HTTP.Client (Manager)
import Prelude
......@@ -213,14 +220,21 @@ class MonadJobStatus m where
-- | Mark 'n' step of the job as failed, while simultaneously substracting this number
-- from the remaining steps. Attach an optional error message to the failure.
markFailure :: Int -> Maybe T.Text -> JobHandle m -> m ()
markFailure :: forall e. ToHumanFriendlyError e => Int -> Maybe e -> JobHandle m -> m ()
-- | Finish tracking a job by marking all the remaining steps as succeeded.
markComplete :: JobHandle m -> m ()
-- | Finish tracking a job by marking all the remaining steps as failed. Attach an optional
-- message to the failure.
markFailed :: Maybe T.Text -> JobHandle m -> m ()
markFailed :: forall e. ToHumanFriendlyError e => Maybe e -> JobHandle m -> m ()
-- | Add 'n' more steps to the running computation, they will be marked as remaining.
addMoreSteps :: MonadJobStatus m => Int -> JobHandle m -> m ()
-- | Helper on top of 'markFailed' for when we don't have a diagnostic to log.
markFailedNoErr :: MonadJobStatus m => JobHandle m -> m ()
markFailedNoErr = markFailed (Nothing :: Maybe Void)
markFailureNoErr :: MonadJobStatus m => Int -> JobHandle m -> m ()
markFailureNoErr steps = markFailure steps (Nothing :: Maybe Void)
......@@ -13,13 +13,12 @@ Portability : POSIX
module Gargantext.Utils.JohnSnowNLP where
import Control.Lens
import Data.Aeson (encode, ToJSON, toJSON, FromJSON, parseJSON, Value(..), (.:), (.:?))
import Data.Aeson.TH (deriveJSON)
import Control.Lens ( FunctorWithIndex(imap) )
import Data.Aeson (encode, Value(..), (.:), (.:?))
import Data.Aeson.Types (prependFailure, typeMismatch)
import Data.List.Safe qualified as LS
import Data.Map.Strict qualified as Map
import Data.Text hiding (map, group, filter, concat, zip)
import Data.Text (unpack)
import Gargantext.Core (Lang(..))
import Gargantext.Core.Text.Terms.Multi.PosTagging.Types
import Gargantext.Core.Types (POS(..))
......
......@@ -17,9 +17,6 @@ Server to be used: https://gitlab.iscpif.fr/gargantext/spacy-server
module Gargantext.Utils.SpacyNLP.Types where
import Control.Lens
import Data.Aeson.TH (deriveJSON)
import Data.Text hiding (map, group, filter, concat, zip)
import Gargantext.Core.Types (POS(..), NER(..))
import Gargantext.Core.Utils.Prefix (unPrefix)
import Gargantext.Prelude
......
......@@ -16,7 +16,6 @@ Portability : POSIX
module Gargantext.Utils.UTCTime where
import Data.Aeson (FromJSON, ToJSON)
import Data.Morpheus.Kind (SCALAR)
import Data.Morpheus.Types (GQLType(..), DecodeScalar(..), EncodeScalar(..))
import Data.Morpheus.Types qualified as DMT
......
......@@ -50,3 +50,9 @@ zipContentsPure :: FilePath -> BSC.ByteString -> BSC.ByteString
zipContentsPure fpath bscContents = ZArch.fromArchive (ZArch.addEntryToArchive e ZArch.emptyArchive)
where
e = ZArch.toEntry fpath 0 bscContents
zipContentsPureWithLastModified :: FilePath -> BSC.ByteString -> Integer -> BSC.ByteString
zipContentsPureWithLastModified fpath bscContents lastModified =
ZArch.fromArchive (ZArch.addEntryToArchive e ZArch.emptyArchive)
where
e = ZArch.toEntry fpath lastModified bscContents
......@@ -4,7 +4,6 @@
- "KMP-0.2.0.0"
- "MissingH-1.4.3.0"
- "Unique-0.4.7.8"
- "dependent-sum-0.7.1.0"
- "fclabels-2.0.5.1"
- "full-text-search-0.2.1.4"
- "fullstop-0.1.4"
......@@ -28,6 +27,7 @@
- "morpheus-graphql-server-0.24.3"
- "morpheus-graphql-subscriptions-0.24.3"
- "morpheus-graphql-tests-0.24.3"
- "opaleye-0.9.6.1"
- "rake-0.0.1"
- "random-1.2.1"
- "recover-rtti-0.4.3"
......@@ -38,7 +38,6 @@
- "servant-ekg-0.3.1"
- "servant-flatten-0.2"
- "servant-server-0.20"
- "snap-server-1.1.2.1"
- "stemmer-0.5.2"
- "taggy-0.2.1"
- "taggy-lens-0.1.2"
......@@ -62,14 +61,6 @@
git: "https://github.com/MercuryTechnologies/ekg-json.git"
subdirs:
- .
- commit: 91928b5d7f9342e9865dde0d94862792d2b88779
git: "https://github.com/adinapoli/boolexpr.git"
subdirs:
- .
- commit: 23603a832117e5352d5b0fb9bb1110228324b35a
git: "https://github.com/adinapoli/duckling.git"
subdirs:
- .
- commit: 7533a9ccd3bfe77141745f6b61039a26aaf5c83b
git: "https://github.com/adinapoli/llvm-hs.git"
subdirs:
......@@ -78,10 +69,6 @@
git: "https://github.com/adinapoli/llvm-hs.git"
subdirs:
- "llvm-hs-pure"
- commit: 85533b5d597e6fc5498411b4bcfc76380ec80d71
git: "https://github.com/adinapoli/text16-compat.git"
subdirs:
- .
- commit: a110807651036ca2228a76507ee35bbf7aedf87a
git: "https://github.com/alpmestan/accelerate-arithmetic.git"
subdirs:
......@@ -98,6 +85,10 @@
git: "https://github.com/alpmestan/sparse-linear.git"
subdirs:
- "sparse-linear"
- commit: bcd7cb20a1b1bc3b58c4ba1b6ae1bccfe62f67ae
git: "https://github.com/boolexpr/boolexpr.git"
subdirs:
- .
- commit: 8fff32a43df743c8c83428a86dd566a0936a4fba
git: "https://github.com/chessai/eigen.git"
subdirs:
......@@ -110,10 +101,6 @@
git: "https://github.com/delanoe/patches-map"
subdirs:
- .
- commit: 6cf1bcfe215143efac17919cfd0abdd60e0f717c
git: "https://github.com/garganscript/haskell-opaleye.git"
subdirs:
- .
- commit: 4fd2edf30c141600ffad6d730cc4c1c08a6dbce4
git: "https://github.com/robstewart57/rdf4h.git"
subdirs:
......@@ -154,7 +141,7 @@
git: "https://gitlab.iscpif.fr/gargantext/gargantext-graph.git"
subdirs:
- .
- commit: 618f711a530df56caefbb1577c4bf3d5ff45e214
- commit: d4f9bee483d41bbdf8ab4e09efb5a5a8216edff4
git: "https://gitlab.iscpif.fr/gargantext/haskell-gargantext-prelude"
subdirs:
- .
......@@ -174,6 +161,10 @@
git: "https://gitlab.iscpif.fr/gargantext/iso639.git"
subdirs:
- .
- commit: cb07b604bfb7a22aa21dd8918de5cb65c8a4bdf1
git: "https://gitlab.iscpif.fr/gargantext/opaleye-textsearch.git"
subdirs:
- .
- commit: 3668d28607867a88b2dfc62158139b3cfd629ddb
git: "https://gitlab.iscpif.fr/gargantext/patches-class.git"
subdirs:
......@@ -260,8 +251,6 @@ flags:
containers: true
distributive: true
"indexed-traversable": true
"constraints-extras":
"build-readme": true
contravariant:
semigroups: true
statevar: true
......@@ -319,10 +308,8 @@ flags:
"build-search-demo": false
gargantext:
"disable-db-obfuscation-executable": false
"no-phylo-debug-logs": false
"no-phylo-debug-logs": true
"test-crypto": false
"generic-deriving":
"base-4-9": true
"ghc-lib-parser":
"threaded-rts": true
"ghc-lib-parser-ex":
......@@ -378,10 +365,6 @@ flags:
"integer-logarithms":
"check-bounds": false
"integer-gmp": true
"io-streams":
network: true
nointeractivetests: false
zlib: true
"ipython-kernel":
examples: false
jose:
......@@ -471,8 +454,6 @@ flags:
reflection:
slow: false
"template-haskell": true
"regex-pcre":
"pkg-config": true
"regex-posix":
"_regex-posix-clib": false
"regex-tdfa":
......@@ -518,16 +499,6 @@ flags:
executable: false
"skylighting-core":
executable: false
"snap-core":
debug: false
"network-uri": true
portable: false
"snap-server":
"build-pong": false
"build-testserver": false
debug: false
openssl: false
portable: false
some:
"newtype-unsafe": true
splitmix:
......@@ -553,13 +524,6 @@ flags:
dev: false
"text-short":
asserts: false
"text-show":
"base-4-9": true
"integer-gmp": true
"new-functor-classes": true
"template-haskell-2-11": true
"text16-compat":
"enable-golden-test-generation": false
"time-compat":
"old-locale": false
"time-locale-compat":
......
#!/bin/bash
FOLDER="logs"
FILE=$(date +%Y%m%d%H%M.log)
LOGFILE=$FOLDER"/"$FILE
mkdir -p $FOLDER
echo "GarganText: Starting project..."
echo "GarganText: First, compiling code..."
bin/install
......@@ -10,7 +16,7 @@ docker compose up -d
echo "GarganText: docker for postgresql database [OK]"
cd ../../
echo "GarganText: gargantext-server with Nix and Cabal..."
nix-shell --run "cabal run gargantext-server -- --ini gargantext.ini --run Prod"
nix-shell --run "cabal run gargantext-server -- --ini gargantext.ini --run Prod +RTS > $LOGFILE 2>&1 & tail -F $LOGFILE"
echo "GarganText: gargantext-server with Nix and Cabal [OK]"
echo "GarganText: project stopped."
......@@ -19,10 +19,9 @@ import Text.RawString.QQ (r)
tests :: Spec
tests = sequential $ aroundAll withTestDBAndPort $ do
describe "Prelude" $ do
it "setup DB triggers" $ \((testEnv, _), _) -> setupEnvironment testEnv
describe "GraphQL" $ do
describe "Prelude" $ do
it "setup DB triggers" $ \((testEnv, _), _) -> setupEnvironment testEnv
describe "get_user_infos" $ do
it "allows 'alice' to see her own info" $ \((testEnv, port), app) -> do
......@@ -34,6 +33,13 @@ tests = sequential $ aroundAll withTestDBAndPort $ do
let expected = [json| {"data":{"user_infos":[{"ui_id":2,"ui_email":"alice@gargan.text"}]}} |]
protected token "POST" "/gql" query `shouldRespondWithFragment` expected
describe "nodes" $ do
it "returns node_type" $ \((_testEnv, port), app) -> do
withApplication app $ do
withValidLogin port "gargantua" (GargPassword "secret_key") $ \token -> do
let query = [r| { "query": "{ nodes(node_id: 2) { node_type } }" } |]
let expected = [json| {"data":{"nodes":[{"node_type":"NodeFolderPrivate"}]}} |]
protected token "POST" "/gql" query `shouldRespondWithFragment` expected
describe "check error format" $ do
it "returns the new error if header X-Garg-Error-Scheme: new is passed" $ \((_testEnv, port), app) -> do
......
......@@ -9,7 +9,6 @@ import Data.Conduit
import Data.String
import Gargantext.Core (Lang(..))
import Gargantext.Core.Text.Corpus.Query
import Gargantext.Core.Types
import Gargantext.Database.Admin.Types.Hyperdata (HyperdataDocument(..))
import Prelude
import System.Environment
......
......@@ -7,8 +7,10 @@ import Data.Coerce
import Data.Map.Strict qualified as Map
import Data.Monoid
import Data.Patch.Class qualified as Patch
import Data.String
import Data.Text qualified as T
import Data.Validity qualified as Validity
import Text.Collate qualified as Unicode
import Gargantext.API.Ngrams
import Gargantext.API.Ngrams.Types
import Gargantext.Core.Types.Main
......@@ -17,16 +19,20 @@ import Gargantext.Prelude
import Test.Ngrams.Query.PaginationCorpus
import Test.Tasty
import Test.Tasty.HUnit
import Test.Utils ((@??=))
tests :: TestTree
tests = testGroup "Ngrams" [unitTests]
curryElem :: NgramsElement
curryElem = mkNgramsElement "curry" MapTerm Nothing mempty
curryElem = mkMapTerm "curry"
elbaElem :: NgramsElement
elbaElem = mkNgramsElement "elba" MapTerm Nothing mempty
elbaElem = mkMapTerm "elba"
mkMapTerm :: T.Text -> NgramsElement
mkMapTerm e = mkNgramsElement (fromString . T.unpack $ e) MapTerm Nothing mempty
mockFlatCorpus :: Versioned (Map NgramsTerm NgramsElement)
mockFlatCorpus = Versioned 0 $ Map.fromList [
......@@ -43,6 +49,9 @@ unitTests = testGroup "Query tests"
[ -- Sorting
testCase "Simple query mockFlatCorpus" testFlat01
, testCase "Simple query (desc sorting)" testFlat02
, testCase "[#331] sorting via DUCET works" testSortDiacriticsDucet
, testCase "[#331] Natural sort ascending works" testNaturalSortAsceding
, testCase "[#331] Natural sort descending works" testNaturalSortDescending
-- -- Filtering
, testCase "Simple query (listType = MapTerm)" testFlat03
, testCase "Simple query (listType = StopTerm)" testFlat04
......@@ -96,6 +105,61 @@ testFlat02 = do
, _nsq_searchQuery = mockQueryFn Nothing
}
testSortDiacriticsDucet :: Assertion
testSortDiacriticsDucet = do
let inputData = [ "étude", "âge", "vue", "période" ]
let expected = [ "âge", "étude", "période", "vue" ]
expected @??= sortBy (Unicode.collate Unicode.rootCollator) inputData
testNaturalSortAsceding :: Assertion
testNaturalSortAsceding = do
let res = searchTableNgrams frenchCorpus searchQuery
res @??= VersionedWithCount 0 4 ( NgramsTable $ map mkMapTerm [ "âge", "étude", "période", "vue" ])
where
frenchCorpus :: Versioned (Map NgramsTerm NgramsElement)
frenchCorpus = Versioned 0 $ Map.fromList [
( "doc_01", mkMapTerm "période")
, ( "doc_02", mkMapTerm "vue")
, ( "doc_03", mkMapTerm "âge")
, ( "doc_04", mkMapTerm "étude")
]
searchQuery = NgramsSearchQuery {
_nsq_limit = Limit 10
, _nsq_offset = Nothing
, _nsq_listType = Nothing
, _nsq_minSize = Nothing
, _nsq_maxSize = Nothing
, _nsq_orderBy = Just TermAsc
, _nsq_searchQuery = mockQueryFn Nothing
}
testNaturalSortDescending :: Assertion
testNaturalSortDescending = do
let res = searchTableNgrams frenchCorpus searchQuery
res @??= VersionedWithCount 0 4 ( NgramsTable $ map mkMapTerm [ "vue", "période", "étude", "âge" ])
where
frenchCorpus :: Versioned (Map NgramsTerm NgramsElement)
frenchCorpus = Versioned 0 $ Map.fromList [
( "doc_01", mkMapTerm "période")
, ( "doc_02", mkMapTerm "vue")
, ( "doc_03", mkMapTerm "âge")
, ( "doc_04", mkMapTerm "étude")
]
searchQuery = NgramsSearchQuery {
_nsq_limit = Limit 10
, _nsq_offset = Nothing
, _nsq_listType = Nothing
, _nsq_minSize = Nothing
, _nsq_maxSize = Nothing
, _nsq_orderBy = Just TermDesc
, _nsq_searchQuery = mockQueryFn Nothing
}
testFlat03 :: Assertion
testFlat03 = do
let res = searchTableNgrams mockFlatCorpus searchQuery
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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