From 65bc93a8672a3ce231aa22c79b8ed296318c2823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Delano=C3=AB?= <devel+git@delanoe.org> Date: Tue, 27 Nov 2018 21:09:13 +0100 Subject: [PATCH] [ANNUAIRE] Contact type and mkAnnuaire function. --- package.yaml | 1 + src/Gargantext/Database/Flow.hs | 35 ++++---- src/Gargantext/Database/Ngrams.hs | 34 +++---- src/Gargantext/Database/Node.hs | 21 +---- src/Gargantext/Database/Node/Contact.hs | 112 ++++++++++++++++++++++++ src/Gargantext/Database/Types/Node.hs | 9 -- src/Gargantext/Database/Utils.hs | 29 +++++- 7 files changed, 174 insertions(+), 67 deletions(-) create mode 100644 src/Gargantext/Database/Node/Contact.hs diff --git a/package.yaml b/package.yaml index a82b20ee..bfc1b253 100644 --- a/package.yaml +++ b/package.yaml @@ -39,6 +39,7 @@ library: - Gargantext.Database.Bashql - Gargantext.Database.Node.Document.Insert - Gargantext.Database.Node.Document.Add + - Gargantext.Database.Node.Contact - Gargantext.Database.Types.Node - Gargantext.Database.User - Gargantext.Database.Cooc diff --git a/src/Gargantext/Database/Flow.hs b/src/Gargantext/Database/Flow.hs index 9fe21b2a..fc1e61f8 100644 --- a/src/Gargantext/Database/Flow.hs +++ b/src/Gargantext/Database/Flow.hs @@ -8,14 +8,6 @@ Stability : experimental Portability : POSIX -Map (NgramsId, NodeId) -> insert -data NgramsType = Sources | Authors | Terms -nodes_ngrams : column type, column list - -documents -sources -authors - -} {-# LANGUAGE DeriveGeneric #-} @@ -36,7 +28,7 @@ import qualified Data.Map as DM import Gargantext.Core.Types (NodePoly(..), ListType(..), listTypeId) import Gargantext.Database.Bashql (runCmd') -- , del) import Gargantext.Database.Ngrams (insertNgrams, Ngrams(..), NgramsT(..), NgramsIndexed(..), indexNgramsT, ngramsTypeId, NgramsType(..), text2ngrams) -import Gargantext.Database.Node (getRoot, mkRoot, mkCorpus, Cmd(..), mkList, mkGraph, mkDashboard) +import Gargantext.Database.Node (getRoot, mkRoot, mkCorpus, Cmd(..), mkList, mkGraph, mkDashboard, mkAnnuaire) import Gargantext.Database.Node.Document.Add (add) import Gargantext.Database.Node.Document.Insert (insertDocuments, ReturnId(..), addUniqIds) import Gargantext.Database.NodeNgram (NodeNgramPoly(..), insertNodeNgrams) @@ -56,12 +48,12 @@ flowDatabase :: FileFormat -> FilePath -> CorpusName -> IO Int flowDatabase ff fp cName = do -- Corus Flow - (masterUserId, _, corpusId) <- subFlow userMaster corpusMasterName + (masterUserId, _, corpusId) <- subFlowCorpus userMaster corpusMasterName -- Documents Flow hyperdataDocuments <- map addUniqIds <$> parseDocs ff fp - --printDebug "hyperdataDocuments" hyperdataDocuments + printDebug "hyperdataDocuments" hyperdataDocuments ids <- runCmd' $ insertDocuments masterUserId corpusId hyperdataDocuments --printDebug "Docs IDs : " (ids) @@ -70,14 +62,14 @@ flowDatabase ff fp cName = do -- Ngrams Flow -- todo: flow for new documents only - -- let tids = toInserted ids - --printDebug "toInserted ids" (length tids, tids) + let tids = toInserted ids + printDebug "toInserted ids" (length tids, tids) - -- let tihs = toInsert hyperdataDocuments - --printDebug "toInsert hyperdataDocuments" (length tihs, tihs) + let tihs = toInsert hyperdataDocuments + printDebug "toInsert hyperdataDocuments" (length tihs, tihs) let documentsWithId = mergeData (toInserted ids) (toInsert hyperdataDocuments) - -- printDebug "documentsWithId" documentsWithId + printDebug "documentsWithId" documentsWithId -- docsWithNgrams <- documentIdWithNgrams documentsWithId extractNgramsT let docsWithNgrams = documentIdWithNgrams extractNgramsT documentsWithId @@ -94,7 +86,7 @@ flowDatabase ff fp cName = do listId2 <- runCmd' $ listFlow masterUserId corpusId indexedNgrams printDebug "list id : " listId2 - (userId, _, corpusId2) <- subFlow userArbitrary cName + (userId, rootUserId, corpusId2) <- subFlowCorpus userArbitrary cName userListId <- runCmd' $ listFlowUser userId corpusId2 printDebug "UserList : " userListId @@ -103,15 +95,18 @@ flowDatabase ff fp cName = do printDebug "Inserted : " (length inserted) _ <- runCmd' $ mkDashboard corpusId2 userId - _ <- runCmd' $ mkGraph corpusId2 userId + _ <- runCmd' $ mkGraph corpusId2 userId + + -- Annuaire Flow + annuaireId <- runCmd' $ mkAnnuaire rootUserId userId pure corpusId2 -- runCmd' $ del [corpusId2, corpusId] type CorpusName = Text -subFlow :: Username -> CorpusName -> IO (UserId, RootId, CorpusId) -subFlow username cName = do +subFlowCorpus :: Username -> CorpusName -> IO (UserId, RootId, CorpusId) +subFlowCorpus username cName = do maybeUserId <- runCmd' (getUser username) let userId = case maybeUserId of diff --git a/src/Gargantext/Database/Ngrams.hs b/src/Gargantext/Database/Ngrams.hs index 30eb2307..307cd7f5 100644 --- a/src/Gargantext/Database/Ngrams.hs +++ b/src/Gargantext/Database/Ngrams.hs @@ -234,22 +234,24 @@ getNgramsTableData conn nodeT ngrmT (NgramsTableParam ul uc) (NgramsTableParam m querySelectTableNgrams :: DPS.Query querySelectTableNgrams = [sql| - WITH tableUser AS (select ngs.terms, ngs.n, nn1.ngrams_type,nn2.weight FROM ngrams ngs - JOIN nodes_ngrams nn1 ON nn1.ngram_id = ngs.id - JOIN nodes_ngrams nn2 ON nn2.ngram_id = ngs.id - JOIN nodes n ON n.id = nn2.node_id - WHERE nn1.node_id = ? -- User listId - AND n.parent_id = ? -- User CorpusId or AnnuaireId - AND n.typename = ? -- both type of childs (Documents or Contacts) - AND nn2.ngrams_type = ? -- both type of ngrams (Authors or Terms?) - ), tableMaster AS (select ngs.terms, ngs.n, nn1.ngrams_type,nn2.weight FROM ngrams ngs - JOIN nodes_ngrams nn1 ON nn1.ngram_id = ngs.id - JOIN nodes_ngrams nn2 ON nn2.ngram_id = ngs.id - JOIN nodes n ON n.id = nn2.node_id - WHERE nn1.node_id = ? -- Master listId - AND n.parent_id = ? -- Master CorpusId or AnnuaireId - AND n.typename = ? -- both type of childs (Documents or Contacts) - AND nn2.ngrams_type = ? -- both type of ngrams (Authors or Terms?) + WITH tableUser AS ( + SELECT ngs.terms, ngs.n, nn1.ngrams_type,nn2.weight FROM ngrams ngs + JOIN nodes_ngrams nn1 ON nn1.ngram_id = ngs.id + JOIN nodes_ngrams nn2 ON nn2.ngram_id = ngs.id + JOIN nodes n ON n.id = nn2.node_id + WHERE nn1.node_id = ? -- User listId + AND n.parent_id = ? -- User CorpusId or AnnuaireId + AND n.typename = ? -- both type of childs (Documents or Contacts) + AND nn2.ngrams_type = ? -- both type of ngrams (Authors or Terms?) + ), tableMaster AS ( + SELECT ngs.terms, ngs.n, nn1.ngrams_type,nn2.weight FROM ngrams ngs + JOIN nodes_ngrams nn1 ON nn1.ngram_id = ngs.id + JOIN nodes_ngrams nn2 ON nn2.ngram_id = ngs.id + JOIN nodes n ON n.id = nn2.node_id + WHERE nn1.node_id = ? -- Master listId + AND n.parent_id = ? -- Master CorpusId or AnnuaireId + AND n.typename = ? -- both type of childs (Documents or Contacts) + AND nn2.ngrams_type = ? -- both type of ngrams (Authors or Terms?) ) SELECT COALESCE(tu.terms,tm.terms) AS terms diff --git a/src/Gargantext/Database/Node.hs b/src/Gargantext/Database/Node.hs index b21cc316..80661ecb 100644 --- a/src/Gargantext/Database/Node.hs +++ b/src/Gargantext/Database/Node.hs @@ -40,6 +40,7 @@ import Prelude hiding (null, id, map, sum) import Gargantext.Core (Lang(..)) import Gargantext.Core.Types +import Gargantext.Database.Utils (fromField') import Gargantext.Database.Types.Node (NodeType, defaultCorpus, Hyperdata) import Gargantext.Database.Queries import Gargantext.Database.Config (nodeTypeId) @@ -139,16 +140,6 @@ instance QueryRunnerColumnDefault PGJsonb HyperdataAnnuaire where queryRunnerColumnDefault = fieldQueryRunnerColumn ------------------------------------------------------------------------ -fromField' :: (Typeable b, FromJSON b) => Field -> Maybe DB.ByteString -> Conversion b -fromField' field mb = do - v <- fromField field mb - valueToHyperdata v - where - valueToHyperdata v = case fromJSON v of - Success a -> pure a - Error _err -> returnError ConversionFailed field "cannot parse hyperdata" - - $(makeAdaptorAndInstance "pNode" ''NodePoly) $(makeLensesWith abbreviatedFields ''NodePoly) @@ -372,14 +363,7 @@ nodeAnnuaireW maybeName maybeAnnuaire pId = node NodeAnnuaire name annuaire (Jus name = maybe "Annuaire" identity maybeName annuaire = maybe defaultAnnuaire identity maybeAnnuaire -------------------------- -defaultContact :: HyperdataContact -defaultContact = HyperdataContact (Just "Name") (Just "email@here") -nodeContactW :: Maybe Name -> Maybe HyperdataContact -> AnnuaireId -> UserId -> NodeWrite' -nodeContactW maybeName maybeContact aId = node NodeContact name contact (Just aId) - where - name = maybe "Contact" identity maybeName - contact = maybe defaultContact identity maybeContact ------------------------------------------------------------------------ arbitraryList :: HyperdataList arbitraryList = HyperdataList (Just "Preferences") @@ -566,7 +550,8 @@ mkGraph p u = insertNodesR' [nodeGraphW Nothing Nothing p u] mkDashboard :: ParentId -> UserId -> Cmd [Int] mkDashboard p u = insertNodesR' [nodeDashboardW Nothing Nothing p u] +mkAnnuaire :: ParentId -> UserId -> Cmd [Int] +mkAnnuaire p u = insertNodesR' [nodeAnnuaireW Nothing Nothing p u] -- | Default CorpusId Master and ListId Master - diff --git a/src/Gargantext/Database/Node/Contact.hs b/src/Gargantext/Database/Node/Contact.hs new file mode 100644 index 00000000..b8ccff59 --- /dev/null +++ b/src/Gargantext/Database/Node/Contact.hs @@ -0,0 +1,112 @@ +{-| +Module : Gargantext.Database.Node.Contact +Description : Update Node in Database (Postgres) +Copyright : (c) CNRS, 2017-Present +License : AGPL + CECILL v3 +Maintainer : team@gargantext.org +Stability : experimental +Portability : POSIX + +-} + +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE FunctionalDependencies #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE TemplateHaskell #-} + +module Gargantext.Database.Node.Contact (NodeContact,HyperdataContact, ContactWho, ContactWhere, ContactTouch) + where + +import GHC.Generics (Generic) +import Data.Aeson.TH (deriveJSON) +import Data.Text (Text) +import qualified Data.Text as DT +import Control.Lens (makeLenses) +import Database.PostgreSQL.Simple +import Opaleye (QueryRunnerColumnDefault + , queryRunnerColumnDefault, PGJsonb, fieldQueryRunnerColumn) +import Gargantext.Database.Utils (fromField') +import Gargantext.Core.Utils.Prefix (unPrefix) +import Gargantext.Database.Node (NodeWrite', AnnuaireId, UserId, Name, node) +import Gargantext.Prelude +import Gargantext.Database.Types.Node (Node,Hyperdata,NodeType(..)) +import Data.Aeson (Result(Error,Success), fromJSON, FromJSON, ToJSON) +import Database.PostgreSQL.Simple.FromField ( Conversion + , ResultError(ConversionFailed) + , FromField + , fromField + , returnError + ) + +------------------------------------------------------------------------ + +type NodeContact = Node HyperdataContact + +data HyperdataContact = + HyperdataContact { _hc_who :: Maybe ContactWho + , _hc_where :: Maybe [ContactWhere] + , _hc_lastValidation :: Maybe Text + + } deriving (Eq, Show, Generic) + +arbitraryHyperdataContact :: HyperdataContact +arbitraryHyperdataContact = HyperdataContact Nothing Nothing Nothing + +data ContactWho = + ContactWho { _cw_id :: Maybe Int + , _cw_firstName :: Maybe Text + , _cw_lastName :: Maybe Text + , _cw_keywords :: Maybe [Text] + , _cw_freetags :: Maybe [Text] + } deriving (Eq, Show, Generic) + + +data ContactWhere = + ContactWhere { _cw_organization :: Maybe [Text] + , _cw_labTeamDepts :: Maybe [Text] + , _cw_role :: Maybe Text + , _cw_office :: Maybe Text + , _cw_country :: Maybe Text + , _cw_city :: Maybe Text + , _cw_touch :: Maybe ContactTouch + } deriving (Eq, Show, Generic) + +data ContactTouch = + ContactTouch { _ct_mail :: Maybe Text + , _ct_phone :: Maybe Text + , _ct_url :: Maybe Text + } deriving (Eq, Show, Generic) + + +nodeContactW :: Maybe Name -> Maybe HyperdataContact + -> AnnuaireId -> UserId -> NodeWrite' +nodeContactW maybeName maybeContact aId = + node NodeContact name contact (Just aId) + where + name = maybe "Contact" identity maybeName + contact = maybe arbitraryHyperdataContact identity maybeContact + + + +instance Hyperdata HyperdataContact +instance FromField HyperdataContact where + fromField = fromField' +instance QueryRunnerColumnDefault PGJsonb HyperdataContact where + queryRunnerColumnDefault = fieldQueryRunnerColumn + +{- +makeLenses ''ContactWho +makeLenses ''ContactWhere +makeLenses ''ContactTouch +makeLenses ''HyperdataContact +-} + +$(deriveJSON (unPrefix "_cw_") ''ContactWho) +$(deriveJSON (unPrefix "_cw_") ''ContactWhere) +$(deriveJSON (unPrefix "_ct_") ''ContactTouch) +$(deriveJSON (unPrefix "_hc_") ''HyperdataContact) + + diff --git a/src/Gargantext/Database/Types/Node.hs b/src/Gargantext/Database/Types/Node.hs index d87ff755..ae3923dc 100644 --- a/src/Gargantext/Database/Types/Node.hs +++ b/src/Gargantext/Database/Types/Node.hs @@ -54,7 +54,6 @@ import Test.QuickCheck (elements) import Gargantext.Prelude import Gargantext.Core.Utils.Prefix (unPrefix) - ------------------------------------------------------------------------ type UTCTime' = UTCTime @@ -260,13 +259,6 @@ hyperdataAnnuaire = HyperdataAnnuaire (Just "Annuaire Title") (Just "Annuaire De instance Arbitrary HyperdataAnnuaire where arbitrary = pure hyperdataAnnuaire -- TODO ------------------------------------------------------------------------- -data HyperdataContact = HyperdataContact { hyperdataContact_name :: Maybe Text - , hyperdataContact_mail :: Maybe Text - } deriving (Show, Generic) -$(deriveJSON (unPrefix "hyperdataContact_") ''HyperdataContact) - -instance Hyperdata HyperdataContact ------------------------------------------------------------------------ newtype HyperdataAny = HyperdataAny Object deriving (Show, Generic, ToJSON, FromJSON) @@ -352,7 +344,6 @@ type NodeCorpusV3 = Node HyperdataCorpus type NodeDocument = Node HyperdataDocument type NodeAnnuaire = Node HyperdataAnnuaire -type NodeContact = Node HyperdataContact ---- | Then a Node can be either a Graph or a Phylo or a Notebook type NodeList = Node HyperdataList diff --git a/src/Gargantext/Database/Utils.hs b/src/Gargantext/Database/Utils.hs index 76ef6476..beff14f8 100644 --- a/src/Gargantext/Database/Utils.hs +++ b/src/Gargantext/Database/Utils.hs @@ -19,15 +19,26 @@ module Gargantext.Database.Utils where import qualified Database.PostgreSQL.Simple as PGS +import Data.Aeson (Result(Error,Success), fromJSON, FromJSON) +import Data.Typeable (Typeable) import Data.Monoid ((<>)) import Data.Either.Extra (Either(Left, Right)) -import Gargantext.Prelude -import Data.Text (unpack, pack) -import Text.Read (read) +import Database.PostgreSQL.Simple.Internal (Field) +import qualified Data.ByteString as DB +import Database.PostgreSQL.Simple.FromField ( Conversion + , ResultError(ConversionFailed) + , FromField + , fromField + , returnError + ) + import Data.Ini (readIniFile, lookupValue) +import Data.Text (unpack, pack) import Data.Word (Word16) -import System.IO (FilePath) import Database.PostgreSQL.Simple (Connection, connect) +import Gargantext.Prelude +import System.IO (FilePath) +import Text.Read (read) -- Utilities import Opaleye (Query, Unpackspec, showSqlForPostgres) @@ -60,4 +71,14 @@ connectGargandb fp = databaseParameters fp >>= \params -> connect params printSql :: Default Unpackspec a a => Query a -> IO () printSql = putStrLn . maybe "Empty query" identity . showSqlForPostgres +fromField' :: (Typeable b, FromJSON b) => Field -> Maybe DB.ByteString -> Conversion b +fromField' field mb = do + v <- fromField field mb + valueToHyperdata v + where + valueToHyperdata v = case fromJSON v of + Success a -> pure a + Error _err -> returnError ConversionFailed field "cannot parse hyperdata" + + -- 2.21.0