module Gargantext.API.Server.Named.Public ( serverPublicGargAPI ) where import Control.Lens ((^?), _Just) import Data.List qualified as List import Data.Map.Strict qualified as Map import Data.Set qualified as Set import Gargantext.API.Node.File (fileApi) import Gargantext.API.Prelude (serverError, IsGargServer) import Gargantext.API.Public.Types import Gargantext.Core.Utils.DateUtils (utc2year) import Gargantext.Database.Admin.Types.Hyperdata.Corpus ( hc_fields ) import Gargantext.Database.Admin.Types.Hyperdata.CorpusField import Gargantext.Database.Admin.Types.Hyperdata.Folder ( HyperdataFolder ) import Gargantext.Database.Admin.Types.Node ( NodeId(..), Node, unNodeId ) import Gargantext.Database.Prelude (Cmd, DBCmd) import Gargantext.Database.Query.Table.Node.Error (HasNodeError(..)) import Gargantext.Database.Query.Table.NodeNode (selectPublicNodes) import Gargantext.Database.Schema.Node ( NodePoly(..), node_date, node_hyperdata ) -- (NodePoly(..)) import Gargantext.Prelude import Servant import Servant.Server.Generic (AsServerT) import qualified Gargantext.API.Routes.Named.File as Named import qualified Gargantext.API.Routes.Named.Public as Named serverPublicGargAPI :: IsGargServer env err m => Text -> Named.GargPublicAPI (AsServerT m) serverPublicGargAPI baseUrl = Named.GargPublicAPI { publicHomeAPI = api_home baseUrl , publicNodeAPI = Named.NodeAPI api_node } api_home :: IsGargServer env err m => Text -> Named.HomeAPI (AsServerT m) api_home baseUrl = Named.HomeAPI $ catMaybes <$> map (toPublicData baseUrl) <$> filterPublicDatas <$> selectPublic api_node :: IsGargServer env err m => NodeId -> Named.FileAPI (AsServerT m) api_node nId = Named.FileAPI $ do pubNodes <- publicNodes -- TODO optimize with SQL case Set.member nId pubNodes of False -> serverError $ err405 { errBody = "Not allowed" } True -> fileApi nId ------------------------------------------------------------------------- selectPublic :: HasNodeError err => DBCmd err [( Node HyperdataFolder, Maybe Int)] selectPublic = selectPublicNodes -- For tests only -- pure $ replicate 6 defaultPublicData filterPublicDatas :: [(Node HyperdataFolder, Maybe Int)] -> [(Node HyperdataFolder, [NodeId])] filterPublicDatas datas = map (\(n,mi) -> let mi' = UnsafeMkNodeId <$> mi in ( _node_id n, (n, maybe [] (:[]) mi' )) ) datas & Map.fromListWith (\(n1,i1) (_n2,i2) -> (n1, i1 <> i2)) & Map.filter (not . null . snd) & Map.elems publicNodes :: HasNodeError err => Cmd err (Set NodeId) publicNodes = do candidates <- filterPublicDatas <$> selectPublicNodes pure $ Set.fromList $ List.concat $ map (\(n, ns) -> (_node_id n) : ns) candidates -- http://localhost:8008/api/v1.0/node/23543/file/download -- http://localhost:8000/images/Gargantextuel-212x300.jpg toPublicData :: Text -> (Node HyperdataFolder, [NodeId]) -> Maybe PublicData toPublicData base (n , mn) = do title <- (hd ^? (_Just . hf_data . cf_title)) abstract <- (hd ^? (_Just . hf_data . cf_desc )) img <- (Just $ url' mn) -- "images/Gargantextuel-212x300.jpg" url <- (Just $ url' mn) date <- Just (show $ utc2year (n^.node_date)) database <- (hd ^? (_Just . hf_data . cf_query)) author <- (hd ^? (_Just . hf_data . cf_authors)) pure $ PublicData { .. } where hd = head $ filter (\(HyperdataField cd _ _) -> cd == JSON) $ n^. (node_hyperdata . hc_fields) url' :: [NodeId] -> Text url' mn' = base <> "/public/" <> (show $ (maybe 0 unNodeId $ head mn')) <> "/file/download"