tvl-depot/tools/website-blocker/main.hs
William Carroll ef5eda4015 Implement isToday predicate
Use the Data.Time package to implement the isToday predicate.
2020-03-29 00:00:47 +00:00

103 lines
3.4 KiB
Haskell

{-# LANGUAGE NamedFieldPuns #-}
module Main (main) where
--------------------------------------------------------------------------------
-- Dependencies
--------------------------------------------------------------------------------
import qualified Data.Maybe as Maybe
import qualified Data.Time.Clock as Clock
import qualified Data.Time.Calendar as Calendar
--------------------------------------------------------------------------------
-- Types
--------------------------------------------------------------------------------
newtype URL = URL { getURL :: String } deriving (Show)
newtype IPAddress = IPAddress { getIPAddress :: String } deriving (Show)
newtype Domain = Domain { getDomain :: String } deriving (Show)
newtype Hour = Hour { getHour :: Integer }
newtype Minute = Minute { getMinute :: Integer }
data EtcHostEntry = EtcHostEntry { ip :: IPAddress
, domains :: [Domain]
} deriving (Show)
data TimeRange = TimeRange { beg :: (Hour, Minute)
, end :: (Hour, Minute)
}
data Allowance = Allowance { day :: Calendar.DayOfWeek
, timeslots :: [TimeRange]
}
data Rule = Rule { urls :: [URL]
, allowed :: [Allowance]
}
--------------------------------------------------------------------------------
-- Functions
--------------------------------------------------------------------------------
isToday :: Clock.UTCTime -> Calendar.DayOfWeek -> Bool
isToday date day = Calendar.dayOfWeek (Clock.utctDay date) == day
isAllowed :: Clock.UTCTime -> [Allowance] -> Bool
isAllowed _ [] = False
isAllowed date xs = do
let rules = filter (isToday date . day) xs
case rules of
[day] -> True
[] -> False
-- Error when more than one rule per day
_ -> False
serializeEntry :: EtcHostEntry -> String
serializeEntry EtcHostEntry{ip, domains} =
(getIPAddress ip) ++ "\t" ++ (unwords $ fmap getDomain domains)
toEtcHostEntry :: Clock.UTCTime -> Rule -> Maybe EtcHostEntry
toEtcHostEntry date Rule{urls, allowed} =
if isAllowed date allowed then
Nothing
else
Just $ EtcHostEntry { ip = IPAddress "127.0.0.1"
, domains = fmap (Domain . getURL) urls
}
-- | Location of the rules.json file.
rulesFile :: FilePath
rulesFile =
"~/.config/website-blocker/rules.json"
-- | Reads and parses JSON from `rulesFile` and returns the result.
getRules :: IO [Rule]
getRules = pure $
[ Rule { urls = [ URL "facebook.com"
, URL "twitter.com"
, URL "youtube.com"
, URL "instagram.com"
]
, allowed = []
}
, Rule { urls = [ URL "chat.googleplex.com" ]
, allowed = [ Allowance { day = Calendar.Saturday
, timeslots = [ TimeRange { beg = (Hour 0, Minute 0)
, end = (Hour 0, Minute 0)
}
]
}
]
}
]
main :: IO ()
main = do
rules <- getRules
date <- Clock.getCurrentTime
let etcHosts = unlines . fmap serializeEntry . Maybe.catMaybes $ fmap (toEtcHostEntry date) rules
putStrLn etcHosts