Commit f9ba0f30 authored by qlobbe's avatar qlobbe

resolve the conflict

parents e7c244d8 240c085a
let Rule : Type = { match : Text, print : Text }
let Config : Type = { rules : List Rule }
let rule = \(match: Text) -> \(replace: Text) ->
{ match = match, print = replace } : Rule
in {
rules =
[
rule "(>>[ICS]>)|(<[ICS]<<)|(>[ICS]>)|(<[ICS]<)" ""
, rule "Couldn't match type" "Couldn't match"
, rule " with" " with"
, rule "Expected type:" "Expected:"
, rule " Actual type:" " Got:"
, rule "Couldn't match expected type ‘(.*?)’" "Expected: $1"
, rule " with actual type ‘(.*?)’" " Got: $1"
, rule "Couldn't match expected type ‘(.*)’ with actual type ‘(.*)’"
''
Expected: $1
Got: $2
''
-- , rule "(?s)>>C>.*?<C<<" ""
, rule "(?s)In a stmt of a 'do' block:.*?<(C|S)<<" "<$1<<"
, rule "(?s)In the \\w+ argument of.*?<(C|S)<<" "<$1<<"
, rule "(?s)In the expression.*?<(C|S)<<" "<$1<<"
, rule "\\(bound at ([^)]*)\\)" " -- $1"
, rule
"Ambiguous type variable (‘\\w+’) arising from a use of (‘\\w+’)"
"Type variable $1 is ambiguous in $2."
, rule
"prevents the constraint (‘.+’) from being solved.*"
"Can't pick an instance for $1."
, rule
"(Probable|Possible) fix:"
''
---
Maybe-fix:''
, rule
"use a type annotation to specify what.*"
"add type annotations to disambiguate."
, rule
"No instance for (.*?) arising from (a|the)( use of)? (.*)"
"Need a $1 instance for usage of $4"
, rule
"(?s)the type signature for:\n "
"\n"
, rule
"(?s)These potential instances .*? -fprint-potential-instances to see them all\\)"
"More info: compile with -fprint-potential-instances."
, rule
"Relevant bindings include"
"Known types:\n"
] : List Rule
} : Config
...@@ -2,8 +2,7 @@ ...@@ -2,8 +2,7 @@
# https://vadosware.io/post/zero-to-continuous-integrated-testing-a-haskell-project-with-gitlab/ # https://vadosware.io/post/zero-to-continuous-integrated-testing-a-haskell-project-with-gitlab/
# #
# #
image: cgenie/stack-build:lts-18.18-garg image: adinapoli/gargantext:v1
#image: cgenie/nixos-stack:latest
variables: variables:
STACK_ROOT: "${CI_PROJECT_DIR}/.stack-root" STACK_ROOT: "${CI_PROJECT_DIR}/.stack-root"
...@@ -15,49 +14,70 @@ variables: ...@@ -15,49 +14,70 @@ variables:
stages: stages:
- deps - deps
- docs
- test - test
- docs
- cabal
deps: deps:
stage: deps
cache: cache:
# cache per branch name # cache per branch name
# key: ${CI_COMMIT_REF_SLUG} # key: ${CI_COMMIT_REF_SLUG}
paths: paths:
- .stack
- .stack-root/ - .stack-root/
- .stack-work/ - .stack-work/
- target - target
script: script:
- stack build --no-terminal --haddock --no-haddock-deps --only-dependencies --fast - echo "Building the project from '$CI_PROJECT_DIR'"
- hpack
- nix-shell --run "LC_ALL=C.UTF-8 stack build --no-terminal --haddock --no-haddock-deps --only-dependencies --fast"
docs: docs:
stage: docs
cache: cache:
# cache per branch name # cache per branch name
# key: ${CI_COMMIT_REF_SLUG} # key: ${CI_COMMIT_REF_SLUG}
paths: paths:
- .stack
- .stack-root/ - .stack-root/
- .stack-work/ - .stack-work/
- target - target
script: script:
- stack build --no-terminal --haddock --no-haddock-deps --fast - hpack
- nix-shell --run "LC_ALL=C.UTF-8 stack build --no-terminal --haddock --no-haddock-deps --fast"
- cp -R "$(stack path --local-install-root)"/doc ./output - cp -R "$(stack path --local-install-root)"/doc ./output
artifacts: artifacts:
paths: paths:
- ./output - ./output
expire_in: 1 week expire_in: 1 week
allow_failure: true
test: test:
stage: test
cache: cache:
# cache per branch name # cache per branch name
# key: ${CI_COMMIT_REF_SLUG} # key: ${CI_COMMIT_REF_SLUG}
paths: paths:
- .stack
- .stack-root/ - .stack-root/
- .stack-work/ - .stack-work/
- target - target
script: script:
- stack test --no-terminal --fast - hpack
- nix-shell --run "LC_ALL=C.UTF-8 stack test --no-terminal --fast"
# TOOO # TOOO
cabal:
stage: cabal
cache:
# cache per branch name
# key: ${CI_COMMIT_REF_SLUG}
paths:
- .stack-root/
- .stack-work/
- dist-newstyle/
- target
script:
- hpack
- nix-shell --run "LC_ALL=C.UTF-8 cabal v2-update 'hackage.haskell.org,2023-04-07T08:35:43Z' && cabal v2-build --dry-run"
allow_failure: true
This diff is collapsed.
...@@ -74,8 +74,12 @@ nix-env (Nix) 2.11.0 ...@@ -74,8 +74,12 @@ nix-env (Nix) 2.11.0
> **NOTE INFO (upgrade/downgrade if needed)** > **NOTE INFO (upgrade/downgrade if needed)**
> Gargantext works with Nix 2.11.0 (older version than current 2.13.2). To downgrade your Nix version: > Gargantext works with Nix 2.11.0 (older version than current 2.13.2). To downgrade your Nix version:
>
> `nix-channel --update; nix-env -iA nixpkgs.nixVersions.nix_2_11 nixpkgs.cacert; systemctl daemon-reload; systemctl restart nix-daemon` > `nix-channel --update; nix-env -iA nixpkgs.nixVersions.nix_2_11 nixpkgs.cacert; systemctl daemon-reload; systemctl restart nix-daemon`
>
> Upgrading Nix: https://nixos.org/manual/nix/unstable/installation/upgrading.html > Upgrading Nix: https://nixos.org/manual/nix/unstable/installation/upgrading.html
>
> **Then, don't forget to exit Terminal and reload to take into account the version change**
#### 3. Build Core Code #### 3. Build Core Code
......
...@@ -23,12 +23,14 @@ import System.Environment (getArgs) ...@@ -23,12 +23,14 @@ import System.Environment (getArgs)
import qualified Data.Text as Text import qualified Data.Text as Text
import Text.Read (readMaybe) import Text.Read (readMaybe)
import Gargantext.API.Dev (withDevEnv, runCmdDev) import Gargantext.API.Dev (withDevEnv, runCmdGargDev)
import Gargantext.API.Admin.EnvTypes (DevEnv(..)) import Gargantext.API.Admin.EnvTypes (DevEnv(..), DevJobHandle(..))
import Gargantext.API.Admin.Orchestrator.Types (JobLog)
import Gargantext.API.Node () -- instances import Gargantext.API.Node () -- instances
import Gargantext.API.Prelude (GargError) import Gargantext.API.Prelude (GargError)
import Gargantext.Core (Lang(..)) import Gargantext.Core (Lang(..))
import Gargantext.Core.Types.Individu (User(..)) import Gargantext.Core.Types.Individu (User(..))
import Gargantext.Core.Types.Query (Limit)
import Gargantext.Database.Action.Flow (flowCorpusFile, flowAnnuaire, TermType(..)) import Gargantext.Database.Action.Flow (flowCorpusFile, flowAnnuaire, TermType(..))
import Gargantext.Database.Action.Flow.Types (FlowCmdM) import Gargantext.Database.Action.Flow.Types (FlowCmdM)
import Gargantext.Database.Admin.Types.Hyperdata (toHyperdataDocument) import Gargantext.Database.Admin.Types.Hyperdata (toHyperdataDocument)
...@@ -36,6 +38,7 @@ import Gargantext.Database.Admin.Types.Node (CorpusId) ...@@ -36,6 +38,7 @@ import Gargantext.Database.Admin.Types.Node (CorpusId)
import Gargantext.Database.Prelude (Cmd) import Gargantext.Database.Prelude (Cmd)
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Core.Text.Corpus.Parsers (FileFormat(..), FileType(..)) import Gargantext.Core.Text.Corpus.Parsers (FileFormat(..), FileType(..))
import Gargantext.Utils.Jobs (MonadJobStatus, JobHandle)
main :: IO () main :: IO ()
main = do main = do
...@@ -47,17 +50,17 @@ main = do ...@@ -47,17 +50,17 @@ main = do
--tt = (Unsupervised EN 6 0 Nothing) --tt = (Unsupervised EN 6 0 Nothing)
tt = (Multi EN) tt = (Multi EN)
format = CsvGargV3 -- CsvHal --WOS format = CsvGargV3 -- CsvHal --WOS
limit' = case (readMaybe limit :: Maybe Int) of limit' = case (readMaybe limit :: Maybe Limit) of
Nothing -> panic $ "Cannot read limit: " <> (Text.pack limit) Nothing -> panic $ "Cannot read limit: " <> (Text.pack limit)
Just l -> l Just l -> l
corpus :: forall m. FlowCmdM DevEnv GargError m => m CorpusId corpus :: forall m. (FlowCmdM DevEnv GargError m, MonadJobStatus m, JobHandle m ~ DevJobHandle) => m CorpusId
corpus = flowCorpusFile (UserName $ cs user) (Left (cs name :: Text)) limit' tt format Plain corpusPath Nothing (\_ -> pure ()) corpus = flowCorpusFile (UserName $ cs user) (Left (cs name :: Text)) limit' tt format Plain corpusPath Nothing DevJobHandle
corpusCsvHal :: forall m. FlowCmdM DevEnv GargError m => m CorpusId corpusCsvHal :: forall m. (FlowCmdM DevEnv GargError m, MonadJobStatus m, JobHandle m ~ DevJobHandle) => m CorpusId
corpusCsvHal = flowCorpusFile (UserName $ cs user) (Left (cs name :: Text)) limit' tt CsvHal Plain corpusPath Nothing (\_ -> pure ()) corpusCsvHal = flowCorpusFile (UserName $ cs user) (Left (cs name :: Text)) limit' tt CsvHal Plain corpusPath Nothing DevJobHandle
annuaire :: forall m. FlowCmdM DevEnv GargError m => m CorpusId annuaire :: forall m. (FlowCmdM DevEnv GargError m, MonadJobStatus m, JobHandle m ~ DevJobHandle) => m CorpusId
annuaire = flowAnnuaire (UserName $ cs user) (Left "Annuaire") (Multi EN) corpusPath (\_ -> pure ()) annuaire = flowAnnuaire (UserName $ cs user) (Left "Annuaire") (Multi EN) corpusPath DevJobHandle
{- {-
let debatCorpus :: forall m. FlowCmdM DevEnv GargError m => m CorpusId let debatCorpus :: forall m. FlowCmdM DevEnv GargError m => m CorpusId
...@@ -72,15 +75,15 @@ main = do ...@@ -72,15 +75,15 @@ main = do
withDevEnv iniPath $ \env -> do withDevEnv iniPath $ \env -> do
_ <- if fun == "corpus" _ <- if fun == "corpus"
then runCmdDev env corpus then runCmdGargDev env corpus
else pure 0 --(cs "false") else pure 0 --(cs "false")
_ <- if fun == "corpusCsvHal" _ <- if fun == "corpusCsvHal"
then runCmdDev env corpusCsvHal then runCmdGargDev env corpusCsvHal
else pure 0 --(cs "false") else pure 0 --(cs "false")
_ <- if fun == "annuaire" _ <- if fun == "annuaire"
then runCmdDev env annuaire then runCmdGargDev env annuaire
else pure 0 else pure 0
{- {-
_ <- if corpusType == "csv" _ <- if corpusType == "csv"
......
...@@ -14,25 +14,17 @@ Portability : POSIX ...@@ -14,25 +14,17 @@ Portability : POSIX
module Main where module Main where
import Data.Either (Either(..))
import Gargantext.API.Dev (withDevEnv, runCmdDev) import Gargantext.API.Dev (withDevEnv, runCmdDev)
import Gargantext.API.Node () -- instances only import Gargantext.API.Node () -- instances only
import Gargantext.API.Prelude (GargError) import Gargantext.API.Prelude (GargError)
import Gargantext.Core.Types.Individu (User(..), arbitraryNewUsers, NewUser(..), arbitraryUsername, GargPassword(..)) import Gargantext.Core.NLP (HasNLPServer)
import Gargantext.Database.Action.Flow (getOrMkRoot, getOrMk_RootWithCorpus) import Gargantext.Core.Types.Individu (User(..))
import Gargantext.Database.Admin.Config (userMaster, corpusMasterName)
import Gargantext.Database.Admin.Trigger.Init (initFirstTriggers, initLastTriggers)
import Gargantext.Database.Admin.Types.Hyperdata (HyperdataCorpus)
import Gargantext.Database.Admin.Types.Node import Gargantext.Database.Admin.Types.Node
import Gargantext.Database.Prelude (CmdR) import Gargantext.Database.Prelude (CmdRandom)
import Gargantext.Database.Query.Table.Node (getOrMkList)
import Gargantext.Database.Query.Table.User (insertNewUsers, )
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Prelude.Config (GargConfig(..), readConfig) import Gargantext.Prelude.Config (readConfig)
import Prelude (getLine, read) import Prelude (read)
import System.Environment (getArgs) import System.Environment (getArgs)
import Gargantext.Database.Action.User.New (newUsers)
import Gargantext.Core.Types.Individu (User(..))
import qualified Gargantext.API.Node.Share as Share import qualified Gargantext.API.Node.Share as Share
main :: IO () main :: IO ()
...@@ -43,9 +35,9 @@ main = do ...@@ -43,9 +35,9 @@ main = do
then panic "USAGE: ./gargantext-init gargantext.ini username node_id student@university.edu" then panic "USAGE: ./gargantext-init gargantext.ini username node_id student@university.edu"
else pure () else pure ()
cfg <- readConfig iniPath _cfg <- readConfig iniPath
let invite :: CmdR GargError Int let invite :: (CmdRandom env GargError m, HasNLPServer env) => m Int
invite = Share.api (UserName $ cs user) (NodeId $ (read node_id :: Int)) (Share.ShareTeamParams $ cs email) invite = Share.api (UserName $ cs user) (NodeId $ (read node_id :: Int)) (Share.ShareTeamParams $ cs email)
withDevEnv iniPath $ \env -> do withDevEnv iniPath $ \env -> do
......
...@@ -278,7 +278,7 @@ main = do ...@@ -278,7 +278,7 @@ main = do
printIOComment (show (length $ nub $ concat $ map text corpus) <> " Size ngs_coterms") printIOComment (show (length $ nub $ concat $ map text corpus) <> " Size ngs_coterms")
printIOComment (show (length mapList) <> " Size ngs_terms List Map Ngrams") printIOComment (show (length mapList) <> " Size ngs_terms List Map Ngrams")
printIOMsg "Reconstruct the phylo" printIOMsg "Reconstruct the phylo"
......
...@@ -11,29 +11,29 @@ Script to start gargantext with different modes (Dev, Prod, Mock). ...@@ -11,29 +11,29 @@ Script to start gargantext with different modes (Dev, Prod, Mock).
-} -}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE Strict #-} {-# LANGUAGE Strict #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -fno-warn-orphans #-} {-# OPTIONS_GHC -fno-warn-orphans #-}
module Main where module Main where
import Data.Version (showVersion)
import Data.Maybe (fromMaybe)
import Data.Text (unpack) import Data.Text (unpack)
import qualified Paths_gargantext as PG -- cabal magic build module import Data.Version (showVersion)
import Database.PostgreSQL.Simple.SqlQQ (sql)
import GHC.IO.Exception (IOException)
import Gargantext.API (startGargantext, Mode(..)) -- , startGargantextMock)
import Gargantext.API.Admin.EnvTypes (DevEnv)
import Gargantext.API.Dev (withDevEnv, runCmdDev)
import Gargantext.Prelude
import Options.Generic import Options.Generic
import System.Exit (exitSuccess) import System.Exit (exitSuccess)
import qualified Paths_gargantext as PG -- cabal magic build module
import Gargantext.Prelude
import Gargantext.API (startGargantext, Mode(..)) -- , startGargantextMock)
--------------------------------------------------------
-- Graph Tests
--import qualified Gargantext.Graph.Utils as U
--import qualified Gargantext.Graph.Distances.Conditional as C
--import qualified Gargantext.Graph.Distances.Distributional as D
--import qualified Gargantext.Graph.Distances.Matrice as M
--------------------------------------------------------
instance ParseRecord Mode instance ParseRecord Mode
instance ParseField Mode instance ParseField Mode
...@@ -59,24 +59,25 @@ main :: IO () ...@@ -59,24 +59,25 @@ main :: IO ()
main = do main = do
MyOptions myMode myPort myIniFile myVersion <- unwrapRecord MyOptions myMode myPort myIniFile myVersion <- unwrapRecord
"Gargantext server" "Gargantext server"
---------------------------------------------------------------
if myVersion then do if myVersion then do
putStrLn $ "Version: " <> showVersion PG.version putStrLn $ "Version: " <> showVersion PG.version
System.Exit.exitSuccess System.Exit.exitSuccess
else else
return () return ()
---------------------------------------------------------------
let myPort' = case myPort of let myPort' = case myPort of
Just p -> p Just p -> p
Nothing -> 8008 Nothing -> 8008
myIniFile' = case myIniFile of
Nothing -> panic "[ERROR] gargantext.ini needed"
Just i -> i
---------------------------------------------------------------
let start = case myMode of let start = case myMode of
Mock -> panic "[ERROR] Mock mode unsupported" Mock -> panic "[ERROR] Mock mode unsupported"
_ -> startGargantext myMode myPort' (unpack myIniFile') _ -> startGargantext myMode myPort' (unpack myIniFile')
where
myIniFile' = case myIniFile of
Nothing -> panic "[ERROR] gargantext.ini needed"
Just i -> i
putStrLn $ "Starting with " <> show myMode <> " mode." putStrLn $ "Starting with " <> show myMode <> " mode."
start start
---------------------------------------------------------------
This diff is collapsed.
...@@ -4,4 +4,4 @@ tmux new -d -s gargantext './server' \; \ ...@@ -4,4 +4,4 @@ tmux new -d -s gargantext './server' \; \
split-window -h -d 'cd ./purescript-gargantext ; ./server' \; \ split-window -h -d 'cd ./purescript-gargantext ; ./server' \; \
select-pane -t 1 \; \ select-pane -t 1 \; \
split-window -d 'cd deps/nlp/CoreNLP ; ./startServer.sh' \; \ split-window -d 'cd deps/nlp/CoreNLP ; ./startServer.sh' \; \
split-window -d 'cd deps/nlp/spacy-server ; source env/bin/activate ; ./server' \; \ split-window -d 'cd deps/nlp/spacy-server ; docker-compose up' \; \
FROM fpco/stack-build:lts-18.18 FROM ubuntu:jammy
#RUN apt-key adv --keyserver hkp://pool.sks-keyservers.net:80 --recv-keys 8B1DA6120C2BF624 ARG DEBIAN_FRONTEND=noninteractive
ARG GHC=8.10.7
ARG STACK=2.7.3
ARG CABAL=3.10.1.0
COPY ./shell.nix /builds/gargantext/shell.nix
COPY ./nix/pkgs.nix /builds/gargantext/nix/pkgs.nix
COPY ./nix/pinned-22.05.nix /builds/gargantext/nix/pinned-22.05.nix
ENV TZ=Europe/Rome
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y ca-certificates git libigraph0-dev && \ apt-get install --no-install-recommends -y \
rm -rf /var/lib/apt/lists/* apt-transport-https \
autoconf \
automake \
build-essential \
ca-certificates \
curl \
gcc \
git \
gnupg2 \
libffi-dev \
libffi7 \
libgmp-dev \
libgmp10 \
libncurses-dev \
libncurses5 \
libnuma-dev \
libtinfo5 \
locales \
lsb-release \
software-properties-common \
strace \
sudo \
wget \
vim \
xz-utils \
zlib1g-dev && \
apt-get clean && rm -rf /var/lib/apt/lists/* && \
mkdir -m 0755 /nix && groupadd -r nixbld && chown root /nix && \
for n in $(seq 1 10); do useradd -c "Nix build user $n" -d /var/empty -g nixbld -G nixbld -M -N -r -s "$(command -v nologin)" "nixbld$n"; done
RUN gpg --batch --keyserver keys.openpgp.org --recv-keys 7D1E8AFD1D4A16D71FADA2F2CCC85C0E40C06A8C && \
gpg --batch --keyserver keyserver.ubuntu.com --recv-keys FE5AB6C91FEA597C3B31180B73EDE9E8CFBAEF01
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN set -o pipefail && \
bash <(curl -L https://releases.nixos.org/nix/nix-2.15.0/install) --no-daemon && \
locale-gen en_US.UTF-8 && chown root -R /nix
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8'
ENV USER=root
ENV SHELL /bin/bash
RUN . "$HOME/.nix-profile/etc/profile.d/nix.sh" && \
mkdir -p "/builds/gargantext/" && chmod 777 -R "/builds/gargantext" && \
echo "source $HOME/.nix-profile/etc/profile.d/nix.sh" >> "$HOME/.bashrc" && \
echo `which nix-env`
ENV PATH=/root/.nix-profile/bin:$PATH
RUN . $HOME/.bashrc && nix-env --version
RUN \
curl https://downloads.haskell.org/~ghcup/x86_64-linux-ghcup > /usr/bin/ghcup && \
chmod +x /usr/bin/ghcup && \
ghcup config set gpg-setting GPGLax && \
ghcup -v install ghc --force ${GHC} && \
ghcup -v install cabal --force ${CABAL} && \
ghcup -v install stack --force ${STACK}
ENV PATH=/root/.ghcup/bin:$PATH
ENV PATH=/root/.local/bin:$PATH
RUN cd /builds/gargantext && nix-shell
RUN ghcup set 8.10.7 && cabal v2-update && cabal v2-install hpack --overwrite-policy=always
WORKDIR "/builds/gargantext/"
...@@ -48,6 +48,8 @@ services: ...@@ -48,6 +48,8 @@ services:
- postgres - postgres
links: links:
- postgres - postgres
volumes:
- pgadmin:/var/lib/pgadmin
corenlp: corenlp:
image: 'cgenie/corenlp-garg' image: 'cgenie/corenlp-garg'
...@@ -65,3 +67,4 @@ volumes: ...@@ -65,3 +67,4 @@ volumes:
#garg-pgdata: #garg-pgdata:
garg-pgdata14: garg-pgdata14:
js-cache: js-cache:
pgadmin:
...@@ -335,3 +335,25 @@ CREATE OR REPLACE function node_pos(int, int) returns bigint ...@@ -335,3 +335,25 @@ CREATE OR REPLACE function node_pos(int, int) returns bigint
--drop index node_by_pos; --drop index node_by_pos;
--create index node_by_pos on nodes using btree(node_pos(id,typename)); --create index node_by_pos on nodes using btree(node_pos(id,typename));
-- Optimization for Ngrams Table View
-- CREATE MATERIALIZED VIEW IF NOT EXISTS context_node_ngrams_view AS
-- SELECT DISTINCT context_node_ngrams.context_id, ngrams_id, nodes_contexts.node_id
-- FROM nodes_contexts
-- JOIN context_node_ngrams
-- ON context_node_ngrams.context_id = nodes_contexts.context_id;
-- CREATE INDEX IF NOT EXISTS context_node_ngrams_view_context_id_idx
-- ON context_node_ngrams_view(context_id);
-- CREATE INDEX IF NOT EXISTS context_node_ngrams_view_ngrams_id_idx
-- ON context_node_ngrams_view(ngrams_id);
-- CREATE INDEX IF NOT EXISTS context_node_ngrams_view_node_id_idx
-- ON context_node_ngrams_view(node_id);
-- CREATE UNIQUE INDEX IF NOT EXISTS context_node_ngrams_view_context_ngrams_node_uniq_idx
-- ON context_node_ngrams_view (context_id, ngrams_id, node_id);
CREATE INDEX IF NOT EXISTS context_node_ngrams_context_id_ngrams_id_idx
ON context_node_ngrams(context_id, ngrams_id);
CREATE INDEX IF NOT EXISTS node_stories_ngrams_id_idx
ON node_stories(ngrams_id);
-- create materialized view if not exists context_node_ngrams_view as
-- select context_node_ngrams.context_id, ngrams_id, nodes_contexts.node_id
-- from nodes_contexts
-- join context_node_ngrams
-- on context_node_ngrams.context_id = nodes_contexts.context_id;
-- create index if not exists context_node_ngrams_view_context_id_idx on context_node_ngrams_view(context_id);
-- create index if not exists context_node_ngrams_view_ngrams_id_idx on context_node_ngrams_view(ngrams_id);
-- create index if not exists context_node_ngrams_view_node_id_idx on context_node_ngrams_view(node_id);
create index if not exists context_node_ngrams_context_id_ngrams_id_idx on context_node_ngrams(context_id, ngrams_id);
create index if not exists node_stories_ngrams_id_idx on node_stories(ngrams_id);
-- Remove unused old materialized view
drop materialized view context_node_ngrams_view;
-- FIX NGRAMS Parents
with query as (
with child_ngrams as
(select jsonb_array_elements_text(ngrams_repo_element->'children') as term
from node_stories),
parent_ngrams as
(select ngrams_repo_element->>'root' as term
from node_stories)
(select child_ngrams.term, ngrams.terms
from child_ngrams
left join ngrams on child_ngrams.term = ngrams.terms
where ngrams.terms is null
union
select parent_ngrams.term, ngrams.terms
from parent_ngrams
left join ngrams on parent_ngrams.term = ngrams.terms
where ngrams.terms is null
and parent_ngrams.term is not null)
order by term
)
INSERT INTO ngrams (terms) select term from query;
-- ADD triggers
CREATE OR REPLACE FUNCTION check_node_stories_json()
RETURNS TRIGGER AS $$
DECLARE
missing_ngrams_exist boolean;
BEGIN
WITH child_ngrams as
(SELECT jsonb_array_elements_text(NEW.ngrams_repo_element->'children') AS term),
parent_ngrams AS
(SELECT NEW.ngrams_repo_element->>'root' AS term),
ngrams_child_parent AS
(SELECT child_ngrams.term, ngrams.terms
FROM child_ngrams
LEFT JOIN ngrams ON child_ngrams.term = ngrams.terms
WHERE ngrams.terms IS NULL
UNION
SELECT parent_ngrams.term, ngrams.terms
FROM parent_ngrams
LEFT JOIN ngrams ON parent_ngrams.term = ngrams.terms
WHERE ngrams.terms IS NULL
AND parent_ngrams.term IS NOT NULL)
SELECT EXISTS(SELECT * FROM ngrams_child_parent) INTO missing_ngrams_exist;
IF missing_ngrams_exist THEN
RAISE EXCEPTION 'node_stories: ngrams are missing: %', row_to_json(NEW);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE TRIGGER check_node_stories_json_trg
AFTER INSERT OR UPDATE
ON node_stories
FOR EACH ROW
EXECUTE PROCEDURE check_node_stories_json();
CREATE OR REPLACE FUNCTION check_ngrams_json()
RETURNS TRIGGER AS $$
DECLARE
missing_ngrams_exist boolean;
BEGIN
WITH child_ngrams as
(SELECT jsonb_array_elements_text(ngrams_repo_element->'children') AS term
FROM node_stories
WHERE term = OLD.terms),
parent_ngrams AS
(SELECT ngrams_repo_element->>'root' AS term
FROM node_stories
WHERE term = OLD.terms),
child_parent_ngrams AS
(SELECT * FROM child_ngrams
UNION SELECT * FROM parent_ngrams)
SELECT EXISTS(SELECT * FROM child_parent_ngrams) INTO missing_ngrams_exist;
IF missing_ngrams_exist THEN
RAISE EXCEPTION 'ngrams are missing: %', row_to_json(OLD);
END IF;
RETURN OLD;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE TRIGGER check_ngrams_json_trg
AFTER DELETE
ON ngrams
FOR EACH ROW
EXECUTE PROCEDURE check_ngrams_json();
with child_ngrams as
(select jsonb_array_elements_text(ngrams_repo_element->'children') as term
from node_stories),
parent_ngrams as
(select ngrams_repo_element->>'root' as term
from node_stories)
(select child_ngrams.term, ngrams.terms
from child_ngrams
left join ngrams on child_ngrams.term = ngrams.terms
where ngrams.terms is null
union
select parent_ngrams.term, ngrams.terms
from parent_ngrams
left join ngrams on parent_ngrams.term = ngrams.terms
where ngrams.terms is null
and parent_ngrams.term is not null)
order by term;
This diff is collapsed.
...@@ -84,3 +84,15 @@ MAIL_PASSWORD = ...@@ -84,3 +84,15 @@ MAIL_PASSWORD =
MAIL_FROM = MAIL_FROM =
# NoAuth | Normal | SSL | TLS | STARTTLS # NoAuth | Normal | SSL | TLS | STARTTLS
MAIL_LOGIN_TYPE = Normal MAIL_LOGIN_TYPE = Normal
[nlp]
# Possible choices (see Gargantext.Core.NLP):
# - spacy:// (for http:// Spacy)
# - spacys:// (for https:// Spacy)
# - corenlp:// (for http:// CoreNLP)
# - corenlps:// (for https:// CoreNLP)
# - johnsnow:// (for http:// JohnSnow)
# - johnsnows:// (for https:// JohnSnow)
EN = corenlp://localhost:9000
FR = spacy://localhost:8001
All = corenlp://localhost:9000
...@@ -3,6 +3,61 @@ ...@@ -3,6 +3,61 @@
rec { rec {
inherit pkgs; inherit pkgs;
ghc = pkgs.haskell.compiler.ghc8107; ghc = pkgs.haskell.compiler.ghc8107;
igraph_0_10_4 = pkgs.igraph.overrideAttrs (finalAttrs: previousAttrs: {
version = "0.10.4";
src = pkgs.fetchFromGitHub {
owner = "igraph";
repo = "igraph";
rev = "0.10.4";
hash = "sha256-LsTOxUktGZcp46Ec9QH3+9C+VADMYTZZCjKF1gp36xk=";
};
postPatch = ''
echo "0.10.4" > IGRAPH_VERSION
'';
outputs = [ "out" "doc" ];
buildInputs = [
pkgs.arpack
pkgs.blas
pkgs.glpk
pkgs.gmp
pkgs.lapack
pkgs.libxml2
pkgs.plfit
] ++ pkgs.lib.optionals pkgs.stdenv.cc.isClang [
pkgs.llvmPackages.openmp
];
cmakeFlags = [
"-DIGRAPH_USE_INTERNAL_BLAS=OFF"
"-DIGRAPH_USE_INTERNAL_LAPACK=OFF"
"-DIGRAPH_USE_INTERNAL_ARPACK=OFF"
"-DIGRAPH_USE_INTERNAL_GLPK=OFF"
"-DIGRAPH_USE_INTERNAL_GMP=OFF"
"-DIGRAPH_USE_INTERNAL_PLFIT=OFF"
"-DIGRAPH_GLPK_SUPPORT=ON"
"-DIGRAPH_GRAPHML_SUPPORT=ON"
"-DIGRAPH_OPENMP_SUPPORT=ON"
"-DIGRAPH_ENABLE_LTO=AUTO"
"-DIGRAPH_ENABLE_TLS=ON"
"-DBUILD_SHARED_LIBS=ON"
];
postInstall = ''
mkdir -p "$out/share"
cp -r doc "$out/share"
'';
postFixup = previousAttrs.postFixup + ''
CUR_DIR=$PWD
cd "$out/include/igraph" && cp *.h ../
cd $CUR_DIR
'';
});
hsBuildInputs = [ hsBuildInputs = [
ghc ghc
pkgs.cabal-install pkgs.cabal-install
...@@ -16,9 +71,8 @@ rec { ...@@ -16,9 +71,8 @@ rec {
gsl gsl
#haskell-language-server #haskell-language-server
hlint hlint
igraph
libffi libffi
liblapack lapack
lzma lzma
pcre pcre
pkgconfig pkgconfig
...@@ -32,6 +86,7 @@ rec { ...@@ -32,6 +86,7 @@ rec {
icu icu
graphviz graphviz
llvm_9 llvm_9
igraph_0_10_4
] ++ ( lib.optionals stdenv.isDarwin [ ] ++ ( lib.optionals stdenv.isDarwin [
darwin.apple_sdk.frameworks.Accelerate darwin.apple_sdk.frameworks.Accelerate
]); ]);
......
...@@ -6,7 +6,7 @@ name: gargantext ...@@ -6,7 +6,7 @@ name: gargantext
# | | | +----- Layers * : New versions with API additions # | | | +----- Layers * : New versions with API additions
# | | | | +--- Layers * : New versions without API breaking changes # | | | | +--- Layers * : New versions without API breaking changes
# | | | | | # | | | | |
version: '0.0.6.9.5' version: '0.0.6.9.9.6.9'
synopsis: Search, map, share synopsis: Search, map, share
description: Please see README.md description: Please see README.md
category: Data category: Data
...@@ -16,7 +16,8 @@ copyright: ...@@ -16,7 +16,8 @@ copyright:
- ! 'Copyright: (c) 2017-Present: see git logs and README' - ! 'Copyright: (c) 2017-Present: see git logs and README'
license: AGPL-3 license: AGPL-3
homepage: https://gargantext.org homepage: https://gargantext.org
ghc-options: -Wall ghc-options:
- -Wall
dependencies: dependencies:
- extra - extra
- text - text
...@@ -25,6 +26,7 @@ default-extensions: ...@@ -25,6 +26,7 @@ default-extensions:
- DeriveGeneric - DeriveGeneric
- FlexibleContexts - FlexibleContexts
- FlexibleInstances - FlexibleInstances
- GADTs
- GeneralizedNewtypeDeriving - GeneralizedNewtypeDeriving
- MultiParamTypeClasses - MultiParamTypeClasses
- NamedFieldPuns - NamedFieldPuns
...@@ -42,6 +44,9 @@ data-files: ...@@ -42,6 +44,9 @@ data-files:
- ekg-assets/bootstrap-1.4.0.min.css - ekg-assets/bootstrap-1.4.0.min.css
- ekg-assets/chart_line_add.png - ekg-assets/chart_line_add.png
- ekg-assets/cross.png - ekg-assets/cross.png
- test-data/ngrams/GarganText_NgramsTerms-QuantumComputing.json
- test-data/phylo/bpa_phylo_test.json
- test-data/phylo/open_science.json
library: library:
source-dirs: src source-dirs: src
ghc-options: ghc-options:
...@@ -52,12 +57,14 @@ library: ...@@ -52,12 +57,14 @@ library:
- -Wunused-imports - -Wunused-imports
- -Werror - -Werror
- -freduction-depth=300 - -freduction-depth=300
- -fplugin=Clippy
exposed-modules: exposed-modules:
- Gargantext - Gargantext
- Gargantext.API - Gargantext.API
- Gargantext.API.Admin.Auth.Types - Gargantext.API.Admin.Auth.Types
- Gargantext.API.Admin.EnvTypes - Gargantext.API.Admin.EnvTypes
- Gargantext.API.Admin.Settings - Gargantext.API.Admin.Settings
- Gargantext.API.Admin.Orchestrator.Types
- Gargantext.API.Admin.Types - Gargantext.API.Admin.Types
- Gargantext.API.Dev - Gargantext.API.Dev
- Gargantext.API.HashedResponse - Gargantext.API.HashedResponse
...@@ -66,18 +73,25 @@ library: ...@@ -66,18 +73,25 @@ library:
- Gargantext.API.Ngrams.Tools - Gargantext.API.Ngrams.Tools
- Gargantext.API.Ngrams.Types - Gargantext.API.Ngrams.Types
- Gargantext.API.Node - Gargantext.API.Node
- Gargantext.API.Node.Corpus.New
- Gargantext.API.Node.Corpus.Types
- Gargantext.API.Node.File - Gargantext.API.Node.File
- Gargantext.API.Node.Share - Gargantext.API.Node.Share
- Gargantext.API.Prelude - Gargantext.API.Prelude
- Gargantext.Core - Gargantext.Core
- Gargantext.Core.NLP
- Gargantext.Core.Methods.Similarities - Gargantext.Core.Methods.Similarities
- Gargantext.Core.NodeStory - Gargantext.Core.NodeStory
- Gargantext.Core.Text - Gargantext.Core.Text
- Gargantext.Core.Text.Context - Gargantext.Core.Text.Context
- Gargantext.Core.Text.Corpus.API - Gargantext.Core.Text.Corpus.API
- Gargantext.Core.Text.Corpus.API.Arxiv
- Gargantext.Core.Text.Corpus.API.Pubmed
- Gargantext.Core.Text.Corpus.Query
- Gargantext.Core.Text.Corpus.Parsers - Gargantext.Core.Text.Corpus.Parsers
- Gargantext.Core.Text.Corpus.Parsers.CSV - Gargantext.Core.Text.Corpus.Parsers.CSV
- Gargantext.Core.Text.Corpus.Parsers.Date.Parsec - Gargantext.Core.Text.Corpus.Parsers.Date.Parsec
- Gargantext.Core.Text.Corpus.Parsers.JSON
- Gargantext.Core.Text.List.Formats.CSV - Gargantext.Core.Text.List.Formats.CSV
- Gargantext.Core.Text.Metrics - Gargantext.Core.Text.Metrics
- Gargantext.Core.Text.Metrics.CharByChar - Gargantext.Core.Text.Metrics.CharByChar
...@@ -88,6 +102,7 @@ library: ...@@ -88,6 +102,7 @@ library:
- Gargantext.Core.Text.Terms - Gargantext.Core.Text.Terms
- Gargantext.Core.Text.Terms.Eleve - Gargantext.Core.Text.Terms.Eleve
- Gargantext.Core.Text.Terms.Mono - Gargantext.Core.Text.Terms.Mono
- Gargantext.Core.Text.Terms.Multi
- Gargantext.Core.Text.Terms.Multi.Lang.En - Gargantext.Core.Text.Terms.Multi.Lang.En
- Gargantext.Core.Text.Terms.Multi.Lang.Fr - Gargantext.Core.Text.Terms.Multi.Lang.Fr
- Gargantext.Core.Text.Terms.Multi.RAKE - Gargantext.Core.Text.Terms.Multi.RAKE
...@@ -95,6 +110,8 @@ library: ...@@ -95,6 +110,8 @@ library:
- Gargantext.Core.Types - Gargantext.Core.Types
- Gargantext.Core.Types.Individu - Gargantext.Core.Types.Individu
- Gargantext.Core.Types.Main - Gargantext.Core.Types.Main
- Gargantext.Core.Types.Query
- Gargantext.Core.Types.Phylo
- Gargantext.Core.Utils - Gargantext.Core.Utils
- Gargantext.Core.Utils.Prefix - Gargantext.Core.Utils.Prefix
- Gargantext.Core.Viz.Graph - Gargantext.Core.Viz.Graph
...@@ -125,7 +142,7 @@ library: ...@@ -125,7 +142,7 @@ library:
- Gargantext.Database.Schema.Ngrams - Gargantext.Database.Schema.Ngrams
- Gargantext.Defaults - Gargantext.Defaults
- Gargantext.Utils.Jobs - Gargantext.Utils.Jobs
- Gargantext.Utils.Jobs.API - Gargantext.Utils.Jobs.Internal
- Gargantext.Utils.Jobs.Map - Gargantext.Utils.Jobs.Map
- Gargantext.Utils.Jobs.Monad - Gargantext.Utils.Jobs.Monad
- Gargantext.Utils.Jobs.Queue - Gargantext.Utils.Jobs.Queue
...@@ -157,11 +174,13 @@ library: ...@@ -157,11 +174,13 @@ library:
- blaze-html - blaze-html
- blaze-markup - blaze-markup
- blaze-svg - blaze-svg
- boolexpr
- bytestring - bytestring
- case-insensitive - case-insensitive
- cassava - cassava
- cereal # (IGraph) - cereal # (IGraph)
- cborg - cborg
- ghc-clippy-plugin
- conduit - conduit
- conduit-extra - conduit-extra
- containers - containers
...@@ -171,6 +190,7 @@ library: ...@@ -171,6 +190,7 @@ library:
- crawlerISTEX - crawlerISTEX
- crawlerIsidore - crawlerIsidore
- crawlerPubMed - crawlerPubMed
- cron
- cryptohash - cryptohash
- data-time-segment - data-time-segment
- deepseq - deepseq
...@@ -222,6 +242,7 @@ library: ...@@ -222,6 +242,7 @@ library:
- morpheus-graphql-subscriptions - morpheus-graphql-subscriptions
- mtl - mtl
- natural-transformation - natural-transformation
- network-uri
- opaleye - opaleye
- pandoc - pandoc
- parallel - parallel
...@@ -242,6 +263,7 @@ library: ...@@ -242,6 +263,7 @@ library:
- rake - rake
- random - random
- rdf4h - rdf4h
- replace-attoparsec
- regex-compat - regex-compat
- regex-tdfa - regex-tdfa
- resource-pool - resource-pool
...@@ -322,15 +344,16 @@ executables: ...@@ -322,15 +344,16 @@ executables:
- -fprof-auto - -fprof-auto
dependencies: dependencies:
- base - base
- cassava
- containers - containers
- full-text-search
- gargantext - gargantext
- gargantext-prelude - gargantext-prelude
- vector
- cassava
- ini - ini
- optparse-generic - optparse-generic
- postgresql-simple
- unordered-containers - unordered-containers
- full-text-search - vector
gargantext-cli: gargantext-cli:
main: Main.hs main: Main.hs
...@@ -383,7 +406,7 @@ executables: ...@@ -383,7 +406,7 @@ executables:
- split - split
- unordered-containers - unordered-containers
- cryptohash - cryptohash
- time - time
gargantext-import: gargantext-import:
main: Main.hs main: Main.hs
...@@ -413,6 +436,7 @@ executables: ...@@ -413,6 +436,7 @@ executables:
- gargantext - gargantext
- gargantext-prelude - gargantext-prelude
- base - base
- cron
gargantext-invitations: gargantext-invitations:
main: Main.hs main: Main.hs
...@@ -443,6 +467,7 @@ executables: ...@@ -443,6 +467,7 @@ executables:
- gargantext-prelude - gargantext-prelude
- base - base
- postgresql-simple - postgresql-simple
- cron
gargantext-admin: gargantext-admin:
main: Main.hs main: Main.hs
...@@ -476,7 +501,6 @@ executables: ...@@ -476,7 +501,6 @@ executables:
- aeson - aeson
- serialise - serialise
tests: tests:
garg-test: garg-test:
main: Main.hs main: Main.hs
...@@ -496,30 +520,38 @@ tests: ...@@ -496,30 +520,38 @@ tests:
- -rtsopts - -rtsopts
- -with-rtsopts=-N - -with-rtsopts=-N
dependencies: dependencies:
- QuickCheck
- aeson
- async
- base - base
- boolexpr
- bytestring
- conduit
- containers
- crawlerArxiv
- duckling
- gargantext - gargantext
- gargantext-prelude - gargantext-prelude
- hspec - hspec
- QuickCheck - http-client
- quickcheck-instances - http-client-tls
- time - mtl
- parsec - parsec
- patches-class
- patches-map
- duckling - duckling
- quickcheck-instances
- raw-strings-qq
- servant-job
- stm
- tasty
- tasty-hspec
- tasty-hunit
- tasty-quickcheck
- text - text
- time
- unordered-containers - unordered-containers
jobqueue-test: - validity
main: Main.hs
source-dirs: tests/queue
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- base
- gargantext
- hspec
- async
- stm
# garg-doctest: # garg-doctest:
# main: Main.hs # main: Main.hs
# source-dirs: src-doctest # source-dirs: src-doctest
...@@ -547,4 +579,3 @@ tests: ...@@ -547,4 +579,3 @@ tests:
# - OverloadedStrings # - OverloadedStrings
# - RankNTypes # - RankNTypes
# #
This diff is collapsed.
...@@ -18,8 +18,8 @@ import Gargantext.Prelude ...@@ -18,8 +18,8 @@ import Gargantext.Prelude
import Gargantext.Core.Utils import Gargantext.Core.Utils
-- | Core.Utils tests -- | Core.Utils tests
test :: IO () test :: Spec
test = hspec $ do test = do
describe "check if groupWithCounts works" $ do describe "check if groupWithCounts works" $ do
it "simple integer array" $ do it "simple integer array" $ do
(groupWithCounts [1, 2, 3, 1, 2, 3]) `shouldBe` [(1, 2), (2, 2), (3, 2)] (groupWithCounts [1, 2, 3, 1, 2, 3]) `shouldBe` [(1, 2), (2, 2), (3, 2)]
......
...@@ -30,8 +30,8 @@ myCooc = HashMap.fromList [((NgramsTerm {unNgramsTerm = "gev au"},NgramsTerm {un ...@@ -30,8 +30,8 @@ myCooc = HashMap.fromList [((NgramsTerm {unNgramsTerm = "gev au"},NgramsTerm {un
test :: IO () test :: Spec
test = hspec $ do test = do
describe "Cross" $ do describe "Cross" $ do
let let
(distanceMap,_,_) = doSimilarityMap Conditional 0 Weak myCooc (distanceMap,_,_) = doSimilarityMap Conditional 0 Weak myCooc
......
...@@ -10,26 +10,45 @@ Portability : POSIX ...@@ -10,26 +10,45 @@ Portability : POSIX
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Core (Lang(..))
import qualified Core.Text.Corpus.Query as CorpusQuery
import qualified Core.Utils as Utils import qualified Core.Utils as Utils
--import qualified Ngrams.Lang.Fr as Fr --import qualified Ngrams.Lang.Fr as Fr
--import qualified Ngrams.Lang as Lang --import qualified Ngrams.Lang as Lang
import qualified Ngrams.Lang.Occurrences as Occ import qualified Ngrams.NLP as NLP
import qualified Ngrams.Metrics as Metrics import qualified Ngrams.Query as NgramsQuery
import qualified Parsers.Date as PD import qualified Parsers.Date as PD
-- import qualified Graph.Distance as GD -- import qualified Graph.Distance as GD
import qualified Graph.Clustering as Graph import qualified Graph.Clustering as Graph
import qualified Utils.Crypto as Crypto import qualified Utils.Crypto as Crypto
import qualified Utils.Jobs as Jobs
import qualified Offline.JSON as JSON
import Test.Tasty
import Test.Tasty.Hspec
main :: IO () main :: IO ()
main = do main = do
Utils.test utilSpec <- testSpec "Utils" Utils.test
clusteringSpec <- testSpec "Graph Clustering" Graph.test
dateParserSpec <- testSpec "Date Parsing" PD.testFromRFC3339
cryptoSpec <- testSpec "Crypto" Crypto.test
nlpSpec <- testSpec "NLP" NLP.test
jobsSpec <- testSpec "Jobs" Jobs.test
defaultMain $ testGroup "Gargantext"
[ utilSpec
, clusteringSpec
, dateParserSpec
, cryptoSpec
, nlpSpec
, jobsSpec
, NgramsQuery.tests
, CorpusQuery.tests
, JSON.tests
]
-- Occ.parsersTest -- Occ.parsersTest
-- Lang.ngramsExtractionTest FR -- Lang.ngramsExtractionTest FR
-- Lang.ngramsExtractionTest EN -- Lang.ngramsExtractionTest EN
-- Metrics.main -- Metrics.main
Graph.test
PD.testFromRFC3339
-- GD.test -- GD.test
Crypto.test
{-|
Module : Ngrams.NLP
Description :
Copyright : (c) CNRS, 2017-Present
License : AGPL + CECILL v3
Maintainer : team@gargantext.org
Stability : experimental
Portability : POSIX
-}
module Ngrams.NLP where
import Data.Text (Text)
import Test.Hspec
import Gargantext.Prelude
import Gargantext.Core.Text.Terms.Multi
test :: Spec
test = do
describe "Text that should be cleaned before sending it to NLP tools as micro-services." $ do
let text = "This is a url http://cnrs.gargantext.org to be remove and another one www.gargantext.org and digits 343242-2332 to be remove and some to keep: 232 231 33." :: Text
let result = "This is a url to be remove and another one and digits to be remove and some to keep: 232 231 33."
it "NLP Clean Text before sending to micro services:" $ cleanTextForNLP text `shouldBe` result
This diff is collapsed.
{-# LANGUAGE ScopedTypeVariables #-}
module Ngrams.Query.PaginationCorpus where
import Prelude
import Data.Aeson
import Data.Map.Strict (Map)
import Gargantext.API.Ngrams
import Gargantext.API.Ngrams.Types
import Gargantext.Core.Types.Main
import Gargantext.Database.Admin.Types.Node
import System.IO.Unsafe
import qualified Data.ByteString as B
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set
import Paths_gargantext
implementationElem :: NgramsElement
implementationElem = NgramsElement {
_ne_ngrams = "implementation"
, _ne_size = 1
, _ne_list = MapTerm
, _ne_occurrences = Set.fromList [ NodeId 1, NodeId 2, NodeId 3, NodeId 4, NodeId 5 ]
, _ne_root = Nothing
, _ne_parent = Nothing
, _ne_children = mSetFromList [ "code", "functions", "language", "programs" ]
}
languagesElem :: NgramsElement
languagesElem = NgramsElement {
_ne_ngrams = NgramsTerm {unNgramsTerm = "languages"}
, _ne_size = 1
, _ne_list = MapTerm
, _ne_occurrences = Set.fromList [ NodeId 1, NodeId 2 , NodeId 3 , NodeId 4 ]
, _ne_root = Nothing
, _ne_parent = Nothing
, _ne_children = mSetFromList [ "approach", "use" ]
}
termsElem :: NgramsElement
termsElem = NgramsElement {
_ne_ngrams = NgramsTerm {unNgramsTerm = "terms"}
, _ne_size = 1
, _ne_list = MapTerm
, _ne_occurrences = Set.fromList [ NodeId 1, NodeId 2 , NodeId 3 ]
, _ne_root = Nothing
, _ne_parent = Nothing
, _ne_children = mSetFromList [ "algorithm", "evaluation", "monad", "programmers" ]
}
proofElem :: NgramsElement
proofElem = NgramsElement {
_ne_ngrams = NgramsTerm {unNgramsTerm = "proof"}
, _ne_size = 1
, _ne_list = MapTerm
, _ne_occurrences = Set.fromList [ NodeId 1, NodeId 2 ]
, _ne_root = Nothing
, _ne_parent = Nothing
, _ne_children = mSetFromList [ "proofs" ]
}
sideEffectsElem :: NgramsElement
sideEffectsElem = NgramsElement {
_ne_ngrams = NgramsTerm {unNgramsTerm = "side effects"}
, _ne_size = 1
, _ne_list = StopTerm
, _ne_occurrences = Set.fromList [ NodeId 1, NodeId 2, NodeId 3, NodeId 4, NodeId 5, NodeId 6 ]
, _ne_root = Nothing
, _ne_parent = Nothing
, _ne_children = mSetFromList [ ]
}
ooElem :: NgramsElement
ooElem = NgramsElement {
_ne_ngrams = NgramsTerm {unNgramsTerm = "object oriented"}
, _ne_size = 1
, _ne_list = StopTerm
, _ne_occurrences = Set.fromList [ NodeId 1, NodeId 2, NodeId 3, NodeId 4, NodeId 5 ]
, _ne_root = Nothing
, _ne_parent = Nothing
, _ne_children = mSetFromList [ "null pointer exception" ]
}
javaElem :: NgramsElement
javaElem = NgramsElement {
_ne_ngrams = NgramsTerm {unNgramsTerm = "java"}
, _ne_size = 1
, _ne_list = StopTerm
, _ne_occurrences = Set.fromList [ NodeId 1, NodeId 2, NodeId 3 ]
, _ne_root = Nothing
, _ne_parent = Nothing
, _ne_children = mSetFromList [ "JVM" ]
}
pascalElem :: NgramsElement
pascalElem = NgramsElement {
_ne_ngrams = NgramsTerm {unNgramsTerm = "pascal"}
, _ne_size = 1
, _ne_list = StopTerm
, _ne_occurrences = Set.fromList [ NodeId 1, NodeId 2 ]
, _ne_root = Nothing
, _ne_parent = Nothing
, _ne_children = mSetFromList [ "turbo", "borland" ]
}
haskellElem :: NgramsElement
haskellElem = NgramsElement {
_ne_ngrams = NgramsTerm {unNgramsTerm = "haskell"}
, _ne_size = 1
, _ne_list = CandidateTerm
, _ne_occurrences = Set.fromList [ NodeId 1, NodeId 2, NodeId 3, NodeId 4, NodeId 5, NodeId 6, NodeId 7, NodeId 8 ]
, _ne_root = Nothing
, _ne_parent = Nothing
, _ne_children = mSetFromList [ ]
}
concHaskellElem :: NgramsElement
concHaskellElem = NgramsElement {
_ne_ngrams = NgramsTerm {unNgramsTerm = "concurrent haskell"}
, _ne_size = 1
, _ne_list = CandidateTerm
, _ne_occurrences = Set.fromList [ NodeId 1, NodeId 2, NodeId 3, NodeId 4, NodeId 5 ]
, _ne_root = Nothing
, _ne_parent = Nothing
, _ne_children = mSetFromList [ "Simon Marlow" ]
}
-- | A big (for the sake of the tests anyway) corpus which has
-- * 4 @MapTerm@s
-- * 4 @StopTerm@s
-- * 2 @CandidateTerm@s
paginationCorpus :: Versioned (Map NgramsTerm NgramsElement)
paginationCorpus = Versioned 0 $ Map.fromList [
-- Map terms
( "implementation", implementationElem)
, ( "languages", languagesElem)
, ( "terms", termsElem)
, ("proof", proofElem)
-- Stop terms
, ("side effects", sideEffectsElem)
, ("object oriented", ooElem)
, ("java", javaElem)
, ("pascal", pascalElem)
-- Candidate terms
, ("haskell", haskellElem)
, ("concurrent haskell", concHaskellElem)
]
quantumComputingCorpus :: Versioned (Map NgramsTerm NgramsElement)
quantumComputingCorpus = unsafePerformIO $ do
pth <- getDataFileName "test-data/ngrams/GarganText_NgramsTerms-QuantumComputing.json"
jsonBlob <- B.readFile pth
case eitherDecodeStrict' jsonBlob of
Left err -> error err
Right (Versioned ver (mp :: Map NgramsTerm NgramsRepoElement)) ->
pure $ Versioned ver (Map.mapWithKey (\k -> ngramsElementFromRepo k) mp)
{-# NOINLINE quantumComputingCorpus #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE QuasiQuotes #-}
module Offline.JSON (tests) where
import Data.Aeson
import Data.Either
import Gargantext.API.Node.Corpus.New
import Gargantext.API.Node.Corpus.Types
import Gargantext.Core.Types.Phylo
import Gargantext.Core.Viz.Phylo.API
import Prelude
import Test.Tasty
import Test.Tasty.HUnit
import Test.Tasty.QuickCheck
import Text.RawString.QQ
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy.Char8 as C8
import Paths_gargantext
jsonRoundtrip :: (Show a, FromJSON a, ToJSON a, Eq a) => a -> Property
jsonRoundtrip a =
counterexample ("Parsed JSON: " <> C8.unpack (encode a)) $ eitherDecode (encode a) === Right a
tests :: TestTree
tests = testGroup "JSON" [
testProperty "Datafield roundtrips" (jsonRoundtrip @Datafield)
, testProperty "WithQuery roundtrips" (jsonRoundtrip @WithQuery)
, testCase "WithQuery frontend compliance" testWithQueryFrontend
, testGroup "Phylo" [
testProperty "PeriodToNode" (jsonRoundtrip @PeriodToNodeData)
, testProperty "GraphData" (jsonRoundtrip @GraphData)
, testProperty "GraphDataData" (jsonRoundtrip @GraphDataData)
, testProperty "ObjectData" (jsonRoundtrip @ObjectData)
, testProperty "PhyloData" (jsonRoundtrip @PhyloData)
, testProperty "LayerData" (jsonRoundtrip @LayerData)
, testCase "can parse bpa_phylo_test.json" testParseBpaPhylo
, testCase "can parse open_science.json" testOpenSciencePhylo
]
]
testWithQueryFrontend :: Assertion
testWithQueryFrontend = do
assertBool "JSON instance will break frontend!"
(isRight $ eitherDecode @WithQuery (C8.pack cannedWithQueryPayload))
-- The aim of this type is to catch regressions in the frontend serialisation; this
-- is what the frontend currently expects, and therefore if we were to change the JSON
-- instances, this test would fail, and we will be notified.
cannedWithQueryPayload :: String
cannedWithQueryPayload = [r| {"query":"Haskell","node_id":138,"lang":"EN","flowListWith":{"type":"MyListsFirst"},"datafield":"External Arxiv","databases":"Arxiv"} |]
testParseBpaPhylo :: Assertion
testParseBpaPhylo = do
pth <- getDataFileName "test-data/phylo/bpa_phylo_test.json"
jsonBlob <- B.readFile pth
case eitherDecodeStrict' @GraphData jsonBlob of
Left err -> error err
Right _ -> pure ()
testOpenSciencePhylo :: Assertion
testOpenSciencePhylo = do
pth <- getDataFileName "test-data/phylo/open_science.json"
jsonBlob <- B.readFile pth
case eitherDecodeStrict' @PhyloData jsonBlob of
Left err -> error err
Right _ -> pure ()
...@@ -36,8 +36,8 @@ fromRFC3339Inv :: Either ParseError ZonedTime -> Text ...@@ -36,8 +36,8 @@ fromRFC3339Inv :: Either ParseError ZonedTime -> Text
fromRFC3339Inv (Right z) = toRFC3339 z fromRFC3339Inv (Right z) = toRFC3339 z
fromRFC3339Inv (Left pe) = panic . pack $ show pe fromRFC3339Inv (Left pe) = panic . pack $ show pe
testFromRFC3339 :: IO () testFromRFC3339 :: Spec
testFromRFC3339 = hspec $ do testFromRFC3339 = do
describe "Test fromRFC3339: " $ do describe "Test fromRFC3339: " $ do
it "is the inverse of Duckling's toRFC3339" $ property $ it "is the inverse of Duckling's toRFC3339" $ property $
((==) <*> (fromRFC3339 . fromRFC3339Inv)) . Right . looseZonedTimePrecision ((==) <*> (fromRFC3339 . fromRFC3339Inv)) . Right . looseZonedTimePrecision
......
...@@ -16,11 +16,10 @@ import Test.Hspec ...@@ -16,11 +16,10 @@ import Test.Hspec
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Prelude.Crypto.Hash import Gargantext.Prelude.Crypto.Hash
import Gargantext.Prelude.Utils
-- | Crypto Hash tests -- | Crypto Hash tests
test :: IO () test :: Spec
test = hspec $ do test = do
describe "Hash String with frontend works" $ do describe "Hash String with frontend works" $ do
let text = "To hash with backend" :: Text let text = "To hash with backend" :: Text
let hashed = "8a69a94d164279af2b7d1443ce08da6184b3d7e815406076e148159c284b53c3" :: Hash let hashed = "8a69a94d164279af2b7d1443ce08da6184b3d7e815406076e148159c284b53c3" :: Hash
......
This diff is collapsed.
...@@ -26,16 +26,20 @@ Pouillard (who mainly made it). ...@@ -26,16 +26,20 @@ Pouillard (who mainly made it).
-} -}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeOperators #-}
module Gargantext.API module Gargantext.API
where where
import Control.Exception (catch, finally, SomeException) import Control.Concurrent
import Control.Exception (catch, finally, SomeException{-, displayException, IOException-})
import Control.Lens import Control.Lens
import Control.Monad.Except import Control.Monad.Except
import Control.Monad.Reader (runReaderT) import Control.Monad.Reader (runReaderT)
import Data.Either import Data.Either
import Data.Foldable (foldlM)
import Data.List (lookup) import Data.List (lookup)
import Data.Text (pack) import Data.Text (pack)
import Data.Text.Encoding (encodeUtf8) import Data.Text.Encoding (encodeUtf8)
...@@ -52,7 +56,8 @@ import Gargantext.API.Ngrams (saveNodeStoryImmediate) ...@@ -52,7 +56,8 @@ import Gargantext.API.Ngrams (saveNodeStoryImmediate)
import Gargantext.API.Routes import Gargantext.API.Routes
import Gargantext.API.Server (server) import Gargantext.API.Server (server)
import Gargantext.Core.NodeStory import Gargantext.Core.NodeStory
import qualified Gargantext.Database.Prelude as DB -- import Gargantext.Database.Prelude (Cmd)
-- import Gargantext.Database.Action.Metrics.NgramsByContext (refreshNgramsMaterialized)
import Gargantext.Prelude hiding (putStrLn) import Gargantext.Prelude hiding (putStrLn)
import Network.HTTP.Types hiding (Query) import Network.HTTP.Types hiding (Query)
import Network.Wai import Network.Wai
...@@ -62,6 +67,8 @@ import Network.Wai.Middleware.RequestLogger ...@@ -62,6 +67,8 @@ import Network.Wai.Middleware.RequestLogger
import Paths_gargantext (getDataDir) import Paths_gargantext (getDataDir)
import Servant import Servant
import System.FilePath import System.FilePath
import qualified Gargantext.Database.Prelude as DB
import qualified System.Cron.Schedule as Cron
data Mode = Dev | Mock | Prod data Mode = Dev | Mock | Prod
deriving (Show, Read, Generic) deriving (Show, Read, Generic)
...@@ -74,7 +81,8 @@ startGargantext mode port file = do ...@@ -74,7 +81,8 @@ startGargantext mode port file = do
portRouteInfo port portRouteInfo port
app <- makeApp env app <- makeApp env
mid <- makeDevMiddleware mode mid <- makeDevMiddleware mode
run port (mid app) `finally` stopGargantext env periodicActions <- schedulePeriodicActions env
run port (mid app) `finally` stopGargantext env periodicActions
where runDbCheck env = do where runDbCheck env = do
r <- runExceptT (runReaderT DB.dbCheck env) `catch` r <- runExceptT (runReaderT DB.dbCheck env) `catch`
...@@ -91,9 +99,12 @@ portRouteInfo port = do ...@@ -91,9 +99,12 @@ portRouteInfo port = do
putStrLn $ "http://localhost:" <> toUrlPiece port <> "/index.html" putStrLn $ "http://localhost:" <> toUrlPiece port <> "/index.html"
putStrLn $ "http://localhost:" <> toUrlPiece port <> "/swagger-ui" putStrLn $ "http://localhost:" <> toUrlPiece port <> "/swagger-ui"
-- | Stops the gargantext server and cancels all the periodic actions
-- scheduled to run up to that point.
-- TODO clean this Monad condition (more generic) ? -- TODO clean this Monad condition (more generic) ?
stopGargantext :: HasNodeStoryImmediateSaver env => env -> IO () stopGargantext :: HasNodeStoryImmediateSaver env => env -> [ThreadId] -> IO ()
stopGargantext env = do stopGargantext env scheduledPeriodicActions = do
forM_ scheduledPeriodicActions killThread
putStrLn "----- Stopping gargantext -----" putStrLn "----- Stopping gargantext -----"
runReaderT saveNodeStoryImmediate env runReaderT saveNodeStoryImmediate env
...@@ -105,6 +116,31 @@ startGargantextMock port = do ...@@ -105,6 +116,31 @@ startGargantextMock port = do
run port application run port application
-} -}
-- | Schedules all sorts of useful periodic actions to be run while
-- the server is alive accepting requests.
schedulePeriodicActions :: DB.CmdCommon env => env -> IO [ThreadId]
schedulePeriodicActions _env =
-- Add your scheduled actions here.
let actions = [
-- refreshDBViews
]
in foldlM (\ !acc action -> (`mappend` acc) <$> Cron.execSchedule action) [] actions
{-
where
refreshDBViews :: Cron.Schedule ()
refreshDBViews = do
let doRefresh = do
res <- DB.runCmd env (refreshNgramsMaterialized :: Cmd IOException ())
case res of
Left e -> liftIO $ putStrLn $ pack ("Refreshing Ngrams materialized view failed: " <> displayException e)
Right () -> do
_ <- liftIO $ putStrLn $ pack "Refresh Index Database done"
pure ()
Cron.addJob doRefresh "* 2 * * *"
-}
---------------------------------------------------------------------- ----------------------------------------------------------------------
fireWall :: Applicative f => Request -> FireWall -> f Bool fireWall :: Applicative f => Request -> FireWall -> f Bool
......
...@@ -40,30 +40,28 @@ module Gargantext.API.Admin.Auth ...@@ -40,30 +40,28 @@ module Gargantext.API.Admin.Auth
import Control.Lens (view, (#)) import Control.Lens (view, (#))
import Data.Aeson import Data.Aeson
import Data.Swagger (ToSchema(..)) import Data.Swagger (ToSchema(..))
import Data.Text (Text)
import Data.Text.Lazy (toStrict)
import Data.UUID (UUID, fromText, toText) import Data.UUID (UUID, fromText, toText)
import Data.UUID.V4 (nextRandom) import Data.UUID.V4 (nextRandom)
import GHC.Generics (Generic)
import Gargantext.API.Admin.Auth.Types import Gargantext.API.Admin.Auth.Types
import Gargantext.API.Admin.EnvTypes (GargJob(..), Env) import Gargantext.API.Admin.EnvTypes (GargJob(..), Env)
import Gargantext.API.Admin.Orchestrator.Types (JobLog(..), AsyncJobs) import Gargantext.API.Admin.Orchestrator.Types (JobLog(..), AsyncJobs)
import Gargantext.API.Admin.Types import Gargantext.API.Admin.Types
import Gargantext.API.Job (jobLogSuccess)
import Gargantext.API.Prelude (HasJoseError(..), joseError, HasServerError, GargServerC, GargServer, _ServerError, GargM, GargError) import Gargantext.API.Prelude (HasJoseError(..), joseError, HasServerError, GargServerC, GargServer, _ServerError, GargM, GargError)
import Gargantext.Core.Mail (MailModel(..), mail) import Gargantext.Core.Mail (MailModel(..), mail)
import Gargantext.Core.Mail.Types (HasMail, mailSettings) import Gargantext.Core.Mail.Types (mailSettings)
import Gargantext.Core.Types.Individu (User(..), Username, GargPassword(..)) import Gargantext.Core.Types.Individu (User(..), Username, GargPassword(..))
import Gargantext.Database.Action.Flow.Types (FlowCmdM) import Gargantext.Database.Action.Flow.Types (FlowCmdM)
import Gargantext.Database.Admin.Types.Node (NodeId(..), UserId) import Gargantext.Database.Admin.Types.Node (NodeId(..), UserId)
import Gargantext.Database.Prelude (Cmd', CmdM, HasConnectionPool, HasConfig) import Gargantext.Database.Prelude (Cmd', CmdM, CmdCommon)
import Gargantext.Database.Query.Table.User import Gargantext.Database.Query.Table.User
import Gargantext.Database.Query.Tree (isDescendantOf, isIn) import Gargantext.Database.Query.Tree (isDescendantOf, isIn)
import Gargantext.Database.Query.Tree.Root (getRoot) import Gargantext.Database.Query.Tree.Root (getRoot)
import Gargantext.Database.Action.User.New (guessUserName)
import Gargantext.Database.Schema.Node (NodePoly(_node_id)) import Gargantext.Database.Schema.Node (NodePoly(_node_id))
import Gargantext.Prelude hiding (reverse) import Gargantext.Prelude hiding (reverse)
import Gargantext.Prelude.Crypto.Pass.User (gargPass) import Gargantext.Prelude.Crypto.Pass.User (gargPass)
import Gargantext.Utils.Jobs (serveJobsAPI) import Gargantext.Utils.Jobs (serveJobsAPI, MonadJobStatus(..))
import Protolude hiding (to)
import Servant import Servant
import Servant.Auth.Server import Servant.Auth.Server
import qualified Data.Text as Text import qualified Data.Text as Text
...@@ -83,26 +81,32 @@ makeTokenForUser uid = do ...@@ -83,26 +81,32 @@ makeTokenForUser uid = do
either joseError (pure . toStrict . LE.decodeUtf8) e either joseError (pure . toStrict . LE.decodeUtf8) e
-- TODO not sure about the encoding... -- TODO not sure about the encoding...
checkAuthRequest :: (HasSettings env, HasConnectionPool env, HasJoseError err, HasConfig env, HasMail env) checkAuthRequest :: ( HasSettings env, CmdCommon env, HasJoseError err)
=> Username => Username
-> GargPassword -> GargPassword
-> Cmd' env err CheckAuth -> Cmd' env err CheckAuth
checkAuthRequest u (GargPassword p) = do checkAuthRequest couldBeEmail (GargPassword p) = do
candidate <- head <$> getUsersWith u -- Sometimes user put email instead of username
-- hence we have to check before
let usrname = case guessUserName couldBeEmail of
Nothing -> couldBeEmail -- we are sure this is not an email
Just (u,_) -> u -- this was an email in fact
candidate <- head <$> getUsersWith usrname
case candidate of case candidate of
Nothing -> pure InvalidUser Nothing -> pure InvalidUser
Just (UserLight { userLight_password = GargPassword h, .. }) -> Just (UserLight { userLight_password = GargPassword h, .. }) ->
case Auth.checkPassword (Auth.mkPassword p) (Auth.PasswordHash h) of case Auth.checkPassword (Auth.mkPassword p) (Auth.PasswordHash h) of
Auth.PasswordCheckFail -> pure InvalidPassword Auth.PasswordCheckFail -> pure InvalidPassword
Auth.PasswordCheckSuccess -> do Auth.PasswordCheckSuccess -> do
muId <- head <$> getRoot (UserName u) muId <- head <$> getRoot (UserName usrname)
case _node_id <$> muId of case _node_id <$> muId of
Nothing -> pure InvalidUser Nothing -> pure InvalidUser
Just uid -> do Just uid -> do
token <- makeTokenForUser uid token <- makeTokenForUser uid
pure $ Valid token uid userLight_id pure $ Valid token uid userLight_id
auth :: (HasSettings env, HasConnectionPool env, HasJoseError err, HasConfig env, HasMail env) auth :: (HasSettings env, CmdCommon env, HasJoseError err)
=> AuthRequest -> Cmd' env err AuthResponse => AuthRequest -> Cmd' env err AuthResponse
auth (AuthRequest u p) = do auth (AuthRequest u p) = do
checkAuthRequest' <- checkAuthRequest u p checkAuthRequest' <- checkAuthRequest u p
...@@ -177,7 +181,7 @@ forgotPassword :: GargServer ForgotPasswordAPI ...@@ -177,7 +181,7 @@ forgotPassword :: GargServer ForgotPasswordAPI
-- => ForgotPasswordRequest -> Cmd' env err ForgotPasswordResponse -- => ForgotPasswordRequest -> Cmd' env err ForgotPasswordResponse
forgotPassword = forgotPasswordPost :<|> forgotPasswordGet forgotPassword = forgotPasswordPost :<|> forgotPasswordGet
forgotPasswordPost :: ( HasConnectionPool env, HasConfig env, HasMail env) forgotPasswordPost :: (CmdCommon env)
=> ForgotPasswordRequest -> Cmd' env err ForgotPasswordResponse => ForgotPasswordRequest -> Cmd' env err ForgotPasswordResponse
forgotPasswordPost (ForgotPasswordRequest email) = do forgotPasswordPost (ForgotPasswordRequest email) = do
us <- getUsersWithEmail (Text.toLower email) us <- getUsersWithEmail (Text.toLower email)
...@@ -189,7 +193,7 @@ forgotPasswordPost (ForgotPasswordRequest email) = do ...@@ -189,7 +193,7 @@ forgotPasswordPost (ForgotPasswordRequest email) = do
-- users' emails -- users' emails
pure $ ForgotPasswordResponse "ok" pure $ ForgotPasswordResponse "ok"
forgotPasswordGet :: (HasSettings env, HasConnectionPool env, HasJoseError err, HasConfig env, HasMail env, HasServerError err) forgotPasswordGet :: (HasSettings env, CmdCommon env, HasJoseError err, HasServerError err)
=> Maybe Text -> Cmd' env err ForgotPasswordGet => Maybe Text -> Cmd' env err ForgotPasswordGet
forgotPasswordGet Nothing = pure $ ForgotPasswordGet "" forgotPasswordGet Nothing = pure $ ForgotPasswordGet ""
forgotPasswordGet (Just uuid) = do forgotPasswordGet (Just uuid) = do
...@@ -205,7 +209,7 @@ forgotPasswordGet (Just uuid) = do ...@@ -205,7 +209,7 @@ forgotPasswordGet (Just uuid) = do
--------------------- ---------------------
forgotPasswordGetUser :: (HasSettings env, HasConnectionPool env, HasJoseError err, HasConfig env, HasMail env, HasServerError err) forgotPasswordGetUser :: ( HasSettings env, CmdCommon env, HasJoseError err, HasServerError err)
=> UserLight -> Cmd' env err ForgotPasswordGet => UserLight -> Cmd' env err ForgotPasswordGet
forgotPasswordGetUser (UserLight { .. }) = do forgotPasswordGetUser (UserLight { .. }) = do
-- pick some random password -- pick some random password
...@@ -224,7 +228,7 @@ forgotPasswordGetUser (UserLight { .. }) = do ...@@ -224,7 +228,7 @@ forgotPasswordGetUser (UserLight { .. }) = do
pure $ ForgotPasswordGet password pure $ ForgotPasswordGet password
forgotUserPassword :: (HasConnectionPool env, HasConfig env, HasMail env) forgotUserPassword :: (CmdCommon env)
=> UserLight -> Cmd' env err () => UserLight -> Cmd' env err ()
forgotUserPassword (UserLight { .. }) = do forgotUserPassword (UserLight { .. }) = do
--printDebug "[forgotUserPassword] userLight_id" userLight_id --printDebug "[forgotUserPassword] userLight_id" userLight_id
...@@ -249,7 +253,7 @@ forgotUserPassword (UserLight { .. }) = do ...@@ -249,7 +253,7 @@ forgotUserPassword (UserLight { .. }) = do
-------------------------- --------------------------
-- Generate a unique (in whole DB) UUID for passwords. -- Generate a unique (in whole DB) UUID for passwords.
generateForgotPasswordUUID :: (HasConnectionPool env, HasConfig env, HasMail env) generateForgotPasswordUUID :: (CmdCommon env)
=> Cmd' env err UUID => Cmd' env err UUID
generateForgotPasswordUUID = do generateForgotPasswordUUID = do
uuid <- liftBase $ nextRandom uuid <- liftBase $ nextRandom
...@@ -268,23 +272,19 @@ type ForgotPasswordAsyncAPI = Summary "Forgot password asnc" ...@@ -268,23 +272,19 @@ type ForgotPasswordAsyncAPI = Summary "Forgot password asnc"
forgotPasswordAsync :: ServerT ForgotPasswordAsyncAPI (GargM Env GargError) forgotPasswordAsync :: ServerT ForgotPasswordAsyncAPI (GargM Env GargError)
forgotPasswordAsync = forgotPasswordAsync =
serveJobsAPI ForgotPasswordJob $ \p log' -> serveJobsAPI ForgotPasswordJob $ \jHandle p -> forgotPasswordAsync' p jHandle
forgotPasswordAsync' p (liftBase . log')
forgotPasswordAsync' :: (FlowCmdM env err m) forgotPasswordAsync' :: (FlowCmdM env err m, MonadJobStatus m)
=> ForgotPasswordAsyncParams => ForgotPasswordAsyncParams
-> (JobLog -> m ()) -> JobHandle m
-> m JobLog -> m ()
forgotPasswordAsync' (ForgotPasswordAsyncParams { email }) logStatus = do forgotPasswordAsync' (ForgotPasswordAsyncParams { email }) jobHandle = do
let jobLog = JobLog { _scst_succeeded = Just 1
, _scst_failed = Just 0 markStarted 2 jobHandle
, _scst_remaining = Just 1 markProgress 1 jobHandle
, _scst_events = Just []
}
logStatus jobLog
-- printDebug "[forgotPasswordAsync'] email" email -- printDebug "[forgotPasswordAsync'] email" email
_ <- forgotPasswordPost $ ForgotPasswordRequest { _fpReq_email = email } _ <- forgotPasswordPost $ ForgotPasswordRequest { _fpReq_email = email }
pure $ jobLogSuccess jobLog markComplete jobHandle
-- | -- |
{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
module Gargantext.API.Admin.EnvTypes where
module Gargantext.API.Admin.EnvTypes (
import Control.Lens GargJob(..)
, Env(..)
, mkJobHandle
, env_logger
, env_manager
, env_self_url
, menv_firewall
, MockEnv(..)
, DevEnv(..)
, DevJobHandle(..)
, ConcreteJobHandle -- opaque
) where
import Control.Lens hiding ((:<))
import Control.Monad.Except import Control.Monad.Except
import Control.Monad.Reader import Control.Monad.Reader
import Data.Monoid
import Data.Pool (Pool) import Data.Pool (Pool)
import Data.Sequence (Seq, ViewL(..), viewl)
import Database.PostgreSQL.Simple (Connection) import Database.PostgreSQL.Simple (Connection)
import GHC.Generics (Generic) import GHC.Generics (Generic)
import Network.HTTP.Client (Manager) import Network.HTTP.Client (Manager)
import Servant.Client (BaseUrl) import Servant.Client (BaseUrl)
import Servant.Job.Async (HasJobEnv(..), Job) import Servant.Job.Async (HasJobEnv(..), Job)
import qualified Servant.Job.Async as SJ
import System.Log.FastLogger import System.Log.FastLogger
import qualified Servant.Job.Core import qualified Servant.Job.Core
import Gargantext.API.Admin.Types import Gargantext.API.Admin.Types
import Gargantext.API.Admin.Orchestrator.Types import Gargantext.API.Admin.Orchestrator.Types
import Gargantext.API.Prelude (GargError) import Gargantext.API.Job
import Gargantext.API.Prelude (GargM)
import Gargantext.Core.NodeStory import Gargantext.Core.NodeStory
import Gargantext.Core.Mail.Types (HasMail, mailSettings) import Gargantext.Core.Mail.Types (HasMail, mailSettings)
import Gargantext.Core.NLP (NLPServerMap, HasNLPServer(..))
import Gargantext.Database.Prelude (HasConnectionPool(..), HasConfig(..)) import Gargantext.Database.Prelude (HasConnectionPool(..), HasConfig(..))
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Prelude.Config (GargConfig(..)) import Gargantext.Prelude.Config (GargConfig(..))
import Gargantext.Prelude.Mail.Types (MailConfig) import Gargantext.Prelude.Mail.Types (MailConfig)
import qualified Gargantext.Utils.Jobs.Monad as Jobs import qualified Gargantext.Utils.Jobs.Monad as Jobs
import Gargantext.Utils.Jobs.Map (LoggerM, J(..), jTask, rjGetLog)
data GargJob data GargJob
= TableNgramsJob = TableNgramsJob
...@@ -48,17 +66,22 @@ data GargJob ...@@ -48,17 +66,22 @@ data GargJob
| RecomputeGraphJob | RecomputeGraphJob
deriving (Show, Eq, Ord, Enum, Bounded) deriving (Show, Eq, Ord, Enum, Bounded)
-- Do /not/ treat the data types of this type as strict, because it's convenient
-- to be able to partially initialise things like an 'Env' during tests, without
-- having to specify /everything/. This means that when we /construct/ an 'Env',
-- we need to remember to force the fields to WHNF at that point.
data Env = Env data Env = Env
{ _env_settings :: !Settings { _env_settings :: ~Settings
, _env_logger :: !LoggerSet , _env_logger :: ~LoggerSet
, _env_pool :: !(Pool Connection) , _env_pool :: ~(Pool Connection)
, _env_nodeStory :: !NodeStoryEnv , _env_nodeStory :: ~NodeStoryEnv
, _env_manager :: !Manager , _env_manager :: ~Manager
, _env_self_url :: !BaseUrl , _env_self_url :: ~BaseUrl
, _env_scrapers :: !ScrapersEnv , _env_scrapers :: ~ScrapersEnv
, _env_jobs :: !(Jobs.JobEnv GargJob (Dual [JobLog]) JobLog) , _env_jobs :: ~(Jobs.JobEnv GargJob (Seq JobLog) JobLog)
, _env_config :: !GargConfig , _env_config :: ~GargConfig
, _env_mail :: !MailConfig , _env_mail :: ~MailConfig
, _env_nlp :: ~NLPServerMap
} }
deriving (Generic) deriving (Generic)
...@@ -91,15 +114,78 @@ instance HasSettings Env where ...@@ -91,15 +114,78 @@ instance HasSettings Env where
instance HasMail Env where instance HasMail Env where
mailSettings = env_mail mailSettings = env_mail
instance HasNLPServer Env where
nlpServer = env_nlp
instance Servant.Job.Core.HasEnv Env (Job JobLog JobLog) where instance Servant.Job.Core.HasEnv Env (Job JobLog JobLog) where
_env = env_scrapers . Servant.Job.Core._env _env = env_scrapers . Servant.Job.Core._env
instance HasJobEnv Env JobLog JobLog where instance HasJobEnv Env JobLog JobLog where
job_env = env_scrapers job_env = env_scrapers
instance Jobs.MonadJob (ReaderT Env (ExceptT GargError IO)) GargJob (Dual [JobLog]) JobLog where instance Jobs.MonadJob (GargM Env err) GargJob (Seq JobLog) JobLog where
getJobEnv = asks (view env_jobs) getJobEnv = asks (view env_jobs)
-- | The /concrete/ 'JobHandle' in use with our 'GargM' (production) monad. Its
-- constructor it's not exported, to not leak internal details of its implementation.
data ConcreteJobHandle err = JobHandle {
_jh_id :: !(SJ.JobID 'SJ.Safe)
, _jh_logger :: LoggerM (GargM Env err) JobLog
}
-- | Creates a new /concrete/ 'JobHandle', given its underlying 'JobID' and the logging function to
-- be used to report the status.
mkJobHandle :: SJ.JobID 'SJ.Safe
-> LoggerM (GargM Env err) JobLog
-> ConcreteJobHandle err
mkJobHandle jId = JobHandle jId
-- | Updates the status of a 'JobHandle' by using the input 'updateJobStatus' function.
updateJobProgress :: ConcreteJobHandle err -> (JobLog -> JobLog) -> GargM Env err ()
updateJobProgress hdl@(JobHandle _ logStatus) updateJobStatus =
Jobs.getLatestJobStatus hdl >>= logStatus . updateJobStatus
instance Jobs.MonadJobStatus (GargM Env err) where
type JobHandle (GargM Env err) = ConcreteJobHandle err
type JobType (GargM Env err) = GargJob
type JobOutputType (GargM Env err) = JobLog
type JobEventType (GargM Env err) = JobLog
getLatestJobStatus (JobHandle jId _) = do
mb_jb <- Jobs.findJob jId
case mb_jb of
Nothing -> pure noJobLog
Just j -> case jTask j of
QueuedJ _ -> pure noJobLog
RunningJ rj -> liftIO (rjGetLog rj) <&>
\lgs -> case viewl lgs of
EmptyL -> noJobLog
l :< _ -> l
DoneJ lgs _ -> pure $ case viewl lgs of
EmptyL -> noJobLog
l :< _ -> l
withTracer extraLogger (JobHandle jId logger) n = n (JobHandle jId (\w -> logger w >> liftIO (extraLogger w)))
markStarted n jh = updateJobProgress jh (const $ jobLogStart (RemainingSteps n))
markProgress steps jh = updateJobProgress jh (jobLogProgress steps)
markFailure steps mb_msg jh =
updateJobProgress jh (\latest -> case mb_msg of
Nothing -> jobLogFailures steps latest
Just msg -> addErrorEvent msg (jobLogFailures steps latest)
)
markComplete jh = updateJobProgress jh jobLogComplete
markFailed mb_msg jh =
updateJobProgress jh (\latest -> case mb_msg of
Nothing -> jobLogFailTotal latest
Just msg -> jobLogFailTotalWithMessage msg latest
)
data MockEnv = MockEnv data MockEnv = MockEnv
{ _menv_firewall :: !FireWall { _menv_firewall :: !FireWall
} }
...@@ -107,18 +193,42 @@ data MockEnv = MockEnv ...@@ -107,18 +193,42 @@ data MockEnv = MockEnv
makeLenses ''MockEnv makeLenses ''MockEnv
data DevEnv = DevEnv data DevEnv = DevEnv
{ _dev_env_settings :: !Settings { _dev_env_settings :: !Settings
, _dev_env_config :: !GargConfig , _dev_env_config :: !GargConfig
, _dev_env_pool :: !(Pool Connection) , _dev_env_pool :: !(Pool Connection)
, _dev_env_nodeStory :: !NodeStoryEnv , _dev_env_nodeStory :: !NodeStoryEnv
, _dev_env_mail :: !MailConfig , _dev_env_mail :: !MailConfig
, _dev_env_nlp :: !NLPServerMap
} }
makeLenses ''DevEnv makeLenses ''DevEnv
-- | Our /mock/ job handle.
data DevJobHandle = DevJobHandle
instance Jobs.MonadJobStatus (GargM DevEnv err) where
type JobHandle (GargM DevEnv err) = DevJobHandle
type JobType (GargM DevEnv err) = GargJob
type JobOutputType (GargM DevEnv err) = JobLog
type JobEventType (GargM DevEnv err) = JobLog
getLatestJobStatus DevJobHandle = pure noJobLog
withTracer _ DevJobHandle n = n DevJobHandle
markStarted _ _ = pure ()
markProgress _ _ = pure ()
markFailure _ _ _ = pure ()
markComplete _ = pure ()
markFailed _ _ = pure ()
instance HasConfig DevEnv where instance HasConfig DevEnv where
hasConfig = dev_env_config hasConfig = dev_env_config
...@@ -146,3 +256,6 @@ instance HasNodeArchiveStoryImmediateSaver DevEnv where ...@@ -146,3 +256,6 @@ instance HasNodeArchiveStoryImmediateSaver DevEnv where
instance HasMail DevEnv where instance HasMail DevEnv where
mailSettings = dev_env_mail mailSettings = dev_env_mail
instance HasNLPServer DevEnv where
nlpServer = dev_env_nlp
{-# OPTIONS_GHC -fno-warn-orphans #-} {-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeOperators #-}
module Gargantext.API.Admin.Orchestrator.Types module Gargantext.API.Admin.Orchestrator.Types
where where
import Control.Lens hiding (elements) import Control.Lens hiding (elements)
import Control.Monad.Reader (MonadReader)
import Data.Aeson import Data.Aeson
import Data.Morpheus.Types import Data.Morpheus.Types
( GQLType ( GQLType
...@@ -24,9 +23,7 @@ import Test.QuickCheck.Arbitrary ...@@ -24,9 +23,7 @@ import Test.QuickCheck.Arbitrary
import qualified Gargantext.API.GraphQL.Utils as GQLU import qualified Gargantext.API.GraphQL.Utils as GQLU
import Gargantext.Core.Types (TODO(..)) import Gargantext.Core.Types (TODO(..))
import Gargantext.Database.Prelude (HasConfig(..))
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Prelude.Config (gc_pubmed_api_key)
------------------------------------------------------------------------ ------------------------------------------------------------------------
instance Arbitrary a => Arbitrary (JobStatus 'Safe a) where instance Arbitrary a => Arbitrary (JobStatus 'Safe a) where
...@@ -37,39 +34,24 @@ instance Arbitrary a => Arbitrary (JobOutput a) where ...@@ -37,39 +34,24 @@ instance Arbitrary a => Arbitrary (JobOutput a) where
-- | Main Types -- | Main Types
-- TODO IsidoreAuth -- TODO IsidoreAuth
data ExternalAPIs = All data ExternalAPIs = PubMed
| PubMed { mAPIKey :: Maybe Text }
| Arxiv | Arxiv
| HAL | HAL
| IsTex | IsTex
| Isidore | Isidore
deriving (Show, Eq, Generic) deriving (Show, Eq, Generic, Enum, Bounded)
-- | Main Instances -- | Main Instances
instance FromJSON ExternalAPIs instance FromJSON ExternalAPIs
instance ToJSON ExternalAPIs instance ToJSON ExternalAPIs
externalAPIs :: ( MonadReader env m externalAPIs :: [ExternalAPIs]
, HasConfig env) => m [ExternalAPIs] externalAPIs = [minBound .. maxBound]
externalAPIs = do
pubmed_api_key <- view $ hasConfig . gc_pubmed_api_key
pure [ All
, PubMed { mAPIKey = Just pubmed_api_key }
, Arxiv
, HAL
, IsTex
, Isidore ]
instance Arbitrary ExternalAPIs instance Arbitrary ExternalAPIs
where where
arbitrary = elements [ All arbitrary = arbitraryBoundedEnum
, PubMed { mAPIKey = Nothing }
, Arxiv
, HAL
, IsTex
, Isidore ]
instance ToSchema ExternalAPIs where instance ToSchema ExternalAPIs where
declareNamedSchema = genericDeclareNamedSchemaUnrestricted defaultSchemaOptions declareNamedSchema = genericDeclareNamedSchemaUnrestricted defaultSchemaOptions
...@@ -101,7 +83,7 @@ data ScraperEvent = ScraperEvent ...@@ -101,7 +83,7 @@ data ScraperEvent = ScraperEvent
, _scev_level :: !(Maybe Text) , _scev_level :: !(Maybe Text)
, _scev_date :: !(Maybe Text) , _scev_date :: !(Maybe Text)
} }
deriving (Show, Generic) deriving (Show, Generic, Eq)
instance Arbitrary ScraperEvent where instance Arbitrary ScraperEvent where
arbitrary = ScraperEvent <$> elements [Nothing, Just "test message"] arbitrary = ScraperEvent <$> elements [Nothing, Just "test message"]
...@@ -122,10 +104,13 @@ data JobLog = JobLog ...@@ -122,10 +104,13 @@ data JobLog = JobLog
, _scst_remaining :: !(Maybe Int) , _scst_remaining :: !(Maybe Int)
, _scst_events :: !(Maybe [ScraperEvent]) , _scst_events :: !(Maybe [ScraperEvent])
} }
deriving (Show, Generic) deriving (Show, Generic, Eq)
makeLenses ''JobLog makeLenses ''JobLog
noJobLog :: JobLog
noJobLog = JobLog Nothing Nothing Nothing Nothing
instance Arbitrary JobLog where instance Arbitrary JobLog where
arbitrary = JobLog arbitrary = JobLog
<$> arbitrary <$> arbitrary
......
...@@ -12,6 +12,7 @@ TODO-SECURITY: Critical ...@@ -12,6 +12,7 @@ TODO-SECURITY: Critical
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TemplateHaskell #-}
...@@ -43,10 +44,12 @@ import qualified Data.ByteString.Lazy as L ...@@ -43,10 +44,12 @@ import qualified Data.ByteString.Lazy as L
import Gargantext.API.Admin.EnvTypes import Gargantext.API.Admin.EnvTypes
import Gargantext.API.Admin.Types import Gargantext.API.Admin.Types
-- import Gargantext.API.Ngrams.Types (NgramsRepo, HasRepo(..), RepoEnv(..), r_version, initRepo, renv_var, renv_lock) -- import Gargantext.API.Ngrams.Types (NgramsRepo, HasRepo(..), RepoEnv(..), r_version, initRepo, renv_var, renv_lock)
import Gargantext.Core.NLP (nlpServerMap)
import Gargantext.Database.Prelude (databaseParameters, hasConfig) import Gargantext.Database.Prelude (databaseParameters, hasConfig)
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Prelude.Config (gc_js_job_timeout, gc_js_id_timeout) import Gargantext.Prelude.Config (gc_js_job_timeout, gc_js_id_timeout)
import qualified Gargantext.Prelude.Mail as Mail import qualified Gargantext.Prelude.Mail as Mail
import qualified Gargantext.Prelude.NLP as NLP
import qualified Gargantext.Utils.Jobs as Jobs import qualified Gargantext.Utils.Jobs as Jobs
import qualified Gargantext.Utils.Jobs.Monad as Jobs import qualified Gargantext.Utils.Jobs.Monad as Jobs
import qualified Gargantext.Utils.Jobs.Queue as Jobs import qualified Gargantext.Utils.Jobs.Queue as Jobs
...@@ -175,31 +178,35 @@ devJwkFile = "dev.jwk" ...@@ -175,31 +178,35 @@ devJwkFile = "dev.jwk"
newEnv :: PortNumber -> FilePath -> IO Env newEnv :: PortNumber -> FilePath -> IO Env
newEnv port file = do newEnv port file = do
manager_env <- newTlsManager !manager_env <- newTlsManager
settings' <- devSettings devJwkFile <&> appPort .~ port -- TODO read from 'file' !settings' <- devSettings devJwkFile <&> appPort .~ port -- TODO read from 'file'
when (port /= settings' ^. appPort) $ when (port /= settings' ^. appPort) $
panic "TODO: conflicting settings of port" panic "TODO: conflicting settings of port"
config_env <- readConfig file !config_env <- readConfig file
prios <- Jobs.readPrios (file <> ".jobs") prios <- Jobs.readPrios (file <> ".jobs")
let prios' = Jobs.applyPrios prios Jobs.defaultPrios let prios' = Jobs.applyPrios prios Jobs.defaultPrios
putStrLn $ "Overrides: " <> show prios putStrLn $ "Overrides: " <> show prios
putStrLn $ "New priorities: " <> show prios' putStrLn $ "New priorities: " <> show prios'
self_url_env <- parseBaseUrl $ "http://0.0.0.0:" <> show port !self_url_env <- parseBaseUrl $ "http://0.0.0.0:" <> show port
dbParam <- databaseParameters file dbParam <- databaseParameters file
pool <- newPool dbParam !pool <- newPool dbParam
--nodeStory_env <- readNodeStoryEnv (_gc_repofilepath config_env) --nodeStory_env <- readNodeStoryEnv (_gc_repofilepath config_env)
nodeStory_env <- readNodeStoryEnv pool !nodeStory_env <- readNodeStoryEnv pool
scrapers_env <- newJobEnv defaultSettings manager_env !scrapers_env <- newJobEnv defaultSettings manager_env
secret <- Jobs.genSecret secret <- Jobs.genSecret
let jobs_settings = (Jobs.defaultJobSettings 1 secret) let jobs_settings = (Jobs.defaultJobSettings 1 secret)
& Jobs.l_jsJobTimeout .~ (fromIntegral $ config_env ^. hasConfig ^. gc_js_job_timeout) & Jobs.l_jsJobTimeout .~ (fromIntegral $ config_env ^. hasConfig ^. gc_js_job_timeout)
& Jobs.l_jsIDTimeout .~ (fromIntegral $ config_env ^. hasConfig ^. gc_js_id_timeout) & Jobs.l_jsIDTimeout .~ (fromIntegral $ config_env ^. hasConfig ^. gc_js_id_timeout)
jobs_env <- Jobs.newJobEnv jobs_settings prios' manager_env !jobs_env <- Jobs.newJobEnv jobs_settings prios' manager_env
logger <- newStderrLoggerSet defaultBufSize !logger <- newStderrLoggerSet defaultBufSize
config_mail <- Mail.readConfig file !config_mail <- Mail.readConfig file
!nlp_env <- nlpServerMap <$> NLP.readConfig file
{- An 'Env' by default doesn't have strict fields, but when constructing one in production
we want to force them to WHNF to avoid accumulating unnecessary thunks.
-}
pure $ Env pure $ Env
{ _env_settings = settings' { _env_settings = settings'
, _env_logger = logger , _env_logger = logger
...@@ -211,6 +218,7 @@ newEnv port file = do ...@@ -211,6 +218,7 @@ newEnv port file = do
, _env_self_url = self_url_env , _env_self_url = self_url_env
, _env_config = config_env , _env_config = config_env
, _env_mail = config_mail , _env_mail = config_mail
, _env_nlp = nlp_env
} }
newPool :: ConnectInfo -> IO (Pool Connection) newPool :: ConnectInfo -> IO (Pool Connection)
......
...@@ -15,15 +15,18 @@ module Gargantext.API.Dev where ...@@ -15,15 +15,18 @@ module Gargantext.API.Dev where
import Control.Exception (finally) import Control.Exception (finally)
import Control.Monad (fail) import Control.Monad (fail)
import Control.Monad.Reader (runReaderT) import Control.Monad.Reader (runReaderT)
import Control.Monad.Except (runExceptT)
import Gargantext.API.Admin.EnvTypes import Gargantext.API.Admin.EnvTypes
import Gargantext.API.Admin.Settings import Gargantext.API.Admin.Settings
import Gargantext.API.Ngrams (saveNodeStoryImmediate) import Gargantext.API.Ngrams (saveNodeStoryImmediate)
import Gargantext.API.Prelude import Gargantext.API.Prelude
import Gargantext.Core.NLP (nlpServerMap)
import Gargantext.Core.NodeStory import Gargantext.Core.NodeStory
import Gargantext.Database.Prelude import Gargantext.Database.Prelude
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Prelude.Config (readConfig) import Gargantext.Prelude.Config (readConfig)
import qualified Gargantext.Prelude.Mail as Mail import qualified Gargantext.Prelude.Mail as Mail
import qualified Gargantext.Prelude.NLP as NLP
import Servant import Servant
import System.IO (FilePath) import System.IO (FilePath)
...@@ -43,12 +46,14 @@ withDevEnv iniPath k = do ...@@ -43,12 +46,14 @@ withDevEnv iniPath k = do
nodeStory_env <- readNodeStoryEnv pool nodeStory_env <- readNodeStoryEnv pool
setts <- devSettings devJwkFile setts <- devSettings devJwkFile
mail <- Mail.readConfig iniPath mail <- Mail.readConfig iniPath
nlp_config <- NLP.readConfig iniPath
pure $ DevEnv pure $ DevEnv
{ _dev_env_pool = pool { _dev_env_pool = pool
, _dev_env_nodeStory = nodeStory_env , _dev_env_nodeStory = nodeStory_env
, _dev_env_settings = setts , _dev_env_settings = setts
, _dev_env_config = cfg , _dev_env_config = cfg
, _dev_env_mail = mail , _dev_env_mail = mail
, _dev_env_nlp = nlpServerMap nlp_config
} }
-- | Run Cmd Sugar for the Repl (GHCI) -- | Run Cmd Sugar for the Repl (GHCI)
...@@ -65,6 +70,10 @@ runCmdReplServantErr = runCmdRepl ...@@ -65,6 +70,10 @@ runCmdReplServantErr = runCmdRepl
runCmdDev :: Show err => DevEnv -> Cmd'' DevEnv err a -> IO a runCmdDev :: Show err => DevEnv -> Cmd'' DevEnv err a -> IO a
runCmdDev env f = runCmdDev env f =
(either (fail . show) pure =<< runCmd env f) (either (fail . show) pure =<< runCmd env f)
runCmdGargDev :: DevEnv -> GargM DevEnv GargError a -> IO a
runCmdGargDev env cmd =
(either (fail . show) pure =<< runExceptT (runReaderT cmd env))
`finally` `finally`
runReaderT saveNodeStoryImmediate env runReaderT saveNodeStoryImmediate env
......
...@@ -31,6 +31,7 @@ import Data.Morpheus.Types ...@@ -31,6 +31,7 @@ import Data.Morpheus.Types
, Undefined(..) , Undefined(..)
) )
import Data.Proxy import Data.Proxy
import Data.Text (Text)
import Gargantext.API.Admin.Auth.Types (AuthenticatedUser) import Gargantext.API.Admin.Auth.Types (AuthenticatedUser)
import Gargantext.API.Admin.Orchestrator.Types (JobLog) import Gargantext.API.Admin.Orchestrator.Types (JobLog)
import Gargantext.API.Prelude (HasJobEnv') import Gargantext.API.Prelude (HasJobEnv')
...@@ -38,6 +39,7 @@ import qualified Gargantext.API.GraphQL.Annuaire as GQLA ...@@ -38,6 +39,7 @@ import qualified Gargantext.API.GraphQL.Annuaire as GQLA
import qualified Gargantext.API.GraphQL.AsyncTask as GQLAT import qualified Gargantext.API.GraphQL.AsyncTask as GQLAT
import qualified Gargantext.API.GraphQL.Context as GQLCTX import qualified Gargantext.API.GraphQL.Context as GQLCTX
import qualified Gargantext.API.GraphQL.IMT as GQLIMT import qualified Gargantext.API.GraphQL.IMT as GQLIMT
import qualified Gargantext.API.GraphQL.NLP as GQLNLP
import qualified Gargantext.API.GraphQL.Node as GQLNode import qualified Gargantext.API.GraphQL.Node as GQLNode
import qualified Gargantext.API.GraphQL.User as GQLUser import qualified Gargantext.API.GraphQL.User as GQLUser
import qualified Gargantext.API.GraphQL.UserInfo as GQLUserInfo import qualified Gargantext.API.GraphQL.UserInfo as GQLUserInfo
...@@ -45,8 +47,8 @@ import qualified Gargantext.API.GraphQL.TreeFirstLevel as GQLTree ...@@ -45,8 +47,8 @@ import qualified Gargantext.API.GraphQL.TreeFirstLevel as GQLTree
import qualified Gargantext.API.GraphQL.Team as GQLTeam import qualified Gargantext.API.GraphQL.Team as GQLTeam
import Gargantext.API.Prelude (GargM, GargError) import Gargantext.API.Prelude (GargM, GargError)
import Gargantext.API.Types import Gargantext.API.Types
import Gargantext.Core.Mail.Types (HasMail) import Gargantext.Core.NLP (HasNLPServer)
import Gargantext.Database.Prelude (HasConnectionPool, HasConfig) import Gargantext.Database.Prelude (CmdCommon)
import Gargantext.Prelude import Gargantext.Prelude
import GHC.Generics (Generic) import GHC.Generics (Generic)
import Servant import Servant
...@@ -67,11 +69,14 @@ import Gargantext.API.Admin.Types (HasSettings) ...@@ -67,11 +69,14 @@ import Gargantext.API.Admin.Types (HasSettings)
data Query m data Query m
= Query = Query
{ annuaire_contacts :: GQLA.AnnuaireContactArgs -> m [GQLA.AnnuaireContact] { annuaire_contacts :: GQLA.AnnuaireContactArgs -> m [GQLA.AnnuaireContact]
, context_ngrams :: GQLCTX.ContextNgramsArgs -> m [Text]
, contexts :: GQLCTX.NodeContextArgs -> m [GQLCTX.NodeContextGQL] , contexts :: GQLCTX.NodeContextArgs -> m [GQLCTX.NodeContextGQL]
, contexts_for_ngrams :: GQLCTX.ContextsForNgramsArgs -> m [GQLCTX.ContextGQL] , contexts_for_ngrams :: GQLCTX.ContextsForNgramsArgs -> m [GQLCTX.ContextGQL]
, imt_schools :: GQLIMT.SchoolsArgs -> m [GQLIMT.School] , imt_schools :: GQLIMT.SchoolsArgs -> m [GQLIMT.School]
, job_logs :: GQLAT.JobLogArgs -> m (Map Int JobLog) , job_logs :: GQLAT.JobLogArgs -> m (Map Int JobLog)
, languages :: GQLNLP.LanguagesArgs -> m GQLNLP.LanguagesMap
, nodes :: GQLNode.NodeArgs -> m [GQLNode.Node] , nodes :: GQLNode.NodeArgs -> m [GQLNode.Node]
, nodes_corpus :: GQLNode.CorpusArgs -> m [GQLNode.Corpus]
, node_parent :: GQLNode.NodeParentArgs -> m [GQLNode.Node] , node_parent :: GQLNode.NodeParentArgs -> m [GQLNode.Node]
, user_infos :: GQLUserInfo.UserInfoArgs -> m [GQLUserInfo.UserInfo] , user_infos :: GQLUserInfo.UserInfoArgs -> m [GQLUserInfo.UserInfo]
, users :: GQLUser.UserArgs -> m [GQLUser.User m] , users :: GQLUser.UserArgs -> m [GQLUser.User m]
...@@ -82,6 +87,7 @@ data Query m ...@@ -82,6 +87,7 @@ data Query m
data Mutation m data Mutation m
= Mutation = Mutation
{ update_user_info :: GQLUserInfo.UserInfoMArgs -> m Int { update_user_info :: GQLUserInfo.UserInfoMArgs -> m Int
, update_user_pubmed_api_key :: GQLUser.UserPubmedAPIKeyMArgs -> m Int
, delete_team_membership :: GQLTeam.TeamDeleteMArgs -> m [Int] , delete_team_membership :: GQLTeam.TeamDeleteMArgs -> m [Int]
, update_node_context_category :: GQLCTX.NodeContextCategoryMArgs -> m [Int] , update_node_context_category :: GQLCTX.NodeContextCategoryMArgs -> m [Int]
} deriving (Generic, GQLType) } deriving (Generic, GQLType)
...@@ -104,29 +110,33 @@ data Contet m ...@@ -104,29 +110,33 @@ data Contet m
-- | The main GraphQL resolver: how queries, mutations and -- | The main GraphQL resolver: how queries, mutations and
-- subscriptions are handled. -- subscriptions are handled.
rootResolver rootResolver
:: (HasConnectionPool env, HasConfig env, HasMail env, HasJobEnv' env, HasSettings env) :: (CmdCommon env, HasNLPServer env, HasJobEnv' env, HasSettings env)
=> RootResolver (GargM env GargError) e Query Mutation Undefined => RootResolver (GargM env GargError) e Query Mutation Undefined
rootResolver = rootResolver =
RootResolver RootResolver
{ queryResolver = Query { annuaire_contacts = GQLA.resolveAnnuaireContacts { queryResolver = Query { annuaire_contacts = GQLA.resolveAnnuaireContacts
, context_ngrams = GQLCTX.resolveContextNgrams
, contexts = GQLCTX.resolveNodeContext , contexts = GQLCTX.resolveNodeContext
, contexts_for_ngrams = GQLCTX.resolveContextsForNgrams , contexts_for_ngrams = GQLCTX.resolveContextsForNgrams
, imt_schools = GQLIMT.resolveSchools , imt_schools = GQLIMT.resolveSchools
, job_logs = GQLAT.resolveJobLogs , job_logs = GQLAT.resolveJobLogs
, languages = GQLNLP.resolveLanguages
, nodes = GQLNode.resolveNodes , nodes = GQLNode.resolveNodes
, nodes_corpus = GQLNode.resolveNodesCorpus
, node_parent = GQLNode.resolveNodeParent , node_parent = GQLNode.resolveNodeParent
, user_infos = GQLUserInfo.resolveUserInfos , user_infos = GQLUserInfo.resolveUserInfos
, users = GQLUser.resolveUsers , users = GQLUser.resolveUsers
, tree = GQLTree.resolveTree , tree = GQLTree.resolveTree
, team = GQLTeam.resolveTeam } , team = GQLTeam.resolveTeam }
, mutationResolver = Mutation { update_user_info = GQLUserInfo.updateUserInfo , mutationResolver = Mutation { update_user_info = GQLUserInfo.updateUserInfo
, update_user_pubmed_api_key = GQLUser.updateUserPubmedAPIKey
, delete_team_membership = GQLTeam.deleteTeamMembership , delete_team_membership = GQLTeam.deleteTeamMembership
, update_node_context_category = GQLCTX.updateNodeContextCategory } , update_node_context_category = GQLCTX.updateNodeContextCategory }
, subscriptionResolver = Undefined } , subscriptionResolver = Undefined }
-- | Main GraphQL "app". -- | Main GraphQL "app".
app app
:: (Typeable env, HasConnectionPool env, HasConfig env, HasMail env, HasJobEnv' env, HasSettings env) :: (Typeable env, CmdCommon env, HasJobEnv' env, HasNLPServer env, HasSettings env)
=> App (EVENT (GargM env GargError)) (GargM env GargError) => App (EVENT (GargM env GargError)) (GargM env GargError)
app = deriveApp rootResolver app = deriveApp rootResolver
...@@ -163,7 +173,7 @@ gqapi = Proxy ...@@ -163,7 +173,7 @@ gqapi = Proxy
-- | Implementation of our API. -- | Implementation of our API.
--api :: Server API --api :: Server API
api api
:: (Typeable env, HasConnectionPool env, HasConfig env, HasMail env, HasJobEnv' env, HasSettings env) :: (Typeable env, CmdCommon env, HasJobEnv' env, HasSettings env)
=> ServerT API (GargM env GargError) => ServerT API (GargM env GargError)
api (SAS.Authenticated _auser) = httpPubApp [] app :<|> pure httpPlayground api (SAS.Authenticated _auser) = httpPubApp [] app :<|> pure httpPlayground
api _ = panic "401 in graphql" -- SAS.throwAll (_ServerError # err401) api _ = panic "401 in graphql" -- SAS.throwAll (_ServerError # err401)
...@@ -13,7 +13,6 @@ import Data.Morpheus.Types ...@@ -13,7 +13,6 @@ import Data.Morpheus.Types
import Data.Proxy import Data.Proxy
import Data.Text (Text) import Data.Text (Text)
import Gargantext.API.Prelude (GargM, GargError) import Gargantext.API.Prelude (GargM, GargError)
import Gargantext.Core.Mail.Types (HasMail)
import Gargantext.Database.Admin.Types.Hyperdata.Contact import Gargantext.Database.Admin.Types.Hyperdata.Contact
( HyperdataContact ( HyperdataContact
, ContactWho , ContactWho
...@@ -21,7 +20,7 @@ import Gargantext.Database.Admin.Types.Hyperdata.Contact ...@@ -21,7 +20,7 @@ import Gargantext.Database.Admin.Types.Hyperdata.Contact
, cw_lastName , cw_lastName
, hc_who, ContactWhere, hc_where, cw_organization, cw_labTeamDepts, cw_role, cw_office, cw_country, cw_city, cw_touch, ct_mail, ct_phone, ct_url, hc_title, hc_source) , hc_who, ContactWhere, hc_where, cw_organization, cw_labTeamDepts, cw_role, cw_office, cw_country, cw_city, cw_touch, ct_mail, ct_phone, ct_url, hc_title, hc_source)
import Gargantext.Database.Admin.Types.Node (NodeId(..)) import Gargantext.Database.Admin.Types.Node (NodeId(..))
import Gargantext.Database.Prelude (HasConnectionPool, HasConfig) import Gargantext.Database.Prelude (CmdCommon)
import Gargantext.Database.Query.Table.Context (getContextWith) import Gargantext.Database.Query.Table.Context (getContextWith)
import Gargantext.Database.Schema.Node (node_hyperdata) import Gargantext.Database.Schema.Node (node_hyperdata)
import Gargantext.Prelude import Gargantext.Prelude
...@@ -55,13 +54,13 @@ type GqlM e env = Resolver QUERY e (GargM env GargError) ...@@ -55,13 +54,13 @@ type GqlM e env = Resolver QUERY e (GargM env GargError)
-- | Function to resolve user from a query. -- | Function to resolve user from a query.
resolveAnnuaireContacts resolveAnnuaireContacts
:: (HasConnectionPool env, HasConfig env, HasMail env) :: (CmdCommon env)
=> AnnuaireContactArgs -> GqlM e env [AnnuaireContact] => AnnuaireContactArgs -> GqlM e env [AnnuaireContact]
resolveAnnuaireContacts AnnuaireContactArgs { contact_id } = dbAnnuaireContacts contact_id resolveAnnuaireContacts AnnuaireContactArgs { contact_id } = dbAnnuaireContacts contact_id
-- | Inner function to fetch the user from DB. -- | Inner function to fetch the user from DB.
dbAnnuaireContacts dbAnnuaireContacts
:: (HasConnectionPool env, HasConfig env, HasMail env) :: CmdCommon env
=> Int -> GqlM e env [AnnuaireContact] => Int -> GqlM e env [AnnuaireContact]
dbAnnuaireContacts contact_id = do dbAnnuaireContacts contact_id = do
-- lift $ printDebug "[dbUsers]" user_id -- lift $ printDebug "[dbUsers]" user_id
......
...@@ -17,11 +17,10 @@ import Data.Time.Format.ISO8601 (iso8601Show) ...@@ -17,11 +17,10 @@ import Data.Time.Format.ISO8601 (iso8601Show)
import Gargantext.API.Admin.Types (HasSettings) import Gargantext.API.Admin.Types (HasSettings)
import Gargantext.API.Prelude (GargM, GargError) import Gargantext.API.Prelude (GargM, GargError)
import Gargantext.Core.Types.Search (HyperdataRow(..), toHyperdataRow) import Gargantext.Core.Types.Search (HyperdataRow(..), toHyperdataRow)
import Gargantext.Core.Mail.Types (HasMail)
import Gargantext.Database.Admin.Types.Hyperdata (HyperdataDocument) import Gargantext.Database.Admin.Types.Hyperdata (HyperdataDocument)
import Gargantext.Database.Admin.Types.Node (ContextTitle, NodeId(..), NodeTypeId, UserId, unNodeId) import Gargantext.Database.Admin.Types.Node (ContextTitle, NodeId(..), NodeTypeId, UserId, unNodeId)
import Gargantext.Database.Prelude (HasConnectionPool, HasConfig) import Gargantext.Database.Prelude (CmdCommon)
import Gargantext.Database.Query.Table.NodeContext (getNodeContext, getContextsForNgramsTerms, ContextForNgramsTerms(..)) import Gargantext.Database.Query.Table.NodeContext (getNodeContext, getContextsForNgramsTerms, ContextForNgramsTerms(..), {- getContextNgrams, -} getContextNgramsMatchingFTS)
import qualified Gargantext.Database.Query.Table.NodeContext as DNC import qualified Gargantext.Database.Query.Table.NodeContext as DNC
import Gargantext.Database.Schema.NodeContext (NodeContext, NodeContextPoly(..)) import Gargantext.Database.Schema.NodeContext (NodeContext, NodeContextPoly(..))
import Gargantext.Prelude import Gargantext.Prelude
...@@ -95,6 +94,12 @@ data NodeContextCategoryMArgs = NodeContextCategoryMArgs ...@@ -95,6 +94,12 @@ data NodeContextCategoryMArgs = NodeContextCategoryMArgs
, category :: Int , category :: Int
} deriving (Generic, GQLType) } deriving (Generic, GQLType)
data ContextNgramsArgs
= ContextNgramsArgs
{ context_id :: Int
, list_id :: Int }
deriving (Generic, GQLType)
type GqlM e env = Resolver QUERY e (GargM env GargError) type GqlM e env = Resolver QUERY e (GargM env GargError)
type GqlM' e env a = ResolverM e (GargM env GargError) a type GqlM' e env a = ResolverM e (GargM env GargError) a
...@@ -102,22 +107,28 @@ type GqlM' e env a = ResolverM e (GargM env GargError) a ...@@ -102,22 +107,28 @@ type GqlM' e env a = ResolverM e (GargM env GargError) a
-- | Function to resolve context from a query. -- | Function to resolve context from a query.
resolveNodeContext resolveNodeContext
:: (HasConnectionPool env, HasConfig env, HasMail env) :: (CmdCommon env)
=> NodeContextArgs -> GqlM e env [NodeContextGQL] => NodeContextArgs -> GqlM e env [NodeContextGQL]
resolveNodeContext NodeContextArgs { context_id, node_id } = resolveNodeContext NodeContextArgs { context_id, node_id } =
dbNodeContext context_id node_id dbNodeContext context_id node_id
resolveContextsForNgrams resolveContextsForNgrams
:: (HasConnectionPool env, HasConfig env, HasMail env) :: (CmdCommon env)
=> ContextsForNgramsArgs -> GqlM e env [ContextGQL] => ContextsForNgramsArgs -> GqlM e env [ContextGQL]
resolveContextsForNgrams ContextsForNgramsArgs { corpus_id, ngrams_terms } = resolveContextsForNgrams ContextsForNgramsArgs { corpus_id, ngrams_terms } =
dbContextForNgrams corpus_id ngrams_terms dbContextForNgrams corpus_id ngrams_terms
resolveContextNgrams
:: (CmdCommon env)
=> ContextNgramsArgs -> GqlM e env [Text]
resolveContextNgrams ContextNgramsArgs { context_id, list_id } =
dbContextNgrams context_id list_id
-- DB -- DB
-- | Inner function to fetch the node context DB. -- | Inner function to fetch the node context DB.
dbNodeContext dbNodeContext
:: (HasConnectionPool env, HasConfig env, HasMail env) :: (CmdCommon env)
=> Int -> Int -> GqlM e env [NodeContextGQL] => Int -> Int -> GqlM e env [NodeContextGQL]
dbNodeContext context_id node_id = do dbNodeContext context_id node_id = do
-- lift $ printDebug "[dbUsers]" user_id -- lift $ printDebug "[dbUsers]" user_id
...@@ -127,14 +138,22 @@ dbNodeContext context_id node_id = do ...@@ -127,14 +138,22 @@ dbNodeContext context_id node_id = do
c <- lift $ getNodeContext (NodeId context_id) (NodeId node_id) c <- lift $ getNodeContext (NodeId context_id) (NodeId node_id)
pure $ toNodeContextGQL <$> [c] pure $ toNodeContextGQL <$> [c]
-- | Returns list of `ContextGQL` for given ngrams in given corpus id.
dbContextForNgrams dbContextForNgrams
:: (HasConnectionPool env, HasConfig env, HasMail env) :: (CmdCommon env)
=> Int -> [Text] -> GqlM e env [ContextGQL] => Int -> [Text] -> GqlM e env [ContextGQL]
dbContextForNgrams node_id ngrams_terms = do dbContextForNgrams node_id ngrams_terms = do
contextsForNgramsTerms <- lift $ getContextsForNgramsTerms (NodeId node_id) ngrams_terms contextsForNgramsTerms <- lift $ getContextsForNgramsTerms (NodeId node_id) ngrams_terms
--lift $ printDebug "[dbContextForNgrams] contextsForNgramsTerms" contextsForNgramsTerms --lift $ printDebug "[dbContextForNgrams] contextsForNgramsTerms" contextsForNgramsTerms
pure $ toContextGQL <$> contextsForNgramsTerms pure $ toContextGQL <$> contextsForNgramsTerms
-- | Fetch ngrams matching given context in a given list id.
dbContextNgrams
:: (CmdCommon env)
=> Int -> Int -> GqlM e env [Text]
dbContextNgrams context_id list_id = do
lift $ getContextNgramsMatchingFTS (NodeId context_id) (NodeId list_id)
-- Conversion functions -- Conversion functions
toNodeContextGQL :: NodeContext -> NodeContextGQL toNodeContextGQL :: NodeContext -> NodeContextGQL
...@@ -192,7 +211,7 @@ toHyperdataRowDocumentGQL hyperdata = ...@@ -192,7 +211,7 @@ toHyperdataRowDocumentGQL hyperdata =
} }
HyperdataRowContact { } -> Nothing HyperdataRowContact { } -> Nothing
updateNodeContextCategory :: (HasConnectionPool env, HasConfig env, HasMail env, HasSettings env) => updateNodeContextCategory :: ( CmdCommon env, HasSettings env) =>
NodeContextCategoryMArgs -> GqlM' e env [Int] NodeContextCategoryMArgs -> GqlM' e env [Int]
updateNodeContextCategory NodeContextCategoryMArgs { context_id, node_id, category } = do updateNodeContextCategory NodeContextCategoryMArgs { context_id, node_id, category } = do
_ <- lift $ DNC.updateNodeContextCategory (NodeId context_id) (NodeId node_id) category _ <- lift $ DNC.updateNodeContextCategory (NodeId context_id) (NodeId node_id) category
......
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DuplicateRecordFields #-}
module Gargantext.API.GraphQL.NLP
( Lang(..)
, LanguagesArgs(..)
, LanguagesMap
, resolveLanguages
)
where
import Control.Lens (view)
import qualified Data.Map.Strict as Map
import Data.Morpheus.Types
( GQLType
, Resolver
, QUERY
)
import Gargantext.API.Prelude (GargM, GargError)
import Gargantext.Core (Lang(..), NLPServerConfig(..), PosTagAlgo) -- , allLangs)
import Gargantext.Core.NLP (HasNLPServer(..))
import Gargantext.Prelude
import Protolude
data LanguagesArgs
= LanguagesArgs
{ } deriving (Generic, GQLType)
type GqlM e env = Resolver QUERY e (GargM env GargError)
type LanguagesMap = Map.Map Lang NLPServer
data NLPServer = NLPServer
{
server :: !PosTagAlgo
, url :: !Text
}
deriving (Show, Eq, Generic, GQLType)
resolveLanguages
:: HasNLPServer env => LanguagesArgs -> GqlM e env LanguagesMap
resolveLanguages LanguagesArgs { } = do
-- pure $ allLangs
lift $ do
ns <- view nlpServer
printDebug "[resolveLanguages] nlpServer" ns
pure $ Map.map (\(NLPServerConfig { .. }) -> NLPServer { server
, url = Protolude.show url }) ns
...@@ -3,7 +3,9 @@ ...@@ -3,7 +3,9 @@
module Gargantext.API.GraphQL.Node where module Gargantext.API.GraphQL.Node where
import Data.Aeson
import Data.Either (Either(..)) import Data.Either (Either(..))
import qualified Data.HashMap.Strict as HashMap
import Data.Morpheus.Types import Data.Morpheus.Types
( GQLType ( GQLType
, Resolver , Resolver
...@@ -13,44 +15,68 @@ import Data.Morpheus.Types ...@@ -13,44 +15,68 @@ import Data.Morpheus.Types
import Data.Text (Text) import Data.Text (Text)
import qualified Data.Text as T import qualified Data.Text as T
import Gargantext.API.Prelude (GargM, GargError) import Gargantext.API.Prelude (GargM, GargError)
import Gargantext.Core.Mail.Types (HasMail)
import Gargantext.Database.Admin.Types.Node (NodeId(..), NodeType) import Gargantext.Database.Admin.Types.Node (NodeId(..), NodeType)
import qualified Gargantext.Database.Admin.Types.Node as NN import qualified Gargantext.Database.Admin.Types.Node as NN
import Gargantext.Database.Query.Table.Node (getClosestParentIdByType, getNode) import Gargantext.Database.Query.Table.Node (getClosestParentIdByType, getNode)
import Gargantext.Database.Prelude (HasConnectionPool, HasConfig) import Gargantext.Database.Prelude (CmdCommon) -- , JSONB)
import qualified Gargantext.Database.Schema.Node as N import qualified Gargantext.Database.Schema.Node as N
import Gargantext.Prelude import Gargantext.Prelude
import GHC.Generics (Generic) import GHC.Generics (Generic)
import qualified Prelude import qualified Prelude
import qualified PUBMED.Types as PUBMED
import Text.Read (readEither) import Text.Read (readEither)
data Corpus = Corpus
{ id :: Int
, name :: Text
, parent_id :: Maybe Int
, type_id :: Int
} deriving (Show, Generic, GQLType)
data Node = Node data Node = Node
{ id :: Int { id :: Int
, name :: Text , name :: Text
, parent_id :: Maybe Int , parent_id :: Maybe Int
, type_id :: Int , type_id :: Int
} deriving (Show, Generic, GQLType) } deriving (Show, Generic, GQLType)
data CorpusArgs
= CorpusArgs
{ corpus_id :: Int
} deriving (Generic, GQLType)
data NodeArgs data NodeArgs
= NodeArgs = NodeArgs
{ node_id :: Int { node_id :: Int
} deriving (Generic, GQLType) } deriving (Generic, GQLType)
type GqlM e env = Resolver QUERY e (GargM env GargError) type GqlM e env = Resolver QUERY e (GargM env GargError)
-- | Function to resolve user from a query. -- | Function to resolve user from a query.
resolveNodes resolveNodes
:: (HasConnectionPool env, HasConfig env, HasMail env) :: (CmdCommon env)
=> NodeArgs -> GqlM e env [Node] => NodeArgs -> GqlM e env [Node]
resolveNodes NodeArgs { node_id } = dbNodes node_id resolveNodes NodeArgs { node_id } = dbNodes node_id
resolveNodesCorpus
:: (CmdCommon env)
=> CorpusArgs -> GqlM e env [Corpus]
resolveNodesCorpus CorpusArgs { corpus_id } = dbNodesCorpus corpus_id
dbNodes dbNodes
:: (HasConnectionPool env, HasConfig env, HasMail env) :: (CmdCommon env)
=> Int -> GqlM e env [Node] => Int -> GqlM e env [Node]
dbNodes node_id = do dbNodes node_id = do
node <- lift $ getNode $ NodeId node_id node <- lift $ getNode $ NodeId node_id
pure [toNode node] pure [toNode node]
dbNodesCorpus
:: (CmdCommon env)
=> Int -> GqlM e env [Corpus]
dbNodesCorpus corpus_id = do
corpus <- lift $ getNode $ NodeId corpus_id
pure [toCorpus corpus]
data NodeParentArgs data NodeParentArgs
= NodeParentArgs = NodeParentArgs
{ node_id :: Int { node_id :: Int
...@@ -58,12 +84,12 @@ data NodeParentArgs ...@@ -58,12 +84,12 @@ data NodeParentArgs
} deriving (Generic, GQLType) } deriving (Generic, GQLType)
resolveNodeParent resolveNodeParent
:: (HasConnectionPool env, HasConfig env, HasMail env) :: (CmdCommon env)
=> NodeParentArgs -> GqlM e env [Node] => NodeParentArgs -> GqlM e env [Node]
resolveNodeParent NodeParentArgs { node_id, parent_type } = dbParentNodes node_id parent_type resolveNodeParent NodeParentArgs { node_id, parent_type } = dbParentNodes node_id parent_type
dbParentNodes dbParentNodes
:: (HasConnectionPool env, HasConfig env, HasMail env) :: (CmdCommon env)
=> Int -> Text -> GqlM e env [Node] => Int -> Text -> GqlM e env [Node]
dbParentNodes node_id parent_type = do dbParentNodes node_id parent_type = do
let mParentType = readEither (T.unpack parent_type) :: Either Prelude.String NodeType let mParentType = readEither (T.unpack parent_type) :: Either Prelude.String NodeType
...@@ -80,7 +106,22 @@ dbParentNodes node_id parent_type = do ...@@ -80,7 +106,22 @@ dbParentNodes node_id parent_type = do
pure [toNode node] pure [toNode node]
toNode :: NN.Node json -> Node toNode :: NN.Node json -> Node
toNode (N.Node { .. }) = Node { id = NN.unNodeId _node_id toNode N.Node { .. } = Node { id = NN.unNodeId _node_id
, name = _node_name , name = _node_name
, parent_id = NN.unNodeId <$> _node_parent_id , parent_id = NN.unNodeId <$> _node_parent_id
, type_id = _node_typename } , type_id = _node_typename }
toCorpus :: NN.Node Value -> Corpus
toCorpus N.Node { .. } = Corpus { id = NN.unNodeId _node_id
, name = _node_name
, parent_id = NN.unNodeId <$> _node_parent_id
, type_id = _node_typename }
pubmedAPIKeyFromValue :: Value -> Maybe PUBMED.APIKey
pubmedAPIKeyFromValue (Object kv) =
case HashMap.lookup "pubmed_api_key" kv of
Nothing -> Nothing
Just v -> case fromJSON v of
Error _ -> Nothing
Success v' -> Just v'
pubmedAPIKeyFromValue _ = Nothing
...@@ -10,11 +10,10 @@ import Data.Text ( Text ) ...@@ -10,11 +10,10 @@ import Data.Text ( Text )
import Gargantext.API.Admin.Types (HasSettings) import Gargantext.API.Admin.Types (HasSettings)
import Gargantext.API.GraphQL.Utils (authUser, AuthStatus (Invalid, Valid)) import Gargantext.API.GraphQL.Utils (authUser, AuthStatus (Invalid, Valid))
import Gargantext.API.Prelude (GargM, GargError) import Gargantext.API.Prelude (GargM, GargError)
import Gargantext.Core.Mail.Types (HasMail)
import Gargantext.Core.Types (NodeId(..), unNodeId) import Gargantext.Core.Types (NodeId(..), unNodeId)
import Gargantext.Database (HasConfig) import qualified Gargantext.Core.Types.Individu as Individu
import Gargantext.Database.Action.Share (membersOf, deleteMemberShip) import Gargantext.Database.Action.Share (membersOf, deleteMemberShip)
import Gargantext.Database.Prelude (HasConnectionPool) import Gargantext.Database.Prelude (CmdCommon)
import Gargantext.Database.Query.Table.Node (getNode) import Gargantext.Database.Query.Table.Node (getNode)
import Gargantext.Database.Query.Table.User (getUsersWithNodeHyperdata) import Gargantext.Database.Query.Table.User (getUsersWithNodeHyperdata)
import Gargantext.Database.Schema.Node (NodePoly(Node, _node_id), _node_user_id) import Gargantext.Database.Schema.Node (NodePoly(Node, _node_id), _node_user_id)
...@@ -45,15 +44,16 @@ type GqlM e env = Resolver QUERY e (GargM env GargError) ...@@ -45,15 +44,16 @@ type GqlM e env = Resolver QUERY e (GargM env GargError)
type GqlM' e env a = ResolverM e (GargM env GargError) a type GqlM' e env a = ResolverM e (GargM env GargError) a
resolveTeam :: (HasConnectionPool env, HasConfig env, HasMail env) => TeamArgs -> GqlM e env Team resolveTeam :: (CmdCommon env) => TeamArgs -> GqlM e env Team
resolveTeam TeamArgs { team_node_id } = dbTeam team_node_id resolveTeam TeamArgs { team_node_id } = dbTeam team_node_id
dbTeam :: (HasConnectionPool env, HasConfig env, HasMail env) => Int -> GqlM e env Team dbTeam :: (CmdCommon env) =>
Int -> GqlM e env Team
dbTeam nodeId = do dbTeam nodeId = do
let nId = NodeId nodeId let nId = NodeId nodeId
res <- lift $ membersOf nId res <- lift $ membersOf nId
teamNode <- lift $ getNode nId teamNode <- lift $ getNode nId
userNodes <- lift $ getUsersWithNodeHyperdata $ uId teamNode userNodes <- lift $ getUsersWithNodeHyperdata $ Individu.UserDBId $ uId teamNode
let username = getUsername userNodes let username = getUsername userNodes
pure $ Team { team_owner_username = username pure $ Team { team_owner_username = username
, team_members = map toTeamMember res , team_members = map toTeamMember res
...@@ -69,10 +69,11 @@ dbTeam nodeId = do ...@@ -69,10 +69,11 @@ dbTeam nodeId = do
getUsername ((UserLight {userLight_username}, _):_) = userLight_username getUsername ((UserLight {userLight_username}, _):_) = userLight_username
-- TODO: list as argument -- TODO: list as argument
deleteTeamMembership :: (HasConnectionPool env, HasConfig env, HasMail env, HasSettings env) => TeamDeleteMArgs -> GqlM' e env [Int] deleteTeamMembership :: (CmdCommon env, HasSettings env) =>
TeamDeleteMArgs -> GqlM' e env [Int]
deleteTeamMembership TeamDeleteMArgs { token, shared_folder_id, team_node_id } = do deleteTeamMembership TeamDeleteMArgs { token, shared_folder_id, team_node_id } = do
teamNode <- lift $ getNode $ NodeId team_node_id teamNode <- lift $ getNode $ NodeId team_node_id
userNodes <- lift (getUsersWithNodeHyperdata $ uId teamNode) userNodes <- lift (getUsersWithNodeHyperdata $ Individu.UserDBId $ uId teamNode)
case userNodes of case userNodes of
[] -> panic $ "[deleteTeamMembership] User with id " <> T.pack (show $ uId teamNode) <> " doesn't exist." [] -> panic $ "[deleteTeamMembership] User with id " <> T.pack (show $ uId teamNode) <> " doesn't exist."
(( _, node_u):_) -> do (( _, node_u):_) -> do
......
...@@ -3,23 +3,21 @@ ...@@ -3,23 +3,21 @@
module Gargantext.API.GraphQL.TreeFirstLevel where module Gargantext.API.GraphQL.TreeFirstLevel where
import Gargantext.Prelude
import Data.Morpheus.Types (GQLType, lift, Resolver, QUERY) import Data.Morpheus.Types (GQLType, lift, Resolver, QUERY)
import GHC.Generics (Generic)
import Data.Text (Text) import Data.Text (Text)
import GHC.Generics (Generic)
import Gargantext.API.Prelude (GargM, GargError) import Gargantext.API.Prelude (GargM, GargError)
import Gargantext.Database.Prelude (HasConnectionPool, HasConfig)
import Gargantext.Core.Mail.Types (HasMail)
import qualified Gargantext.Database.Query.Tree as T
import qualified Gargantext.Database.Schema.Node as N
import qualified Gargantext.Database.Admin.Types.Node as NN
import Gargantext.Database.Admin.Types.Node (allNodeTypes, NodeId (NodeId))
import Gargantext.Core.Types (Tree, NodeTree, NodeType) import Gargantext.Core.Types (Tree, NodeTree, NodeType)
import Gargantext.Core.Types.Main import Gargantext.Core.Types.Main ( Tree(TreeN), _tn_node, _tn_children, NodeTree(NodeTree, _nt_id, _nt_type), _nt_name )
( Tree(TreeN), _tn_node, _tn_children, NodeTree(NodeTree, _nt_id, _nt_type), _nt_name )
import Gargantext.Database.Query.Table.Node (getNode)
import Gargantext.Database.Admin.Config (fromNodeTypeId) import Gargantext.Database.Admin.Config (fromNodeTypeId)
import Gargantext.Database.Admin.Types.Node (allNodeTypes, NodeId (NodeId))
import Gargantext.Database.Prelude (CmdCommon)
import Gargantext.Database.Query.Table.Node (getNode)
import Gargantext.Database.Schema.Node (NodePoly(_node_parent_id)) import Gargantext.Database.Schema.Node (NodePoly(_node_parent_id))
import Gargantext.Prelude
import qualified Gargantext.Database.Admin.Types.Node as NN
import qualified Gargantext.Database.Query.Tree as T
import qualified Gargantext.Database.Schema.Node as N
data TreeArgs = TreeArgs data TreeArgs = TreeArgs
{ {
...@@ -45,10 +43,11 @@ type GqlM e env = Resolver QUERY e (GargM env GargError) ...@@ -45,10 +43,11 @@ type GqlM e env = Resolver QUERY e (GargM env GargError)
type ParentId = Maybe NodeId type ParentId = Maybe NodeId
resolveTree :: (HasConnectionPool env, HasConfig env, HasMail env) => TreeArgs -> GqlM e env (TreeFirstLevel (GqlM e env)) resolveTree :: (CmdCommon env) => TreeArgs -> GqlM e env (TreeFirstLevel (GqlM e env))
resolveTree TreeArgs { root_id } = dbTree root_id resolveTree TreeArgs { root_id } = dbTree root_id
dbTree :: (HasConnectionPool env, HasConfig env, HasMail env) => Int -> GqlM e env (TreeFirstLevel (GqlM e env)) dbTree :: (CmdCommon env) =>
Int -> GqlM e env (TreeFirstLevel (GqlM e env))
dbTree root_id = do dbTree root_id = do
let rId = NodeId root_id let rId = NodeId root_id
t <- lift $ T.tree T.TreeFirstLevel rId allNodeTypes t <- lift $ T.tree T.TreeFirstLevel rId allNodeTypes
...@@ -59,7 +58,7 @@ dbTree root_id = do ...@@ -59,7 +58,7 @@ dbTree root_id = do
toParentId N.Node { _node_parent_id } = _node_parent_id toParentId N.Node { _node_parent_id } = _node_parent_id
toTree :: (HasConnectionPool env, HasConfig env, HasMail env) => NodeId -> ParentId -> Tree NodeTree -> TreeFirstLevel (GqlM e env) toTree :: (CmdCommon env) => NodeId -> ParentId -> Tree NodeTree -> TreeFirstLevel (GqlM e env)
toTree rId pId TreeN { _tn_node, _tn_children } = TreeFirstLevel toTree rId pId TreeN { _tn_node, _tn_children } = TreeFirstLevel
{ parent = resolveParent pId { parent = resolveParent pId
, root = toTreeNode pId _tn_node , root = toTreeNode pId _tn_node
...@@ -75,7 +74,7 @@ toTreeNode pId NodeTree { _nt_name, _nt_id, _nt_type } = TreeNode { name = _nt_n ...@@ -75,7 +74,7 @@ toTreeNode pId NodeTree { _nt_name, _nt_id, _nt_type } = TreeNode { name = _nt_n
childrenToTreeNodes :: (Tree NodeTree, NodeId) -> TreeNode childrenToTreeNodes :: (Tree NodeTree, NodeId) -> TreeNode
childrenToTreeNodes (TreeN {_tn_node}, rId) = toTreeNode (Just rId) _tn_node childrenToTreeNodes (TreeN {_tn_node}, rId) = toTreeNode (Just rId) _tn_node
resolveParent :: (HasConnectionPool env, HasConfig env, HasMail env) => Maybe NodeId -> GqlM e env (Maybe TreeNode) resolveParent :: (CmdCommon env) => Maybe NodeId -> GqlM e env (Maybe TreeNode)
resolveParent (Just pId) = do resolveParent (Just pId) = do
node <- lift $ getNode pId node <- lift $ getNode pId
pure $ nodeToTreeNode node pure $ nodeToTreeNode node
......
{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DuplicateRecordFields #-}
module Gargantext.API.GraphQL.User where module Gargantext.API.GraphQL.User where
import Data.Maybe (listToMaybe) import Data.Maybe (listToMaybe)
import Data.Morpheus.Types import Data.Morpheus.Types
( GQLType ( GQLType
, Resolver, QUERY , Resolver, ResolverM, QUERY
, lift , lift
) )
import Data.Text (Text) import Data.Text (Text)
import Gargantext.API.Admin.Types (HasSettings)
import Gargantext.API.Prelude (GargM, GargError) import Gargantext.API.Prelude (GargM, GargError)
import Gargantext.Core.Mail.Types (HasMail)
import Gargantext.Database.Admin.Types.Hyperdata (HyperdataUser(..)) import Gargantext.Database.Admin.Types.Hyperdata (HyperdataUser(..))
import Gargantext.Database.Prelude (HasConnectionPool, HasConfig) import Gargantext.Database.Admin.Types.Node (NodeId(..))
import Gargantext.Database.Query.Table.User (getUsersWithId, getUserHyperdata) import Gargantext.Database.Prelude (CmdCommon)
import qualified Gargantext.Database.Query.Table.User as DBUser
import Gargantext.Database.Schema.User (UserLight(..)) import Gargantext.Database.Schema.User (UserLight(..))
import Gargantext.Prelude import Gargantext.Prelude
import GHC.Generics (Generic) import GHC.Generics (Generic)
import qualified Gargantext.Core.Types.Individu as Individu
data User m = User data User m = User
{ u_email :: Text { u_email :: Text
...@@ -31,22 +34,29 @@ data UserArgs ...@@ -31,22 +34,29 @@ data UserArgs
{ user_id :: Int { user_id :: Int
} deriving (Generic, GQLType) } deriving (Generic, GQLType)
data UserPubmedAPIKeyMArgs
= UserPubmedAPIKeyMArgs
{ user_id :: Int
, api_key :: Text }
deriving (Generic, GQLType)
type GqlM e env = Resolver QUERY e (GargM env GargError) type GqlM e env = Resolver QUERY e (GargM env GargError)
type GqlM' e env a = ResolverM e (GargM env GargError) a
-- | Function to resolve user from a query. -- | Function to resolve user from a query.
resolveUsers resolveUsers
:: (HasConnectionPool env, HasConfig env, HasMail env) :: (CmdCommon env)
=> UserArgs -> GqlM e env [User (GqlM e env)] => UserArgs -> GqlM e env [User (GqlM e env)]
resolveUsers UserArgs { user_id } = dbUsers user_id resolveUsers UserArgs { user_id } = dbUsers user_id
-- | Inner function to fetch the user from DB. -- | Inner function to fetch the user from DB.
dbUsers dbUsers
:: (HasConnectionPool env, HasConfig env, HasMail env) :: (CmdCommon env)
=> Int -> GqlM e env [User (GqlM e env)] => Int -> GqlM e env [User (GqlM e env)]
dbUsers user_id = lift (map toUser <$> getUsersWithId user_id) dbUsers user_id = lift (map toUser <$> DBUser.getUsersWithId (Individu.RootId $ NodeId user_id))
toUser toUser
:: (HasConnectionPool env, HasConfig env, HasMail env) :: (CmdCommon env)
=> UserLight -> User (GqlM e env) => UserLight -> User (GqlM e env)
toUser (UserLight { .. }) = User { u_email = userLight_email toUser (UserLight { .. }) = User { u_email = userLight_email
, u_hyperdata = resolveHyperdata userLight_id , u_hyperdata = resolveHyperdata userLight_id
...@@ -54,6 +64,13 @@ toUser (UserLight { .. }) = User { u_email = userLight_email ...@@ -54,6 +64,13 @@ toUser (UserLight { .. }) = User { u_email = userLight_email
, u_username = userLight_username } , u_username = userLight_username }
resolveHyperdata resolveHyperdata
:: (HasConnectionPool env, HasConfig env, HasMail env) :: (CmdCommon env)
=> Int -> GqlM e env (Maybe HyperdataUser) => Int -> GqlM e env (Maybe HyperdataUser)
resolveHyperdata userid = lift (listToMaybe <$> getUserHyperdata userid) resolveHyperdata userid = lift (listToMaybe <$> DBUser.getUserHyperdata (Individu.UserDBId userid))
updateUserPubmedAPIKey :: ( CmdCommon env, HasSettings env) =>
UserPubmedAPIKeyMArgs -> GqlM' e env Int
updateUserPubmedAPIKey UserPubmedAPIKeyMArgs { user_id, api_key } = do
_ <- lift $ DBUser.updateUserPubmedAPIKey (Individu.RootId $ NodeId user_id) api_key
pure 1
...@@ -16,7 +16,6 @@ import Data.Morpheus.Types ...@@ -16,7 +16,6 @@ import Data.Morpheus.Types
import Data.Text (Text) import Data.Text (Text)
import qualified Data.Text as T import qualified Data.Text as T
import Gargantext.API.Prelude (GargM, GargError) import Gargantext.API.Prelude (GargM, GargError)
import Gargantext.Core.Mail.Types (HasMail)
import Gargantext.Database.Admin.Types.Hyperdata import Gargantext.Database.Admin.Types.Hyperdata
( HyperdataUser(..) ( HyperdataUser(..)
, hc_source , hc_source
...@@ -40,7 +39,7 @@ import Gargantext.Database.Admin.Types.Hyperdata.Contact ...@@ -40,7 +39,7 @@ import Gargantext.Database.Admin.Types.Hyperdata.Contact
, ct_phone , ct_phone
, hc_who , hc_who
, hc_where) , hc_where)
import Gargantext.Database.Prelude (HasConnectionPool, HasConfig) import Gargantext.Database.Prelude (CmdCommon)
import Gargantext.Database.Query.Table.Node.UpdateOpaleye (updateHyperdata) import Gargantext.Database.Query.Table.Node.UpdateOpaleye (updateHyperdata)
import Gargantext.Database.Query.Table.User (getUsersWithHyperdata, getUsersWithNodeHyperdata, updateUserEmail) import Gargantext.Database.Query.Table.User (getUsersWithHyperdata, getUsersWithNodeHyperdata, updateUserEmail)
import Gargantext.Database.Schema.User (UserLight(..)) import Gargantext.Database.Schema.User (UserLight(..))
...@@ -49,6 +48,7 @@ import Gargantext.Prelude ...@@ -49,6 +48,7 @@ import Gargantext.Prelude
import GHC.Generics (Generic) import GHC.Generics (Generic)
import Gargantext.API.GraphQL.Utils (AuthStatus(Invalid, Valid), authUser) import Gargantext.API.GraphQL.Utils (AuthStatus(Invalid, Valid), authUser)
import Gargantext.API.Admin.Types (HasSettings) import Gargantext.API.Admin.Types (HasSettings)
import qualified Gargantext.Core.Types.Individu as Individu
data UserInfo = UserInfo data UserInfo = UserInfo
{ ui_id :: Int { ui_id :: Int
...@@ -105,18 +105,18 @@ type GqlM' e env err = ResolverM e (GargM env err) Int ...@@ -105,18 +105,18 @@ type GqlM' e env err = ResolverM e (GargM env err) Int
-- | Function to resolve user from a query. -- | Function to resolve user from a query.
resolveUserInfos resolveUserInfos
:: (HasConnectionPool env, HasConfig env, HasMail env) :: (CmdCommon env)
=> UserInfoArgs -> GqlM e env [UserInfo] => UserInfoArgs -> GqlM e env [UserInfo]
resolveUserInfos UserInfoArgs { user_id } = dbUsers user_id resolveUserInfos UserInfoArgs { user_id } = dbUsers user_id
-- | Mutation for user info -- | Mutation for user info
updateUserInfo updateUserInfo
:: (HasConnectionPool env, HasConfig env, HasMail env, HasSettings env) :: (CmdCommon env, HasSettings env)
-- => UserInfoMArgs -> ResolverM e (GargM env err) Int -- => UserInfoMArgs -> ResolverM e (GargM env err) Int
=> UserInfoMArgs -> GqlM' e env err => UserInfoMArgs -> GqlM' e env err
updateUserInfo (UserInfoMArgs { ui_id, .. }) = do updateUserInfo (UserInfoMArgs { ui_id, .. }) = do
-- lift $ printDebug "[updateUserInfo] ui_id" ui_id -- lift $ printDebug "[updateUserInfo] ui_id" ui_id
users <- lift (getUsersWithNodeHyperdata ui_id) users <- lift (getUsersWithNodeHyperdata (Individu.UserDBId ui_id))
case users of case users of
[] -> panic $ "[updateUserInfo] User with id " <> (T.pack $ show ui_id) <> " doesn't exist." [] -> panic $ "[updateUserInfo] User with id " <> (T.pack $ show ui_id) <> " doesn't exist."
((UserLight { .. }, node_u):_) -> do ((UserLight { .. }, node_u):_) -> do
...@@ -160,14 +160,14 @@ updateUserInfo (UserInfoMArgs { ui_id, .. }) = do ...@@ -160,14 +160,14 @@ updateUserInfo (UserInfoMArgs { ui_id, .. }) = do
-- | Inner function to fetch the user from DB. -- | Inner function to fetch the user from DB.
dbUsers dbUsers
:: (HasConnectionPool env, HasConfig env, HasMail env) :: (CmdCommon env)
=> Int -> GqlM e env [UserInfo] => Int -> GqlM e env [UserInfo]
dbUsers user_id = do dbUsers user_id = do
-- lift $ printDebug "[dbUsers]" user_id -- lift $ printDebug "[dbUsers]" user_id
-- user <- getUsersWithId user_id -- user <- getUsersWithId user_id
-- hyperdata <- getUserHyperdata user_id -- hyperdata <- getUserHyperdata user_id
-- lift (map toUser <$> zip user hyperdata) -- lift (map toUser <$> zip user hyperdata)
lift (map toUser <$> (getUsersWithHyperdata user_id)) lift (map toUser <$> getUsersWithHyperdata (Individu.UserDBId user_id))
toUser :: (UserLight, HyperdataUser) -> UserInfo toUser :: (UserLight, HyperdataUser) -> UserInfo
toUser (UserLight { .. }, u_hyperdata) = toUser (UserLight { .. }, u_hyperdata) =
......
module Gargantext.API.Job where module Gargantext.API.Job where
import Control.Lens (over, _Just) import Control.Lens (over, _Just)
import Data.IORef
import Data.Maybe import Data.Maybe
import qualified Data.Text as T import qualified Data.Text as T
...@@ -9,11 +8,13 @@ import Gargantext.Prelude ...@@ -9,11 +8,13 @@ import Gargantext.Prelude
import Gargantext.API.Admin.Orchestrator.Types import Gargantext.API.Admin.Orchestrator.Types
newtype RemainingSteps = RemainingSteps { _RemainingSteps :: Int }
deriving (Show, Eq, Num)
jobLogInit :: Int -> JobLog jobLogStart :: RemainingSteps -> JobLog
jobLogInit rem = jobLogStart rem =
JobLog { _scst_succeeded = Just 0 JobLog { _scst_succeeded = Just 0
, _scst_remaining = Just rem , _scst_remaining = Just (_RemainingSteps rem)
, _scst_failed = Just 0 , _scst_failed = Just 0
, _scst_events = Just [] } , _scst_events = Just [] }
...@@ -25,13 +26,24 @@ addEvent level message (JobLog { _scst_events = mEvts, .. }) = JobLog { _scst_ev ...@@ -25,13 +26,24 @@ addEvent level message (JobLog { _scst_events = mEvts, .. }) = JobLog { _scst_ev
, _scev_level = Just level , _scev_level = Just level
, _scev_date = Nothing } , _scev_date = Nothing }
jobLogSuccess :: JobLog -> JobLog addErrorEvent :: T.Text -> JobLog -> JobLog
jobLogSuccess jl = over (scst_succeeded . _Just) (+ 1) $ addErrorEvent message = addEvent "ERROR" message
over (scst_remaining . _Just) (\x -> x - 1) jl
jobLogFail :: JobLog -> JobLog jobLogProgress :: Int -> JobLog -> JobLog
jobLogFail jl = over (scst_failed . _Just) (+ 1) $ jobLogProgress n jl = over (scst_succeeded . _Just) (+ n) $
over (scst_remaining . _Just) (\x -> x - 1) jl over (scst_remaining . _Just) (\x -> x - n) jl
-- | Mark a job as completely done, by adding the 'remaining' into 'succeeded'.
-- At the end 'scst_remaining' will be 0, and 'scst_succeeded' will be 'oldvalue + remaining'.
jobLogComplete :: JobLog -> JobLog
jobLogComplete jl =
let remainingNow = fromMaybe 0 (_scst_remaining jl)
in jl & over scst_succeeded (Just . maybe remainingNow ((+) remainingNow))
& over scst_remaining (const (Just 0))
jobLogFailures :: Int -> JobLog -> JobLog
jobLogFailures n jl = over (scst_failed . _Just) (+ n) $
over (scst_remaining . _Just) (\x -> x - n) jl
jobLogFailTotal :: JobLog -> JobLog jobLogFailTotal :: JobLog -> JobLog
jobLogFailTotal (JobLog { _scst_succeeded = mSucc jobLogFailTotal (JobLog { _scst_succeeded = mSucc
...@@ -48,25 +60,7 @@ jobLogFailTotal (JobLog { _scst_succeeded = mSucc ...@@ -48,25 +60,7 @@ jobLogFailTotal (JobLog { _scst_succeeded = mSucc
Just rem -> (Just 0, (+ rem) <$> mFail) Just rem -> (Just 0, (+ rem) <$> mFail)
jobLogFailTotalWithMessage :: T.Text -> JobLog -> JobLog jobLogFailTotalWithMessage :: T.Text -> JobLog -> JobLog
jobLogFailTotalWithMessage message jl = addEvent "ERROR" message $ jobLogFailTotal jl jobLogFailTotalWithMessage message jl = addErrorEvent message $ jobLogFailTotal jl
jobLogEvt :: JobLog -> ScraperEvent -> JobLog jobLogEvt :: JobLog -> ScraperEvent -> JobLog
jobLogEvt jl evt = over (scst_events . _Just) (\evts -> (evt:evts)) jl jobLogEvt jl evt = over (scst_events . _Just) (\evts -> (evt:evts)) jl
runJobLog :: MonadBase IO m => Int -> (JobLog -> m ()) -> m (m (), m (), m JobLog)
runJobLog num logStatus = do
jlRef <- liftBase $ newIORef $ jobLogInit num
return (logRefF jlRef, logRefSuccessF jlRef, getRefF jlRef)
where
logRefF ref = do
jl <- liftBase $ readIORef ref
logStatus jl
logRefSuccessF ref = do
jl <- liftBase $ readIORef ref
let jl' = jobLogSuccess jl
liftBase $ writeIORef ref jl'
logStatus jl'
getRefF ref = do
liftBase $ readIORef ref
...@@ -9,8 +9,7 @@ import Gargantext.Core.Types (UserId) ...@@ -9,8 +9,7 @@ import Gargantext.Core.Types (UserId)
import Gargantext.Database.Admin.Types.Node (NodeType(NodeTeam)) import Gargantext.Database.Admin.Types.Node (NodeType(NodeTeam))
import Gargantext.Database.Query.Table.Node (getNodesIdWithType) import Gargantext.Database.Query.Table.Node (getNodesIdWithType)
import Gargantext.Database.Action.Share (membersOf) import Gargantext.Database.Action.Share (membersOf)
import Gargantext.Database.Prelude (HasConnectionPool, HasConfig) import Gargantext.Database.Prelude (CmdCommon)
import Gargantext.Core.Mail.Types (HasMail)
import Control.Monad.Extra (concatMapM) import Control.Monad.Extra (concatMapM)
type MembersAPI = Get '[JSON] [Text] type MembersAPI = Get '[JSON] [Text]
...@@ -19,7 +18,8 @@ members :: UserId -> ServerT MembersAPI (GargM Env GargError) ...@@ -19,7 +18,8 @@ members :: UserId -> ServerT MembersAPI (GargM Env GargError)
members _ = do members _ = do
getMembers getMembers
getMembers :: (HasConnectionPool env, HasConfig env, HasMail env) => GargM env GargError [Text] getMembers :: (CmdCommon env) =>
GargM env GargError [Text]
getMembers = do getMembers = do
teamNodeIds <- getNodesIdWithType NodeTeam teamNodeIds <- getNodesIdWithType NodeTeam
m <- concatMapM membersOf teamNodeIds m <- concatMapM membersOf teamNodeIds
......
...@@ -27,7 +27,8 @@ import Gargantext.API.Ngrams.NgramsTree ...@@ -27,7 +27,8 @@ import Gargantext.API.Ngrams.NgramsTree
import Gargantext.API.Ngrams.Types import Gargantext.API.Ngrams.Types
import Gargantext.API.Prelude (GargServer) import Gargantext.API.Prelude (GargServer)
import Gargantext.Core.Text.Metrics (Scored(..), {-normalizeGlobal,-} normalizeLocal) import Gargantext.Core.Text.Metrics (Scored(..), {-normalizeGlobal,-} normalizeLocal)
import Gargantext.Core.Types (CorpusId, Limit, ListId, ListType(..)) import Gargantext.Core.Types (CorpusId, ListId, ListType(..))
import Gargantext.Core.Types.Query (Limit)
import Gargantext.Core.Viz.Chart import Gargantext.Core.Viz.Chart
import Gargantext.Core.Viz.Types import Gargantext.Core.Viz.Types
import Gargantext.Database.Admin.Types.Hyperdata (HyperdataList(..), hl_chart, hl_pie, hl_scatter, hl_tree) import Gargantext.Database.Admin.Types.Hyperdata (HyperdataList(..), hl_chart, hl_pie, hl_scatter, hl_tree)
...@@ -49,12 +50,12 @@ import qualified Gargantext.Database.Action.Metrics as Metrics ...@@ -49,12 +50,12 @@ import qualified Gargantext.Database.Action.Metrics as Metrics
type ScatterAPI = Summary "SepGen IncExc metrics" type ScatterAPI = Summary "SepGen IncExc metrics"
:> QueryParam "list" ListId :> QueryParam "list" ListId
:> QueryParamR "ngramsType" TabType :> QueryParamR "ngramsType" TabType
:> QueryParam "limit" Int :> QueryParam "limit" Limit
:> Get '[JSON] (HashedResponse Metrics) :> Get '[JSON] (HashedResponse Metrics)
:<|> Summary "Scatter update" :<|> Summary "Scatter update"
:> QueryParam "list" ListId :> QueryParam "list" ListId
:> QueryParamR "ngramsType" TabType :> QueryParamR "ngramsType" TabType
:> QueryParam "limit" Int :> QueryParam "limit" Limit
:> Post '[JSON] () :> Post '[JSON] ()
:<|> "hash" :> Summary "Scatter Hash" :<|> "hash" :> Summary "Scatter Hash"
:> QueryParam "list" ListId :> QueryParam "list" ListId
...@@ -149,7 +150,7 @@ type ChartApi = Summary " Chart API" ...@@ -149,7 +150,7 @@ type ChartApi = Summary " Chart API"
:<|> Summary "Chart update" :<|> Summary "Chart update"
:> QueryParam "list" ListId :> QueryParam "list" ListId
:> QueryParamR "ngramsType" TabType :> QueryParamR "ngramsType" TabType
:> QueryParam "limit" Int :> QueryParam "limit" Limit
:> Post '[JSON] () :> Post '[JSON] ()
:<|> "hash" :> Summary "Chart Hash" :<|> "hash" :> Summary "Chart Hash"
:> QueryParam "list" ListId :> QueryParam "list" ListId
...@@ -224,7 +225,7 @@ getChartHash :: FlowCmdM env err m => ...@@ -224,7 +225,7 @@ getChartHash :: FlowCmdM env err m =>
-> m Text -> m Text
getChartHash cId maybeListId tabType = do getChartHash cId maybeListId tabType = do
hash <$> getChart cId Nothing Nothing maybeListId tabType hash <$> getChart cId Nothing Nothing maybeListId tabType
------------------------------------------------------------- -------------------------------------------------------------
-- | Pie metrics API -- | Pie metrics API
type PieApi = Summary "Pie Chart" type PieApi = Summary "Pie Chart"
...@@ -236,7 +237,7 @@ type PieApi = Summary "Pie Chart" ...@@ -236,7 +237,7 @@ type PieApi = Summary "Pie Chart"
:<|> Summary "Pie Chart update" :<|> Summary "Pie Chart update"
:> QueryParam "list" ListId :> QueryParam "list" ListId
:> QueryParamR "ngramsType" TabType :> QueryParamR "ngramsType" TabType
:> QueryParam "limit" Int :> QueryParam "limit" Limit
:> Post '[JSON] () :> Post '[JSON] ()
:<|> "hash" :> Summary "Pie Hash" :<|> "hash" :> Summary "Pie Hash"
:> QueryParam "list" ListId :> QueryParam "list" ListId
......
This diff is collapsed.
...@@ -34,10 +34,12 @@ import Gargantext.API.Prelude (GargServer, GargM, GargError) ...@@ -34,10 +34,12 @@ import Gargantext.API.Prelude (GargServer, GargM, GargError)
import Gargantext.API.Types import Gargantext.API.Types
import Gargantext.Core.NodeStory import Gargantext.Core.NodeStory
import Gargantext.Core.Text.Terms (ExtractedNgrams(..)) import Gargantext.Core.Text.Terms (ExtractedNgrams(..))
import Gargantext.Core.Text.Terms.WithList (buildPatterns, termsInText) import Gargantext.Core.Text.Terms.WithList (MatchedText, buildPatterns, termsInText)
import Gargantext.Core.Types (TermsCount)
import Gargantext.Core.Types.Main (ListType(..)) import Gargantext.Core.Types.Main (ListType(..))
import Gargantext.Database.Action.Flow (saveDocNgramsWith) import Gargantext.Database.Action.Flow (saveDocNgramsWith)
import Gargantext.Database.Action.Flow.Types (FlowCmdM) import Gargantext.Database.Action.Flow.Types (FlowCmdM)
-- import Gargantext.Database.Action.Metrics.NgramsByContext (refreshNgramsMaterialized)
import Gargantext.Database.Admin.Types.Hyperdata.Document import Gargantext.Database.Admin.Types.Hyperdata.Document
import Gargantext.Database.Admin.Types.Node import Gargantext.Database.Admin.Types.Node
import Gargantext.Database.Query.Table.Node (getNode) import Gargantext.Database.Query.Table.Node (getNode)
...@@ -47,9 +49,8 @@ import Gargantext.Database.Schema.Ngrams ...@@ -47,9 +49,8 @@ import Gargantext.Database.Schema.Ngrams
import Gargantext.Database.Schema.Node (_node_parent_id) import Gargantext.Database.Schema.Node (_node_parent_id)
import Gargantext.Database.Types (Indexed(..)) import Gargantext.Database.Types (Indexed(..))
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Utils.Jobs (serveJobsAPI) import Gargantext.Utils.Jobs (serveJobsAPI, MonadJobStatus(..))
import Servant import Servant
-- import Servant.Job.Async
import qualified Data.ByteString.Lazy as BSL import qualified Data.ByteString.Lazy as BSL
import qualified Data.Csv as Csv import qualified Data.Csv as Csv
import qualified Data.HashMap.Strict as HashMap import qualified Data.HashMap.Strict as HashMap
...@@ -166,23 +167,30 @@ reIndexWith cId lId nt lts = do ...@@ -166,23 +167,30 @@ reIndexWith cId lId nt lts = do
-- fromListWith (<>) -- fromListWith (<>)
ngramsByDoc = map (HashMap.fromListWith (Map.unionWith (Map.unionWith (\(_a,b) (_a',b') -> (1,b+b'))))) ngramsByDoc = map (HashMap.fromListWith (Map.unionWith (Map.unionWith (\(_a,b) (_a',b') -> (1,b+b')))))
$ map (map (\((k, cnt), v) -> (SimpleNgrams (text2ngrams k), over (traverse . traverse) (\p -> (p, cnt)) v))) $ map (map (\((k, cnt), v) -> (SimpleNgrams (text2ngrams k), over (traverse . traverse) (\p -> (p, cnt)) v)))
$ map (\doc -> List.zip $ map (docNgrams nt ts) docs
(termsInText (buildPatterns $ map (\k -> (Text.splitOn " " $ unNgramsTerm k, [])) ts)
$ Text.unlines $ catMaybes
[ doc ^. context_hyperdata . hd_title
, doc ^. context_hyperdata . hd_abstract
]
)
(List.cycle [Map.fromList $ [(nt, Map.singleton (doc ^. context_id) 1 )]])
) docs
-- printDebug "ngramsByDoc: " ngramsByDoc -- printDebug "ngramsByDoc: " ngramsByDoc
-- Saving the indexation in database -- Saving the indexation in database
_ <- mapM (saveDocNgramsWith lId) ngramsByDoc _ <- mapM (saveDocNgramsWith lId) ngramsByDoc
-- _ <- refreshNgramsMaterialized
pure () pure ()
docNgrams :: NgramsType
-> [NgramsTerm]
-> Gargantext.Database.Admin.Types.Node.Context HyperdataDocument
-> [((MatchedText, TermsCount),
Map NgramsType (Map NodeId Int))]
docNgrams nt ts doc =
List.zip
(termsInText (buildPatterns $ map (\k -> (Text.splitOn " " $ unNgramsTerm k, [])) ts)
$ Text.unlines $ catMaybes
[ doc ^. context_hyperdata . hd_title
, doc ^. context_hyperdata . hd_abstract
]
)
(List.cycle [Map.fromList $ [(nt, Map.singleton (doc ^. context_id) 1 )]])
toIndexedNgrams :: HashMap Text NgramsId -> Text -> Maybe (Indexed Int Ngrams) toIndexedNgrams :: HashMap Text NgramsId -> Text -> Maybe (Indexed Int Ngrams)
toIndexedNgrams m t = Indexed <$> i <*> n toIndexedNgrams m t = Indexed <$> i <*> n
where where
...@@ -192,53 +200,35 @@ toIndexedNgrams m t = Indexed <$> i <*> n ...@@ -192,53 +200,35 @@ toIndexedNgrams m t = Indexed <$> i <*> n
------------------------------------------------------------------------ ------------------------------------------------------------------------
jsonPostAsync :: ServerT JSONAPI (GargM Env GargError) jsonPostAsync :: ServerT JSONAPI (GargM Env GargError)
jsonPostAsync lId = jsonPostAsync lId =
serveJobsAPI UpdateNgramsListJobJSON $ \f log' -> serveJobsAPI UpdateNgramsListJobJSON $ \jHandle f ->
let postAsync' lId f jHandle
log'' x = do
-- printDebug "postAsync ListId" x postAsync' :: (FlowCmdM env err m, MonadJobStatus m)
liftBase $ log' x
in postAsync' lId f log''
postAsync' :: FlowCmdM env err m
=> ListId => ListId
-> WithJsonFile -> WithJsonFile
-> (JobLog -> m ()) -> JobHandle m
-> m JobLog -> m ()
postAsync' l (WithJsonFile m _) logStatus = do postAsync' l (WithJsonFile m _) jobHandle = do
logStatus JobLog { _scst_succeeded = Just 0 markStarted 2 jobHandle
, _scst_failed = Just 0
, _scst_remaining = Just 2
, _scst_events = Just []
}
-- printDebug "New list as file" l -- printDebug "New list as file" l
_ <- setList l m _ <- setList l m
-- printDebug "Done" r -- printDebug "Done" r
logStatus JobLog { _scst_succeeded = Just 1 markProgress 1 jobHandle
, _scst_failed = Just 0
, _scst_remaining = Just 1
, _scst_events = Just []
}
corpus_node <- getNode l -- (Proxy :: Proxy HyperdataList) corpus_node <- getNode l -- (Proxy :: Proxy HyperdataList)
let corpus_id = fromMaybe (panic "") (_node_parent_id corpus_node) let corpus_id = fromMaybe (panic "") (_node_parent_id corpus_node)
_ <- reIndexWith corpus_id l NgramsTerms (Set.fromList [MapTerm, CandidateTerm]) _ <- reIndexWith corpus_id l NgramsTerms (Set.fromList [MapTerm, CandidateTerm])
pure JobLog { _scst_succeeded = Just 2 markComplete jobHandle
, _scst_failed = Just 0
, _scst_remaining = Just 0
, _scst_events = Just []
}
------------------------------------------------------------------------ ------------------------------------------------------------------------
readCsvText :: Text -> [(Text, Text, Text)] readCsvText :: Text -> Either Text [(Text, Text, Text)]
readCsvText t = case eDec of readCsvText t = case eDec of
Left _ -> [] Left err -> Left $ pack err
Right dec -> Vec.toList dec Right dec -> Right $ Vec.toList dec
where where
lt = BSL.fromStrict $ P.encodeUtf8 t lt = BSL.fromStrict $ P.encodeUtf8 t
eDec = Csv.decodeWith eDec = Csv.decodeWith
...@@ -268,50 +258,44 @@ parseCsvData lst = Map.fromList $ conv <$> lst ...@@ -268,50 +258,44 @@ parseCsvData lst = Map.fromList $ conv <$> lst
csvPost :: FlowCmdM env err m csvPost :: FlowCmdM env err m
=> ListId => ListId
-> Text -> Text
-> m Bool -> m (Either Text ())
csvPost l m = do csvPost l m = do
-- printDebug "[csvPost] l" l -- printDebug "[csvPost] l" l
-- printDebug "[csvPost] m" m -- printDebug "[csvPost] m" m
-- status label forms -- status label forms
let lst = readCsvText m let eLst = readCsvText m
let p = parseCsvData lst case eLst of
--printDebug "[csvPost] lst" lst Left err -> pure $ Left err
-- printDebug "[csvPost] p" p Right lst -> do
_ <- setListNgrams l NgramsTerms p let p = parseCsvData lst
-- printDebug "ReIndexing List" l --printDebug "[csvPost] lst" lst
corpus_node <- getNode l -- (Proxy :: Proxy HyperdataList) -- printDebug "[csvPost] p" p
let corpus_id = fromMaybe (panic "") (_node_parent_id corpus_node) _ <- setListNgrams l NgramsTerms p
_ <- reIndexWith corpus_id l NgramsTerms (Set.fromList [MapTerm, CandidateTerm]) -- printDebug "ReIndexing List" l
corpus_node <- getNode l -- (Proxy :: Proxy HyperdataList)
pure True let corpus_id = fromMaybe (panic "") (_node_parent_id corpus_node)
_ <- reIndexWith corpus_id l NgramsTerms (Set.fromList [MapTerm, CandidateTerm])
pure $ Right ()
------------------------------------------------------------------------ ------------------------------------------------------------------------
csvPostAsync :: ServerT CSVAPI (GargM Env GargError) csvPostAsync :: ServerT CSVAPI (GargM Env GargError)
csvPostAsync lId = csvPostAsync lId =
serveJobsAPI UpdateNgramsListJobCSV $ \f@(WithTextFile _ft _ _n) log' -> do serveJobsAPI UpdateNgramsListJobCSV $ \jHandle f -> do
let log'' x = do markStarted 1 jHandle
-- printDebug "[csvPostAsync] filetype" ft ePost <- csvPost lId (_wtf_data f)
-- printDebug "[csvPostAsync] name" n case ePost of
liftBase $ log' x Left err -> markFailed (Just err) jHandle
csvPostAsync' lId f log'' Right () -> markComplete jHandle
getLatestJobStatus jHandle >>= printDebug "[csvPostAsync] job ended with joblog: "
csvPostAsync' :: FlowCmdM env err m
=> ListId
-> WithTextFile
-> (JobLog -> m ())
-> m JobLog
csvPostAsync' l (WithTextFile _ m _) logStatus = do
logStatus JobLog { _scst_succeeded = Just 0
, _scst_failed = Just 0
, _scst_remaining = Just 1
, _scst_events = Just []
}
_r <- csvPost l m
pure JobLog { _scst_succeeded = Just 1
, _scst_failed = Just 0
, _scst_remaining = Just 0
, _scst_events = Just []
}
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- | This is for debugging the CSV parser in the REPL
importCsvFile :: FlowCmdM env err m
=> ListId -> P.FilePath -> m (Either Text ())
importCsvFile lId fp = do
contents <- liftBase $ P.readFile fp
csvPost lId contents
...@@ -138,7 +138,7 @@ filterListWithRootHashMap lt m = snd <$> HM.filter isMapTerm m ...@@ -138,7 +138,7 @@ filterListWithRootHashMap lt m = snd <$> HM.filter isMapTerm m
isMapTerm (l, maybeRoot) = case maybeRoot of isMapTerm (l, maybeRoot) = case maybeRoot of
Nothing -> l == lt Nothing -> l == lt
Just r -> case HM.lookup r m of Just r -> case HM.lookup r m of
Nothing -> panic $ "[Garg.API.Ngrams.Tools] filterWithRoot, unknown key: " <> unNgramsTerm r Nothing -> panic $ "[Garg.API.Ngrams.Tools] filterListWithRootHashMap, unknown key: " <> unNgramsTerm r
Just (l',_) -> l' == lt Just (l',_) -> l' == lt
filterListWithRoot :: [ListType] filterListWithRoot :: [ListType]
...@@ -149,7 +149,7 @@ filterListWithRoot lt m = snd <$> HM.filter isMapTerm m ...@@ -149,7 +149,7 @@ filterListWithRoot lt m = snd <$> HM.filter isMapTerm m
isMapTerm (l, maybeRoot) = case maybeRoot of isMapTerm (l, maybeRoot) = case maybeRoot of
Nothing -> elem l lt Nothing -> elem l lt
Just r -> case HM.lookup r m of Just r -> case HM.lookup r m of
Nothing -> panic $ "[Garg.API.Ngrams.Tools] filterWithRoot, unknown key: " <> unNgramsTerm r Nothing -> panic $ "[Garg.API.Ngrams.Tools] filterListWithRoot, unknown key: " <> unNgramsTerm r
Just (l',_) -> elem l' lt Just (l',_) -> elem l' lt
groupNodesByNgrams :: ( At root_map groupNodesByNgrams :: ( At root_map
......
This diff is collapsed.
...@@ -47,6 +47,7 @@ import Gargantext.API.Table ...@@ -47,6 +47,7 @@ import Gargantext.API.Table
import Gargantext.Core.Types (NodeTableResult) import Gargantext.Core.Types (NodeTableResult)
import Gargantext.Core.Types.Individu (User(..)) import Gargantext.Core.Types.Individu (User(..))
import Gargantext.Core.Types.Main (Tree, NodeTree) import Gargantext.Core.Types.Main (Tree, NodeTree)
import Gargantext.Core.Types.Query (Limit, Offset)
import Gargantext.Core.Utils.Prefix (unPrefix) import Gargantext.Core.Utils.Prefix (unPrefix)
import Gargantext.Core.Viz.Phylo.API (PhyloAPI, phyloAPI) import Gargantext.Core.Viz.Phylo.API (PhyloAPI, phyloAPI)
import Gargantext.Database.Action.Flow.Pairing (pairing) import Gargantext.Database.Action.Flow.Pairing (pairing)
...@@ -61,7 +62,7 @@ import Gargantext.Database.Query.Table.Node.Update (Update(..), update) ...@@ -61,7 +62,7 @@ import Gargantext.Database.Query.Table.Node.Update (Update(..), update)
import Gargantext.Database.Query.Table.Node.UpdateOpaleye (updateHyperdata) import Gargantext.Database.Query.Table.Node.UpdateOpaleye (updateHyperdata)
import Gargantext.Database.Query.Table.NodeContext (nodeContextsCategory, nodeContextsScore) import Gargantext.Database.Query.Table.NodeContext (nodeContextsCategory, nodeContextsScore)
import Gargantext.Database.Query.Table.NodeNode import Gargantext.Database.Query.Table.NodeNode
import Gargantext.Database.Query.Tree (tree, TreeMode(..)) import Gargantext.Database.Query.Tree (tree, tree_flat, TreeMode(..))
import Gargantext.Prelude import Gargantext.Prelude
import Servant import Servant
import Test.QuickCheck (elements) import Test.QuickCheck (elements)
...@@ -169,8 +170,8 @@ type PostNodeApi = Summary " PostNode Node with ParentId as {id}" ...@@ -169,8 +170,8 @@ type PostNodeApi = Summary " PostNode Node with ParentId as {id}"
type ChildrenApi a = Summary " Summary children" type ChildrenApi a = Summary " Summary children"
:> QueryParam "type" NodeType :> QueryParam "type" NodeType
:> QueryParam "offset" Int :> QueryParam "offset" Offset
:> QueryParam "limit" Int :> QueryParam "limit" Limit
-- :> Get '[JSON] [Node a] -- :> Get '[JSON] [Node a]
:> Get '[JSON] (NodeTableResult a) :> Get '[JSON] (NodeTableResult a)
...@@ -296,8 +297,8 @@ scoreApi = putScore ...@@ -296,8 +297,8 @@ scoreApi = putScore
type PairingApi = Summary " Pairing API" type PairingApi = Summary " Pairing API"
:> QueryParam "view" TabType :> QueryParam "view" TabType
-- TODO change TabType -> DocType (CorpusId for pairing) -- TODO change TabType -> DocType (CorpusId for pairing)
:> QueryParam "offset" Int :> QueryParam "offset" Offset
:> QueryParam "limit" Int :> QueryParam "limit" Limit
:> QueryParam "order" OrderBy :> QueryParam "order" OrderBy
:> Get '[JSON] [FacetDoc] :> Get '[JSON] [FacetDoc]
...@@ -335,6 +336,13 @@ treeAPI :: NodeId -> GargServer TreeAPI ...@@ -335,6 +336,13 @@ treeAPI :: NodeId -> GargServer TreeAPI
treeAPI id = tree TreeAdvanced id treeAPI id = tree TreeAdvanced id
:<|> tree TreeFirstLevel id :<|> tree TreeFirstLevel id
type TreeFlatAPI = QueryParams "type" NodeType
:> QueryParam "query" Text
:> Get '[JSON] [NodeTree]
treeFlatAPI :: NodeId -> GargServer TreeFlatAPI
treeFlatAPI = tree_flat
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- | TODO Check if the name is less than 255 char -- | TODO Check if the name is less than 255 char
rename :: NodeId -> RenameNode -> Cmd err [Int] rename :: NodeId -> RenameNode -> Cmd err [Int]
......
...@@ -46,9 +46,9 @@ import Gargantext.Database.Action.Flow.Types (FlowCmdM) ...@@ -46,9 +46,9 @@ import Gargantext.Database.Action.Flow.Types (FlowCmdM)
import Gargantext.Database.Admin.Types.Hyperdata (HyperdataAnnuaire(..), HyperdataContact) import Gargantext.Database.Admin.Types.Hyperdata (HyperdataAnnuaire(..), HyperdataContact)
import Gargantext.Database.Admin.Types.Hyperdata.Contact (hyperdataContact) import Gargantext.Database.Admin.Types.Hyperdata.Contact (hyperdataContact)
import Gargantext.Database.Admin.Types.Node import Gargantext.Database.Admin.Types.Node
import Gargantext.Prelude (($), liftBase, (.), {-printDebug,-} pure) import Gargantext.Prelude (($), {-printDebug,-})
import qualified Gargantext.Utils.Aeson as GUA import qualified Gargantext.Utils.Aeson as GUA
import Gargantext.Utils.Jobs (serveJobsAPI) import Gargantext.Utils.Jobs (serveJobsAPI, MonadJobStatus(..))
------------------------------------------------------------------------ ------------------------------------------------------------------------
type API = "contact" :> Summary "Contact endpoint" type API = "contact" :> Summary "Contact endpoint"
...@@ -73,35 +73,23 @@ data AddContactParams = AddContactParams { firstname :: !Text, lastname ...@@ -73,35 +73,23 @@ data AddContactParams = AddContactParams { firstname :: !Text, lastname
---------------------------------------------------------------------- ----------------------------------------------------------------------
api_async :: User -> NodeId -> ServerT API_Async (GargM Env GargError) api_async :: User -> NodeId -> ServerT API_Async (GargM Env GargError)
api_async u nId = api_async u nId =
serveJobsAPI AddContactJob $ \p log -> serveJobsAPI AddContactJob $ \jHandle p ->
let addContact u nId p jHandle
log' x = do
-- printDebug "addContact" x addContact :: (HasSettings env, FlowCmdM env err m, MonadJobStatus m)
liftBase $ log x
in addContact u nId p (liftBase . log')
addContact :: (HasSettings env, FlowCmdM env err m)
=> User => User
-> NodeId -> NodeId
-> AddContactParams -> AddContactParams
-> (JobLog -> m ()) -> JobHandle m
-> m JobLog -> m ()
addContact u nId (AddContactParams fn ln) logStatus = do addContact u nId (AddContactParams fn ln) jobHandle = do
logStatus JobLog { _scst_succeeded = Just 1 markStarted 2 jobHandle
, _scst_failed = Just 0 _ <- flow (Nothing :: Maybe HyperdataAnnuaire) u (Right [nId]) (Multi EN) Nothing (Just 1, yield $ hyperdataContact fn ln) jobHandle
, _scst_remaining = Just 1
, _scst_events = Just [] markComplete jobHandle
} addContact _uId _nId _p jobHandle = do
_ <- flow (Nothing :: Maybe HyperdataAnnuaire) u (Right [nId]) (Multi EN) Nothing (Just 1, yield $ hyperdataContact fn ln) logStatus simuLogs jobHandle 10
pure JobLog { _scst_succeeded = Just 2
, _scst_failed = Just 0
, _scst_remaining = Just 0
, _scst_events = Just []
}
addContact _uId _nId _p logStatus = do
simuLogs logStatus 10
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- TODO unPrefix "pn_" FromJSON, ToJSON, ToSchema, adapt frontend. -- TODO unPrefix "pn_" FromJSON, ToJSON, ToSchema, adapt frontend.
......
This diff is collapsed.
This diff is collapsed.
...@@ -14,6 +14,8 @@ data FileType = CSV ...@@ -14,6 +14,8 @@ data FileType = CSV
| CSV_HAL | CSV_HAL
| PresseRIS | PresseRIS
| WOS | WOS
| Iramuteq
| JSON
deriving (Eq, Show, Generic) deriving (Eq, Show, Generic)
instance ToSchema FileType instance ToSchema FileType
instance Arbitrary FileType where arbitrary = elements [CSV, PresseRIS] instance Arbitrary FileType where arbitrary = elements [CSV, PresseRIS]
...@@ -26,7 +28,9 @@ instance FromHttpApiData FileType where ...@@ -26,7 +28,9 @@ instance FromHttpApiData FileType where
parseUrlPiece "CSV_HAL" = pure CSV_HAL parseUrlPiece "CSV_HAL" = pure CSV_HAL
parseUrlPiece "PresseRis" = pure PresseRIS parseUrlPiece "PresseRis" = pure PresseRIS
parseUrlPiece "WOS" = pure WOS parseUrlPiece "WOS" = pure WOS
parseUrlPiece _ = pure CSV -- TODO error here parseUrlPiece "Iramuteq" = pure Iramuteq
parseUrlPiece "JSON" = pure JSON
parseUrlPiece s = panic $ "[G.A.A.Node.Corpus.New] File Type not implemented (yet): " <> s
instance ToHttpApiData FileType where instance ToHttpApiData FileType where
toUrlPiece = pack . show toUrlPiece = pack . show
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -20,6 +20,7 @@ import Data.Swagger ...@@ -20,6 +20,7 @@ import Data.Swagger
import Data.Text (Text) import Data.Text (Text)
import GHC.Generics (Generic) import GHC.Generics (Generic)
import Gargantext.API.Prelude import Gargantext.API.Prelude
import Gargantext.Core.NLP (HasNLPServer)
import Gargantext.Core.Types.Individu (User(..), arbitraryUsername) import Gargantext.Core.Types.Individu (User(..), arbitraryUsername)
import Gargantext.Database.Action.Share (ShareNodeWith(..)) import Gargantext.Database.Action.Share (ShareNodeWith(..))
import Gargantext.Database.Action.Share as DB (shareNodeWith, unPublish) import Gargantext.Database.Action.Share as DB (shareNodeWith, unPublish)
...@@ -56,11 +57,11 @@ instance Arbitrary ShareNodeParams where ...@@ -56,11 +57,11 @@ instance Arbitrary ShareNodeParams where
-- TODO permission -- TODO permission
-- TODO refactor userId which is used twice -- TODO refactor userId which is used twice
-- TODO change return type for better warning/info/success/error handling on the front -- TODO change return type for better warning/info/success/error handling on the front
api :: HasNodeError err api :: (HasNodeError err, HasNLPServer env, CmdRandom env err m)
=> User => User
-> NodeId -> NodeId
-> ShareNodeParams -> ShareNodeParams
-> CmdR err Int -> m Int
api userInviting nId (ShareTeamParams user') = do api userInviting nId (ShareTeamParams user') = do
let user'' = Text.toLower user' let user'' = Text.toLower user'
user <- case guessUserName user'' of user <- case guessUserName user'' of
...@@ -88,7 +89,7 @@ api userInviting nId (ShareTeamParams user') = do ...@@ -88,7 +89,7 @@ api userInviting nId (ShareTeamParams user') = do
True -> do True -> do
-- printDebug "[G.A.N.Share.api]" ("Invitation is enabled if you share a corpus at least" :: Text) -- printDebug "[G.A.N.Share.api]" ("Invitation is enabled if you share a corpus at least" :: Text)
pure 0 pure 0
False -> do False -> do
-- printDebug "[G.A.N.Share.api]" ("Your invitation is sent to: " <> user'') -- printDebug "[G.A.N.Share.api]" ("Your invitation is sent to: " <> user'')
newUsers [user''] newUsers [user'']
pure () pure ()
......
...@@ -15,7 +15,7 @@ import GHC.Generics (Generic) ...@@ -15,7 +15,7 @@ import GHC.Generics (Generic)
import Servant.Job.Utils (jsonOptions) import Servant.Job.Utils (jsonOptions)
import Web.FormUrlEncoded (FromForm, ToForm) import Web.FormUrlEncoded (FromForm, ToForm)
import Gargantext.Core (Lang(..){-, allLangs-}) import Gargantext.Core (Lang(..))
import Gargantext.Core.Utils.Prefix (unPrefixSwagger) import Gargantext.Core.Utils.Prefix (unPrefixSwagger)
import Gargantext.Prelude import Gargantext.Prelude
import qualified Gargantext.Database.GargDB as GargDB import qualified Gargantext.Database.GargDB as GargDB
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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