1 {-# OPTIONS_GHC -fno-warn-orphans -fno-warn-unused-matches #-}
3 {-# LANGUAGE AllowAmbiguousTypes #-}
4 {-# LANGUAGE TypeOperators #-}
6 {-# LANGUAGE IncoherentInstances #-}
7 module Gargantext.API.Node.File where
9 import Control.Lens ((^.))
12 import GHC.Generics (Generic)
14 import qualified Data.ByteString as BS
15 import qualified Data.ByteString.Lazy as BSL
16 import qualified Data.MIME.Types as DMT
17 import qualified Gargantext.Database.GargDB as GargDB
18 import qualified Network.HTTP.Media as M
20 import Gargantext.API.Admin.Orchestrator.Types (JobLog(..), AsyncJobs)
21 import Gargantext.API.Admin.EnvTypes (GargJob(..), Env)
22 import Gargantext.API.Admin.Types (HasSettings)
23 import Gargantext.API.Node.Types
24 import Gargantext.API.Prelude
25 import Gargantext.Core.Types (TODO)
26 import Gargantext.Database.Action.Flow.Types
27 import Gargantext.Database.Action.Node (mkNodeWithParent)
28 import Gargantext.Database.Admin.Types.Hyperdata.File
29 import Gargantext.Database.Admin.Types.Node
30 import Gargantext.Database.Query.Table.Node (getNodeWith)
31 import Gargantext.Database.Query.Table.Node.UpdateOpaleye (updateHyperdata)
32 import Gargantext.Database.Schema.Node (node_hyperdata)
33 import Gargantext.Prelude
34 import Gargantext.Utils.Jobs (serveJobsAPI)
37 data RESPONSE deriving Typeable
39 instance Accept RESPONSE where
40 contentType _ = "text" M.// "*"
42 instance MimeRender RESPONSE BSResponse where
43 mimeRender _ (BSResponse val) = BSL.fromStrict $ val
45 type FileApi = Summary "File download"
47 :> Get '[RESPONSE] (Headers '[Servant.Header "Content-Type" Text] BSResponse)
49 instance MimeUnrender RESPONSE BSResponse where
50 mimeUnrender _ lbs = Right $ BSResponse (BSL.toStrict lbs)
52 fileApi :: UserId -> NodeId -> GargServer FileApi
53 fileApi uId nId = fileDownload uId nId
55 newtype Contents = Contents BS.ByteString
57 instance GargDB.ReadFile Contents where
62 newtype BSResponse = BSResponse BS.ByteString
65 instance ToSchema BSResponse where
66 declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy TODO)
68 fileDownload :: (HasSettings env, FlowCmdM env err m)
71 -> m (Headers '[Servant.Header "Content-Type" Text] BSResponse)
72 fileDownload uId nId = do
73 -- printDebug "[fileDownload] uId" uId
74 -- printDebug "[fileDownload] nId" nId
76 node <- getNodeWith nId (Proxy :: Proxy HyperdataFile)
77 let (HyperdataFile { _hff_name = name'
78 , _hff_path = path }) = node ^. node_hyperdata
80 Contents c <- GargDB.readGargFile $ unpack path
82 let (mMime, _) = DMT.guessType DMT.defaultmtd False $ unpack name'
85 Nothing -> "text/plain"
87 pure $ addHeader (pack mime) $ BSResponse c
91 -- let settings = embeddedSettings [("", encodeUtf8 c)]
93 -- Tagged $ staticApp settings
95 -- let settings = embeddedSettings [("", "hello")]
96 -- Tagged $ staticApp settings
98 type FileAsyncApi = Summary "File Async Api"
101 :> AsyncJobs JobLog '[FormUrlEncoded] NewWithFile JobLog
103 fileAsyncApi :: UserId -> NodeId -> ServerT FileAsyncApi (GargM Env GargError)
104 fileAsyncApi uId nId =
105 serveJobsAPI AddFileJob $ \i l ->
108 -- printDebug "addWithFile" x
110 in addWithFile uId nId i log'
113 addWithFile :: (HasSettings env, FlowCmdM env err m)
119 addWithFile uId nId nwf@(NewWithFile _d _l fName) logStatus = do
121 -- printDebug "[addWithFile] Uploading file: " nId
122 logStatus JobLog { _scst_succeeded = Just 0
123 , _scst_failed = Just 0
124 , _scst_remaining = Just 1
125 , _scst_events = Just []
128 fPath <- GargDB.writeFile nwf
129 -- printDebug "[addWithFile] File saved as: " fPath
131 nIds <- mkNodeWithParent NodeFile (Just nId) uId fName
135 node <- getNodeWith nId' (Proxy :: Proxy HyperdataFile)
136 let hl = node ^. node_hyperdata
137 _ <- updateHyperdata nId' $ hl { _hff_name = fName
138 , _hff_path = pack fPath }
140 -- printDebug "[addWithFile] Created node with id: " nId'
144 -- printDebug "[addWithFile] File upload finished: " nId
145 pure $ JobLog { _scst_succeeded = Just 1
146 , _scst_failed = Just 0
147 , _scst_remaining = Just 0
148 , _scst_events = Just []