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)
13 import Servant.Job.Async (JobFunction(..), serveJobsAPI)
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.Types (HasSettings)
22 import Gargantext.API.Node.Types
23 import Gargantext.API.Prelude
24 import Gargantext.Core.Types (TODO)
25 import Gargantext.Database.Action.Flow.Types
26 import Gargantext.Database.Action.Node (mkNodeWithParent)
27 import Gargantext.Database.Admin.Types.Hyperdata.File
28 import Gargantext.Database.Admin.Types.Node
29 import Gargantext.Database.Query.Table.Node (getNodeWith)
30 import Gargantext.Database.Query.Table.Node.UpdateOpaleye (updateHyperdata)
31 import Gargantext.Database.Schema.Node (node_hyperdata)
32 import Gargantext.Prelude
34 data RESPONSE deriving Typeable
36 instance Accept RESPONSE where
37 contentType _ = "text" M.// "*"
39 instance MimeRender RESPONSE BSResponse where
40 mimeRender _ (BSResponse val) = BSL.fromStrict $ val
42 type FileApi = Summary "File download"
44 :> Get '[RESPONSE] (Headers '[Servant.Header "Content-Type" Text] BSResponse)
46 fileApi :: UserId -> NodeId -> GargServer FileApi
47 fileApi uId nId = fileDownload uId nId
49 newtype Contents = Contents BS.ByteString
51 instance GargDB.ReadFile Contents where
56 newtype BSResponse = BSResponse BS.ByteString
59 instance ToSchema BSResponse where
60 declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy TODO)
62 fileDownload :: (HasSettings env, FlowCmdM env err m)
65 -> m (Headers '[Servant.Header "Content-Type" Text] BSResponse)
66 fileDownload uId nId = do
67 printDebug "[fileDownload] uId" uId
68 printDebug "[fileDownload] nId" nId
70 node <- getNodeWith nId (Proxy :: Proxy HyperdataFile)
71 let (HyperdataFile { _hff_name = name'
72 , _hff_path = path }) = node ^. node_hyperdata
74 Contents c <- GargDB.readFile $ unpack path
76 let (mMime, _) = DMT.guessType DMT.defaultmtd False $ unpack name'
79 Nothing -> "text/plain"
81 pure $ addHeader (pack mime) $ BSResponse c
85 -- let settings = embeddedSettings [("", encodeUtf8 c)]
87 -- Tagged $ staticApp settings
89 -- let settings = embeddedSettings [("", "hello")]
90 -- Tagged $ staticApp settings
92 type FileAsyncApi = Summary "File Async Api"
95 :> AsyncJobs JobLog '[FormUrlEncoded] NewWithFile JobLog
97 fileAsyncApi :: UserId -> NodeId -> GargServer FileAsyncApi
98 fileAsyncApi uId nId =
103 printDebug "addWithFile" x
105 in addWithFile uId nId i log')
108 addWithFile :: (HasSettings env, FlowCmdM env err m)
114 addWithFile uId nId nwf@(NewWithFile _d _l fName) logStatus = do
116 printDebug "[addWithFile] Uploading file: " nId
117 logStatus JobLog { _scst_succeeded = Just 0
118 , _scst_failed = Just 0
119 , _scst_remaining = Just 1
120 , _scst_events = Just []
123 fPath <- GargDB.writeFile nwf
124 printDebug "[addWithFile] File saved as: " fPath
126 nIds <- mkNodeWithParent NodeFile (Just nId) uId fName
130 node <- getNodeWith nId' (Proxy :: Proxy HyperdataFile)
131 let hl = node ^. node_hyperdata
132 _ <- updateHyperdata nId' $ hl { _hff_name = fName
133 , _hff_path = pack fPath }
135 printDebug "[addWithFile] Created node with id: " nId'
138 printDebug "[addWithFile] File upload finished: " nId
139 pure $ JobLog { _scst_succeeded = Just 1
140 , _scst_failed = Just 0
141 , _scst_remaining = Just 0
142 , _scst_events = Just []