1 {-# OPTIONS_GHC -fno-warn-orphans -fno-warn-unused-matches #-}
3 {-# LANGUAGE AllowAmbiguousTypes #-}
4 {-# LANGUAGE TypeOperators #-}
6 module Gargantext.API.Node.File where
8 import Control.Lens ((^.))
11 import GHC.Generics (Generic)
12 import Gargantext.API.Admin.Orchestrator.Types (JobLog(..), AsyncJobs)
13 import Gargantext.API.Admin.Types (HasSettings)
14 import Gargantext.API.Node.Types
15 import Gargantext.API.Prelude
16 import Gargantext.Core.Types (TODO)
17 import Gargantext.Database.Action.Flow.Types
18 import Gargantext.Database.Action.Node (mkNodeWithParent)
19 import Gargantext.Database.Admin.Types.Hyperdata.File
20 import Gargantext.Database.Admin.Types.Node
21 import Gargantext.Database.Query.Table.Node (getNodeWith)
22 import Gargantext.Database.Query.Table.Node.UpdateOpaleye (updateHyperdata)
23 import Gargantext.Database.Schema.Node (node_hyperdata)
24 import Gargantext.Prelude
26 import Servant.Job.Async (JobFunction(..), serveJobsAPI)
27 import qualified Data.ByteString as BS
28 import qualified Data.ByteString.Lazy as BSL
29 import qualified Data.MIME.Types as DMT
30 import qualified Gargantext.Database.GargDB as GargDB
31 import qualified Network.HTTP.Media as M
33 data RESPONSE deriving Typeable
35 instance Accept RESPONSE where
36 contentType _ = "text" M.// "*"
38 instance MimeRender RESPONSE BSResponse where
39 mimeRender _ (BSResponse val) = BSL.fromStrict $ val
41 type FileApi = Summary "File download"
43 :> Get '[RESPONSE] (Headers '[Servant.Header "Content-Type" Text] BSResponse)
45 fileApi :: UserId -> NodeId -> GargServer FileApi
46 fileApi uId nId = fileDownload uId nId
48 newtype Contents = Contents BS.ByteString
50 instance GargDB.ReadFile Contents where
55 newtype BSResponse = BSResponse BS.ByteString
58 instance ToSchema BSResponse where
59 declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy TODO)
61 fileDownload :: (HasSettings env, FlowCmdM env err m)
64 -> m (Headers '[Servant.Header "Content-Type" Text] BSResponse)
65 fileDownload uId nId = do
66 printDebug "[fileDownload] uId" uId
67 printDebug "[fileDownload] nId" nId
69 node <- getNodeWith nId (Proxy :: Proxy HyperdataFile)
70 let (HyperdataFile { _hff_name = name'
71 , _hff_path = path }) = node ^. node_hyperdata
73 Contents c <- GargDB.readFile $ unpack path
75 let (mMime, _) = DMT.guessType DMT.defaultmtd False $ unpack name'
78 Nothing -> "text/plain"
80 pure $ addHeader (pack mime) $ BSResponse c
84 -- let settings = embeddedSettings [("", encodeUtf8 c)]
86 -- Tagged $ staticApp settings
88 -- let settings = embeddedSettings [("", "hello")]
89 -- Tagged $ staticApp settings
91 type FileAsyncApi = Summary "File Async Api"
94 :> AsyncJobs JobLog '[FormUrlEncoded] NewWithFile JobLog
96 fileAsyncApi :: UserId -> NodeId -> GargServer FileAsyncApi
97 fileAsyncApi uId nId =
102 printDebug "addWithFile" x
104 in addWithFile uId nId i log')
107 addWithFile :: (HasSettings env, FlowCmdM env err m)
113 addWithFile uId nId nwf@(NewWithFile _d _l fName) logStatus = do
115 printDebug "[addWithFile] Uploading file: " nId
116 logStatus JobLog { _scst_succeeded = Just 0
117 , _scst_failed = Just 0
118 , _scst_remaining = Just 1
119 , _scst_events = Just []
122 fPath <- GargDB.writeFile nwf
123 printDebug "[addWithFile] File saved as: " fPath
125 nIds <- mkNodeWithParent NodeFile (Just nId) uId fName
129 node <- getNodeWith nId' (Proxy :: Proxy HyperdataFile)
130 let hl = node ^. node_hyperdata
131 _ <- updateHyperdata nId' $ hl { _hff_name = fName
132 , _hff_path = pack fPath }
134 printDebug "[addWithFile] Created node with id: " nId'
137 printDebug "[addWithFile] File upload finished: " nId
138 pure $ JobLog { _scst_succeeded = Just 1
139 , _scst_failed = Just 0
140 , _scst_remaining = Just 0
141 , _scst_events = Just []