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 Servant.Job.Async (JobFunction(..), serveJobsAPI)
15 import qualified Data.ByteString as BS
16 import qualified Data.ByteString.Lazy as BSL
17 import qualified Data.MIME.Types as DMT
18 import qualified Gargantext.Database.GargDB as GargDB
19 import qualified Network.HTTP.Media as M
21 import Gargantext.API.Admin.Orchestrator.Types (JobLog(..), AsyncJobs)
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
36 data RESPONSE deriving Typeable
38 instance Accept RESPONSE where
39 contentType _ = "text" M.// "*"
41 instance MimeRender RESPONSE BSResponse where
42 mimeRender _ (BSResponse val) = BSL.fromStrict $ val
44 type FileApi = Summary "File download"
46 :> Get '[RESPONSE] (Headers '[Servant.Header "Content-Type" Text] BSResponse)
48 instance MimeUnrender RESPONSE BSResponse where
49 mimeUnrender _ lbs = Right $ BSResponse (BSL.toStrict lbs)
51 fileApi :: UserId -> NodeId -> GargServer FileApi
52 fileApi uId nId = fileDownload uId nId
54 newtype Contents = Contents BS.ByteString
56 instance GargDB.ReadFile Contents where
61 newtype BSResponse = BSResponse BS.ByteString
64 instance ToSchema BSResponse where
65 declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy TODO)
67 fileDownload :: (HasSettings env, FlowCmdM env err m)
70 -> m (Headers '[Servant.Header "Content-Type" Text] BSResponse)
71 fileDownload uId nId = do
72 printDebug "[fileDownload] uId" uId
73 printDebug "[fileDownload] nId" nId
75 node <- getNodeWith nId (Proxy :: Proxy HyperdataFile)
76 let (HyperdataFile { _hff_name = name'
77 , _hff_path = path }) = node ^. node_hyperdata
79 Contents c <- GargDB.readFile $ unpack path
81 let (mMime, _) = DMT.guessType DMT.defaultmtd False $ unpack name'
84 Nothing -> "text/plain"
86 pure $ addHeader (pack mime) $ BSResponse c
90 -- let settings = embeddedSettings [("", encodeUtf8 c)]
92 -- Tagged $ staticApp settings
94 -- let settings = embeddedSettings [("", "hello")]
95 -- Tagged $ staticApp settings
97 type FileAsyncApi = Summary "File Async Api"
100 :> AsyncJobs JobLog '[FormUrlEncoded] NewWithFile JobLog
102 fileAsyncApi :: UserId -> NodeId -> GargServer FileAsyncApi
103 fileAsyncApi uId nId =
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'
143 printDebug "[addWithFile] File upload finished: " nId
144 pure $ JobLog { _scst_succeeded = Just 1
145 , _scst_failed = Just 0
146 , _scst_remaining = Just 0
147 , _scst_events = Just []