2 Module : Gargantext.Core.Text.List.Social
4 Copyright : (c) CNRS, 2018-Present
5 License : AGPL + CECILL v3
6 Maintainer : team@gargantext.org
7 Stability : experimental
11 module Gargantext.Core.Text.List.Social
15 import Gargantext.Core.Types.Individu
16 import Gargantext.Database.Admin.Config
17 import Gargantext.Database.Admin.Types.Node
18 import Gargantext.Database.Prelude
19 import Gargantext.Database.Query.Table.Node.Error
20 import Gargantext.Database.Query.Tree
21 import Gargantext.Database.Query.Tree.Root (getRootId)
22 import Gargantext.Prelude
25 import Data.Maybe (fromMaybe)
28 import Data.Semigroup (Semigroup(..))
29 import Data.Text (Text)
30 import Gargantext.API.Ngrams.Tools -- (getListNgrams)
31 import Gargantext.API.Ngrams.Types
32 import Gargantext.Core.Types.Main
33 import Gargantext.Database.Schema.Ngrams
34 import qualified Data.List as List
35 import qualified Data.Map as Map
36 import qualified Data.Set as Set
38 flowSocialList :: ( RepoCmdM env err m
43 => User -> NgramsType -> Set Text
44 -> m (Map ListType (Set Text))
45 flowSocialList user nt ngrams' = do
46 privateLists <- flowSocialListByMode Private user nt ngrams'
47 printDebug "* privateLists *: \n" privateLists
48 -- here preference to privateLists (discutable)
49 sharedLists <- flowSocialListByMode Shared user nt (termsByList CandidateTerm privateLists)
50 printDebug "* sharedLists *: \n" sharedLists
53 let result = unions [ Map.mapKeys (fromMaybe CandidateTerm) privateLists
54 , Map.mapKeys (fromMaybe CandidateTerm) sharedLists
56 printDebug "* socialLists *: results \n" sharedLists
60 ------------------------------------------------------------------------
61 unions :: (Ord a, Semigroup a, Semigroup b, Ord b)
62 => [Map a (Set b)] -> Map a (Set b)
63 unions = foldl' union Map.empty
65 union :: (Ord a, Semigroup a, Semigroup b, Ord b)
66 => Map a (Set b) -> Map a (Set b) -> Map a (Set b)
67 union m1 m2 = invertBack $ Map.unionWith (<>) (invert m1) (invert m2)
69 invert :: (Ord b, Semigroup a) => Map a (Set b) -> Map b a
70 invert = Map.unionsWith (<>)
71 . (map (\(k,ss) -> Map.fromSet (\_ -> k) ss))
74 invertBack :: (Ord a, Ord b) => Map b a -> Map a (Set b)
75 invertBack = Map.fromListWith (<>)
76 . (map (\(b,a) -> (a, Set.singleton b)))
79 ------------------------------------------------------------------------
81 termsByList :: ListType -> (Map (Maybe ListType) (Set Text)) -> Set Text
82 termsByList CandidateTerm m = Set.unions
83 $ map (\lt -> fromMaybe Set.empty $ Map.lookup lt m)
84 [ Nothing, Just CandidateTerm ]
86 fromMaybe Set.empty $ Map.lookup (Just l) m
89 flowSocialListByMode :: ( RepoCmdM env err m
94 => NodeMode -> User -> NgramsType -> Set Text
95 -> m (Map (Maybe ListType) (Set Text))
96 flowSocialListByMode mode user nt ngrams' = do
97 listIds <- findListsId mode user
99 [] -> pure $ Map.fromList [(Nothing, ngrams')]
101 counts <- countFilterList ngrams' nt listIds Map.empty
102 printDebug "flowSocialListByMode counts" counts
103 let r = toSocialList counts ngrams'
104 printDebug "flowSocialListByMode r" r
107 ---------------------------------------------------------------------------
108 -- TODO: maybe use social groups too
109 toSocialList :: Map Text (Map ListType Int)
111 -> Map (Maybe ListType) (Set Text)
112 toSocialList m = Map.fromListWith (<>)
114 . Set.map (toSocialList1 m)
116 -- | TODO what if equality ?
117 -- choice depends on Ord instance of ListType
118 -- for now : data ListType = StopTerm | CandidateTerm | MapTerm
119 -- means MapTerm > CandidateTerm > StopTerm in case of equality of counts
120 -- (we minimize errors on MapTerms if doubt)
121 toSocialList1 :: Map Text (Map ListType Int)
123 -> (Maybe ListType, Set Text)
124 toSocialList1 m t = case Map.lookup t m of
125 Nothing -> (Nothing, Set.singleton t)
126 Just m' -> ( (fst . fst) <$> Map.maxViewWithKey m'
130 toSocialList1_testIsTrue :: Bool
131 toSocialList1_testIsTrue = result == (Just MapTerm, Set.singleton token)
133 result = toSocialList1 (Map.fromList [(token, m)]) token
135 m = Map.fromList [ (CandidateTerm, 1)
140 ---------------------------------------------------------------------------
141 -- | [ListId] does not merge the lists (it is for Master and User lists
142 -- here we need UserList only
143 countFilterList :: RepoCmdM env err m
144 => Set Text -> NgramsType -> [ListId]
145 -> Map Text (Map ListType Int)
146 -> m (Map Text (Map ListType Int))
147 countFilterList st nt ls input =
148 foldM' (\m l -> countFilterList' st nt [l] m) input ls
151 countFilterList' :: RepoCmdM env err m
152 => Set Text -> NgramsType -> [ListId]
153 -> Map Text (Map ListType Int)
154 -> m (Map Text (Map ListType Int))
155 countFilterList' st nt ls input = do
156 ml <- toMapTextListType <$> getListNgrams ls nt
157 -- printDebug "countFilterList'" ml
158 pure $ Set.foldl' (\m t -> countList t ml m) input st
160 ---------------------------------------------------------------------------
161 -- FIXME children have to herit the ListType of the parent
162 toMapTextListType :: Map Text NgramsRepoElement -> Map Text ListType
163 toMapTextListType m = Map.fromListWith (<>)
168 toList :: Map Text NgramsRepoElement -> (Text, NgramsRepoElement) -> [(Text, ListType)]
169 toList m (t, nre@(NgramsRepoElement _ _ _ _ (MSet children))) =
170 List.zip terms (List.cycle [lt'])
173 -- <> maybe [] (\n -> [unNgramsTerm n]) root
174 -- <> maybe [] (\n -> [unNgramsTerm n]) parent
175 <> (map unNgramsTerm $ Map.keys children)
178 listOf :: Map Text NgramsRepoElement -> NgramsRepoElement -> ListType
179 listOf m ng = case _nre_parent ng of
180 Nothing -> _nre_list ng
181 Just p -> case Map.lookup (unNgramsTerm p) m of
182 Just ng' -> listOf m ng'
183 Nothing -> CandidateTerm -- Should Not happen
185 ---------------------------------------------------------------------------
188 -> Map Text (Map ListType Int)
189 -> Map Text (Map ListType Int)
190 countList t m input = case Map.lookup t m of
192 Just l -> Map.alter addList t input
194 addList Nothing = Just $ addCount l Map.empty
195 addList (Just lm) = Just $ addCount l lm
197 addCount :: ListType -> Map ListType Int -> Map ListType Int
198 addCount l m = Map.alter plus l m
200 plus Nothing = Just 1
201 plus (Just x) = Just $ x + 1
203 ------------------------------------------------------------------------
204 findListsId :: (HasNodeError err, HasTreeError err)
205 => NodeMode -> User -> Cmd err [NodeId]
206 findListsId mode u = do
208 ns <- map _dt_nodeId <$> filter (\n -> _dt_typeId n == nodeTypeId NodeList)
209 <$> findNodes' mode r
210 -- printDebug "findListsIds" ns
213 commonNodes:: [NodeType]
214 commonNodes = [NodeFolder, NodeCorpus, NodeList]
216 findNodes' :: HasTreeError err
217 => NodeMode -> RootId
218 -> Cmd err [DbTreeNode]
219 findNodes' Private r = findNodes Private r $ [NodeFolderPrivate] <> commonNodes
220 findNodes' Shared r = findNodes Shared r $ [NodeFolderShared ] <> commonNodes
221 findNodes' Public r = findNodes Public r $ [NodeFolderPublic ] <> commonNodes