2 Module : Gargantext.Viz.Graph
4 Copyright : (c) CNRS, 2017-Present
5 License : AGPL + CECILL v3
6 Maintainer : team@gargantext.org
7 Stability : experimental
13 {-# OPTIONS_GHC -fno-warn-orphans #-}
15 {-# LANGUAGE OverloadedLists #-} -- allows to write Map and HashMap as lists
16 {-# LANGUAGE TypeOperators #-}
18 module Gargantext.Viz.Graph.API
21 import Control.Lens (set, (^.), _Just, (^?))
23 import Data.Maybe (Maybe(..))
26 import Debug.Trace (trace)
27 import GHC.Generics (Generic)
28 import Gargantext.API.Admin.Orchestrator.Types
29 import Gargantext.API.Ngrams (NgramsRepo, r_version)
30 import Gargantext.API.Ngrams.Tools
31 import Gargantext.API.Prelude
32 import Gargantext.Core.Types.Main
33 import Gargantext.Database.Action.Metrics.NgramsByNode (getNodesByNgramsOnlyUser)
34 import Gargantext.Database.Admin.Config
35 import Gargantext.Database.Admin.Types.Node
36 import Gargantext.Database.Prelude (Cmd)
37 import Gargantext.Database.Query.Table.Node
38 import Gargantext.Database.Query.Table.Node.Error (HasNodeError)
39 import Gargantext.Database.Query.Table.Node.Select
40 import Gargantext.Database.Query.Table.Node.UpdateOpaleye (updateHyperdata)
41 import Gargantext.Database.Schema.Ngrams
42 import Gargantext.Database.Schema.Node (node_parentId, node_hyperdata)
43 import Gargantext.Prelude
44 import Gargantext.Viz.Graph
45 import Gargantext.Viz.Graph.GEXF ()
46 import Gargantext.Viz.Graph.Tools -- (cooc2graph)
47 import Gargantext.Viz.Graph.Distances (Distance(..), GraphMetric(..))
49 import Servant.Job.Async
51 import qualified Data.Map as Map
53 ------------------------------------------------------------------------
54 -- | There is no Delete specific API for Graph since it can be deleted
56 type GraphAPI = Get '[JSON] Graph
57 :<|> "gexf" :> Get '[XML] (Headers '[Servant.Header "Content-Disposition" Text] Graph)
59 :<|> "versions" :> GraphVersionsAPI
62 GraphVersions { gv_graph :: Maybe Int
65 deriving (Show, Generic)
67 instance ToJSON GraphVersions
68 instance ToSchema GraphVersions
70 graphAPI :: UserId -> NodeId -> GargServer GraphAPI
71 graphAPI u n = getGraph u n
74 :<|> graphVersionsAPI u n
76 ------------------------------------------------------------------------
77 getGraph :: UserId -> NodeId -> GargNoServer Graph
78 getGraph _uId nId = do
79 nodeGraph <- getNodeWith nId HyperdataGraph
80 let graph = nodeGraph ^. node_hyperdata . hyperdataGraph
84 let cId = maybe (panic "[G.V.G.API] Node has no parent")
86 $ nodeGraph ^. node_parentId
88 -- TODO Distance in Graph params
91 graph' <- computeGraph cId Conditional NgramsTerms repo
92 _ <- updateHyperdata nId (HyperdataGraph $ Just graph')
93 pure $ trace "[G.V.G.API] Graph empty, computing" graph'
95 Just graph' -> pure $ trace "[G.V.G.API] Graph exists, returning" graph'
98 recomputeGraph :: UserId -> NodeId -> Distance -> GargNoServer Graph
99 recomputeGraph _uId nId d = do
100 nodeGraph <- getNodeWith nId HyperdataGraph
101 let graph = nodeGraph ^. node_hyperdata . hyperdataGraph
102 let listVersion = graph ^? _Just
109 let v = repo ^. r_version
110 let cId = maybe (panic "[G.V.G.API.recomputeGraph] Node has no parent")
112 $ nodeGraph ^. node_parentId
116 graph' <- computeGraph cId d NgramsTerms repo
117 _ <- updateHyperdata nId (HyperdataGraph $ Just graph')
118 pure $ trace "[G.V.G.API.recomputeGraph] Graph empty, computed" graph'
120 Just graph' -> if listVersion == Just v
123 graph'' <- computeGraph cId d NgramsTerms repo
124 _ <- updateHyperdata nId (HyperdataGraph $ Just graph'')
125 pure $ trace "[G.V.G.API] Graph exists, recomputing" graph''
128 -- TODO use Database Monad only here ?
129 computeGraph :: HasNodeError err
135 computeGraph cId d nt repo = do
136 lId <- defaultList cId
138 let metadata = GraphMetadata "Title"
141 [ LegendField 1 "#FFF" "Cluster"
142 , LegendField 2 "#FFF" "Cluster"
144 (ListForGraph lId (repo ^. r_version))
145 -- (map (\n -> LegendField n "#FFFFFF" (pack $ show n)) [1..10])
147 lIds <- selectNodesWithUsername NodeList userMaster
148 let ngs = filterListWithRoot MapTerm $ mapTermListRoot [lId] nt repo
150 -- TODO split diagonal
151 myCooc <- Map.filter (>1)
152 <$> getCoocByNgrams (Diagonal True)
153 <$> groupNodesByNgrams ngs
154 <$> getNodesByNgramsOnlyUser cId (lIds <> [lId]) nt (Map.keys ngs)
156 graph <- liftBase $ cooc2graph d 0 myCooc
157 let graph' = set graph_metadata (Just metadata) graph
160 ------------------------------------------------------------
161 type GraphAsyncAPI = Summary "Update graph"
163 :> AsyncJobsAPI JobLog () JobLog
166 graphAsync :: UserId -> NodeId -> GargServer GraphAsyncAPI
169 JobFunction (\_ log' -> graphAsync' u n (liftBase . log'))
172 graphAsync' :: UserId
174 -> (JobLog -> GargNoServer ())
175 -> GargNoServer JobLog
176 graphAsync' u n logStatus = do
177 logStatus JobLog { _scst_succeeded = Just 0
178 , _scst_failed = Just 0
179 , _scst_remaining = Just 1
180 , _scst_events = Just []
182 _g <- trace (show u) $ recomputeGraph u n Conditional
183 pure JobLog { _scst_succeeded = Just 1
184 , _scst_failed = Just 0
185 , _scst_remaining = Just 0
186 , _scst_events = Just []
189 ------------------------------------------------------------
190 type GraphVersionsAPI = Summary "Graph versions"
191 :> Get '[JSON] GraphVersions
192 :<|> Summary "Recompute graph version"
193 :> Post '[JSON] Graph
195 graphVersionsAPI :: UserId -> NodeId -> GargServer GraphVersionsAPI
196 graphVersionsAPI u n =
198 :<|> recomputeVersions u n
200 graphVersions :: UserId -> NodeId -> GargNoServer GraphVersions
201 graphVersions _uId nId = do
202 nodeGraph <- getNodeWith nId HyperdataGraph
203 let graph = nodeGraph ^. node_hyperdata . hyperdataGraph
204 let listVersion = graph ^? _Just
211 let v = repo ^. r_version
213 pure $ GraphVersions { gv_graph = listVersion
216 recomputeVersions :: UserId -> NodeId -> GargNoServer Graph
217 recomputeVersions uId nId = recomputeGraph uId nId Conditional
219 ------------------------------------------------------------
220 getGraphGexf :: UserId
222 -> GargNoServer (Headers '[Servant.Header "Content-Disposition" Text] Graph)
223 getGraphGexf uId nId = do
224 graph <- getGraph uId nId
225 pure $ addHeader "attachment; filename=graph.gexf" graph