2 Module : Gargantext.Prelude.Utils
3 Description : Useful Tools near Prelude of the project
4 Copyright : (c) CNRS, 2017-Present
5 License : AGPL + CECILL v3
6 Maintainer : team@gargantext.org
7 Stability : experimental
12 {-# OPTIONS_GHC -fno-warn-orphans #-}
14 module Gargantext.Prelude.Utils
17 import Prelude (String)
19 import Data.List (foldl)
20 import Control.Lens (view)
21 import Control.Monad.Random.Class (MonadRandom)
22 import Control.Monad.Reader (MonadReader)
23 import Control.Monad.Reader (ask)
24 import Data.Text (Text)
25 import GHC.IO (FilePath)
26 import Gargantext.API.Admin.Settings
27 import Gargantext.Database.Admin.Types.Node (NodeId, NodeType)
28 import Gargantext.Prelude
29 import System.Directory (createDirectoryIfMissing)
30 import System.Random (newStdGen)
31 import qualified Data.ByteString.Lazy.Char8 as Char
32 import qualified Data.Digest.Pure.SHA as SHA (sha256, showDigest)
33 import qualified Data.Set as Set
34 import qualified Data.Text as Text
35 import qualified System.Random.Shuffle as SRS
37 --------------------------------------------------------------------------
38 shuffle :: MonadRandom m => [a] -> m [a]
39 shuffle ns = SRS.shuffleM ns
41 --------------------------------------------------------------------------
42 -- | Use this datatype to keep traceability of hashes
46 -- | Class to make hashes
47 class IsHashable a where
50 -- | Main API to hash text
51 -- using sha256 for now
52 instance IsHashable Char.ByteString where
57 instance {-# OVERLAPPING #-} IsHashable String where
58 hash = hash . Char.pack
60 instance IsHashable Text where
61 hash = hash . Text.unpack
63 instance IsHashable (Set Hash) where
64 hash = hash . foldl (<>) "" . Set.toList
66 instance {-# OVERLAPPABLE #-} IsHashable a => IsHashable [a] where
67 hash = hash . Set.fromList . map hash
69 --------------------------------------------------------------------------
70 data NodeToHash = NodeToHash { nodeType :: NodeType
74 type FolderPath = FilePath
75 type FileName = FilePath
77 toPath :: Int -> Text -> (FolderPath,FileName)
78 toPath n x = (Text.unpack $ Text.intercalate "/" [x1,x2], Text.unpack xs)
80 (x1,x') = Text.splitAt n x
81 (x2,xs) = Text.splitAt n x'
83 class SaveFile a where
84 saveFile' :: FilePath -> a -> IO ()
86 class ReadFile a where
87 readFile' :: FilePath -> IO a
90 writeFile :: (MonadReader env m, MonadBase IO m, HasSettings env, SaveFile a)
93 dataPath <- view (settings . fileFolder) <$> ask
94 (fp,fn) <- liftBase $ (toPath 3) . hash . show <$> newStdGen
96 let foldPath = dataPath <> "/" <> fp
97 filePath = foldPath <> "/" <> fn
99 _ <- liftBase $ createDirectoryIfMissing True foldPath
100 _ <- liftBase $ saveFile' filePath a
105 readFile :: (MonadReader env m, MonadBase IO m, HasSettings env, ReadFile a)
108 dataPath <- view (settings . fileFolder) <$> ask
109 liftBase $ readFile' $ dataPath <> "/" <> fp