Creating boards if they don't exist

This commit is contained in:
towards-a-new-leftypol 2023-10-07 01:12:30 -04:00
parent 0f77c17e5c
commit 8d3a2c05d0
6 changed files with 99 additions and 20 deletions

View File

@ -69,6 +69,8 @@ executable chan-delorean
JSONParsing JSONParsing
DataClient DataClient
Types Types
SitesType
BoardsType
-- LANGUAGE extensions used by modules in this package. -- LANGUAGE extensions used by modules in this package.
-- other-extensions: -- other-extensions:

View File

@ -39,7 +39,7 @@ CREATE TABLE IF NOT EXISTS sites
CREATE TABLE IF NOT EXISTS boards CREATE TABLE IF NOT EXISTS boards
( board_id serial primary key ( board_id serial primary key
, name text NOT NULL , name text
, pathpart text NOT NULL -- if it's /a/ then the pathpart is a , pathpart text NOT NULL -- if it's /a/ then the pathpart is a
, site_id int NOT NULL , site_id int NOT NULL
, CONSTRAINT site_fk FOREIGN KEY (site_id) REFERENCES sites (site_id) ON DELETE CASCADE , CONSTRAINT site_fk FOREIGN KEY (site_id) REFERENCES sites (site_id) ON DELETE CASCADE
@ -117,7 +117,8 @@ GRANT SELECT ON boards TO chan_archive_anon;
GRANT SELECT ON threads TO chan_archive_anon; GRANT SELECT ON threads TO chan_archive_anon;
GRANT SELECT ON posts TO chan_archive_anon; GRANT SELECT ON posts TO chan_archive_anon;
GRANT SELECT ON attachments TO chan_archive_anon; GRANT SELECT ON attachments TO chan_archive_anon;
GRANT usage, select ON SEQUENCE sites_site_id_seq TO chan_archive_anon; -- GRANT usage, select ON SEQUENCE sites_site_id_seq TO chan_archive_anon;
-- GRANT usage, select ON SEQUENCE boards_board_id_seq TO chan_archive_anon;
GRANT chan_archive_anon TO admin; GRANT chan_archive_anon TO admin;
CREATE ROLE chan_archiver noinherit login password 'test_password'; CREATE ROLE chan_archiver noinherit login password 'test_password';
@ -130,6 +131,7 @@ GRANT ALL ON posts TO chan_archiver;
GRANT ALL ON attachments TO chan_archiver; GRANT ALL ON attachments TO chan_archiver;
GRANT EXECUTE ON FUNCTION update_post_body_search_index TO chan_archiver; GRANT EXECUTE ON FUNCTION update_post_body_search_index TO chan_archiver;
GRANT usage, select ON SEQUENCE sites_site_id_seq TO chan_archiver; GRANT usage, select ON SEQUENCE sites_site_id_seq TO chan_archiver;
GRANT usage, select ON SEQUENCE boards_board_id_seq TO chan_archiver;
GRANT chan_archiver TO admin; GRANT chan_archiver TO admin;
COMMIT; COMMIT;

View File

@ -12,10 +12,13 @@ import System.Console.CmdArgs
import System.Directory (listDirectory, doesFileExist) import System.Directory (listDirectory, doesFileExist)
import System.FilePath ((</>)) import System.FilePath ((</>))
import Data.List (find) import Data.List (find)
import qualified Data.Set as Set
import JSONParsing import JSONParsing
import Types import Types
import qualified DataClient as Client import qualified DataClient as Client
import qualified SitesType as Sites
import qualified BoardsType as Boards
data SettingsCLI = SettingsCLI data SettingsCLI = SettingsCLI
{ jsonFile :: FilePath { jsonFile :: FilePath
@ -43,10 +46,10 @@ ensureSiteExists settings = do
case sitesResult of case sitesResult of
Right siteList -> Right siteList ->
case find (\site -> Client.name site == site_name settings) siteList of case find (\site -> Sites.name site == site_name settings) siteList of
Just site -> do Just site -> do
putStrLn $ site_name settings ++ " already exists!" putStrLn $ site_name settings ++ " already exists!"
return $ Client.site_id site return $ Sites.site_id site
Nothing -> do Nothing -> do
putStrLn $ site_name settings ++ " does not exist. Creating..." putStrLn $ site_name settings ++ " does not exist. Creating..."
postResult <- Client.postSite settings postResult <- Client.postSite settings
@ -54,7 +57,7 @@ ensureSiteExists settings = do
case postResult of case postResult of
Right (site:_) -> do Right (site:_) -> do
putStrLn $ "Successfully created " ++ site_name settings ++ ". " ++ show site putStrLn $ "Successfully created " ++ site_name settings ++ ". " ++ show site
return $ Client.site_id site return $ Sites.site_id site
Right [] -> do Right [] -> do
putStrLn $ "Did not get new site id back from postgrest" putStrLn $ "Did not get new site id back from postgrest"
exitFailure exitFailure
@ -68,6 +71,29 @@ ensureSiteExists settings = do
exitFailure exitFailure
createArchivesForNewBoards :: JSONSettings -> [ String ] -> [ String ] -> Int -> IO [ Boards.Board ]
createArchivesForNewBoards settings dirs archived_boards siteid = do
let dirsSet = Set.fromList dirs
let archivedBoardsSet = Set.fromList archived_boards
-- Find boards that are in dirs but not in archived_boards
let boardsToArchive = dirsSet `Set.difference` archivedBoardsSet
putStrLn "Creating boards:"
mapM_ putStrLn boardsToArchive
post_result <- Client.postBoards settings (Set.toList boardsToArchive) siteid
case post_result of
Left err -> do
putStrLn $ "Error posting boards: " ++ show err
exitFailure
Right boards -> do
putStrLn "Created the following boards:"
mapM_ putStrLn (map Boards.pathpart boards)
return boards
processBackupDirectory :: JSONSettings -> IO () processBackupDirectory :: JSONSettings -> IO ()
processBackupDirectory settings = do processBackupDirectory settings = do
putStrLn "JSON successfully read!" putStrLn "JSON successfully read!"
@ -76,14 +102,17 @@ processBackupDirectory settings = do
dirs <- listCatalogDirectories settings dirs <- listCatalogDirectories settings
boards_result <- Client.getSiteBoards settings site_id_ boards_result <- Client.getSiteBoards settings site_id_
putStrLn "Boards fetched!" putStrLn "Boards fetched!"
case boards_result of case boards_result of
Left err -> do Left err -> do
putStrLn $ "Error fetching boards: " ++ show err putStrLn $ "Error fetching boards: " ++ show err
exitFailure exitFailure
Right archived_boards -> do Right archived_boards -> do
print archived_boards let boardnames = map Boards.pathpart archived_boards
created_boards <- createArchivesForNewBoards settings dirs boardnames site_id_
let boards :: [ Boards.Board ] = archived_boards ++ created_boards
return ()
mapM_ putStrLn dirs
mapM_ processDir dirs mapM_ processDir dirs
where where
backupDir :: FilePath backupDir :: FilePath
@ -102,6 +131,7 @@ processBackupDirectory settings = do
putStrLn $ "Failed to parse the JSON file in directory: " putStrLn $ "Failed to parse the JSON file in directory: "
++ dir ++ ". Error: " ++ errMsg ++ dir ++ ". Error: " ++ errMsg
main :: IO () main :: IO ()
main = do main = do
settingsValue <- cmdArgs settingsCLI settingsValue <- cmdArgs settingsCLI

16
src/BoardsType.hs Normal file
View File

@ -0,0 +1,16 @@
{-# LANGUAGE DeriveAnyClass #-}
module BoardsType
( Board (..) )
where
import GHC.Generics
import Data.Aeson (FromJSON)
data Board = Board
{ board_id :: Int
, name :: Maybe String
, pathpart :: String
, site_id :: Int
} deriving (Show, Generic, FromJSON)

View File

@ -1,4 +1,3 @@
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
module DataClient module DataClient
@ -8,7 +7,7 @@ module DataClient
, getAllSites , getAllSites
, postSite , postSite
, post , post
, SiteResponse(..) , postBoards
) where ) where
import Network.HTTP.Simple import Network.HTTP.Simple
@ -23,21 +22,18 @@ import Data.Aeson
, (.=) , (.=)
, object , object
, encode , encode
, Value
) )
import GHC.Generics
import qualified Types as T import qualified Types as T
import qualified SitesType as Sites
import qualified BoardsType as Boards
data HttpError data HttpError
= HttpException SomeException = HttpException SomeException
| StatusCodeError Int LBS.ByteString | StatusCodeError Int LBS.ByteString
deriving (Show) deriving (Show)
data SiteResponse = SiteResponse
{ site_id :: Int
, name :: String
, url :: String
} deriving (Show, Generic, FromJSON)
get :: T.JSONSettings -> String -> IO (Either HttpError LBS.ByteString) get :: T.JSONSettings -> String -> IO (Either HttpError LBS.ByteString)
get settings path = do get settings path = do
@ -87,13 +83,13 @@ handleHttp action = do
Left e -> return $ Left $ HttpException e Left e -> return $ Left $ HttpException e
getSiteBoards :: T.JSONSettings -> Int -> IO (Either HttpError [ String ]) getSiteBoards :: T.JSONSettings -> Int -> IO (Either HttpError [ Boards.Board ])
getSiteBoards settings site_id_ = get settings path >>= return . eitherDecodeResponse getSiteBoards settings site_id_ = get settings path >>= return . eitherDecodeResponse
where where
path = "/boards?select=name&site_id=eq." ++ show site_id_ path = "/boards?select=*&site_id=eq." ++ show site_id_
postSite :: T.JSONSettings -> IO (Either HttpError [SiteResponse]) postSite :: T.JSONSettings -> IO (Either HttpError [ Sites.Site ])
postSite settings = postSite settings =
post settings "/sites" payload True >>= return . eitherDecodeResponse post settings "/sites" payload True >>= return . eitherDecodeResponse
@ -103,10 +99,28 @@ postSite settings =
, "url" .= T.site_url settings , "url" .= T.site_url settings
] ]
postBoards
:: T.JSONSettings
-> [] String
-> Int
-> IO (Either HttpError [ Boards.Board ])
postBoards settings boards siteid =
post settings "/boards" payload True >>= return . eitherDecodeResponse
getAllSites :: T.JSONSettings -> IO (Either HttpError [SiteResponse]) where
payload = encode $ fmap mk_obj boards
mk_obj :: String -> Value
mk_obj board = object
[ "pathpart" .= board
, "site_id" .= siteid
]
getAllSites :: T.JSONSettings -> IO (Either HttpError [ Sites.Site ])
getAllSites settings = get settings "/sites" >>= return . eitherDecodeResponse getAllSites settings = get settings "/sites" >>= return . eitherDecodeResponse
eitherDecodeResponse :: (FromJSON a) => Either HttpError LBS.ByteString -> Either HttpError a eitherDecodeResponse :: (FromJSON a) => Either HttpError LBS.ByteString -> Either HttpError a
eitherDecodeResponse (Left err) = Left err eitherDecodeResponse (Left err) = Left err
eitherDecodeResponse (Right bs) = eitherDecodeResponse (Right bs) =

15
src/SitesType.hs Normal file
View File

@ -0,0 +1,15 @@
{-# LANGUAGE DeriveAnyClass #-}
module SitesType
( Site (..) )
where
import GHC.Generics
import Data.Aeson (FromJSON)
data Site = Site
{ site_id :: Int
, name :: String
, url :: String
} deriving (Show, Generic, FromJSON)