Commit 2474d912 authored by qlobbe's avatar qlobbe

Merge branch 'dev' into dev-phylo

parents 9e2e41c8 f417bede
# This file is a template, and might need editing before it works on your project. # Thanks to:
# see https://docs.gitlab.com/ce/ci/yaml/README.html for all available options # https://vadosware.io/post/zero-to-continuous-integrated-testing-a-haskell-project-with-gitlab/
#
# you can delete this line if you're not using Docker #
#image: busybox:latest image: haskell:8
before_script: variables:
- echo "Before script section" STACK_ROOT: "${CI_PROJECT_DIR}/.stack"
- echo "For example you might run an update here or install a build dependency" STACK_OPTS: "--system-ghc"
- echo "Or perhaps you might print out some debugging details"
cache:
after_script: paths:
- echo "After script section" - .stack
- echo "For example you might do some cleanup here" - .stack-work
- target
build1:
#before_script:
#- apt-get update
#- apt-get install make xz-utils
stages:
- build
- test
build:
stage: build stage: build
script: script:
- ./install - make setup
- make build
#test1:
# TOOO
#unit-test:
# stage: test # stage: test
# script: # script:
# - echo "Do a test here" # - make test-unit
# - echo "For example run a test suite" #
# #int-test:
#test2:
# stage: test # stage: test
# script:
# - echo "Do another parallel test here"
# - echo "For example run a lint test"
#
#deploy1:
# stage: deploy
# script: # script:
# - echo "Do your deploy here" # - make test-int
#
#e2e-test:
# stage: test
# script:
# - make test-e2e
#
# If you find yourself with a non-sensical build error when you know your project should be building just fine, this fragment should help:
#
#build:
# stage: build
# script:
# # Clear out cache files
# - rm -rf .stack
# - rm -rf .stack-work
# - stack setup --system-ghc
# - stack install --local-bin-path target --system-ghc
...@@ -18,38 +18,83 @@ progress. Please report and improve this documentation if you encounter ...@@ -18,38 +18,83 @@ progress. Please report and improve this documentation if you encounter
issues. issues.
### Build Core Code ### Build Core Code
#### Docker #### Docker
curl -sSL https://gitlab.iscpif.fr/gargantext/haskell-gargantext/raw/master/devops/docker-install | sh
``` sh
curl -sSL https://gitlab.iscpif.fr/gargantext/haskell-gargantext/raw/master/devops/docker/docker-install | sh
```
#### Debian #### Debian
curl -sSL https://gitlab.iscpif.fr/gargantext/haskell-gargantext/raw/master/devops/debian-install | sh
``` sh
curl -sSL https://gitlab.iscpif.fr/gargantext/haskell-gargantext/raw/master/devops/debian/install | sh
```
### Add dependencies ### Add dependencies
1. CoreNLP is needed (EN and FR); This dependency will not be needed 1. CoreNLP is needed (EN and FR); This dependency will not be needed
soon. soon.
- wget https://dl.gargantext.org/coreNLP.tar.bz2
- tar xvjf coreNLP.tar.bz2 ``` sh
- ./startServer.sh ./devops/install-corenlp
```
2. Louvain C++ needed to draw the socio-semantic graphs 2. Louvain C++ needed to draw the socio-semantic graphs
- git clone https://gitlab.iscpif.fr/gargantext/clustering-louvain-cplusplus.git
- cd clustering-louvain-cplusplus NOTE: This is already added in the Docker build.
- ./install
``` sh
git clone https://gitlab.iscpif.fr/gargantext/clustering-louvain-cplusplus.git
cd clustering-louvain-cplusplus
./install
```
### Initialization ### Initialization
Users has to be created first (user1 is created as instance): #### Docker
Run PostgreSQL first:
``` sh
cd devops/docker
docker-compose up
```
- stack install Initialization schema should be loaded automatically (from `devops/postgres/schema.sql`).
- ~/.local/bin/gargantext-init "gargantext.ini"
#### Gargantext
Users have to be created first (`user1` is created as instance):
``` sh
stack install
~/.local/bin/gargantext-init "gargantext.ini"
```
For Docker env, run:
``` sh
stack --docker run gargantext-init -- gargantext.ini
```
### Importing data
You can import some data with:
``` sh
docker run --rm -it -p 9000:9000 cgenie/corenlp-garg
stack exec gargantext-import -- "corpusCsvHal" "user1" "IMT3" gargantext.ini 10000 ./1000.csv
```
## Use Cases ## Use Cases
### Multi-User with Graphical User Interface (Server Mode) ### Multi-User with Graphical User Interface (Server Mode)
``` sh
~/.local/bin/stack --docker exec gargantext-server -- --ini "gargantext.ini" --run Prod ~/.local/bin/stack --docker exec gargantext-server -- --ini "gargantext.ini" --run Prod
Then you can log in with user1:1resu ```
Then you can log in with `user1:1resu`.
### Command Line Mode tools ### Command Line Mode tools
......
...@@ -23,14 +23,14 @@ import Data.Either ...@@ -23,14 +23,14 @@ import Data.Either
import Prelude (read) import Prelude (read)
import Control.Exception (finally) import Control.Exception (finally)
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Database.Flow (FlowCmdM, flowCorpusFile) import Gargantext.Database.Flow (FlowCmdM, flowCorpusFile, flowAnnuaire)
import Gargantext.Text.Corpus.Parsers (FileFormat(..)) import Gargantext.Text.Corpus.Parsers (FileFormat(..))
import Gargantext.Database.Utils (Cmd, ) import Gargantext.Database.Utils (Cmd, )
import Gargantext.Database.Types.Node (CorpusId, toHyperdataDocument) import Gargantext.Database.Types.Node (CorpusId, toHyperdataDocument)
import Gargantext.Database.Schema.User (insertUsersDemo) import Gargantext.Database.Schema.User (insertUsersDemo)
import Gargantext.Text.Terms (TermType(..)) import Gargantext.Text.Terms (TermType(..))
import Gargantext.Core (Lang(..)) import Gargantext.Core (Lang(..))
import Gargantext.API -- (GargError) import Gargantext.API.Types (GargError)
import Gargantext.API.Node () -- instances import Gargantext.API.Node () -- instances
import Gargantext.API.Settings (withDevEnv, runCmdDev, DevEnv) import Gargantext.API.Settings (withDevEnv, runCmdDev, DevEnv)
import System.Environment (getArgs) import System.Environment (getArgs)
...@@ -41,18 +41,27 @@ import Control.Monad.IO.Class (liftIO) ...@@ -41,18 +41,27 @@ import Control.Monad.IO.Class (liftIO)
main :: IO () main :: IO ()
main = do main = do
[userCreate, user, name, iniPath, limit, corpusPath] <- getArgs [fun, user, name, iniPath, limit, corpusPath] <- getArgs
--{- --{-
let createUsers :: Cmd GargError Int64 let createUsers :: Cmd GargError Int64
createUsers = insertUsersDemo createUsers = insertUsersDemo
let let
--tt = (Unsupervised EN 6 0 Nothing) --tt = (Unsupervised EN 6 0 Nothing)
tt = (Multi EN) tt = (Multi EN)
format = CsvGargV3 -- CsvHalFormat --WOS format = CsvGargV3 -- CsvHal --WOS
cmd :: forall m. FlowCmdM DevEnv GargError m => m CorpusId corpus :: forall m. FlowCmdM DevEnv GargError m => m CorpusId
cmd = flowCorpusFile (cs user) (Left (cs name :: Text)) (read limit :: Int) tt format corpusPath corpus = flowCorpusFile (cs user) (Left (cs name :: Text)) (read limit :: Int) tt format corpusPath
corpusCsvHal :: forall m. FlowCmdM DevEnv GargError m => m CorpusId
corpusCsvHal = flowCorpusFile (cs user) (Left (cs name :: Text)) (read limit :: Int) tt CsvHal corpusPath
annuaire :: forall m. FlowCmdM DevEnv GargError m => m CorpusId
annuaire = flowAnnuaire (cs user) (Left "Annuaire") (Multi EN) corpusPath
{- {-
let debatCorpus :: forall m. FlowCmdM DevEnv GargError m => m CorpusId let debatCorpus :: forall m. FlowCmdM DevEnv GargError m => m CorpusId
debatCorpus = do debatCorpus = do
...@@ -64,13 +73,23 @@ main = do ...@@ -64,13 +73,23 @@ main = do
flowCorpus (Text.pack user) (Text.pack name) (Multi FR) (map (map toHyperdataDocument) docs) flowCorpus (Text.pack user) (Text.pack name) (Multi FR) (map (map toHyperdataDocument) docs)
--} --}
withDevEnv iniPath $ \env -> do withDevEnv iniPath $ \env -> do
_ <- if userCreate == "true" _ <- if fun == "users"
then runCmdDev env createUsers then runCmdDev env createUsers
else pure 0 --(cs "false") else pure 0 --(cs "false")
_ <- runCmdDev env cmd _ <- if fun == "corpus"
then runCmdDev env corpus
else pure 0 --(cs "false")
_ <- if fun == "corpusCsvHal"
then runCmdDev env corpusCsvHal
else pure 0 --(cs "false")
_ <- if fun == "annuaire"
then runCmdDev env annuaire
else pure 0
{- {-
_ <- if corpusType == "csv" _ <- if corpusType == "csv"
then runCmdDev env csvCorpus then runCmdDev env csvCorpus
......
...@@ -19,36 +19,43 @@ Import a corpus binary. ...@@ -19,36 +19,43 @@ Import a corpus binary.
module Main where module Main where
import Data.Either (Either(..))
import Data.Maybe (Maybe(..))
import System.Environment (getArgs) import System.Environment (getArgs)
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Database.Flow (FlowCmdM, flowCorpusFile, getOrMkRoot) import Gargantext.Database.Flow (getOrMkRoot, getOrMk_RootWithCorpus)
import Gargantext.Text.Corpus.Parsers (FileFormat(..)) import Gargantext.Database.Schema.Node (getOrMkList)
import Gargantext.Database.Utils (Cmd, ) import Gargantext.Database.Utils (Cmd, )
import Gargantext.Database.Types.Node (CorpusId, toHyperdataDocument, RootId) import Gargantext.Database.Types.Node (CorpusId, RootId, HyperdataCorpus, ListId)
import Gargantext.Database.Schema.User (insertUsersDemo, UserId) import Gargantext.Database.Schema.User (insertUsersDemo, UserId)
import Gargantext.Text.Terms (TermType(..)) import Gargantext.API.Types (GargError)
import Gargantext.Core (Lang(..))
import Gargantext.API -- (GargError)
import Gargantext.API.Node () -- instances import Gargantext.API.Node () -- instances
import Gargantext.API.Settings (withDevEnv, runCmdDev, DevEnv) import Gargantext.API.Settings (withDevEnv, runCmdDev)
--import Gargantext.Text.Corpus.Parsers.GrandDebat (readFile, GrandDebatReference(..)) import Gargantext.Database.Config (userMaster, corpusMasterName)
import Data.Text (Text) import Gargantext.Database.Init (initTriggers)
import qualified Data.Text as Text
import Control.Monad.IO.Class (liftIO)
main :: IO () main :: IO ()
main = do main = do
[iniPath] <- getArgs [iniPath] <- getArgs
let createUsers :: Cmd GargError Int64 let createUsers :: Cmd GargError Int64
createUsers = insertUsersDemo createUsers = insertUsersDemo
let let
mkRoots :: Cmd GargError (UserId, RootId) mkRoots :: Cmd GargError [(UserId, RootId)]
mkRoots = getOrMkRoot "user1" mkRoots = mapM getOrMkRoot ["gargantua", "user1", "user2"]
-- TODO create all users roots
let
initMaster :: Cmd GargError (UserId, RootId, CorpusId, ListId)
initMaster = do
(masterUserId, masterRootId, masterCorpusId) <- getOrMk_RootWithCorpus userMaster (Left corpusMasterName) (Nothing :: Maybe HyperdataCorpus)
masterListId <- getOrMkList masterCorpusId masterUserId
_triggers <- initTriggers masterListId
pure (masterUserId, masterRootId, masterCorpusId, masterListId)
withDevEnv iniPath $ \env -> do withDevEnv iniPath $ \env -> do
_ <- runCmdDev env createUsers _ <- runCmdDev env createUsers
_ <- runCmdDev env mkRoots _ <- runCmdDev env mkRoots
x <- runCmdDev env initMaster
putStrLn $ show x
pure () pure ()
{ghc}:
with (import <nixpkgs> {});
haskell.lib.buildStackProject {
inherit ghc;
name = "gargantext";
buildInputs = [
docker-compose
blas
bzip2
#gfortran
gfortran.cc.lib
glibc
gmp
gsl
igraph
liblapack
pcre
postgresql
#stack
xz
zlib
];
}
FROM openjdk
ADD home/debian/CoreNLP /CoreNLP
WORKDIR /CoreNLP
CMD ./startServer.sh
with (import <nixpkgs> {});
stdenv.mkDerivation rec {
name = "env";
env = buildEnv {
name = name;
paths = buildInputs;
};
buildInputs = [
docker-compose
#glibc
#gmp
#gsl
#igraph
#pcre
#postgresql
#stack
#xz
];
builder = builtins.toFile "builder.sh" ''
source $stdenv/setup
touch $out
'';
}
#!/bin/bash
if git --version;
then
echo "git installed, ok"
else
sudo apt update && sudo apt install git
fi
sudo apt update
sudo apt install liblzma-dev libpcre3-dev libblas-dev liblapack-dev pkg-config libgsl-dev libbz2-dev postgresql postgresql-server-dev-9.6 nginx libigraph-dev
#echo "Which user?"
#read USER
#sudo adduser --disabled-password --gecos "" $USER
#sudo su $USER
curl -sSL https://get.haskellstack.org/ | sh
stack update
stack upgrade
git clone https://gitlab.iscpif.fr/gargantext/haskell-gargantext.git
cd haskell-gargantext
git clone https://gitlab.iscpif.fr/gargantext/purescript-gargantext
mkdir deps
cd deps
git clone https://gitlab.iscpif.fr/gargantext/clustering-louvain.git
git clone https://github.com/np/servant-job.git
git clone https://github.com/np/patches-map
git clone https://gitlab.com/npouillard/patches-class.git
git clone https://github.com/delanoe/haskell-opaleye
git clone -b next --single-branch https://github.com/delanoe/hsparql
cd ..
stack setup
stack build
stack install
# Specific to our servers
### Configure timezone and locale ###################################
echo "########### LOCALES & TZ #################"
echo "Europe/Paris" > /etc/timezone
dpkg-reconfigure --frontend=noninteractive tzdata
#ENV TZ "Europe/Paris"
sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen && \
sed -i -e 's/# fr_FR.UTF-8 UTF-8/fr_FR.UTF-8 UTF-8/' /etc/locale.gen && \
locale-gen && \
update-locale LANG=fr_FR.UTF-8 && \
update-locale LANGUAGE=fr_FR.UTF-8 && \
update-locale LC_ALL=fr_FR.UTF-8
################################################################
# Database configuration
# CREATE USER gargantua WITH PASSWORD $(grep DB_PASS gargantext.ini)
# GRANT ALL PRIVILEGES ON DATABASE gargandbV4 to gargantua
#######################################################################
## POSTGRESQL DATA (as ROOT)
#######################################################################
sed -iP "s%^data_directory.*%data_directory = \'\/srv\/gargandata\'%" /etc/postgresql/9.6/main/postgresql.conf
echo "host all all 0.0.0.0/0 md5" >> /etc/postgresql/9.6/main/pg_hba.conf
echo "listen_addresses='*'" >> /etc/postgresql/9.6/main/postgresql.conf
...@@ -14,5 +14,5 @@ sudo apt install liblzma-dev libpcre3-dev libblas-dev liblapack-dev pkg-config l ...@@ -14,5 +14,5 @@ sudo apt install liblzma-dev libpcre3-dev libblas-dev liblapack-dev pkg-config l
# Phylo management # Phylo management
sudo apt install graphviz sudo apt install graphviz
sudo apt install postgresql-server-dev-9.6 sudo apt install postgresql-server-dev-11
#!/bin/bash
git clone https://gitlab.iscpif.fr/gargantext/clustering-louvain-cplusplus.git
cd clustering-louvain-cplusplus
./install
cd ..
sudo apt install default-jdk
wget https://dl.gargantext.org/coreNLP.tar.bz2
tar xvjf coreNLP.tar.bz2
# ./startServer.sh
This diff is collapsed.
from fpco/stack-build:lts-12.26 from fpco/stack-build:lts-14.6
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y git libigraph0-dev && \ apt-get install -y git libigraph0-dev && \
......
...@@ -10,9 +10,15 @@ services: ...@@ -10,9 +10,15 @@ services:
POSTGRES_PASSWORD: C8kdcUrAQy66U POSTGRES_PASSWORD: C8kdcUrAQy66U
POSTGRES_DB: gargandbV5 POSTGRES_DB: gargandbV5
volumes: volumes:
- pgdata:/var/lib/postgresql/data - garg-pgdata:/var/lib/postgresql/data
- ../:/gargantext - ../:/gargantext
- ../dbs:/dbs - ../dbs:/dbs
- ../postgres/schema.sql:/docker-entrypoint-initdb.d/schema.sql:ro
corenlp:
image: 'cgenie/corenlp-garg'
ports:
- 9000:9000
volumes: volumes:
pgdata: garg-pgdata:
#!/bin/bash
if [ "$#" -lt 3 ]; then if [ "$#" -lt 3 ]; then
echo "Usage: $0 <name> <path> <limit>" echo "Usage: $0 <name> <path> <limit>"
exit 1 exit 1
......
...@@ -37,27 +37,27 @@ exec sudo -E /usr/bin/docker \"\$@\"" >> $DOCKERBIN ...@@ -37,27 +37,27 @@ exec sudo -E /usr/bin/docker \"\$@\"" >> $DOCKERBIN
fi fi
######################################################################## ########################################################################
curl -sSL https://get.haskellstack.org/ | sh if stack --version;
stack update then
stack upgrade echo "Haskell stack installed, ok"
else
curl -sSL https://get.haskellstack.org/ | sh
stack update
stack upgrade
fi
git clone https://gitlab.iscpif.fr/gargantext/haskell-gargantext.git git clone https://gitlab.iscpif.fr/gargantext/haskell-gargantext.git
cd haskell-gargantext cd haskell-gargantext
git clone https://gitlab.iscpif.fr/gargantext/purescript-gargantext git clone https://gitlab.iscpif.fr/gargantext/purescript-gargantext
mkdir deps ../install-deps $(pwd)
cd deps
git clone https://gitlab.iscpif.fr/gargantext/clustering-louvain.git pushd devops/docker
git clone https://github.com/np/servant-job.git docker build --pull -t fpco/stack-build:lts-14.22-garg .
git clone https://github.com/np/patches-map popd
git clone https://gitlab.com/npouillard/patches-class.git
git clone https://github.com/delanoe/haskell-opaleye
git clone -b next --single-branch https://github.com/delanoe/hsparql
cd ..
stack docker pull #stack docker pull
stack --docker setup stack --docker setup
stack --docker build stack --docker build
stack --docker install stack --docker install
......
#!/bin/bash
set -eu set -eu
docker stop dbgarg || : docker stop dbgarg || :
docker rm --volumes dbgarg || : docker rm --volumes dbgarg || :
export PGPASSWORD="$(grep DB_PASS gargantext.ini | \awk '{print $3}')" export PGPASSWORD="$(grep DB_PASS gargantext.ini | \awk '{print $3}')"
docker run --name dbgarg -e POSTGRES_USER=gargantua -e POSTGRES_DB=gargandbV5 -e POSTGRES_PASSWORD=${PGPASSWORD} -d postgres docker run --name dbgarg -e POSTGRES_USER=gargantua -e POSTGRES_DB=gargandbV5 -e POSTGRES_PASSWORD=${PGPASSWORD} -d postgres
sleep 3 sleep 3
docker run -e PGPASSWORD -i --rm --link dbgarg:postgres postgres psql -h postgres -U gargantua -d gargandbV5 < src/Gargantext/Database/Schema/schema.sql docker run -e PGPASSWORD -i --rm --link dbgarg:postgres postgres psql -h postgres -U gargantua -d gargandbV5 < devops/postgres/schema.sql
#docker run -e PGPASSWORD -i --rm --link dbgarg:postgres postgres psql -h postgres -U gargantua -d gargandbV5 < gargantext.dump #docker run -e PGPASSWORD -i --rm --link dbgarg:postgres postgres psql -h postgres -U gargantua -d gargandbV5 < gargantext.dump
#docker run -e PGPASSWORD -i --rm --link dbgarg:postgres postgres dropdb -h postgres -U gargantua gargandbV5 #docker run -e PGPASSWORD -i --rm --link dbgarg:postgres postgres dropdb -h postgres -U gargantua gargandbV5
#!/bin/bash
stack --docker exec gargantext-server -- --run Prod --ini gargantext.ini stack --docker exec gargantext-server -- --run Prod --ini gargantext.ini
#!/bin/bash
if [ ! -d coreNLP ]; then
mkdir -v coreNLP
fi
pushd coreNLP
wget https://dl.gargantext.org/coreNLP.tar.bz2
tar xvjf coreNLP.tar.bz2
pushd home/debian/CoreNLP
./startServer.sh
#!/bin/bash
DIR=$1
DEPS_DIR=${DIR}/deps
function clone_or_update() {
REPO=$1
echo "Checking repo ${REPO}"
# strip only dir name from URL
DIR=${REPO##*/}
# strip the remaining '.git' suffix
RAW_DIR=${DIR%.*}
if [ -d "${RAW_DIR}" ]; then
pushd ${RAW_DIR}
git pull
popd ..
else
git clone "$@"
fi
}
if [ ! -d "${DEPS_DIR}" ]; then
mkdir ${DIR}/deps
fi
cd ${DIR}/deps
clone_or_update https://gitlab.iscpif.fr/gargantext/clustering-louvain.git
clone_or_update https://github.com/np/servant-job.git
clone_or_update https://github.com/np/patches-map
clone_or_update https://gitlab.com/npouillard/patches-class.git
clone_or_update https://github.com/delanoe/haskell-opaleye
clone_or_update https://github.com/delanoe/hsparql -b next --single-branch
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# http://wiki.nginx.org/Pitfalls
# http://wiki.nginx.org/QuickStart
# http://wiki.nginx.org/Configuration
#
# Generally, you will want to move this file somewhere, and start with a clean
# file but keep this around for reference. Or just disable in sites-enabled.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##
server {
if ($host = dev.gargantext.org) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name dev.gargantext.org;
add_header Cache-Control "no-cache";
location '/.well-known/acme-challenge' {
root /var/www/gargantext;
}
# Always redirect to https
return 301 https://dev.gargantext.org$request_uri;
}
server {
listen 443;
listen [::]:443 ssl;
server_name dev.gargantext.org;
# Some options configurations:
# https://github.com/h5bp/server-configs-nginx/blob/master/h5bp/location/expires.conf
add_header Cache-Control "no-cache";
# SSL configuration
#
# listen 443 ssl default_server;
# listen [::]:443 ssl default_server;
ssl on;
ssl_certificate /etc/letsencrypt/live/dev.gargantext.org/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/dev.gargantext.org/privkey.pem; # managed by Certbot
# Note: You should disable gzip for SSL traffic.
# See: https://bugs.debian.org/773332
#
# Read up on ssl_ciphers to ensure a secure configuration.
# See: https://bugs.debian.org/765782
#
# Self signed certs generated by the ssl-cert package
# Don't use them in a production server!
#
# include snippets/snakeoil.conf;
client_max_body_size 800M;
client_body_timeout 12;
client_header_timeout 12;
keepalive_timeout 15;
send_timeout 10;
root /var/www/html;
index index.html;
#add_header Access-Control-Allow-Origin $http_origin always;
# Add index.php to the list if you are using PHP
#index index.html index.htm index.nginx-debian.html;
# CORS config borrowed from: https://gist.github.com/pauloricardomg/7084524
# NP: not sure we need CORS yet
#
if ($http_origin ~* (^https?://(127.0.0.1|localhost|dev\.gargantext\.com))) {
set $cors "1";
}
#
# Cross-Origin Resource Sharing
if ($request_method = "OPTIONS") {
set $cors "${cors}o";
}
# SSL CERT renewal
location '/.well-known/acme-challenge' {
alias /var/www/gargantext/.well-known/acme-challenge ;
}
location /api {
# limit_except OPTIONS {
# auth_basic "Gargantext's Development Version";
# auth_basic_user_file /etc/nginx/haskell_gargantext.htpasswd;
# }
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://127.0.0.1:8008;
}
location / {
# https://stackoverflow.com/a/48708812
limit_except OPTIONS {
auth_basic "Gargantext's Development Version";
auth_basic_user_file /etc/nginx/haskell_gargantext.htpasswd;
}
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://127.0.0.1:8008;
}
#access_log off;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
}
sudo apt install apache2-utils
htpasswd -c /etc/nginx/haskell_gargantext.htpasswd username1
sudo apt-get install certbot python-certbot-nginx
sudo certbot --nginx
#!/bin/bash #!/bin/bash
sudo su postgres # sudo su postgres
PW="password" # postgresql://$USER:$PW@localhost/$DB
PW="C8kdcUrAQy66U"
DB="gargandbV5" DB="gargandbV5"
USER="gargantua" USER="gargantua"
psql -c "CREATE USER \"${USER}\" psql -c "CREATE USER \"${USER}\""
psql -c "ALTER USER \"${USER}\" with PASSWORD \"${PW}\"" psql -c "ALTER USER \"${USER}\" with PASSWORD '${PW}'"
psql -c "DROP DATABASE IF EXISTS \"${DB}\"" psql -c "DROP DATABASE IF EXISTS \"${DB}\""
createdb "${DB}" createdb "${DB}"
psql "${DB}" < schema.sql psql "${DB}" < schema.sql
psql -c "ALTER DATABASE \"${DB}\" OWNER to \"${USER}\" ;" psql -c "ALTER DATABASE \"${DB}\" OWNER to \"${USER}\""
......
This diff is collapsed.
name: gargantext name: gargantext
version: '4.0.0.6' version: '0.0.0.4'
synopsis: Search, map, share synopsis: Search, map, share
description: Please see README.md description: Please see README.md
category: Data category: Data
...@@ -33,11 +33,14 @@ library: ...@@ -33,11 +33,14 @@ library:
# - Gargantext.API.Orchestrator # - Gargantext.API.Orchestrator
- Gargantext.API.Search - Gargantext.API.Search
- Gargantext.API.Settings - Gargantext.API.Settings
- Gargantext.API.Types
- Gargantext.Core - Gargantext.Core
- Gargantext.Core.Types - Gargantext.Core.Types
- Gargantext.Core.Types.Main - Gargantext.Core.Types.Main
- Gargantext.Core.Utils.Prefix - Gargantext.Core.Utils.Prefix
- Gargantext.Database - Gargantext.Database
- Gargantext.Database.Init
- Gargantext.Database.Config
- Gargantext.Database.Flow - Gargantext.Database.Flow
- Gargantext.Database.Schema.Node - Gargantext.Database.Schema.Node
- Gargantext.Database.Tree - Gargantext.Database.Tree
...@@ -85,11 +88,13 @@ library: ...@@ -85,11 +88,13 @@ library:
- aeson - aeson
- aeson-lens - aeson-lens
- aeson-pretty - aeson-pretty
- argon2
- async - async
- attoparsec - attoparsec
- auto-update - auto-update
- base >=4.7 && <5 - base >=4.7 && <5
- base16-bytestring - base16-bytestring
- base64-bytestring
- blaze-html - blaze-html
- blaze-markup - blaze-markup
- blaze-svg - blaze-svg
...@@ -97,6 +102,7 @@ library: ...@@ -97,6 +102,7 @@ library:
- case-insensitive - case-insensitive
- cassava - cassava
#- charsetdetect-ae # detect charset #- charsetdetect-ae # detect charset
- clock
- clustering-louvain - clustering-louvain
- conduit - conduit
- conduit-extra - conduit-extra
...@@ -112,6 +118,7 @@ library: ...@@ -112,6 +118,7 @@ library:
- duckling - duckling
- exceptions - exceptions
- filepath - filepath
- formatting
- fullstop - fullstop
- fclabels - fclabels
- fgl - fgl
...@@ -133,7 +140,7 @@ library: ...@@ -133,7 +140,7 @@ library:
- hlcm - hlcm
- ini - ini
- insert-ordered-containers - insert-ordered-containers
- jose-jwt - jose
# - kmeans-vector # - kmeans-vector
- json-stream - json-stream
- KMP - KMP
...@@ -159,10 +166,13 @@ library: ...@@ -159,10 +166,13 @@ library:
- profunctors - profunctors
- protolude - protolude
- pureMD5 - pureMD5
- random-shuffle
- MonadRandom
- SHA - SHA
- simple-reflect - simple-reflect
- cereal # (IGraph) - cereal # (IGraph)
- singletons # (IGraph) - singletons # (IGraph)
- quickcheck-instances
- random - random
- rake - rake
- regex-compat - regex-compat
...@@ -172,9 +182,12 @@ library: ...@@ -172,9 +182,12 @@ library:
- semigroups - semigroups
- servant - servant
- servant-auth - servant-auth
- servant-auth-server >= 0.4.4.0
- servant-auth-swagger
- servant-blaze - servant-blaze
- servant-client - servant-client
# - servant-job - servant-flatten
- servant-job
- servant-mock - servant-mock
- servant-multipart - servant-multipart
- servant-server - servant-server
...@@ -196,6 +209,7 @@ library: ...@@ -196,6 +209,7 @@ library:
- transformers - transformers
- transformers-base - transformers-base
- unordered-containers - unordered-containers
- Unique
- uuid - uuid
- validity - validity
- vector - vector
......
This diff is collapsed.
{-|
Module : Gargantext.API.Annuaire
Description : New annuaire API
Copyright : (c) CNRS, 2017-Present
License : AGPL + CECILL v3
Maintainer : team@gargantext.org
Stability : experimental
Portability : POSIX
-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
module Gargantext.API.Annuaire
where
import Control.Lens hiding (elements)
import Data.Aeson
import Data.Swagger
import Data.Text (Text)
import GHC.Generics (Generic)
import qualified Gargantext.API.Corpus.New.File as NewFile
import Gargantext.API.Orchestrator.Types
import Gargantext.Core (Lang(..))
import Gargantext.Core.Utils.Prefix (unPrefixSwagger)
import Gargantext.Database.Flow (FlowCmdM) -- flowAnnuaire
import Gargantext.Database.Types.Node (AnnuaireId)
import Gargantext.Prelude
import Servant
import Servant.API.Flatten (Flat)
import Servant.Job.Core
import Servant.Job.Types
import Servant.Job.Utils (jsonOptions)
import Web.FormUrlEncoded (FromForm)
type Api = Summary "New Annuaire endpoint"
:> Post '[JSON] AnnuaireId
------------------------------------------------------------------------
------------------------------------------------------------------------
data WithForm = WithForm
{ _wf_filetype :: !NewFile.FileType
, _wf_data :: !Text
, _wf_lang :: !(Maybe Lang)
} deriving (Eq, Show, Generic)
makeLenses ''WithForm
instance FromForm WithForm
instance FromJSON WithForm where
parseJSON = genericParseJSON $ jsonOptions "_wf_"
instance ToSchema WithForm where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_wf_")
------------------------------------------------------------------------
type AsyncJobs event ctI input output =
Flat (AsyncJobsAPI' 'Unsafe 'Safe ctI '[JSON] Maybe event input output)
------------------------------------------------------------------------
type AddWithForm = Summary "Add with FormUrlEncoded to annuaire endpoint"
:> "annuaire"
:> Capture "annuaire_id" AnnuaireId
:> "add"
:> "form"
:> "async"
:> AsyncJobs ScraperStatus '[FormUrlEncoded] WithForm ScraperStatus
------------------------------------------------------------------------
addToAnnuaireWithForm :: FlowCmdM env err m
=> AnnuaireId
-> WithForm
-> (ScraperStatus -> m ())
-> m ScraperStatus
addToAnnuaireWithForm _cid (WithForm ft _d _l) logStatus = do
printDebug "ft" ft
-- let
-- parse = case ft of
-- CSV_HAL -> Parser.parseFormat Parser.CsvHal
-- CSV -> Parser.parseFormat Parser.CsvGargV3
-- WOS -> Parser.parseFormat Parser.WOS
-- PresseRIS -> Parser.parseFormat Parser.RisPresse
-- docs <- liftIO
-- $ splitEvery 500
-- <$> take 1000000
-- <$> parse (cs d)
logStatus ScraperStatus { _scst_succeeded = Just 1
, _scst_failed = Just 0
, _scst_remaining = Just 1
, _scst_events = Just []
}
-- cid' <- flowCorpus "user1"
-- (Right [cid])
-- (Multi $ fromMaybe EN l)
-- (map (map toHyperdataDocument) docs)
-- printDebug "cid'" cid'
pure ScraperStatus { _scst_succeeded = Just 2
, _scst_failed = Just 0
, _scst_remaining = Just 0
, _scst_events = Just []
}
...@@ -7,7 +7,7 @@ Maintainer : team@gargantext.org ...@@ -7,7 +7,7 @@ Maintainer : team@gargantext.org
Stability : experimental Stability : experimental
Portability : POSIX Portability : POSIX
Main authorisation of Gargantext are managed in this module Main authorization of Gargantext are managed in this module
-- 1: Implement the Server / Client JWT authentication -- 1: Implement the Server / Client JWT authentication
-> Client towards Python Backend -> Client towards Python Backend
...@@ -16,27 +16,41 @@ Main authorisation of Gargantext are managed in this module ...@@ -16,27 +16,41 @@ Main authorisation of Gargantext are managed in this module
-- 2: Implement the Auth API backend -- 2: Implement the Auth API backend
https://github.com/haskell-servant/servant-auth https://github.com/haskell-servant/servant-auth
TODO-ACCESS Critical
-} -}
{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
module Gargantext.API.Auth module Gargantext.API.Auth
where where
import Control.Lens (view)
import Control.Monad.IO.Class (liftIO)
import Data.Aeson.TH (deriveJSON) import Data.Aeson.TH (deriveJSON)
import Data.List (elem) import Data.List (elem)
import Data.Swagger import Data.Swagger
import Data.Text (Text, reverse) import Data.Text (Text, reverse)
import Data.Text.Lazy (toStrict)
import Data.Text.Lazy.Encoding (decodeUtf8)
import GHC.Generics (Generic) import GHC.Generics (Generic)
import Gargantext.Core.Utils.Prefix (unPrefix) import Servant
import Servant.Auth.Server
import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
import Gargantext.API.Settings
import Gargantext.API.Types (HasJoseError(..), joseError, HasServerError, GargServerC)
--import Gargantext.API.Types (HasJoseError(..), joseError, HasServerError, serverError, GargServerC)
import Gargantext.Database.Root (getRoot) import Gargantext.Database.Root (getRoot)
import Gargantext.Database.Types.Node (NodePoly(_node_id), NodeId) import Gargantext.Database.Tree (isDescendantOf, isIn)
import Gargantext.Database.Utils (Cmd) import Gargantext.Database.Types.Node (NodePoly(_node_id), NodeId(..), UserId, ListId, DocId)
import Gargantext.Database.Utils (Cmd', CmdM, HasConnection)
import Gargantext.Prelude hiding (reverse) import Gargantext.Prelude hiding (reverse)
import Test.QuickCheck (elements, oneof) import Test.QuickCheck (elements, oneof)
import Test.QuickCheck.Arbitrary (Arbitrary, arbitrary) import Test.QuickCheck.Arbitrary (Arbitrary, arbitrary)
...@@ -69,20 +83,34 @@ type TreeId = NodeId ...@@ -69,20 +83,34 @@ type TreeId = NodeId
-- | Main functions of authorization -- | Main functions of authorization
-- | Main types of authorization -- | Main types of authorization
data CheckAuth = InvalidUser | InvalidPassword | Valid Token TreeId data CheckAuth = InvalidUser | InvalidPassword | Valid Token TreeId
deriving (Eq) deriving (Eq)
checkAuthRequest :: Username -> Password -> Cmd err CheckAuth makeTokenForUser :: (HasSettings env, HasJoseError err)
=> NodeId -> Cmd' env err Token
makeTokenForUser uid = do
jwtS <- view $ settings . jwtSettings
e <- liftIO $ makeJWT (AuthenticatedUser uid) jwtS Nothing
-- TODO-SECURITY here we can implement token expiration ^^.
either joseError (pure . toStrict . decodeUtf8) e
-- TODO not sure about the encoding...
checkAuthRequest :: (HasSettings env, HasConnection env, HasJoseError err)
=> Username -> Password -> Cmd' env err CheckAuth
checkAuthRequest u p checkAuthRequest u p
| not (u `elem` arbitraryUsername) = pure InvalidUser | not (u `elem` arbitraryUsername) = pure InvalidUser
| u /= reverse p = pure InvalidPassword | u /= reverse p = pure InvalidPassword
| otherwise = do | otherwise = do
muId <- getRoot "user1" muId <- head <$> getRoot u
pure $ maybe InvalidUser (Valid "token" . _node_id) $ head muId case _node_id <$> muId of
Nothing -> pure InvalidUser
auth :: AuthRequest -> Cmd err AuthResponse Just uid -> do
token <- makeTokenForUser uid
pure $ Valid token uid
auth :: (HasSettings env, HasConnection env, HasJoseError err)
=> AuthRequest -> Cmd' env err AuthResponse
auth (AuthRequest u p) = do auth (AuthRequest u p) = do
checkAuthRequest' <- checkAuthRequest u p checkAuthRequest' <- checkAuthRequest u p
case checkAuthRequest' of case checkAuthRequest' of
...@@ -90,9 +118,36 @@ auth (AuthRequest u p) = do ...@@ -90,9 +118,36 @@ auth (AuthRequest u p) = do
InvalidPassword -> pure $ AuthResponse Nothing (Just $ AuthInvalid "Invalid password") InvalidPassword -> pure $ AuthResponse Nothing (Just $ AuthInvalid "Invalid password")
Valid to trId -> pure $ AuthResponse (Just $ AuthValid to trId) Nothing Valid to trId -> pure $ AuthResponse (Just $ AuthValid to trId) Nothing
newtype AuthenticatedUser = AuthenticatedUser
{ _authUser_id :: NodeId
} deriving (Generic)
$(deriveJSON (unPrefix "_authUser_") ''AuthenticatedUser)
instance ToSchema AuthenticatedUser where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_authUser_")
instance ToJWT AuthenticatedUser
instance FromJWT AuthenticatedUser
--type instance BasicAuthCfg = BasicAuthData -> IO (AuthResult AuthenticatedUser)
-- TODO-SECURITY why is the CookieSettings necessary?
type AuthContext = '[JWTSettings, CookieSettings] -- , BasicAuthCfg
{-
instance FromBasicAuthData AuthenticatedUser where
fromBasicAuthData authData authCheckFunction = authCheckFunction authData
authCheck :: forall env. env
-> BasicAuthData
-> IO (AuthResult AuthenticatedUser)
authCheck _env (BasicAuthData login password) = pure $
maybe Indefinite Authenticated $ TODO
-}
-- | Instances -- | Instances
$(deriveJSON (unPrefix "_authReq_") ''AuthRequest) $(deriveJSON (unPrefix "_authReq_") ''AuthRequest)
instance ToSchema AuthRequest instance ToSchema AuthRequest where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_authReq_")
instance Arbitrary AuthRequest where instance Arbitrary AuthRequest where
arbitrary = elements [ AuthRequest u p arbitrary = elements [ AuthRequest u p
...@@ -101,23 +156,60 @@ instance Arbitrary AuthRequest where ...@@ -101,23 +156,60 @@ instance Arbitrary AuthRequest where
] ]
$(deriveJSON (unPrefix "_authRes_") ''AuthResponse) $(deriveJSON (unPrefix "_authRes_") ''AuthResponse)
instance ToSchema AuthResponse instance ToSchema AuthResponse where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_authRes_")
instance Arbitrary AuthResponse where instance Arbitrary AuthResponse where
arbitrary = oneof [ AuthResponse Nothing . Just <$> arbitrary arbitrary = oneof [ AuthResponse Nothing . Just <$> arbitrary
, flip AuthResponse Nothing . Just <$> arbitrary ] , flip AuthResponse Nothing . Just <$> arbitrary ]
$(deriveJSON (unPrefix "_authInv_") ''AuthInvalid) $(deriveJSON (unPrefix "_authInv_") ''AuthInvalid)
instance ToSchema AuthInvalid instance ToSchema AuthInvalid where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_authInv_")
instance Arbitrary AuthInvalid where instance Arbitrary AuthInvalid where
arbitrary = elements [ AuthInvalid m arbitrary = elements [ AuthInvalid m
| m <- [ "Invalid user", "Invalid password"] | m <- [ "Invalid user", "Invalid password"]
] ]
$(deriveJSON (unPrefix "_authVal_") ''AuthValid) $(deriveJSON (unPrefix "_authVal_") ''AuthValid)
instance ToSchema AuthValid instance ToSchema AuthValid where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_authVal_")
instance Arbitrary AuthValid where instance Arbitrary AuthValid where
arbitrary = elements [ AuthValid to tr arbitrary = elements [ AuthValid to tr
| to <- ["token0", "token1"] | to <- ["token0", "token1"]
, tr <- [1..3] , tr <- [1..3]
] ]
data PathId = PathNode NodeId | PathNodeNode ListId DocId
withAccessM :: (CmdM env err m, HasServerError err)
=> UserId
-> PathId
-> m a
-> m a
withAccessM uId (PathNode id) m = do
d <- id `isDescendantOf` NodeId uId
if d then m else m -- serverError err401
withAccessM uId (PathNodeNode cId docId) m = do
_a <- isIn cId docId -- TODO use one query for all ?
_d <- cId `isDescendantOf` NodeId uId
if True -- a && d
then m
else m
withAccess :: forall env err m api.
(GargServerC env err m, HasServer api '[]) =>
Proxy api -> Proxy m ->
UserId -> PathId ->
ServerT api m -> ServerT api m
withAccess p _ uId id = hoistServer p f
where
f :: forall a. m a -> m a
f = withAccessM uId id
{- | Collaborative Schema
User at his root can create Teams Folder
User can create Team in Teams Folder.
User can invite User in Team as NodeNode only if Team in his parents.
All users can access to the Team folder as if they were owner.
-}
...@@ -18,30 +18,44 @@ New corpus means either: ...@@ -18,30 +18,44 @@ New corpus means either:
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeOperators #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RankNTypes #-}
module Gargantext.API.Corpus.New module Gargantext.API.Corpus.New
where where
import Data.Either --import Gargantext.Text.Corpus.Parsers (parseFile, FileFormat(..))
import Control.Lens hiding (elements)
import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Class (liftIO)
import Data.Aeson
import Data.Aeson.TH (deriveJSON) import Data.Aeson.TH (deriveJSON)
import Data.Maybe (fromMaybe)
import Data.Either
import Data.Swagger import Data.Swagger
import Data.Text (Text) import Data.Text (Text)
import GHC.Generics (Generic) import GHC.Generics (Generic)
import Gargantext.Core.Utils.Prefix (unPrefix) import Gargantext.API.Corpus.New.File
import Gargantext.API.Orchestrator.Types
import Gargantext.Core (Lang(..))
import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
import Gargantext.Database.Flow (FlowCmdM, flowCorpus)
import Gargantext.Database.Flow (flowCorpusSearchInDatabase) import Gargantext.Database.Flow (flowCorpusSearchInDatabase)
import Gargantext.Database.Types.Node (CorpusId) import Gargantext.Database.Types.Node (CorpusId)
import Gargantext.Text.Terms (TermType(..)) import Gargantext.Database.Types.Node (ToHyperdataDocument(..))
import Gargantext.Database.Types.Node (UserId)
import Gargantext.Prelude import Gargantext.Prelude
import qualified Gargantext.Text.Corpus.Parsers as Parser (FileFormat(..), parseFormat)
import Gargantext.Text.Terms (TermType(..))
import Servant import Servant
import Servant.API.Flatten (Flat)
import Servant.Job.Core
import Servant.Job.Types
import Servant.Job.Utils (jsonOptions)
import Servant.Multipart
import Test.QuickCheck (elements) import Test.QuickCheck (elements)
import Test.QuickCheck.Arbitrary import Test.QuickCheck.Arbitrary
import Gargantext.Core (Lang(..)) import Web.FormUrlEncoded (FromForm)
import Gargantext.Database.Flow (FlowCmdM, flowCorpus)
import qualified Gargantext.Text.Corpus.API as API import qualified Gargantext.Text.Corpus.API as API
import Gargantext.Database.Types.Node (UserId)
data Query = Query { query_query :: Text data Query = Query { query_query :: Text
, query_corpus_id :: Int , query_corpus_id :: Int
...@@ -60,9 +74,7 @@ instance Arbitrary Query where ...@@ -60,9 +74,7 @@ instance Arbitrary Query where
] ]
instance ToSchema Query where instance ToSchema Query where
declareNamedSchema = declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "query_")
genericDeclareNamedSchema
defaultSchemaOptions {fieldLabelModifier = \fieldLabel -> drop 6 fieldLabel}
type Api = Summary "New Corpus endpoint" type Api = Summary "New Corpus endpoint"
:> ReqBody '[JSON] Query :> ReqBody '[JSON] Query
...@@ -70,8 +82,10 @@ type Api = Summary "New Corpus endpoint" ...@@ -70,8 +82,10 @@ type Api = Summary "New Corpus endpoint"
:<|> Get '[JSON] ApiInfo :<|> Get '[JSON] ApiInfo
-- | TODO manage several apis -- | TODO manage several apis
api :: (FlowCmdM env err m) => Query -> m CorpusId -- TODO-ACCESS
api (Query q _ as) = do -- TODO this is only the POST
api :: (FlowCmdM env err m) => UserId -> Query -> m CorpusId
api _uId (Query q _ as) = do
cId <- case head as of cId <- case head as of
Nothing -> flowCorpusSearchInDatabase "user1" EN q Nothing -> flowCorpusSearchInDatabase "user1" EN q
Just API.All -> flowCorpusSearchInDatabase "user1" EN q Just API.All -> flowCorpusSearchInDatabase "user1" EN q
...@@ -95,4 +109,151 @@ instance ToSchema ApiInfo ...@@ -95,4 +109,151 @@ instance ToSchema ApiInfo
info :: FlowCmdM env err m => UserId -> m ApiInfo info :: FlowCmdM env err m => UserId -> m ApiInfo
info _u = pure $ ApiInfo API.externalAPIs info _u = pure $ ApiInfo API.externalAPIs
------------------------------------------------------------------------
------------------------------------------------------------------------
data WithQuery = WithQuery
{ _wq_query :: !Text
, _wq_databases :: ![ExternalAPIs]
, _wq_lang :: !(Maybe Lang)
}
deriving Generic
makeLenses ''WithQuery
instance FromJSON WithQuery where
parseJSON = genericParseJSON $ jsonOptions "_wq_"
instance ToSchema WithQuery where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_wq_")
-------------------------------------------------------
data WithForm = WithForm
{ _wf_filetype :: !FileType
, _wf_data :: !Text
, _wf_lang :: !(Maybe Lang)
} deriving (Eq, Show, Generic)
makeLenses ''WithForm
instance FromForm WithForm
instance FromJSON WithForm where
parseJSON = genericParseJSON $ jsonOptions "_wf_"
instance ToSchema WithForm where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_wf_")
------------------------------------------------------------------------
type AsyncJobs event ctI input output =
Flat (AsyncJobsAPI' 'Unsafe 'Safe ctI '[JSON] Maybe event input output)
------------------------------------------------------------------------
type Upload = Summary "Corpus Upload endpoint"
:> "corpus"
:> Capture "corpus_id" CorpusId
:<|> "addWithquery" :> AsyncJobsAPI ScraperStatus WithQuery ScraperStatus
:<|> "addWithfile" :> AsyncJobs ScraperStatus '[FormUrlEncoded] WithForm ScraperStatus
type AddWithQuery = Summary "Add with Query to corpus endpoint"
:> "corpus"
:> Capture "corpus_id" CorpusId
:> "add"
:> "query"
:> "async"
:> AsyncJobsAPI ScraperStatus WithQuery ScraperStatus
type AddWithFile = Summary "Add with MultipartData to corpus endpoint"
:> "corpus"
:> Capture "corpus_id" CorpusId
:> "add"
:> "file"
:> MultipartForm Mem (MultipartData Mem)
:> QueryParam "fileType" FileType
:> "async"
:> AsyncJobs ScraperStatus '[JSON] () ScraperStatus
type AddWithForm = Summary "Add with FormUrlEncoded to corpus endpoint"
:> "corpus"
:> Capture "corpus_id" CorpusId
:> "add"
:> "form"
:> "async"
:> AsyncJobs ScraperStatus '[FormUrlEncoded] WithForm ScraperStatus
------------------------------------------------------------------------
-- TODO WithQuery also has a corpus id
addToCorpusJobFunction :: FlowCmdM env err m
=> CorpusId
-> WithQuery
-> (ScraperStatus -> m ())
-> m ScraperStatus
addToCorpusJobFunction _cid (WithQuery _q _dbs _l) logStatus = do
-- TODO ...
logStatus ScraperStatus { _scst_succeeded = Just 10
, _scst_failed = Just 2
, _scst_remaining = Just 138
, _scst_events = Just []
}
-- TODO ...
pure ScraperStatus { _scst_succeeded = Just 137
, _scst_failed = Just 13
, _scst_remaining = Just 0
, _scst_events = Just []
}
addToCorpusWithFile :: FlowCmdM env err m
=> CorpusId
-> MultipartData Mem
-> Maybe FileType
-> (ScraperStatus -> m ())
-> m ScraperStatus
addToCorpusWithFile cid input filetype logStatus = do
logStatus ScraperStatus { _scst_succeeded = Just 10
, _scst_failed = Just 2
, _scst_remaining = Just 138
, _scst_events = Just []
}
_h <- postUpload cid filetype input
pure ScraperStatus { _scst_succeeded = Just 137
, _scst_failed = Just 13
, _scst_remaining = Just 0
, _scst_events = Just []
}
addToCorpusWithForm :: FlowCmdM env err m
=> CorpusId
-> WithForm
-> (ScraperStatus -> m ())
-> m ScraperStatus
addToCorpusWithForm cid (WithForm ft d l) logStatus = do
printDebug "ft" ft
let
parse = case ft of
CSV_HAL -> Parser.parseFormat Parser.CsvHal
CSV -> Parser.parseFormat Parser.CsvGargV3
WOS -> Parser.parseFormat Parser.WOS
PresseRIS -> Parser.parseFormat Parser.RisPresse
docs <- liftIO
$ splitEvery 500
<$> take 1000000
<$> parse (cs d)
logStatus ScraperStatus { _scst_succeeded = Just 1
, _scst_failed = Just 0
, _scst_remaining = Just 1
, _scst_events = Just []
}
cid' <- flowCorpus "user1"
(Right [cid])
(Multi $ fromMaybe EN l)
(map (map toHyperdataDocument) docs)
printDebug "cid'" cid'
pure ScraperStatus { _scst_succeeded = Just 2
, _scst_failed = Just 0
, _scst_remaining = Just 0
, _scst_events = Just []
}
{-|
Module : Gargantext.API.Corpus.New.File
Description : Server API
Copyright : (c) CNRS, 2017-Present
License : AGPL + CECILL v3
Maintainer : team@gargantext.org
Stability : experimental
Portability : POSIX
-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
module Gargantext.API.Corpus.New.File
where
import Control.Lens ((.~), (?~))
import Control.Monad (forM)
import Control.Monad.IO.Class (liftIO)
import Data.Maybe
import Data.Aeson
import Data.Monoid (mempty)
import Data.Swagger
import Data.Text (Text())
import GHC.Generics (Generic)
import Gargantext.API.Ngrams (TODO)
import Gargantext.Database.Types.Node
import Gargantext.Database.Utils -- (Cmd, CmdM)
import Gargantext.Prelude
import Gargantext.Prelude.Utils (sha)
import Servant
import Servant.Multipart
import Servant.Swagger (HasSwagger(toSwagger))
import Servant.Swagger.Internal
import Test.QuickCheck (elements)
import Test.QuickCheck.Arbitrary (Arbitrary, arbitrary)
-------------------------------------------------------------
type Hash = Text
data FileType = CSV
| CSV_HAL
| PresseRIS
| WOS
deriving (Eq, Show, Generic)
instance ToSchema FileType
instance Arbitrary FileType
where
arbitrary = elements [CSV, PresseRIS]
instance ToParamSchema FileType
instance FromJSON FileType
instance ToParamSchema (MultipartData Mem) where
toParamSchema _ = toParamSchema (Proxy :: Proxy TODO)
instance FromHttpApiData FileType
where
parseUrlPiece "CSV" = pure CSV
parseUrlPiece "CSV_HAL" = pure CSV_HAL
parseUrlPiece "PresseRis" = pure PresseRIS
parseUrlPiece _ = pure CSV -- TODO error here
instance (ToParamSchema a, HasSwagger sub) =>
HasSwagger (MultipartForm tag a :> sub) where
-- TODO
toSwagger _ = toSwagger (Proxy :: Proxy sub)
& addParam param
where
param = mempty
& required ?~ True
& schema .~ ParamOther sch
sch = mempty
& in_ .~ ParamFormData
& paramSchema .~ toParamSchema (Proxy :: Proxy a)
type WithUpload' = Summary "Upload file(s) to a corpus"
:> QueryParam "fileType" FileType
:> MultipartForm Mem (MultipartData Mem)
:> Post '[JSON] [Hash]
--postUpload :: NodeId -> Maybe FileType -> GargServer UploadAPI
--postUpload :: NodeId -> GargServer UploadAPI
postUpload :: NodeId
-> Maybe FileType
-> MultipartData Mem
-> Cmd err [Hash]
postUpload _ Nothing _ = panic "fileType is a required parameter"
postUpload _ (Just fileType) multipartData = do
putStrLn $ "File Type: " <> (show fileType)
is <- liftIO $ do
putStrLn ("Inputs:" :: Text)
forM (inputs multipartData) $ \input -> do
putStrLn $ ("iName " :: Text) <> (iName input)
<> ("iValue " :: Text) <> (iValue input)
pure $ iName input
_ <- forM (files multipartData) $ \file -> do
let content = fdPayload file
putStrLn $ ("XXX " :: Text) <> (fdFileName file)
putStrLn $ ("YYY " :: Text) <> cs content
--pure $ cs content
-- is <- inputs multipartData
pure $ map (sha . cs) is
-------------------------------------------------------------------
...@@ -41,7 +41,7 @@ import Test.QuickCheck (elements) ...@@ -41,7 +41,7 @@ import Test.QuickCheck (elements)
-- import Control.Applicative ((<*>)) -- import Control.Applicative ((<*>))
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Core.Utils.Prefix (unPrefix) import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
----------------------------------------------------------------------- -----------------------------------------------------------------------
-- TODO-ACCESS: CanCount -- TODO-ACCESS: CanCount
...@@ -93,7 +93,9 @@ instance Arbitrary Query where ...@@ -93,7 +93,9 @@ instance Arbitrary Query where
, n <- take 10 $ permutations scrapers , n <- take 10 $ permutations scrapers
] ]
instance ToSchema Query instance ToSchema Query where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "query_")
----------------------------------------------------------------------- -----------------------------------------------------------------------
type Code = Integer type Code = Integer
type Error = Text type Error = Text
...@@ -144,7 +146,8 @@ data Count = Count { count_name :: Scraper ...@@ -144,7 +146,8 @@ data Count = Count { count_name :: Scraper
$(deriveJSON (unPrefix "count_") ''Count) $(deriveJSON (unPrefix "count_") ''Count)
instance ToSchema Count instance ToSchema Count where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "count_")
--instance Arbitrary Count where --instance Arbitrary Count where
-- arbitrary = Count <$> arbitrary <*> arbitrary <*> arbitrary -- arbitrary = Count <$> arbitrary <*> arbitrary <*> arbitrary
......
{-|
Module : Gargantext.API.Export
Description : Get Metrics from Storage (Database like)
Copyright : (c) CNRS, 2017-Present
License : AGPL + CECILL v3
Maintainer : team@gargantext.org
Stability : experimental
Portability : POSIX
Main exports of Gargantext:
- corpus
- document and ngrams
- lists
-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
module Gargantext.API.Export
where
import Data.Aeson.TH (deriveJSON)
import Data.Map (Map)
import Data.Set (Set)
import Data.Maybe (fromMaybe)
import Data.Swagger
import Data.Text (Text)
import GHC.Generics (Generic)
import Gargantext.API.Ngrams
import Gargantext.API.Ngrams.Tools (filterListWithRoot, mapTermListRoot, getRepo)
import Gargantext.API.Types (GargNoServer)
import Gargantext.Core.Types --
import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
import Gargantext.Database.Config (userMaster)
import Gargantext.Database.Metrics.NgramsByNode (getNgramsByNodeOnlyUser)
import Gargantext.Database.Node.Select (selectNodesWithUsername)
import Gargantext.Database.Schema.Ngrams (NgramsType(..))
import Gargantext.Database.Schema.Node (defaultList, HasNodeError)
import Gargantext.Database.Schema.NodeNode (selectDocNodes)
import Gargantext.Database.Types.Node (Node, HyperdataDocument(..), NodeId, ListId, CorpusId)
import Gargantext.Database.Utils (Cmd)
import Gargantext.Prelude
import Gargantext.Prelude.Utils (sha)
import Servant
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.List as List
-- Corpus Export
data Corpus =
Corpus { _c_corpus :: [Document]
, _c_hash :: Hash
} deriving (Generic)
-- | Document Export
data Document =
Document { _d_document :: Node HyperdataDocument
, _d_ngrams :: Ngrams
, _d_hash :: Hash
} deriving (Generic)
data Ngrams =
Ngrams { _ng_ngrams :: [Text]
, _ng_hash :: Hash
} deriving (Generic)
type Hash = Text
-------
instance ToSchema Corpus where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_c_")
instance ToSchema Document where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_d_")
instance ToSchema Ngrams where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_ng_")
-------
instance ToParamSchema Corpus where
toParamSchema _ = toParamSchema (Proxy :: Proxy TODO)
instance ToParamSchema Document where
toParamSchema _ = toParamSchema (Proxy :: Proxy TODO)
instance ToParamSchema Ngrams where
toParamSchema _ = toParamSchema (Proxy :: Proxy TODO)
--------------------------------------------------
type API = Summary "Corpus Export"
:> "export"
:> QueryParam "listId" ListId
:> QueryParam "ngramsType" NgramsType
:> Get '[JSON] Corpus
--------------------------------------------------
getCorpus :: CorpusId
-> Maybe ListId
-> Maybe NgramsType
-> GargNoServer Corpus
getCorpus cId lId nt' = do
let
nt = case nt' of
Nothing -> NgramsTerms
Just t -> t
ns <- Map.fromList
<$> map (\n -> (_node_id n, n))
<$> selectDocNodes cId
repo <- getRepo
ngs <- getNodeNgrams cId lId nt repo
let -- uniqId is hash computed already for each document imported in database
r = Map.intersectionWith (\a b -> Document a (Ngrams (Set.toList b) (ng_hash b)) (d_hash a b)
) ns ngs
where
ng_hash b = sha $ List.foldl (\x y -> x<>y) "" $ List.sort $ Set.toList b
d_hash a b = sha $ (fromMaybe "" (_hyperdataDocument_uniqId $ _node_hyperdata a))
<> (ng_hash b)
pure $ Corpus (Map.elems r) (sha $ List.foldl (\a b -> a<>b) ""
$ List.map _d_hash $ Map.elems r
)
getNodeNgrams :: HasNodeError err
=> CorpusId
-> Maybe ListId
-> NgramsType
-> NgramsRepo
-> Cmd err (Map NodeId (Set Text))
getNodeNgrams cId lId' nt repo = do
lId <- case lId' of
Nothing -> defaultList cId
Just l -> pure l
lIds <- selectNodesWithUsername NodeList userMaster
let ngs = filterListWithRoot GraphTerm $ mapTermListRoot [lId] nt repo
r <- getNgramsByNodeOnlyUser cId (lIds <> [lId]) nt (Map.keys ngs)
pure r
$(deriveJSON (unPrefix "_c_") ''Corpus)
$(deriveJSON (unPrefix "_d_") ''Document)
$(deriveJSON (unPrefix "_ng_") ''Ngrams)
-- TODO
-- Exports List
-- Version number of the list
...@@ -12,15 +12,16 @@ Loads all static file for the front-end. ...@@ -12,15 +12,16 @@ Loads all static file for the front-end.
-} -}
{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DataKinds #-}
{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeOperators #-}
--------------------------------------------------------------------- ---------------------------------------------------------------------
module Gargantext.API.FrontEnd where module Gargantext.API.FrontEnd where
import Servant.Static.TH (createApiAndServerDecs) import Servant
import Servant.Server.StaticFiles (serveDirectoryFileServer)
--------------------------------------------------------------------- type FrontEndAPI = Raw
$(createApiAndServerDecs "FrontEndAPI" "frontEndServer" "purescript-gargantext/dist")
---------------------------------------------------------------------
frontEndServer :: Server FrontEndAPI
frontEndServer = serveDirectoryFileServer "./purescript-gargantext/dist"
...@@ -31,7 +31,7 @@ import Data.Time (UTCTime) ...@@ -31,7 +31,7 @@ import Data.Time (UTCTime)
import Data.Text (Text) import Data.Text (Text)
import GHC.Generics (Generic) import GHC.Generics (Generic)
import Gargantext.Core.Types (ListType(..)) import Gargantext.Core.Types (ListType(..))
import Gargantext.Core.Utils.Prefix (unPrefix) import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
import Gargantext.Database.Utils import Gargantext.Database.Utils
import Gargantext.Core.Types (CorpusId, ListId, Limit) import Gargantext.Core.Types (CorpusId, ListId, Limit)
import Gargantext.Prelude import Gargantext.Prelude
...@@ -50,7 +50,8 @@ data Metrics = Metrics ...@@ -50,7 +50,8 @@ data Metrics = Metrics
{ metrics_data :: [Metric]} { metrics_data :: [Metric]}
deriving (Generic, Show) deriving (Generic, Show)
instance ToSchema Metrics instance ToSchema Metrics where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "metrics_")
instance Arbitrary Metrics instance Arbitrary Metrics
where where
arbitrary = Metrics <$> arbitrary arbitrary = Metrics <$> arbitrary
...@@ -62,7 +63,8 @@ data Metric = Metric ...@@ -62,7 +63,8 @@ data Metric = Metric
, m_cat :: !ListType , m_cat :: !ListType
} deriving (Generic, Show) } deriving (Generic, Show)
instance ToSchema Metric instance ToSchema Metric where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "m_")
instance Arbitrary Metric instance Arbitrary Metric
where where
arbitrary = Metric <$> arbitrary arbitrary = Metric <$> arbitrary
...@@ -78,7 +80,8 @@ deriveJSON (unPrefix "m_") ''Metric ...@@ -78,7 +80,8 @@ deriveJSON (unPrefix "m_") ''Metric
data ChartMetrics a = ChartMetrics { chartMetrics_data :: a } data ChartMetrics a = ChartMetrics { chartMetrics_data :: a }
deriving (Generic, Show) deriving (Generic, Show)
instance (ToSchema a) => ToSchema (ChartMetrics a) instance (ToSchema a) => ToSchema (ChartMetrics a) where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "chartMetrics_")
instance (Arbitrary a) => Arbitrary (ChartMetrics a) instance (Arbitrary a) => Arbitrary (ChartMetrics a)
where where
arbitrary = ChartMetrics <$> arbitrary arbitrary = ChartMetrics <$> arbitrary
...@@ -86,7 +89,8 @@ instance (Arbitrary a) => Arbitrary (ChartMetrics a) ...@@ -86,7 +89,8 @@ instance (Arbitrary a) => Arbitrary (ChartMetrics a)
deriveJSON (unPrefix "chartMetrics_") ''ChartMetrics deriveJSON (unPrefix "chartMetrics_") ''ChartMetrics
------------------------------------------------------------- -------------------------------------------------------------
instance ToSchema Histo instance ToSchema Histo where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "histo_")
instance Arbitrary Histo instance Arbitrary Histo
where where
arbitrary = elements [ Histo ["2012"] [1] arbitrary = elements [ Histo ["2012"] [1]
...@@ -95,11 +99,6 @@ instance Arbitrary Histo ...@@ -95,11 +99,6 @@ instance Arbitrary Histo
deriveJSON (unPrefix "histo_") ''Histo deriveJSON (unPrefix "histo_") ''Histo
instance ToSchema MyTree
instance Arbitrary MyTree
where
arbitrary = MyTree <$> arbitrary <*> arbitrary <*> arbitrary
------------------------------------------------------------- -------------------------------------------------------------
-- | Scatter metrics API -- | Scatter metrics API
......
This diff is collapsed.
...@@ -23,16 +23,18 @@ import Data.Text (Text) ...@@ -23,16 +23,18 @@ import Data.Text (Text)
import Gargantext.Prelude import Gargantext.Prelude
import GHC.Generics (Generic) import GHC.Generics (Generic)
import Data.Aeson.TH (deriveJSON) import Data.Aeson.TH (deriveJSON)
import Gargantext.Core.Utils.Prefix (unPrefix) import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
import Gargantext.Core.Types (ListType(..), NodeId) import Gargantext.Core.Types (ListType(..), NodeId)
import Gargantext.API.Ngrams import Gargantext.API.Ngrams
import Data.Tree import Data.Tree
import Data.Maybe (catMaybes) import Data.Maybe (catMaybes)
import Data.Map (Map) import Data.Map (Map)
import Data.Set (Set) import Data.Set (Set)
import Data.Swagger
import qualified Data.Set as Set import qualified Data.Set as Set
import qualified Data.Map as Map import qualified Data.Map as Map
import qualified Data.List as List import qualified Data.List as List
import Test.QuickCheck
type Children = Text type Children = Text
type Root = Text type Root = Text
...@@ -47,12 +49,17 @@ toMyTree (Node (l,v) xs) = MyTree l v (map toMyTree xs) ...@@ -47,12 +49,17 @@ toMyTree (Node (l,v) xs) = MyTree l v (map toMyTree xs)
deriveJSON (unPrefix "mt_") ''MyTree deriveJSON (unPrefix "mt_") ''MyTree
instance ToSchema MyTree where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "mt_")
instance Arbitrary MyTree
where
arbitrary = MyTree <$> arbitrary <*> arbitrary <*> arbitrary
toTree :: ListType -> Map Text (Set NodeId) -> Map Text NgramsRepoElement -> [MyTree] toTree :: ListType -> Map Text (Set NodeId) -> Map Text NgramsRepoElement -> [MyTree]
toTree lt vs m = map toMyTree $ unfoldForest buildNode roots toTree lt vs m = map toMyTree $ unfoldForest buildNode roots
where where
buildNode r = maybe ((r, value r),[]) (\x -> ((r, value r), mSetToList $ _nre_children x)) (Map.lookup r m) buildNode r = maybe ((r, value r),[]) (\x -> ((r, value r), mSetToList $ _nre_children x)) (Map.lookup r m)
value l = maybe 0 (fromIntegral . Set.size) $ Map.lookup l vs value l = maybe 0 (fromIntegral . Set.size) $ Map.lookup l vs
rootsCandidates = catMaybes rootsCandidates = catMaybes
...@@ -60,7 +67,7 @@ toTree lt vs m = map toMyTree $ unfoldForest buildNode roots ...@@ -60,7 +67,7 @@ toTree lt vs m = map toMyTree $ unfoldForest buildNode roots
$ map (\(c,c') -> case _nre_root c' of $ map (\(c,c') -> case _nre_root c' of
Nothing -> Just c Nothing -> Just c
_ -> _nre_root c' ) (Map.toList m) _ -> _nre_root c' ) (Map.toList m)
roots = map fst roots = map fst
$ filter (\(_,l) -> l == lt) $ filter (\(_,l) -> l == lt)
$ catMaybes $ catMaybes
......
...@@ -33,20 +33,28 @@ import qualified Data.Set as Set ...@@ -33,20 +33,28 @@ import qualified Data.Set as Set
type RootTerm = Text type RootTerm = Text
getListNgrams :: RepoCmdM env err m getRepo :: RepoCmdM env err m => m NgramsRepo
=> [ListId] -> NgramsType getRepo = do
-> m (Map Text NgramsRepoElement) v <- view repoVar
getListNgrams nodeIds ngramsType = do liftIO $ readMVar v
v <- view repoVar
repo <- liftIO $ readMVar v listNgramsFromRepo :: [ListId] -> NgramsType
-> NgramsRepo -> Map Text NgramsRepoElement
let listNgramsFromRepo nodeIds ngramsType repo = ngrams
where
ngramsMap = repo ^. r_state . at ngramsType . _Just ngramsMap = repo ^. r_state . at ngramsType . _Just
ngrams = Map.unionsWith mergeNgramsElement ngrams = Map.unionsWith mergeNgramsElement
[ ngramsMap ^. at nodeId . _Just | nodeId <- nodeIds ] [ ngramsMap ^. at nodeId . _Just | nodeId <- nodeIds ]
pure ngrams -- TODO-ACCESS: We want to do the security check before entering here.
-- Add a static capability parameter would be nice.
-- Ideally this is the access to `repoVar` which needs to
-- be properly guarded.
getListNgrams :: RepoCmdM env err m
=> [ListId] -> NgramsType
-> m (Map Text NgramsRepoElement)
getListNgrams nodeIds ngramsType = listNgramsFromRepo nodeIds ngramsType <$> getRepo
getTermsWith :: (RepoCmdM env err m, Ord a) getTermsWith :: (RepoCmdM env err m, Ord a)
=> (Text -> a ) -> [ListId] => (Text -> a ) -> [ListId]
...@@ -57,19 +65,19 @@ getTermsWith f ls ngt lt = Map.fromListWith (<>) ...@@ -57,19 +65,19 @@ getTermsWith f ls ngt lt = Map.fromListWith (<>)
<$> Map.toList <$> Map.toList
<$> Map.filter (\f' -> (fst f') == lt) <$> Map.filter (\f' -> (fst f') == lt)
<$> mapTermListRoot ls ngt <$> mapTermListRoot ls ngt
<$> getRepo
where where
toTreeWith f'' (t, (_lt, maybeRoot)) = case maybeRoot of toTreeWith f'' (t, (_lt, maybeRoot)) = case maybeRoot of
Nothing -> (f'' t, []) Nothing -> (f'' t, [])
Just r -> (f'' r, map f'' [t]) Just r -> (f'' r, map f'' [t])
mapTermListRoot :: RepoCmdM env err m mapTermListRoot :: [ListId] -> NgramsType
=> [ListId] -> NgramsType -> NgramsRepo -> Map Text (ListType, (Maybe Text))
-> m (Map Text (ListType, (Maybe Text))) mapTermListRoot nodeIds ngramsType repo =
mapTermListRoot nodeIds ngramsType = do Map.fromList [ (t, (_nre_list nre, _nre_root nre))
ngrams <- getListNgrams nodeIds ngramsType | (t, nre) <- Map.toList ngrams
pure $ Map.fromList [ (t, (_nre_list nre, _nre_root nre)) ]
| (t, nre) <- Map.toList ngrams where ngrams = listNgramsFromRepo nodeIds ngramsType repo
]
filterListWithRoot :: ListType -> Map Text (ListType, Maybe Text) filterListWithRoot :: ListType -> Map Text (ListType, Maybe Text)
-> Map Text (Maybe RootTerm) -> Map Text (Maybe RootTerm)
......
This diff is collapsed.
...@@ -66,10 +66,14 @@ pipeline scrapyurl client_env input log_status = do ...@@ -66,10 +66,14 @@ pipeline scrapyurl client_env input log_status = do
e <- runJobMLog client_env log_status $ callScraper scrapyurl input e <- runJobMLog client_env log_status $ callScraper scrapyurl input
either (panic . cs . show) pure e -- TODO throwError either (panic . cs . show) pure e -- TODO throwError
-- TODO integrate to ServerT
-- use:
-- * serveJobsAPI instead of simpleServeJobsAPI
-- * JobFunction instead of simpleJobFunction
scrapyOrchestrator :: Env -> IO (Server (WithCallbacks ScraperAPI)) scrapyOrchestrator :: Env -> IO (Server (WithCallbacks ScraperAPI))
scrapyOrchestrator env = do scrapyOrchestrator env = do
apiWithCallbacksServer (Proxy :: Proxy ScraperAPI) apiWithCallbacksServer (Proxy :: Proxy ScraperAPI)
defaultSettings (extendBaseUrl ("scraper" :: String) $ env ^. env_self_url) defaultSettings (extendBaseUrl ("scraper" :: String) $ env ^. env_self_url)
(env ^. env_manager) (LogEvent logConsole) $ (env ^. env_manager) (LogEvent logConsole) $
serveJobsAPI (env ^. env_scrapers) . simpleServeJobsAPI (env ^. env_scrapers) .
JobFunction . pipeline (URL $ env ^. env_settings . scrapydUrl) simpleJobFunction . pipeline (URL $ env ^. env_settings . scrapydUrl)
...@@ -13,37 +13,53 @@ module Gargantext.API.Orchestrator.Types where ...@@ -13,37 +13,53 @@ module Gargantext.API.Orchestrator.Types where
import Gargantext.Prelude import Gargantext.Prelude
import Control.Lens hiding (elements) import Control.Lens hiding (elements)
import Data.Aeson import Data.Aeson
import Data.Proxy
import Data.Text (Text) import Data.Text (Text)
import Data.Swagger hiding (URL, url, port) import Data.Swagger hiding (URL, url, port)
import GHC.Generics hiding (to) import GHC.Generics hiding (to)
import Servant.Job.Async import Servant.Job.Async
import Servant.Job.Client
import Servant.Job.Types import Servant.Job.Types
import Servant.Job.Utils (jsonOptions) import Servant.Job.Utils (jsonOptions)
import Test.QuickCheck (elements) import Test.QuickCheck (elements)
import Test.QuickCheck.Arbitrary import Test.QuickCheck.Arbitrary
import Gargantext.Core.Types (TODO(..))
instance Arbitrary a => Arbitrary (JobStatus 'Safe a) where instance Arbitrary a => Arbitrary (JobStatus 'Safe a) where
arbitrary = panic "TODO" arbitrary = panic "TODO"
instance Arbitrary a => Arbitrary (JobOutput a) where instance Arbitrary a => Arbitrary (JobOutput a) where
arbitrary = JobOutput <$> arbitrary arbitrary = JobOutput <$> arbitrary
instance ToSchema URL where -- | Main Types
declareNamedSchema = panic "TODO" data ExternalAPIs = All
| PubMed
| HAL_EN
| HAL_FR
| IsTex_EN
| IsTex_FR
instance ToSchema AnyOutput where | Isidore_EN
declareNamedSchema = panic "TODO" | Isidore_FR
-- | IsidoreAuth
deriving (Show, Eq, Enum, Bounded, Generic)
instance ToSchema AnyInput where
declareNamedSchema = panic "TODO"
instance ToSchema AnyEvent where -- | Main Instances
declareNamedSchema = panic "TODO" instance FromJSON ExternalAPIs
instance ToJSON ExternalAPIs
instance ToSchema a => ToSchema (JobInput a) externalAPIs :: [ExternalAPIs]
externalAPIs = [minBound..maxBound]
instance ToSchema a => ToSchema (JobOutput a) instance Arbitrary ExternalAPIs
where
arbitrary = elements externalAPIs
instance ToSchema ExternalAPIs
instance ToSchema URL where
declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy TODO)
data ScraperInput = ScraperInput data ScraperInput = ScraperInput
{ _scin_spider :: !Text { _scin_spider :: !Text
...@@ -62,6 +78,8 @@ makeLenses ''ScraperInput ...@@ -62,6 +78,8 @@ makeLenses ''ScraperInput
instance FromJSON ScraperInput where instance FromJSON ScraperInput where
parseJSON = genericParseJSON $ jsonOptions "_scin_" parseJSON = genericParseJSON $ jsonOptions "_scin_"
-- Proposal to replace the Corpus.API.Query type which seems to generically named.
data ScraperEvent = ScraperEvent data ScraperEvent = ScraperEvent
{ _scev_message :: !(Maybe Text) { _scev_message :: !(Maybe Text)
, _scev_level :: !(Maybe Text) , _scev_level :: !(Maybe Text)
...@@ -89,7 +107,11 @@ data ScraperStatus = ScraperStatus ...@@ -89,7 +107,11 @@ data ScraperStatus = ScraperStatus
deriving Generic deriving Generic
instance Arbitrary ScraperStatus where instance Arbitrary ScraperStatus where
arbitrary = ScraperStatus <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary arbitrary = ScraperStatus
<$> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
instance ToJSON ScraperStatus where instance ToJSON ScraperStatus where
toJSON = genericToJSON $ jsonOptions "_scst_" toJSON = genericToJSON $ jsonOptions "_scst_"
...@@ -102,12 +124,12 @@ instance ToSchema ScraperStatus -- TODO _scst_ prefix ...@@ -102,12 +124,12 @@ instance ToSchema ScraperStatus -- TODO _scst_ prefix
instance ToSchema ScraperInput -- TODO _scin_ prefix instance ToSchema ScraperInput -- TODO _scin_ prefix
instance ToSchema ScraperEvent -- TODO _scev_ prefix instance ToSchema ScraperEvent -- TODO _scev_ prefix
instance ToParamSchema Offset where instance ToParamSchema Offset -- where
toParamSchema = panic "TODO" -- toParamSchema = panic "TODO"
instance ToParamSchema Limit where instance ToParamSchema Limit -- where
toParamSchema = panic "TODO" -- toParamSchema = panic "TODO"
type ScrapersEnv = JobEnv ScraperStatus ScraperStatus type ScrapersEnv = JobEnv ScraperStatus ScraperStatus
type ScraperAPI = AsyncJobsAPI ScraperStatus ScraperInput ScraperStatus type ScraperAPI = AsyncJobsAPI ScraperStatus ScraperInput ScraperStatus
...@@ -12,6 +12,7 @@ Count API part of Gargantext. ...@@ -12,6 +12,7 @@ Count API part of Gargantext.
{-# OPTIONS_GHC -fno-warn-name-shadowing #-} {-# OPTIONS_GHC -fno-warn-name-shadowing #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DataKinds #-}
{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TemplateHaskell #-}
...@@ -35,7 +36,7 @@ import Test.QuickCheck (elements) ...@@ -35,7 +36,7 @@ import Test.QuickCheck (elements)
-- import Control.Applicative ((<*>)) -- import Control.Applicative ((<*>))
import Gargantext.API.Types (GargServer) import Gargantext.API.Types (GargServer)
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Core.Utils.Prefix (unPrefix) import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
import Gargantext.Database.Types.Node import Gargantext.Database.Types.Node
import Gargantext.Database.TextSearch import Gargantext.Database.TextSearch
import Gargantext.Database.Facet import Gargantext.Database.Facet
...@@ -48,9 +49,7 @@ data SearchQuery = SearchQuery ...@@ -48,9 +49,7 @@ data SearchQuery = SearchQuery
$(deriveJSON (unPrefix "sq_") ''SearchQuery) $(deriveJSON (unPrefix "sq_") ''SearchQuery)
instance ToSchema SearchQuery where instance ToSchema SearchQuery where
declareNamedSchema = declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "sq_")
genericDeclareNamedSchema
defaultSchemaOptions {fieldLabelModifier = drop 3}
instance Arbitrary SearchQuery where instance Arbitrary SearchQuery where
arbitrary = elements [SearchQuery ["electrodes"]] arbitrary = elements [SearchQuery ["electrodes"]]
...@@ -64,11 +63,10 @@ instance Arbitrary SearchDocResults where ...@@ -64,11 +63,10 @@ instance Arbitrary SearchDocResults where
arbitrary = SearchDocResults <$> arbitrary arbitrary = SearchDocResults <$> arbitrary
instance ToSchema SearchDocResults where instance ToSchema SearchDocResults where
declareNamedSchema = declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "sdr_")
genericDeclareNamedSchema
defaultSchemaOptions {fieldLabelModifier = drop 4}
data SearchPairedResults = SearchPairedResults { spr_results :: [FacetPaired Int UTCTime HyperdataDocument Int [Pair Int Text]] } data SearchPairedResults =
SearchPairedResults { spr_results :: [FacetPaired Int UTCTime HyperdataDocument Int [Pair Int Text]] }
deriving (Generic) deriving (Generic)
$(deriveJSON (unPrefix "spr_") ''SearchPairedResults) $(deriveJSON (unPrefix "spr_") ''SearchPairedResults)
...@@ -76,32 +74,33 @@ instance Arbitrary SearchPairedResults where ...@@ -76,32 +74,33 @@ instance Arbitrary SearchPairedResults where
arbitrary = SearchPairedResults <$> arbitrary arbitrary = SearchPairedResults <$> arbitrary
instance ToSchema SearchPairedResults where instance ToSchema SearchPairedResults where
declareNamedSchema = declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "spr_")
genericDeclareNamedSchema
defaultSchemaOptions {fieldLabelModifier = \fieldLabel -> drop 4 fieldLabel}
----------------------------------------------------------------------- -----------------------------------------------------------------------
-- TODO-ACCESS: CanSearch? or is it part of CanGetNode -- TODO-ACCESS: CanSearch? or is it part of CanGetNode
-- TODO-EVENTS: No event, this is a read-only query. -- TODO-EVENTS: No event, this is a read-only query.
type SearchAPI results type SearchAPI results = Summary "Search endpoint"
= Summary "Search endpoint" :> ReqBody '[JSON] SearchQuery
:> ReqBody '[JSON] SearchQuery :> QueryParam "offset" Int
:> QueryParam "offset" Int :> QueryParam "limit" Int
:> QueryParam "limit" Int :> QueryParam "order" OrderBy
:> QueryParam "order" OrderBy :> Post '[JSON] results
:> Post '[JSON] results
type SearchDocsAPI = SearchAPI SearchDocResults type SearchDocsAPI = SearchAPI SearchDocResults
type SearchPairsAPI = SearchAPI SearchPairedResults
-----------------------------------------------------------------------
searchPairs :: NodeId -> GargServer SearchPairsAPI
searchPairs pId (SearchQuery q) o l order =
SearchPairedResults <$> searchInCorpusWithContacts pId q o l order
searchDocs :: NodeId -> GargServer SearchDocsAPI searchDocs :: NodeId -> GargServer SearchDocsAPI
searchDocs nId (SearchQuery q) o l order = searchDocs nId (SearchQuery q) o l order =
SearchDocResults <$> searchInCorpus nId False q o l order SearchDocResults <$> searchInCorpus nId False q o l order
--SearchResults <$> searchInCorpusWithContacts nId q o l order --SearchResults <$> searchInCorpusWithContacts nId q o l order
-----------------------------------------------------------------------
type SearchPairsAPI = Summary ""
:> "list"
:> Capture "list" ListId
:> SearchAPI SearchPairedResults
searchPairs :: NodeId -> GargServer SearchPairsAPI
searchPairs pId lId (SearchQuery q) o l order =
SearchPairedResults <$> searchInCorpusWithContacts pId lId q o l order
-----------------------------------------------------------------------
...@@ -6,6 +6,8 @@ License : AGPL + CECILL v3 ...@@ -6,6 +6,8 @@ License : AGPL + CECILL v3
Maintainer : team@gargantext.org Maintainer : team@gargantext.org
Stability : experimental Stability : experimental
Portability : POSIX Portability : POSIX
TODO-SECURITY: Critical
-} -}
{-# OPTIONS_GHC -fno-warn-name-shadowing #-} {-# OPTIONS_GHC -fno-warn-name-shadowing #-}
...@@ -14,6 +16,7 @@ Portability : POSIX ...@@ -14,6 +16,7 @@ Portability : POSIX
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RankNTypes #-}
...@@ -40,16 +43,16 @@ import Data.Aeson ...@@ -40,16 +43,16 @@ import Data.Aeson
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
import Data.Either (either) import Data.Either (either)
import Data.Text import Data.Text
import Data.Text.Encoding (encodeUtf8) --import Data.Text.Encoding (encodeUtf8)
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy as L
import Servant import Servant
import Servant.Auth.Server (defaultJWTSettings, JWTSettings, CookieSettings, defaultCookieSettings, readKey, writeKey)
import Servant.Client (BaseUrl, parseBaseUrl) import Servant.Client (BaseUrl, parseBaseUrl)
--import Servant.Job.Async (newJobEnv, defaultSettings) import qualified Servant.Job.Core
import Servant.Job.Async (newJobEnv, defaultSettings, HasJobEnv(..), Job)
import Web.HttpApiData (parseUrlPiece) import Web.HttpApiData (parseUrlPiece)
import qualified Jose.Jwk as Jose
import qualified Jose.Jwa as Jose
import Control.Concurrent import Control.Concurrent
import Control.Debounce (mkDebounce, defaultDebounceSettings, debounceFreq, debounceAction) import Control.Debounce (mkDebounce, defaultDebounceSettings, debounceFreq, debounceAction)
...@@ -60,7 +63,7 @@ import Control.Lens ...@@ -60,7 +63,7 @@ import Control.Lens
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Database.Utils (databaseParameters, HasConnection(..), Cmd', runCmd) import Gargantext.Database.Utils (databaseParameters, HasConnection(..), Cmd', runCmd)
import Gargantext.API.Ngrams (NgramsRepo, HasRepoVar(..), HasRepoSaver(..), HasRepo(..), RepoEnv(..), r_version, saveRepo, initRepo, renv_var, renv_lock) import Gargantext.API.Ngrams (NgramsRepo, HasRepoVar(..), HasRepoSaver(..), HasRepo(..), RepoEnv(..), r_version, saveRepo, initRepo, renv_var, renv_lock)
--import Gargantext.API.Orchestrator.Types import Gargantext.API.Orchestrator.Types
type PortNumber = Int type PortNumber = Int
...@@ -77,7 +80,8 @@ data Settings = Settings ...@@ -77,7 +80,8 @@ data Settings = Settings
, _logLevelLimit :: LogLevel -- log level from the monad-logger package , _logLevelLimit :: LogLevel -- log level from the monad-logger package
-- , _dbServer :: Text -- , _dbServer :: Text
-- ^ this is not used yet -- ^ this is not used yet
, _jwtSecret :: Jose.Jwk -- key from the jose-jwt package , _jwtSettings :: JWTSettings
, _cookieSettings :: CookieSettings
, _sendLoginEmails :: SendEmailType , _sendLoginEmails :: SendEmailType
, _scrapydUrl :: BaseUrl , _scrapydUrl :: BaseUrl
, _fileFolder :: FilePath , _fileFolder :: FilePath
...@@ -88,30 +92,22 @@ makeLenses ''Settings ...@@ -88,30 +92,22 @@ makeLenses ''Settings
class HasSettings env where class HasSettings env where
settings :: Getter env Settings settings :: Getter env Settings
devSettings :: FilePath -> IO Settings
parseJwk :: Text -> Jose.Jwk devSettings jwkFile = do
parseJwk secretStr = jwk jwkExists <- doesFileExist jwkFile
where when (not jwkExists) $ writeKey jwkFile
secretBs = encodeUtf8 secretStr jwk <- readKey jwkFile
jwk = Jose.SymmetricJwk secretBs pure $ Settings
Nothing
Nothing
(Just $ Jose.Signed Jose.HS256)
devSettings :: Settings
devSettings = Settings
{ _allowedOrigin = "http://localhost:8008" { _allowedOrigin = "http://localhost:8008"
, _allowedHost = "localhost:3000" , _allowedHost = "localhost:3000"
, _appPort = 3000 , _appPort = 3000
, _logLevelLimit = LevelDebug , _logLevelLimit = LevelDebug
-- , _dbServer = "localhost" -- , _dbServer = "localhost"
-- generate with dd if=/dev/urandom bs=1 count=32 | base64
-- make sure jwtSecret differs between development and production, because you do not want
-- your production key inside source control.
, _jwtSecret = parseJwk "MVg0YAPVSPiYQc/qIs/rV/X32EFR0zOJWfHFgMbszMw="
, _sendLoginEmails = LogEmailToConsole , _sendLoginEmails = LogEmailToConsole
, _scrapydUrl = fromMaybe (panic "Invalid scrapy URL") $ parseBaseUrl "http://localhost:6800" , _scrapydUrl = fromMaybe (panic "Invalid scrapy URL") $ parseBaseUrl "http://localhost:6800"
, _fileFolder = "data" , _fileFolder = "data"
, _cookieSettings = defaultCookieSettings -- TODO-SECURITY tune
, _jwtSettings = defaultJWTSettings jwk -- TODO-SECURITY tune
} }
...@@ -147,7 +143,7 @@ data Env = Env ...@@ -147,7 +143,7 @@ data Env = Env
, _env_repo :: !RepoEnv , _env_repo :: !RepoEnv
, _env_manager :: !Manager , _env_manager :: !Manager
, _env_self_url :: !BaseUrl , _env_self_url :: !BaseUrl
--, _env_scrapers :: !ScrapersEnv , _env_scrapers :: !ScrapersEnv
} }
deriving (Generic) deriving (Generic)
...@@ -168,6 +164,12 @@ instance HasRepo Env where ...@@ -168,6 +164,12 @@ instance HasRepo Env where
instance HasSettings Env where instance HasSettings Env where
settings = env_settings settings = env_settings
instance Servant.Job.Core.HasEnv Env (Job ScraperStatus ScraperStatus) where
_env = env_scrapers . Servant.Job.Core._env
instance HasJobEnv Env ScraperStatus ScraperStatus where
job_env = env_scrapers
data MockEnv = MockEnv data MockEnv = MockEnv
{ _menv_firewall :: !FireWall { _menv_firewall :: !FireWall
} }
...@@ -176,14 +178,18 @@ data MockEnv = MockEnv ...@@ -176,14 +178,18 @@ data MockEnv = MockEnv
makeLenses ''MockEnv makeLenses ''MockEnv
-- | TODO add this path in Settings -- | TODO add this path in Settings
repoDir :: FilePath
repoDir = "repos"
repoSnapshot :: FilePath repoSnapshot :: FilePath
repoSnapshot = "repo.json" repoSnapshot = repoDir <> "/repo.json"
-- | TODO add hard coded file in Settings -- | TODO add hard coded file in Settings
-- This assumes we own the lock on repoSnapshot. -- This assumes we own the lock on repoSnapshot.
repoSaverAction :: ToJSON a => a -> IO () repoSaverAction :: ToJSON a => a -> IO ()
repoSaverAction a = do repoSaverAction a = do
withTempFile "." "tmp-repo.json" $ \fp h -> do withTempFile "repos" "tmp-repo.json" $ \fp h -> do
-- printDebug "repoSaverAction" fp -- printDebug "repoSaverAction" fp
L.hPut h $ encode a L.hPut h $ encode a
hClose h hClose h
...@@ -208,6 +214,8 @@ mkRepoSaver repo_var = mkDebounce settings ...@@ -208,6 +214,8 @@ mkRepoSaver repo_var = mkDebounce settings
readRepoEnv :: IO RepoEnv readRepoEnv :: IO RepoEnv
readRepoEnv = do readRepoEnv = do
-- Does file exist ? :: Bool -- Does file exist ? :: Bool
_repoDir <- createDirectoryIfMissing True repoDir
repoFile <- doesFileExist repoSnapshot repoFile <- doesFileExist repoSnapshot
-- Is file not empty ? :: Bool -- Is file not empty ? :: Bool
...@@ -228,14 +236,17 @@ readRepoEnv = do ...@@ -228,14 +236,17 @@ readRepoEnv = do
pure repo pure repo
else else
pure initRepo pure initRepo
-- TODO save in DB here
saver <- mkRepoSaver mvar saver <- mkRepoSaver mvar
pure $ RepoEnv { _renv_var = mvar, _renv_saver = saver, _renv_lock = lock } pure $ RepoEnv { _renv_var = mvar, _renv_saver = saver, _renv_lock = lock }
devJwkFile :: FilePath
devJwkFile = "dev.jwk"
newEnv :: PortNumber -> FilePath -> IO Env newEnv :: PortNumber -> FilePath -> IO Env
newEnv port file = do newEnv port file = do
manager <- newTlsManager manager <- newTlsManager
settings <- pure (devSettings & 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"
...@@ -243,7 +254,7 @@ newEnv port file = do ...@@ -243,7 +254,7 @@ newEnv port file = do
param <- databaseParameters file param <- databaseParameters file
conn <- connect param conn <- connect param
repo <- readRepoEnv repo <- readRepoEnv
--scrapers_env <- newJobEnv defaultSettings manager scrapers_env <- newJobEnv defaultSettings manager
logger <- newStderrLoggerSet defaultBufSize logger <- newStderrLoggerSet defaultBufSize
pure $ Env pure $ Env
...@@ -252,7 +263,7 @@ newEnv port file = do ...@@ -252,7 +263,7 @@ newEnv port file = do
, _env_conn = conn , _env_conn = conn
, _env_repo = repo , _env_repo = repo
, _env_manager = manager , _env_manager = manager
--, _env_scrapers = scrapers_env , _env_scrapers = scrapers_env
, _env_self_url = self_url , _env_self_url = self_url
} }
...@@ -295,10 +306,11 @@ withDevEnv iniPath k = do ...@@ -295,10 +306,11 @@ withDevEnv iniPath k = do
param <- databaseParameters iniPath param <- databaseParameters iniPath
conn <- connect param conn <- connect param
repo <- readRepoEnv repo <- readRepoEnv
setts <- devSettings devJwkFile
pure $ DevEnv pure $ DevEnv
{ _dev_env_conn = conn { _dev_env_conn = conn
, _dev_env_repo = repo , _dev_env_repo = repo
, _dev_env_settings = devSettings , _dev_env_settings = setts
} }
-- | Run Cmd Sugar for the Repl (GHCI) -- | Run Cmd Sugar for the Repl (GHCI)
......
...@@ -44,9 +44,9 @@ import Data.Swagger ...@@ -44,9 +44,9 @@ import Data.Swagger
import Data.Text (Text()) import Data.Text (Text())
import GHC.Generics (Generic) import GHC.Generics (Generic)
import Gargantext.API.Ngrams (TabType(..)) import Gargantext.API.Ngrams (TabType(..))
import Gargantext.Core.Types (Offset, Limit) import Gargantext.Core.Types (Offset, Limit, TableResult(..))
import Gargantext.Core.Utils.Prefix (unPrefix) import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
import Gargantext.Database.Facet (FacetDoc , runViewDocuments, OrderBy(..),runViewAuthorsDoc) import Gargantext.Database.Facet (FacetDoc , runViewDocuments, OrderBy(..), runViewAuthorsDoc)
import Gargantext.Database.Learn (FavOrTrash(..), moreLike) import Gargantext.Database.Learn (FavOrTrash(..), moreLike)
import Gargantext.Database.TextSearch import Gargantext.Database.TextSearch
import Gargantext.Database.Types.Node import Gargantext.Database.Types.Node
...@@ -57,11 +57,11 @@ import Test.QuickCheck (elements) ...@@ -57,11 +57,11 @@ import Test.QuickCheck (elements)
import Test.QuickCheck.Arbitrary (Arbitrary, arbitrary) import Test.QuickCheck.Arbitrary (Arbitrary, arbitrary)
------------------------------------------------------------------------ ------------------------------------------------------------------------
type TableApi = Summary " Table API" type TableApi = Summary " Table API"
:> ReqBody '[JSON] TableQuery :> ReqBody '[JSON] TableQuery
:> Post '[JSON] [FacetDoc] :> Post '[JSON] FacetTableResult
--{-
data TableQuery = TableQuery data TableQuery = TableQuery
{ tq_offset :: Int { tq_offset :: Int
, tq_limit :: Int , tq_limit :: Int
...@@ -70,42 +70,64 @@ data TableQuery = TableQuery ...@@ -70,42 +70,64 @@ data TableQuery = TableQuery
, tq_query :: Text , tq_query :: Text
} deriving (Generic) } deriving (Generic)
type FacetTableResult = TableResult FacetDoc
$(deriveJSON (unPrefix "tq_") ''TableQuery) $(deriveJSON (unPrefix "tq_") ''TableQuery)
instance ToSchema TableQuery where instance ToSchema TableQuery where
declareNamedSchema = declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "tq_")
genericDeclareNamedSchema
defaultSchemaOptions {fieldLabelModifier = drop 3}
instance Arbitrary TableQuery where instance Arbitrary TableQuery where
arbitrary = elements [TableQuery 0 10 DateAsc Docs "electrodes"] arbitrary = elements [TableQuery 0 10 DateAsc Docs "electrodes"]
tableApi :: NodeId -> TableQuery -> Cmd err [FacetDoc] tableApi :: NodeId -> TableQuery -> Cmd err FacetTableResult
tableApi cId (TableQuery o l order ft "") = getTable cId (Just ft) (Just o) (Just l) (Just order) tableApi cId (TableQuery o l order ft "") = getTable cId (Just ft) (Just o) (Just l) (Just order)
tableApi cId (TableQuery o l order ft q) = case ft of tableApi cId (TableQuery o l order ft q) = case ft of
Docs -> searchInCorpus cId False [q] (Just o) (Just l) (Just order) Docs -> searchInCorpus' cId False [q] (Just o) (Just l) (Just order)
Trash -> searchInCorpus cId True [q] (Just o) (Just l) (Just order) Trash -> searchInCorpus' cId True [q] (Just o) (Just l) (Just order)
x -> panic $ "not implemented in tableApi " <> (cs $ show x) x -> panic $ "not implemented in tableApi " <> (cs $ show x)
searchInCorpus' :: CorpusId
-> Bool
-> [Text]
-> Maybe Offset
-> Maybe Limit
-> Maybe OrderBy
-> Cmd err FacetTableResult
searchInCorpus' cId t q o l order = do
docs <- searchInCorpus cId t q o l order
countAllDocs <- searchCountInCorpus cId t q
pure $ TableResult { tr_docs = docs, tr_count = countAllDocs }
getTable :: NodeId -> Maybe TabType getTable :: NodeId -> Maybe TabType
-> Maybe Offset -> Maybe Limit
-> Maybe OrderBy -> Cmd err FacetTableResult
getTable cId ft o l order = do
docs <- getTable' cId ft o l order
-- TODO: Rewrite to use runCountOpaQuery and avoid (length allDocs)
allDocs <- getTable' cId ft Nothing Nothing Nothing
pure $ TableResult { tr_docs = docs, tr_count = length allDocs }
getTable' :: NodeId -> Maybe TabType
-> Maybe Offset -> Maybe Limit -> Maybe Offset -> Maybe Limit
-> Maybe OrderBy -> Cmd err [FacetDoc] -> Maybe OrderBy -> Cmd err [FacetDoc]
getTable cId ft o l order = getTable' cId ft o l order =
case ft of case ft of
(Just Docs) -> runViewDocuments cId False o l order (Just Docs) -> runViewDocuments cId False o l order
(Just Trash) -> runViewDocuments cId True o l order (Just Trash) -> runViewDocuments cId True o l order
(Just MoreFav) -> moreLike cId o l order IsFav (Just MoreFav) -> moreLike cId o l order IsFav
(Just MoreTrash) -> moreLike cId o l order IsTrash (Just MoreTrash) -> moreLike cId o l order IsTrash
x -> panic $ "not implemented in getTable: " <> (cs $ show x) x -> panic $ "not implemented in getTable: " <> (cs $ show x)
getPairing :: ContactId -> Maybe TabType
getPair :: ContactId -> Maybe TabType
-> Maybe Offset -> Maybe Limit -> Maybe Offset -> Maybe Limit
-> Maybe OrderBy -> Cmd err [FacetDoc] -> Maybe OrderBy -> Cmd err [FacetDoc]
getPairing cId ft o l order = getPair cId ft o l order =
case ft of case ft of
(Just Docs) -> runViewAuthorsDoc cId False o l order (Just Docs) -> runViewAuthorsDoc cId False o l order
(Just Trash) -> runViewAuthorsDoc cId True o l order (Just Trash) -> runViewAuthorsDoc cId True o l order
_ -> panic $ "not implemented: get Pairing" <> (cs $ show ft) _ -> panic $ "not implemented: get Pairing" <> (cs $ show ft)
...@@ -10,32 +10,129 @@ Portability : POSIX ...@@ -10,32 +10,129 @@ Portability : POSIX
-} -}
{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Gargantext.API.Types module Gargantext.API.Types
( module Gargantext.API.Types
, HasServerError(..)
, serverError
)
where where
import Control.Exception (Exception)
import Control.Lens (Prism', (#))
import Control.Lens.TH (makePrisms)
import Control.Monad.Error.Class (MonadError(throwError))
import Crypto.JOSE.Error as Jose
import Data.Aeson.Types
import Data.Typeable
import Data.Validity
import Servant import Servant
import Servant.Job.Core (HasServerError(..), serverError)
import Servant.Job.Async (HasJobEnv)
import Gargantext.Prelude
import Gargantext.API.Settings import Gargantext.API.Settings
import Gargantext.API.Orchestrator.Types
import Gargantext.API.Ngrams import Gargantext.API.Ngrams
import Gargantext.Database.Tree
import Gargantext.Core.Types import Gargantext.Core.Types
import Gargantext.Database.Tree
import Gargantext.Database.Utils import Gargantext.Database.Utils
import Gargantext.Database.Schema.Node import Gargantext.Database.Schema.Node
class HasJoseError e where
_JoseError :: Prism' e Jose.Error
type GargServer api = joseError :: (MonadError e m, HasJoseError e) => Jose.Error -> m a
forall env err m. joseError = throwError . (_JoseError #)
( CmdM env err m
, HasNodeError err class ThrowAll' e a | a -> e where
, HasInvalidError err -- | 'throwAll' is a convenience function to throw errors across an entire
, HasTreeError err -- sub-API
, HasRepo env --
, HasSettings env --
-- > throwAll err400 :: Handler a :<|> Handler b :<|> Handler c
-- > == throwError err400 :<|> throwError err400 :<|> err400
throwAll' :: e -> a
instance (ThrowAll' e a, ThrowAll' e b) => ThrowAll' e (a :<|> b) where
throwAll' e = throwAll' e :<|> throwAll' e
-- Really this shouldn't be necessary - ((->) a) should be an instance of
-- MonadError, no?
instance {-# OVERLAPPING #-} ThrowAll' e b => ThrowAll' e (a -> b) where
throwAll' e = const $ throwAll' e
instance {-# OVERLAPPABLE #-} (MonadError e m) => ThrowAll' e (m a) where
throwAll' = throwError
type GargServerC env err m =
( CmdM env err m
, HasNodeError err
, HasInvalidError err
, HasTreeError err
, HasServerError err
, HasJoseError err
, ToJSON err -- TODO this is arguable
, Exception err
, HasRepo env
, HasSettings env
, HasJobEnv env ScraperStatus ScraperStatus
) )
=> ServerT api m
type GargServerT env err m api = GargServerC env err m => ServerT api m
type GargServer api =
forall env err m. GargServerT env err m api
-------------------------------------------------------------------
-- | This Type is needed to prepare the function before the GargServer
type GargNoServer' env err m =
( CmdM env err m
, HasRepo env
, HasSettings env
, HasNodeError err
)
type GargNoServer t =
forall env err m. GargNoServer' env err m => m t
-------------------------------------------------------------------
data GargError
= GargNodeError NodeError
| GargTreeError TreeError
| GargInvalidError Validation
| GargJoseError Jose.Error
| GargServerError ServerError
deriving (Show, Typeable)
makePrisms ''GargError
instance ToJSON GargError where
toJSON _ = String "SomeGargErrorPleaseReport"
instance Exception GargError
instance HasNodeError GargError where
_NodeError = _GargNodeError
instance HasInvalidError GargError where
_InvalidError = _GargInvalidError
instance HasTreeError GargError where
_TreeError = _GargTreeError
instance HasServerError GargError where
_ServerError = _GargServerError
instance HasJoseError GargError where
_JoseError = _GargJoseError
...@@ -21,22 +21,6 @@ import Gargantext.Prelude ...@@ -21,22 +21,6 @@ import Gargantext.Prelude
import Data.Maybe (Maybe, fromMaybe) import Data.Maybe (Maybe, fromMaybe)
import Prelude (String) import Prelude (String)
import qualified Data.Text as T import qualified Data.Text as T
import Data.Swagger
import Data.Text (Text)
swaggerOptions :: Text -> SchemaOptions
swaggerOptions pref = defaultSchemaOptions
{ Data.Swagger.fieldLabelModifier = modifier pref
, Data.Swagger.unwrapUnaryRecords = False
}
modifier :: Text -> String -> String
modifier pref field = T.unpack
$ T.stripPrefix pref (T.pack field) ?! "Expecting prefix " <> T.unpack pref
infixr 4 ?| infixr 4 ?|
......
...@@ -9,11 +9,20 @@ Portability : POSIX ...@@ -9,11 +9,20 @@ Portability : POSIX
-} -}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE OverloadedStrings #-}
module Gargantext.Core module Gargantext.Core
where where
import Gargantext.Prelude
import GHC.Generics (Generic)
import Data.Aeson
import Data.Either(Either(Left))
import Data.Swagger
import Servant.API
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- | Language of a Text -- | Language of a Text
-- For simplicity, we suppose text has an homogenous language -- For simplicity, we suppose text has an homogenous language
...@@ -30,9 +39,17 @@ module Gargantext.Core ...@@ -30,9 +39,17 @@ module Gargantext.Core
-- | All languages supported -- | All languages supported
-- TODO : DE | SP | CH -- TODO : DE | SP | CH
data Lang = EN | FR data Lang = EN | FR | All
deriving (Show, Eq, Ord, Bounded, Enum) deriving (Show, Eq, Ord, Bounded, Enum, Generic)
instance ToJSON Lang
instance FromJSON Lang
instance ToSchema Lang
instance FromHttpApiData Lang
where
parseUrlPiece "EN" = pure EN
parseUrlPiece "FR" = pure FR
parseUrlPiece "All" = pure All
parseUrlPiece _ = Left "Unexpected value of OrderBy"
allLangs :: [Lang] allLangs :: [Lang]
allLangs = [minBound ..] allLangs = [minBound ..]
{-| {-|
Module : Gargantext.Core.Flow Module : Gargantext.Core.Flow.Types
Description : Core Flow main Types Description : Core Flow main Types
Copyright : (c) CNRS, 2017-Present Copyright : (c) CNRS, 2017-Present
License : AGPL + CECILL v3 License : AGPL + CECILL v3
...@@ -13,7 +13,7 @@ Portability : POSIX ...@@ -13,7 +13,7 @@ Portability : POSIX
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ConstrainedClassMethods #-} {-# LANGUAGE ConstrainedClassMethods #-}
module Gargantext.Core.Flow where module Gargantext.Core.Flow.Types where
import Control.Lens (Lens') import Control.Lens (Lens')
import Data.Map (Map) import Data.Map (Map)
...@@ -40,14 +40,15 @@ class UniqId a ...@@ -40,14 +40,15 @@ class UniqId a
class ExtractNgramsT h class ExtractNgramsT h
where where
extractNgramsT :: HasText h => TermType Lang -> h -> Cmd err (Map Ngrams (Map NgramsType Int)) extractNgramsT :: HasText h
=> TermType Lang
-> h
-> Cmd err (Map Ngrams (Map NgramsType Int))
class HasText h class HasText h
where where
hasText :: h -> [Text] hasText :: h -> [Text]
------------------------------------------------------------------------
instance UniqId HyperdataDocument instance UniqId HyperdataDocument
where where
uniqId = hyperdataDocument_uniqId uniqId = hyperdataDocument_uniqId
...@@ -55,5 +56,3 @@ instance UniqId HyperdataDocument ...@@ -55,5 +56,3 @@ instance UniqId HyperdataDocument
instance UniqId HyperdataContact instance UniqId HyperdataContact
where where
uniqId = hc_uniqId uniqId = hc_uniqId
...@@ -14,6 +14,7 @@ commentary with @some markup@. ...@@ -14,6 +14,7 @@ commentary with @some markup@.
------------------------------------------------------------------------ ------------------------------------------------------------------------
{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TemplateHaskell #-}
module Gargantext.Core.Types ( module Gargantext.Core.Types.Main module Gargantext.Core.Types ( module Gargantext.Core.Types.Main
, module Gargantext.Database.Types.Node , module Gargantext.Database.Types.Node
...@@ -22,27 +23,31 @@ module Gargantext.Core.Types ( module Gargantext.Core.Types.Main ...@@ -22,27 +23,31 @@ module Gargantext.Core.Types ( module Gargantext.Core.Types.Main
, Label, Stems , Label, Stems
, HasInvalidError(..), assertValid , HasInvalidError(..), assertValid
, Name , Name
, TableResult(..)
, NodeTableResult
, TODO(..)
) where ) where
--import qualified Data.Set as S
import Control.Lens (Prism', (#)) import Control.Lens (Prism', (#))
import Control.Monad.Error.Class (MonadError, throwError) import Control.Monad.Error.Class (MonadError, throwError)
import Data.Aeson import Data.Aeson
import Data.Semigroup import Data.Aeson.TH (deriveJSON)
import Data.Monoid import Data.Monoid
import Data.Semigroup
import Data.Set (Set, empty) import Data.Set (Set, empty)
--import qualified Data.Set as S import Data.Swagger (ToParamSchema)
import Data.Swagger (ToSchema(..), genericDeclareNamedSchema)
import Data.Text (Text, unpack) import Data.Text (Text, unpack)
import Data.Validity import Data.Validity
import GHC.Generics
import Gargantext.Core.Types.Main import Gargantext.Core.Types.Main
import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
import Gargantext.Database.Types.Node import Gargantext.Database.Types.Node
import Gargantext.Prelude import Gargantext.Prelude
import Test.QuickCheck.Arbitrary (Arbitrary, arbitrary)
import GHC.Generics
------------------------------------------------------------------------ ------------------------------------------------------------------------
type Name = Text type Name = Text
type Term = Text type Term = Text
type Stems = Set Text type Stems = Set Text
...@@ -135,3 +140,28 @@ assertValid :: (MonadError e m, HasInvalidError e) => Validation -> m () ...@@ -135,3 +140,28 @@ assertValid :: (MonadError e m, HasInvalidError e) => Validation -> m ()
assertValid v = when (not $ validationIsValid v) $ throwError $ _InvalidError # v assertValid v = when (not $ validationIsValid v) $ throwError $ _InvalidError # v
-- assertValid :: MonadIO m => Validation -> m () -- assertValid :: MonadIO m => Validation -> m ()
-- assertValid v = when (not $ validationIsValid v) $ fail $ show v -- assertValid v = when (not $ validationIsValid v) $ fail $ show v
data TableResult a = TableResult { tr_count :: Int
, tr_docs :: [a]
} deriving (Generic)
$(deriveJSON (unPrefix "tr_") ''TableResult)
instance ToSchema a => ToSchema (TableResult a) where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "tr_")
instance Arbitrary a => Arbitrary (TableResult a) where
arbitrary = TableResult <$> arbitrary <*> arbitrary
type NodeTableResult a = TableResult (Node a)
-- TO BE removed
data TODO = TODO
deriving (Generic)
instance ToSchema TODO where
instance ToParamSchema TODO where
...@@ -22,8 +22,7 @@ module Gargantext.Core.Types.Main where ...@@ -22,8 +22,7 @@ module Gargantext.Core.Types.Main where
------------------------------------------------------------------------ ------------------------------------------------------------------------
import Prelude (Enum, Bounded, minBound, maxBound) import Prelude (Enum, Bounded, minBound, maxBound)
import Data.Aeson (FromJSON, ToJSON, toJSON) import Data.Aeson (FromJSON, ToJSON)
import Data.Aeson as A
import Data.Aeson.TH (deriveJSON) import Data.Aeson.TH (deriveJSON)
import Data.Map (fromList, lookup) import Data.Map (fromList, lookup)
import Data.Either (Either(..)) import Data.Either (Either(..))
...@@ -33,7 +32,7 @@ import Data.Text (Text, unpack) ...@@ -33,7 +32,7 @@ import Data.Text (Text, unpack)
import Data.Swagger import Data.Swagger
import Gargantext.Database.Types.Node -- (NodeType(..), Node, Hyperdata(..)) import Gargantext.Database.Types.Node -- (NodeType(..), Node, Hyperdata(..))
import Gargantext.Core.Utils.Prefix (unPrefix) import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
import Gargantext.Prelude import Gargantext.Prelude
import GHC.Generics (Generic) import GHC.Generics (Generic)
...@@ -49,38 +48,10 @@ data NodeTree = NodeTree { _nt_name :: Text ...@@ -49,38 +48,10 @@ data NodeTree = NodeTree { _nt_name :: Text
} deriving (Show, Read, Generic) } deriving (Show, Read, Generic)
$(deriveJSON (unPrefix "_nt_") ''NodeTree) $(deriveJSON (unPrefix "_nt_") ''NodeTree)
instance ToSchema NodeTree where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_nt_")
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- Garg Network is a network of all Garg nodes
--gargNetwork = undefined
-- | Garg Node is Database Schema Typed as specification
-- gargNode gathers all the Nodes of all users on one Node
gargNode :: [Tree NodeTree]
gargNode = [userTree]
-- | User Tree simplified
userTree :: Tree NodeTree
userTree = TreeN (NodeTree "user name" NodeUser 1) [annuaireTree, projectTree]
-- | Project Tree
projectTree :: Tree NodeTree
projectTree = TreeN (NodeTree "Project CNRS/IMT" NodeFolder 2) [corpusTree 10 "A", corpusTree 20 "B"]
-- | Corpus Tree
annuaireTree :: Tree NodeTree
annuaireTree = (leafT $ NodeTree "Annuaire" NodeAnnuaire 41)
corpusTree :: NodeId -> Text -> Tree NodeTree
corpusTree nId t = TreeN (NodeTree ("Corpus " <> t) NodeCorpus nId) ( [ leafT $ NodeTree "Dashboard" NodeDashboard (nId +1)
, leafT $ NodeTree "Graph" NodeGraph (nId +2)
]
-- <> [ leafT $ NodeTree "My lists" Lists 5]
-- <> [ leafT (NodeTree "Metrics A" Metrics 6) ]
-- <> [ leafT (NodeTree "Class A" Classification 7)]
)
--data Classification = Favorites | MyClassifcation --data Classification = Favorites | MyClassifcation
type HashId = Text type HashId = Text
...@@ -127,17 +98,14 @@ type IsTrash = Bool ...@@ -127,17 +98,14 @@ type IsTrash = Bool
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- All the Database is structred like a hierarchical Tree -- All the Database is structred like a hierarchical Tree
data Tree a = TreeN a [Tree a] data Tree a = TreeN { _tn_node :: a, _tn_children :: [Tree a] }
deriving (Show, Read, Eq, Generic, Ord) deriving (Show, Read, Eq, Generic, Ord)
instance ToJSON a => ToJSON (Tree a) where $(deriveJSON (unPrefix "_tn_") ''Tree)
toJSON (TreeN node nodes) =
object ["node" A..= toJSON node, "children" A..= toJSON nodes]
instance FromJSON a => FromJSON (Tree a) instance ToSchema a => ToSchema (Tree a) where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_tn_")
instance ToSchema NodeTree
instance ToSchema a => ToSchema (Tree a)
instance Arbitrary (Tree NodeTree) where instance Arbitrary (Tree NodeTree) where
arbitrary = elements [userTree, userTree] arbitrary = elements [userTree, userTree]
...@@ -146,3 +114,33 @@ instance Arbitrary (Tree NodeTree) where ...@@ -146,3 +114,33 @@ instance Arbitrary (Tree NodeTree) where
-- same as Data.Tree -- same as Data.Tree
leafT :: a -> Tree a leafT :: a -> Tree a
leafT x = TreeN x [] leafT x = TreeN x []
------------------------------------------------------------------------
-- Garg Network is a network of all Garg nodes
--gargNetwork = undefined
-- | Garg Node is Database Schema Typed as specification
-- gargNode gathers all the Nodes of all users on one Node
gargNode :: [Tree NodeTree]
gargNode = [userTree]
-- | User Tree simplified
userTree :: Tree NodeTree
userTree = TreeN (NodeTree "user name" NodeUser 1) [annuaireTree, projectTree]
-- | Project Tree
projectTree :: Tree NodeTree
projectTree = TreeN (NodeTree "Project CNRS/IMT" NodeFolder 2) [corpusTree 10 "A", corpusTree 20 "B"]
-- | Corpus Tree
annuaireTree :: Tree NodeTree
annuaireTree = (leafT $ NodeTree "Annuaire" NodeAnnuaire 41)
corpusTree :: NodeId -> Text -> Tree NodeTree
corpusTree nId t = TreeN (NodeTree ("Corpus " <> t) NodeCorpus nId) ( [ leafT $ NodeTree "Dashboard" NodeDashboard (nId +1)
, leafT $ NodeTree "Graph" NodeGraph (nId +2)
]
-- <> [ leafT $ NodeTree "My lists" Lists 5]
-- <> [ leafT (NodeTree "Metrics A" Metrics 6) ]
-- <> [ leafT (NodeTree "Class A" Classification 7)]
)
...@@ -25,15 +25,18 @@ Phylomemy was first described in Chavalarias, D., Cointet, J.-P., 2013. Phylomem ...@@ -25,15 +25,18 @@ Phylomemy was first described in Chavalarias, D., Cointet, J.-P., 2013. Phylomem
module Gargantext.Core.Types.Phylo where module Gargantext.Core.Types.Phylo where
import Control.Lens (makeLenses)
import Data.Aeson.TH (deriveJSON) import Data.Aeson.TH (deriveJSON)
import Data.Maybe (Maybe) import Data.Maybe (Maybe)
import Data.Swagger
import Data.Text (Text) import Data.Text (Text)
import Data.Time.Clock.POSIX (POSIXTime) import Data.Time.Clock.POSIX (POSIXTime)
import GHC.Generics (Generic) import GHC.Generics (Generic)
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Core.Utils.Prefix (unPrefix) import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- | Phylo datatype descriptor of a phylomemy -- | Phylo datatype descriptor of a phylomemy
...@@ -94,8 +97,24 @@ type PhyloGroupId = (PhyloLevelId, Int) ...@@ -94,8 +97,24 @@ type PhyloGroupId = (PhyloLevelId, Int)
type Edge = (PhyloGroupId, Weight) type Edge = (PhyloGroupId, Weight)
type Weight = Double type Weight = Double
-- | Lenses
makeLenses ''Phylo
makeLenses ''PhyloPeriod
makeLenses ''PhyloLevel
makeLenses ''PhyloGroup
-- | JSON instances -- | JSON instances
$(deriveJSON (unPrefix "_phylo_" ) ''Phylo ) $(deriveJSON (unPrefix "_phylo_" ) ''Phylo )
$(deriveJSON (unPrefix "_phylo_Period" ) ''PhyloPeriod ) $(deriveJSON (unPrefix "_phylo_Period" ) ''PhyloPeriod )
$(deriveJSON (unPrefix "_phylo_Level" ) ''PhyloLevel ) $(deriveJSON (unPrefix "_phylo_Level" ) ''PhyloLevel )
$(deriveJSON (unPrefix "_phylo_Group" ) ''PhyloGroup ) $(deriveJSON (unPrefix "_phylo_Group" ) ''PhyloGroup )
-- | ToSchema instances
instance ToSchema Phylo where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_phylo_")
instance ToSchema PhyloPeriod where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_phylo_Period")
instance ToSchema PhyloLevel where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_phylo_Level")
instance ToSchema PhyloGroup where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_phylo_Group")
...@@ -22,6 +22,7 @@ import Data.Aeson.TH (Options, fieldLabelModifier, omitNothingFields) ...@@ -22,6 +22,7 @@ import Data.Aeson.TH (Options, fieldLabelModifier, omitNothingFields)
import Data.Aeson.Types (Parser) import Data.Aeson.Types (Parser)
import Data.Char (toLower) import Data.Char (toLower)
import Data.Monoid ((<>)) import Data.Monoid ((<>))
import Data.Swagger.SchemaOptions (SchemaOptions, fromAesonOptions)
import Text.Read (Read(..),readMaybe) import Text.Read (Read(..),readMaybe)
...@@ -32,6 +33,9 @@ unPrefix prefix = defaultOptions ...@@ -32,6 +33,9 @@ unPrefix prefix = defaultOptions
, omitNothingFields = True , omitNothingFields = True
} }
unPrefixSwagger :: String -> SchemaOptions
unPrefixSwagger = fromAesonOptions . unPrefix
-- | Lower case leading character -- | Lower case leading character
unCapitalize :: String -> String unCapitalize :: String -> String
unCapitalize [] = [] unCapitalize [] = []
......
...@@ -17,9 +17,9 @@ Gargantext's database. ...@@ -17,9 +17,9 @@ Gargantext's database.
{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE NoImplicitPrelude #-}
module Gargantext.Database ( module Gargantext.Database.Utils module Gargantext.Database ( module Gargantext.Database.Utils
, module Gargantext.Database.Bashql -- , module Gargantext.Database.Bashql
) )
where where
import Gargantext.Database.Utils (connectGargandb) import Gargantext.Database.Utils (connectGargandb)
import Gargantext.Database.Bashql -- import Gargantext.Database.Bashql
...@@ -7,6 +7,7 @@ Maintainer : team@gargantext.org ...@@ -7,6 +7,7 @@ Maintainer : team@gargantext.org
Stability : experimental Stability : experimental
Portability : POSIX Portability : POSIX
TODO-SECURITY review purpose of this module
-} -}
{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE NoImplicitPrelude #-}
......
{-# OPTIONS_GHC -fno-warn-unused-top-binds #-}
{-| {-|
Module : Gargantext.Database.Bashql Module : Gargantext.Database.Bashql
Description : BASHQL to deal with Gargantext Database. Description : BASHQL to deal with Gargantext Database.
...@@ -55,13 +56,15 @@ AMS, and by SIAM. ...@@ -55,13 +56,15 @@ AMS, and by SIAM.
[3] https://github.com/Gabriel439/Haskell-Turtle-Library [3] https://github.com/Gabriel439/Haskell-Turtle-Library
TODO-ACCESS: should the checks be done here or before.
-} -}
{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RankNTypes #-}
module Gargantext.Database.Bashql ( get module Gargantext.Database.Bashql () {-( get
, ls , ls
, home , home
, post , post
...@@ -71,7 +74,7 @@ module Gargantext.Database.Bashql ( get ...@@ -71,7 +74,7 @@ module Gargantext.Database.Bashql ( get
, rename , rename
, tree , tree
-- , mkCorpus, mkAnnuaire -- , mkCorpus, mkAnnuaire
) )-}
where where
import Control.Monad.Reader -- (Reader, ask) import Control.Monad.Reader -- (Reader, ask)
......
...@@ -43,6 +43,10 @@ nodeTypeId n = ...@@ -43,6 +43,10 @@ nodeTypeId n =
case n of case n of
NodeUser -> 1 NodeUser -> 1
NodeFolder -> 2 NodeFolder -> 2
NodeFolderPrivate -> 20
NodeFolderShared -> 21
NodeTeam -> 210
NodeFolderPublic -> 22
NodeCorpusV3 -> 3 NodeCorpusV3 -> 3
NodeCorpus -> 30 NodeCorpus -> 30
NodeAnnuaire -> 31 NodeAnnuaire -> 31
...@@ -53,14 +57,15 @@ nodeTypeId n = ...@@ -53,14 +57,15 @@ nodeTypeId n =
---- Lists ---- Lists
NodeList -> 5 NodeList -> 5
NodeListModel -> 10 NodeListCooc -> 50
NodeListModel -> 52
---- Scores ---- Scores
-- NodeOccurrences -> 10 -- NodeOccurrences -> 10
NodeGraph -> 9 NodeGraph -> 9
NodePhylo -> 90 NodePhylo -> 90
NodeDashboard -> 7 NodeChart -> 7
NodeChart -> 51 NodeDashboard -> 71
NodeNoteBook -> 88 NodeNoteBook -> 88
-- Cooccurrences -> 9 -- Cooccurrences -> 9
...@@ -90,4 +95,5 @@ nodeTypes = [ (n, nodeTypeId n) | n <- allNodeTypes ] ...@@ -90,4 +95,5 @@ nodeTypes = [ (n, nodeTypeId n) | n <- allNodeTypes ]
fromNodeTypeId :: NodeTypeId -> NodeType fromNodeTypeId :: NodeTypeId -> NodeType
fromNodeTypeId tId = fromMaybe (panic $ pack $ "Type Id " <> show tId <> " does not exist") fromNodeTypeId tId = fromMaybe (panic $ pack $ "Type Id " <> show tId <> " does not exist")
(lookup tId nodeTypeInv) (lookup tId nodeTypeInv)
...@@ -26,10 +26,23 @@ Portability : POSIX ...@@ -26,10 +26,23 @@ Portability : POSIX
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilies #-}
------------------------------------------------------------------------ ------------------------------------------------------------------------
module Gargantext.Database.Facet module Gargantext.Database.Facet
( runViewAuthorsDoc
, runViewDocuments
, filterWith
, Pair(..)
, Facet(..)
, FacetDoc
, FacetDocRead
, FacetPaired(..)
, FacetPairedRead
, OrderBy(..)
)
where where
------------------------------------------------------------------------ ------------------------------------------------------------------------
import Control.Arrow (returnA) import Control.Arrow (returnA)
import Control.Lens.TH (makeLensesWith, abbreviatedFields) import Control.Lens ((^.))
-- import Control.Lens.TH (makeLensesWith, abbreviatedFields)
import Data.Aeson (FromJSON, ToJSON) import Data.Aeson (FromJSON, ToJSON)
import Data.Aeson.TH (deriveJSON) import Data.Aeson.TH (deriveJSON)
import Data.Either(Either(Left)) import Data.Either(Either(Left))
...@@ -41,15 +54,16 @@ import Data.Time (UTCTime) ...@@ -41,15 +54,16 @@ import Data.Time (UTCTime)
import Data.Time.Segment (jour) import Data.Time.Segment (jour)
import GHC.Generics (Generic) import GHC.Generics (Generic)
import Gargantext.Core.Types import Gargantext.Core.Types
import Gargantext.Core.Utils.Prefix (unPrefix) import Gargantext.Core.Utils.Prefix (unPrefix, unPrefixSwagger)
import Gargantext.Database.Config (nodeTypeId) import Gargantext.Database.Config (nodeTypeId)
import Gargantext.Database.Schema.Ngrams
import Gargantext.Database.Schema.Node import Gargantext.Database.Schema.Node
import Gargantext.Database.Schema.NodeNgram import Gargantext.Database.Schema.Ngrams
import Gargantext.Database.Schema.NodeNode import Gargantext.Database.Schema.NodeNode
import Gargantext.Database.Schema.NodeNodeNgrams
-- import Gargantext.Database.Schema.NodeNodeNgrams2
import Gargantext.Database.Utils import Gargantext.Database.Utils
import Gargantext.Database.Queries.Join
import Gargantext.Database.Queries.Filter import Gargantext.Database.Queries.Filter
import Gargantext.Database.Queries.Join (leftJoin5)
import Opaleye import Opaleye
import Prelude hiding (null, id, map, sum, not, read) import Prelude hiding (null, id, map, sum, not, read)
import Servant.API import Servant.API
...@@ -70,9 +84,9 @@ type Title = Text ...@@ -70,9 +84,9 @@ type Title = Text
-- TODO remove Title -- TODO remove Title
type FacetDoc = Facet NodeId UTCTime Title HyperdataDocument (Maybe Favorite) (Maybe Double) type FacetDoc = Facet NodeId UTCTime Title HyperdataDocument (Maybe Favorite) (Maybe Double)
type FacetSources = FacetDoc -- type FacetSources = FacetDoc
type FacetAuthors = FacetDoc -- type FacetAuthors = FacetDoc
type FacetTerms = FacetDoc -- type FacetTerms = FacetDoc
data Facet id created title hyperdata favorite ngramCount = data Facet id created title hyperdata favorite ngramCount =
...@@ -99,50 +113,50 @@ $(deriveJSON (unPrefix "_p_") ''Pair) ...@@ -99,50 +113,50 @@ $(deriveJSON (unPrefix "_p_") ''Pair)
$(makeAdaptorAndInstance "pPair" ''Pair) $(makeAdaptorAndInstance "pPair" ''Pair)
instance (ToSchema i, ToSchema l) => ToSchema (Pair i l) where instance (ToSchema i, ToSchema l) => ToSchema (Pair i l) where
declareNamedSchema = declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_p_")
genericDeclareNamedSchema
defaultSchemaOptions {fieldLabelModifier = \fieldLabel -> drop 3 fieldLabel}
instance (Arbitrary i, Arbitrary l) => Arbitrary (Pair i l) where instance (Arbitrary i, Arbitrary l) => Arbitrary (Pair i l) where
arbitrary = Pair <$> arbitrary <*> arbitrary arbitrary = Pair <$> arbitrary <*> arbitrary
data FacetPaired id date hyperdata score pairs = data FacetPaired id date hyperdata score pair =
FacetPaired {_fp_id :: id FacetPaired {_fp_id :: id
,_fp_date :: date ,_fp_date :: date
,_fp_hyperdata :: hyperdata ,_fp_hyperdata :: hyperdata
,_fp_score :: score ,_fp_score :: score
,_fp_pairs :: pairs ,_fp_pair :: pair
} deriving (Show, Generic) } deriving (Show, Generic)
$(deriveJSON (unPrefix "_fp_") ''FacetPaired) $(deriveJSON (unPrefix "_fp_") ''FacetPaired)
$(makeAdaptorAndInstance "pFacetPaired" ''FacetPaired) $(makeAdaptorAndInstance "pFacetPaired" ''FacetPaired)
instance (ToSchema id, ToSchema date, ToSchema hyperdata, ToSchema pairs, ToSchema score) => ToSchema (FacetPaired id date hyperdata score pairs) where instance ( ToSchema id
declareNamedSchema = , ToSchema date
genericDeclareNamedSchema , ToSchema hyperdata
defaultSchemaOptions {fieldLabelModifier = \fieldLabel -> drop 4 fieldLabel} , ToSchema score
, ToSchema pair
) => ToSchema (FacetPaired id date hyperdata score pair) where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_fp_")
instance ( Arbitrary id instance ( Arbitrary id
, Arbitrary date , Arbitrary date
, Arbitrary hyperdata , Arbitrary hyperdata
, Arbitrary score , Arbitrary score
, Arbitrary pairs , Arbitrary pair
) => Arbitrary (FacetPaired id date hyperdata score pairs) where ) => Arbitrary (FacetPaired id date hyperdata score pair) where
arbitrary = FacetPaired <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary arbitrary = FacetPaired <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
--{-
type FacetPairedRead = FacetPaired (Column PGInt4 ) type FacetPairedRead = FacetPaired (Column PGInt4 )
(Column PGTimestamptz) (Column PGTimestamptz)
(Column PGJsonb ) (Column PGJsonb )
(Column PGInt4 ) (Column PGInt4 )
(Pair (Column (Nullable PGInt4)) (Column (Nullable PGText))) ( Column (Nullable PGInt4)
--} , Column (Nullable PGText)
)
-- | JSON instance -- | JSON instance
$(deriveJSON (unPrefix "facetDoc_") ''Facet) $(deriveJSON (unPrefix "facetDoc_") ''Facet)
-- | Documentation instance -- | Documentation instance
instance ToSchema FacetDoc instance ToSchema FacetDoc where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "facetDoc_")
-- | Mock and Quickcheck instances -- | Mock and Quickcheck instances
instance Arbitrary FacetDoc where instance Arbitrary FacetDoc where
...@@ -158,7 +172,7 @@ instance Arbitrary FacetDoc where ...@@ -158,7 +172,7 @@ instance Arbitrary FacetDoc where
-- Facets / Views for the Front End -- Facets / Views for the Front End
-- | Database instances -- | Database instances
$(makeAdaptorAndInstance "pFacetDoc" ''Facet) $(makeAdaptorAndInstance "pFacetDoc" ''Facet)
$(makeLensesWith abbreviatedFields ''Facet) -- $(makeLensesWith abbreviatedFields ''Facet)
type FacetDocRead = Facet (Column PGInt4 ) type FacetDocRead = Facet (Column PGInt4 )
(Column PGTimestamptz) (Column PGTimestamptz)
...@@ -196,6 +210,9 @@ instance Arbitrary OrderBy ...@@ -196,6 +210,9 @@ instance Arbitrary OrderBy
arbitrary = elements [minBound..maxBound] arbitrary = elements [minBound..maxBound]
-- TODO-SECURITY check
--{-
runViewAuthorsDoc :: ContactId -> IsTrash -> Maybe Offset -> Maybe Limit -> Maybe OrderBy -> Cmd err [FacetDoc] runViewAuthorsDoc :: ContactId -> IsTrash -> Maybe Offset -> Maybe Limit -> Maybe OrderBy -> Cmd err [FacetDoc]
runViewAuthorsDoc cId t o l order = runOpaQuery $ filterWith o l order $ viewAuthorsDoc cId t ntId runViewAuthorsDoc cId t o l order = runOpaQuery $ filterWith o l order $ viewAuthorsDoc cId t ntId
where where
...@@ -214,28 +231,34 @@ viewAuthorsDoc cId _ nt = proc () -> do ...@@ -214,28 +231,34 @@ viewAuthorsDoc cId _ nt = proc () -> do
restrict -< _node_id contact .== (toNullable $ pgNodeId cId) restrict -< _node_id contact .== (toNullable $ pgNodeId cId)
restrict -< _node_typename doc .== (pgInt4 $ nodeTypeId nt) restrict -< _node_typename doc .== (pgInt4 $ nodeTypeId nt)
returnA -< FacetDoc (_node_id doc) (_node_date doc) (_node_name doc) (_node_hyperdata doc) (toNullable $ pgInt4 1) (toNullable $ pgDouble 1) returnA -< FacetDoc (_node_id doc)
(_node_date doc)
(_node_name doc)
(_node_hyperdata doc)
(toNullable $ pgInt4 1)
(toNullable $ pgDouble 1)
queryAuthorsDoc :: Query (NodeRead, (NodeNgramReadNull, (NgramsReadNull, (NodeNgramReadNull, NodeReadNull)))) queryAuthorsDoc :: Query (NodeRead, (NodeNodeNgramsReadNull, (NgramsReadNull, (NodeNodeNgramsReadNull, NodeReadNull))))
queryAuthorsDoc = leftJoin5 queryNodeTable queryNodeNgramTable queryNgramsTable queryNodeNgramTable queryNodeTable cond12 cond23 cond34 cond45 queryAuthorsDoc = leftJoin5 queryNodeTable queryNodeNodeNgramsTable queryNgramsTable queryNodeNodeNgramsTable queryNodeTable cond12 cond23 cond34 cond45
where where
cond12 :: (NodeNgramRead, NodeRead) -> Column PGBool cond12 :: (NodeNodeNgramsRead, NodeRead) -> Column PGBool
cond12 (nodeNgram, doc) = _node_id doc cond12 (nodeNgram, doc) = _node_id doc
.== nng_node_id nodeNgram .== _nnng_node1_id nodeNgram
cond23 :: (NgramsRead, (NodeNodeNgramsRead, NodeReadNull)) -> Column PGBool
cond23 (ngrams, (nodeNgram, _)) = ngrams^.ngrams_id
.== _nnng_ngrams_id nodeNgram
cond23 :: (NgramsRead, (NodeNgramRead, NodeReadNull)) -> Column PGBool cond34 :: (NodeNodeNgramsRead, (NgramsRead, (NodeNodeNgramsReadNull, NodeReadNull))) -> Column PGBool
cond23 (ngrams, (nodeNgram, _)) = ngrams_id ngrams cond34 (nodeNgram2, (ngrams, (_,_)))= ngrams^.ngrams_id .== _nnng_ngrams_id nodeNgram2
.== nng_ngrams_id nodeNgram
cond34 :: (NodeNgramRead, (NgramsRead, (NodeNgramReadNull, NodeReadNull))) -> Column PGBool
cond34 (nodeNgram2, (ngrams, (_,_)))= ngrams_id ngrams .== nng_ngrams_id nodeNgram2
cond45 :: (NodeRead, (NodeNgramRead, (NgramsReadNull, (NodeNgramReadNull, NodeReadNull)))) -> Column PGBool
cond45 (contact, (nodeNgram2, (_, (_,_)))) = _node_id contact .== nng_node_id nodeNgram2
cond45 :: (NodeRead, (NodeNodeNgramsRead, (NgramsReadNull, (NodeNodeNgramsReadNull, NodeReadNull)))) -> Column PGBool
cond45 (contact, (nodeNgram2, (_, (_,_)))) = _node_id contact .== _nnng_node1_id nodeNgram2
--}
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- TODO-SECURITY check
runViewDocuments :: CorpusId -> IsTrash -> Maybe Offset -> Maybe Limit -> Maybe OrderBy -> Cmd err [FacetDoc] runViewDocuments :: CorpusId -> IsTrash -> Maybe Offset -> Maybe Limit -> Maybe OrderBy -> Cmd err [FacetDoc]
runViewDocuments cId t o l order = runViewDocuments cId t o l order =
runOpaQuery $ filterWith o l order $ viewDocuments cId t ntId runOpaQuery $ filterWith o l order $ viewDocuments cId t ntId
...@@ -246,13 +269,17 @@ viewDocuments :: CorpusId -> IsTrash -> NodeTypeId -> Query FacetDocRead ...@@ -246,13 +269,17 @@ viewDocuments :: CorpusId -> IsTrash -> NodeTypeId -> Query FacetDocRead
viewDocuments cId t ntId = proc () -> do viewDocuments cId t ntId = proc () -> do
n <- queryNodeTable -< () n <- queryNodeTable -< ()
nn <- queryNodeNodeTable -< () nn <- queryNodeNodeTable -< ()
restrict -< _node_id n .== nn_node2_id nn restrict -< n^.node_id .== nn^.nn_node2_id
restrict -< nn_node1_id nn .== (pgNodeId cId) restrict -< nn^.nn_node1_id .== (pgNodeId cId)
restrict -< _node_typename n .== (pgInt4 ntId) restrict -< n^.node_typename .== (pgInt4 ntId)
restrict -< if t then nn_category nn .== (pgInt4 0) restrict -< if t then nn^.nn_category .== (pgInt4 0)
else nn_category nn .>= (pgInt4 1) else nn^.nn_category .>= (pgInt4 1)
returnA -< FacetDoc (_node_id n) (_node_date n) (_node_name n) (_node_hyperdata n) (toNullable $ nn_category nn) (toNullable $ nn_score nn) returnA -< FacetDoc (_node_id n)
(_node_date n)
(_node_name n)
(_node_hyperdata n)
(toNullable $ nn^.nn_category)
(toNullable $ nn^.nn_score)
------------------------------------------------------------------------ ------------------------------------------------------------------------
filterWith :: (PGOrd date, PGOrd title, PGOrd score, hyperdata ~ Column SqlJsonb) => filterWith :: (PGOrd date, PGOrd title, PGOrd score, hyperdata ~ Column SqlJsonb) =>
......
This diff is collapsed.
{-|
Module : Gargantext.Database.Flow.List
Description : List Flow
Copyright : (c) CNRS, 2017-Present
License : AGPL + CECILL v3
Maintainer : team@gargantext.org
Stability : experimental
Portability : POSIX
-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ConstrainedClassMethods #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
module Gargantext.Database.Flow.List
where
import Data.Text (Text)
import Control.Monad (mapM_)
import Data.Map (Map, toList)
import Data.Maybe (Maybe(..), catMaybes)
import Gargantext.API.Ngrams (NgramsElement(..), putListNgrams)
import Gargantext.Database.Schema.Ngrams -- (insertNgrams, Ngrams(..), NgramsIndexed(..), indexNgrams, NgramsType(..), text2ngrams, ngramsTypeId)
import Gargantext.Core.Types.Main (ListType(CandidateTerm))
import Gargantext.Database.Schema.NodeNgrams (NodeNgramsPoly(..), NodeNgramsW, listInsertDb, getCgramsId)
import Gargantext.Database.Schema.Node_NodeNgramsNodeNgrams -- (insert_Node_NodeNgrams_NodeNgrams, Node_NodeNgrams_NodeNgrams(..))
import Gargantext.Database.Types.Node -- (HyperdataDocument(..), NodeType(..), NodeId, UserId, ListId, CorpusId, RootId, MasterCorpusId, MasterUserId)
import Gargantext.Database.Flow.Types
import Gargantext.Prelude
import qualified Data.List as List
import qualified Data.Map as Map
-- FLOW LIST
-- | TODO check optimization
mapNodeIdNgrams :: [DocumentIdWithNgrams a]
-> Map Ngrams (Map NgramsType (Map NodeId Int))
mapNodeIdNgrams = Map.unionsWith (Map.unionWith (Map.unionWith (+))) . fmap f
where
f :: DocumentIdWithNgrams a
-> Map Ngrams (Map NgramsType (Map NodeId Int))
f d = fmap (fmap (Map.singleton nId)) $ document_ngrams d
where
nId = documentId $ documentWithId d
------------------------------------------------------------------------
flowList_DbRepo :: FlowCmdM env err m
=> ListId
-> Map NgramsType [NgramsElement]
-> m ListId
flowList_DbRepo lId ngs = do
-- printDebug "listId flowList" lId
mapCgramsId <- listInsertDb lId toNodeNgramsW (Map.toList ngs)
let toInsert = catMaybes [ (,) <$> (getCgramsId mapCgramsId ntype <$> parent)
<*> getCgramsId mapCgramsId ntype ngram
| (ntype, ngs') <- Map.toList ngs
, NgramsElement ngram _ _ _ _ parent _ <- ngs'
]
-- Inserting groups of ngrams
_r <- insert_Node_NodeNgrams_NodeNgrams
$ map (\(a,b) -> Node_NodeNgrams_NodeNgrams lId a b Nothing) toInsert
listInsert lId ngs
--trace (show $ List.filter (\n -> _ne_ngrams n == "versatile") $ List.concat $ Map.elems ngs) $ listInsert lId ngs
pure lId
------------------------------------------------------------------------
------------------------------------------------------------------------
toNodeNgramsW :: ListId
-> [(NgramsType, [NgramsElement])]
-> [NodeNgramsW]
toNodeNgramsW l ngs = List.concat $ map (toNodeNgramsW'' l) ngs
where
toNodeNgramsW'' :: ListId
-> (NgramsType, [NgramsElement])
-> [NodeNgramsW]
toNodeNgramsW'' l' (ngrams_type, elms) =
[ NodeNgrams Nothing l' list_type ngrams_terms' ngrams_type Nothing Nothing Nothing 0 |
(NgramsElement ngrams_terms' _size list_type _occ _root _parent _children) <- elms
]
toNodeNgramsW' :: ListId
-> [(Text, [NgramsType])]
-> [NodeNgramsW]
toNodeNgramsW' l'' ngs = [ NodeNgrams Nothing l'' CandidateTerm terms ngrams_type Nothing Nothing Nothing 0
| (terms, ngrams_types) <- ngs
, ngrams_type <- ngrams_types
]
listInsert :: FlowCmdM env err m
=> ListId
-> Map NgramsType [NgramsElement]
-> m ()
listInsert lId ngs = mapM_ (\(typeList, ngElmts)
-> putListNgrams lId typeList ngElmts
) $ toList ngs
------------------------------------------------------------------------
------------------------------------------------------------------------
...@@ -16,10 +16,11 @@ Portability : POSIX ...@@ -16,10 +16,11 @@ Portability : POSIX
-- {-# LANGUAGE Arrows #-} -- {-# LANGUAGE Arrows #-}
module Gargantext.Database.Flow.Pairing module Gargantext.Database.Flow.Pairing
(pairing)
where where
--import Debug.Trace (trace) --import Debug.Trace (trace)
import Control.Lens (_Just,view) import Control.Lens (_Just, (^.))
import Database.PostgreSQL.Simple.SqlQQ (sql) import Database.PostgreSQL.Simple.SqlQQ (sql)
-- import Opaleye -- import Opaleye
-- import Opaleye.Aggregate -- import Opaleye.Aggregate
...@@ -31,55 +32,69 @@ import qualified Data.Map as DM ...@@ -31,55 +32,69 @@ import qualified Data.Map as DM
import Data.Text (Text, toLower) import Data.Text (Text, toLower)
import qualified Data.Text as DT import qualified Data.Text as DT
import Gargantext.Prelude hiding (sum) import Gargantext.Prelude hiding (sum)
import Gargantext.Core.Types (TableResult(..))
import Gargantext.Database.Schema.Ngrams -- (NgramsType(..)) import Gargantext.Database.Schema.Ngrams -- (NgramsType(..))
--import Gargantext.Database.Node.Contact -- (HyperdataContact(..)) import Gargantext.Database.Node.Contact -- (HyperdataContact(..))
--import Gargantext.Database.Types.Node -- (Hyperdata(..))
import Gargantext.Database.Node.Contact
import Gargantext.Database.Flow.Utils import Gargantext.Database.Flow.Utils
import Gargantext.Database.Utils (Cmd, runPGSQuery) import Gargantext.Database.Utils (Cmd, runPGSQuery)
import Gargantext.Database.Types.Node (AnnuaireId, CorpusId) import Gargantext.Database.Types.Node (AnnuaireId, CorpusId, ListId{-, DocId, ContactId-})
import Gargantext.Database.Node.Children import Gargantext.Database.Node.Children (getAllContacts)
import Gargantext.Core.Types (NodeType(..))
-- TODO mv this type in Types Main -- TODO mv this type in Types Main
type Terms = Text type Terms = Text
{-
pairing'' :: (CorpusId, CorpusId) -> (DocId -> DocId)
pairing'' = undefined
pairing' :: (CorpusId, AnnuaireId) -> (DocId -> ContactId)
pairing' = undefined
-}
-- | TODO : add paring policy as parameter -- | TODO : add paring policy as parameter
pairing :: AnnuaireId -> CorpusId -> Cmd err Int pairing :: CorpusId -- (CorpusId, ListId) -- Pair (Either CorpusId AnnuaireId) ListId
pairing aId cId = do -> AnnuaireId -- (AnnuaireId, ListId) -- Pair (Either CorpusId AnnuaireId) ListId
contacts' <- getContacts aId (Just NodeContact) -> ListId
let contactsMap = pairingPolicyToMap toLower $ toMaps extractNgramsT contacts' -> Cmd err Int
pairing cId aId lId = do
contacts' <- getAllContacts aId
let contactsMap = pairingPolicyToMap toLower
$ toMaps extractNgramsT (tr_docs contacts')
ngramsMap' <- getNgramsTindexed cId Authors ngramsMap' <- getNgramsTindexed cId Authors
let ngramsMap = pairingPolicyToMap lastName ngramsMap' let ngramsMap = pairingPolicyToMap lastName ngramsMap'
let indexedNgrams = pairMaps contactsMap ngramsMap let indexedNgrams = pairMaps contactsMap ngramsMap
insertToNodeNgrams indexedNgrams insertDocNgrams lId indexedNgrams
-- TODO add List
lastName :: Terms -> Terms lastName :: Terms -> Terms
lastName texte = DT.toLower $ maybe texte (\x -> if DT.length x > 3 then x else texte) (lastName' texte) lastName texte = DT.toLower
$ maybe texte (\x -> if DT.length x > 3 then x else texte) (lastName' texte)
where where
lastName' = lastMay . DT.splitOn " " lastName' = lastMay . DT.splitOn " "
-- TODO: this methods is dangerous (maybe equalities of the result are not taken into account -- TODO: this method is dangerous (maybe equalities of the result are not taken into account
-- emergency demo plan... -- emergency demo plan...)
pairingPolicyToMap :: (Terms -> Terms) pairingPolicyToMap :: (Terms -> Terms)
-> Map (NgramsT Ngrams) a -> Map (NgramsT Ngrams) a -> Map (NgramsT Ngrams) a
-> Map (NgramsT Ngrams) a
pairingPolicyToMap f = DM.mapKeys (pairingPolicy f) pairingPolicyToMap f = DM.mapKeys (pairingPolicy f)
pairingPolicy :: (Terms -> Terms) -> NgramsT Ngrams -> NgramsT Ngrams pairingPolicy :: (Terms -> Terms)
-> NgramsT Ngrams
-> NgramsT Ngrams
pairingPolicy f (NgramsT nt (Ngrams ng _)) = (NgramsT nt (Ngrams (f ng) 1)) pairingPolicy f (NgramsT nt (Ngrams ng _)) = (NgramsT nt (Ngrams (f ng) 1))
-- | TODO : use Occurrences in place of Int -- | TODO : use Occurrences in place of Int
extractNgramsT :: HyperdataContact -> Map (NgramsT Ngrams) Int extractNgramsT :: HyperdataContact
-> Map (NgramsT Ngrams) Int
extractNgramsT contact = fromList [(NgramsT Authors a' , 1)| a' <- authors ] extractNgramsT contact = fromList [(NgramsT Authors a' , 1)| a' <- authors ]
where where
authors = map text2ngrams $ catMaybes [view (hc_who . _Just . cw_lastName) contact] authors = map text2ngrams
--} $ catMaybes [ contact^.(hc_who . _Just . cw_lastName) ]
-- NP: notice how this function is no longer specific to the ContactId type
pairMaps :: Map (NgramsT Ngrams) a pairMaps :: Map (NgramsT Ngrams) a
-> Map (NgramsT Ngrams) NgramsId -> Map (NgramsT Ngrams) NgramsId
-> Map NgramsIndexed (Map NgramsType a) -> Map NgramsIndexed (Map NgramsType a)
...@@ -91,23 +106,28 @@ pairMaps m1 m2 = ...@@ -91,23 +106,28 @@ pairMaps m1 m2 =
] ]
----------------------------------------------------------------------- -----------------------------------------------------------------------
getNgramsTindexed:: CorpusId -> NgramsType -> Cmd err (Map (NgramsT Ngrams) NgramsId) getNgramsTindexed :: CorpusId
-> NgramsType
-> Cmd err (Map (NgramsT Ngrams) NgramsId)
getNgramsTindexed corpusId ngramsType' = fromList getNgramsTindexed corpusId ngramsType' = fromList
<$> map (\(ngramsId',t,n) -> (NgramsT ngramsType' (Ngrams t n),ngramsId')) <$> map (\(ngramsId',t,n) -> (NgramsT ngramsType' (Ngrams t n),ngramsId'))
<$> selectNgramsTindexed corpusId ngramsType' <$> selectNgramsTindexed corpusId ngramsType'
selectNgramsTindexed :: CorpusId -> NgramsType -> Cmd err [(NgramsId, Terms, Int)]
selectNgramsTindexed corpusId ngramsType'' = runPGSQuery selectQuery (corpusId, ngramsTypeId ngramsType'')
where where
selectQuery = [sql| SELECT n.id,n.terms,n.n from ngrams n selectNgramsTindexed :: CorpusId
JOIN nodes_ngrams occ ON occ.ngram_id = n.id -> NgramsType
JOIN nodes_nodes nn ON nn.node2_id = occ.node_id -> Cmd err [(NgramsId, Terms, Int)]
selectNgramsTindexed corpusId' ngramsType'' = runPGSQuery selectQuery (corpusId', ngramsTypeId ngramsType'')
WHERE nn.node1_id = ? where
AND occ.ngrams_type = ? selectQuery = [sql| SELECT n.id,n.terms,n.n from ngrams n
AND occ.node_id = nn.node2_id JOIN node_node_ngrams occ ON occ.ngrams_id = n.id
GROUP BY n.id; -- JOIN node_node_ngrams2 occ ON occ.ngrams_id = n.id
|] JOIN nodes_nodes nn ON nn.node2_id = occ.node2_id
WHERE nn.node1_id = ?
AND occ.ngrams_type = ?
AND occ.node2_id = nn.node2_id
GROUP BY n.id;
|]
{- | TODO more typed SQL queries {- | TODO more typed SQL queries
selectNgramsTindexed :: CorpusId -> NgramsType -> Query NgramsRead selectNgramsTindexed :: CorpusId -> NgramsType -> Query NgramsRead
...@@ -123,5 +143,3 @@ selectNgramsTindexed corpusId ngramsType = proc () -> do ...@@ -123,5 +143,3 @@ selectNgramsTindexed corpusId ngramsType = proc () -> do
result <- aggregate groupBy (ngrams_id ngrams) result <- aggregate groupBy (ngrams_id ngrams)
returnA -< result returnA -< result
--} --}
{-|
Module : Gargantext.Database.Flow.Types
Description : Types for Flow
Copyright : (c) CNRS, 2017-Present
License : AGPL + CECILL v3
Maintainer : team@gargantext.org
Stability : experimental
Portability : POSIX
-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ConstrainedClassMethods #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
module Gargantext.Database.Flow.Types
where
import Data.Map (Map)
import Gargantext.Prelude
import Gargantext.Core.Flow.Types
import Gargantext.API.Ngrams (HasRepoVar, RepoCmdM)
import Gargantext.Database.Schema.Ngrams (Ngrams(..), NgramsType(..))
import Gargantext.Database.Types.Node (NodeId)
import Gargantext.Database.Schema.Node (HasNodeError)
import Gargantext.Database.Utils (CmdM)
type FlowCmdM env err m =
( CmdM env err m
, RepoCmdM env err m
, HasNodeError err
, HasRepoVar env
)
data DocumentIdWithNgrams a = DocumentIdWithNgrams
{ documentWithId :: !(DocumentWithId a)
, document_ngrams :: !(Map Ngrams (Map NgramsType Int))
} deriving (Show)
data DocumentWithId a = DocumentWithId
{ documentId :: !NodeId
, documentData :: !a
} deriving (Show)
instance HasText a => HasText (DocumentWithId a)
where
hasText (DocumentWithId _ a) = hasText a
This diff is collapsed.
{-|
Module : Gargantext.Database.Init
Description : Triggers configuration
Copyright : (c) CNRS, 2017-Present
License : AGPL + CECILL v3
Maintainer : team@gargantext.org
Stability : experimental
Portability : POSIX
Ngrams by node enable contextual metrics.
-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
module Gargantext.Database.Init
where
-- import Database.PostgreSQL.Simple.Types (Values(..), QualifiedIdentifier(..))
import Gargantext.Database.Utils (Cmd)
import Gargantext.Prelude
import Gargantext.Database.Triggers.Nodes (triggerSearchUpdate)
import Gargantext.Database.Triggers.NodesNodes (triggerDeleteCount, triggerInsertCount, triggerUpdateAdd, triggerUpdateDel, MasterListId) -- , triggerCoocInsert)
import Gargantext.Database.Triggers.NodeNodeNgrams (triggerCountInsert, triggerCountInsert2)
------------------------------------------------------------------------
initTriggers :: MasterListId -> Cmd err [Int64]
initTriggers lId = do
t0 <- triggerSearchUpdate
t1 <- triggerCountInsert
t1' <- triggerCountInsert2
-- t1'' <- triggerCoocInsert lId
t2 <- triggerDeleteCount lId
t3 <- triggerInsertCount lId
t4 <- triggerUpdateAdd lId
t5 <- triggerUpdateDel lId
pure [t0
,t1
,t1'
-- ,t1''
,t2
,t3
,t4
,t5]
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