{-# OPTIONS -fno-warn-orphans #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE FlexibleInstances #-} import Data.Proxy import Data.Patch(HunkStatus (..)) import Dixi.API import Dixi.Forms() import Dixi.Markup() import Servant.Docs import Servant.API import Servant.HTML.Blaze import System.Environment import Data.Text (Text) import Dixi.Config import Dixi.Page import Data.Time import Dixi.Common import Data.Monoid import Control.Lens import qualified Data.Vector as V import Text.Hamlet import Data.Aeson.Parser import Data.Attoparsec.ByteString.Lazy import Data.Aeson.Encode.Pretty import qualified Data.ByteString.Lazy as LBS instance ToSample RevReq where toSamples _ = just $ DR 5 7 (Just "Revert changes 5-6, 6-7") instance ToSample RawPage where toSamples _ = just $ RP defaultRenders "Page_Title" 3 $ Page "Some page content, in input format (e.g org mode)" (Last (Just "An optional comment")) (Last (Just (UTCTime (ModifiedJulianDay 0) 0))) instance ToSample PrettyPage where toSamples _ = just $ PP defaultRenders "Page_Title" 3 $ Page [shamlet|Some page content, in HTML from Pandoc.|] (Last (Just "An optional comment")) (Last (Just (UTCTime (ModifiedJulianDay 0) 0))) instance ToSample NewBody where toSamples _ = just $ NB "Some new content, in input format (e.g org mode)" (Just "An optional comment") instance ToSample History where toSamples _ = just $ H defaultRenders "Page_Title" [ Page (4, 9, 14) (Last (Just "Change 1")) (Last (Just (UTCTime (ModifiedJulianDay 0) 0))) , Page (12, 3, 1) (Last (Just "Change 2")) (Last (Just (UTCTime (ModifiedJulianDay 1) 0))) , Page (12, 0, 0) (Last (Just "Change 3")) (Last (Just (UTCTime (ModifiedJulianDay 2) 0))) ] instance ToSample DiffPage where toSamples _ = just $ DP defaultRenders "Page_Title" 5 7 (Page [ (V.fromList "This is the ", Unchanged) , (V.fromList "new", Replaced) , (V.fromList "ginal", Deleted) , (V.fromList " document.", Unchanged) ] (Last (Just "An optional comment")) (Last (Just (UTCTime (ModifiedJulianDay 0) 0)))) just x = [("",x)] instance ToParam (QueryParam "from" Int) where toParam _ = DocQueryParam "from" [] "Version to diff from, starting from 0 to N-1" Normal instance ToParam (QueryParam "to" Int) where toParam _ = DocQueryParam "to" [] "Version to diff to, from 1 to N" Normal instance ToCapture (Capture "page" Text) where toCapture _ = DocCapture "page" "Title of the page, using underscores for spaces." instance ToCapture (Capture "version" Int) where toCapture _ = DocCapture "version" "A page version to examine. All pages have a zeroth version, which is empty." main :: IO () main = do filename <- fmap (\x -> if null x then "docs.md" else head x) getArgs writeFile filename (markdown $ postprocess $ docsWith defaultDocOptions intro extra dixi) postprocess :: API -> API postprocess = over (apiEndpoints . traverse . rqbody) (filter ((== contentType (Proxy :: Proxy JSON)) . view _1) . fmap (over _2 prettify)) . over (apiEndpoints . traverse . response . respBody) (filter ((== contentType (Proxy :: Proxy JSON)) . view _2) . fmap (over _3 prettify)) diffNote, revertNote, historyNote, amendNote :: String -> [DocNote] diffNote page = [ DocNote "Description" [ "Compute the diff between two versions of " ++ page ++ "." , "If the `from` version is greater than the `to` version, they are swapped." ] , DocNote "Reponse details" ["Each diff hunk uses a single character string to " ++ "indicate the type of change, where " ++ "`+` is used for additions, `-` for deletions, and `~` for replacements."] ] revertNote page = [ DocNote "Description" [ "Apply a new patch which reverts any still-extant changes made in a certain version range of " ++ page ++ "." , "If the `from` version is greater than the `to` version they are swapped." ] , DocNote "Response details" ["The response is just the most recent version of the page, " ++ "with the revert patch applied."] ] historyNote page = [ DocNote "Description" [ "Returns the complete version history of " ++ page ++ ", with patch summaries, times, and change comments."]] amendNote page = [ DocNote "Description" [ "Submit a new version to be applied to the " ++ page ++ ", based on the given version." , "The change will be transformed and applied to the latest version." ] ] prettyNote, rawNote :: String -> String -> [DocNote] prettyNote version page = [ DocNote "Description" [ "Returns the " ++ version ++ " of the " ++ page ++ ", in HTML format as processed by Pandoc."]] rawNote version page = [ DocNote "Description" [ "Returns the " ++ version ++ " of the " ++ page ++ ", in the input format (e.g org mode, markdown)."]] intro :: [DocIntro] intro = [ DocIntro "Dixi API Documentation" ["What follows is the documentation for the JSON API of `dixi`." ,"Unlike other wikis `dixi` supports editing of any version of a page, and the changes will be propagated through to the latest version in a way that makes sense." ,"It is also able to revert changes (or the composition of several changes) from deep in a document's history and preserve every other change." ] , DocIntro "Structure" ["In general, there are two of each API action, one applying to a particular, specified page and one applying to the page entitled `Main_Page`" ,"The behaviour of these actions is identical, except for the page to which they apply."] ] prettify :: LBS.ByteString -> LBS.ByteString prettify x = go (parse json x) where go (Done _ r) = encodePretty r go _ = error "Error, cannot parse json value! Something is seriously wrong here." extra :: ExtraInfo Dixi extra = mconcat [ extraInfo (Proxy :: Proxy (Capture "page" Key :> "history" :> "diff" :> QueryParam "from" Version :> QueryParam "to" Version :> Get '[HTML,JSON] DiffPage)) $ defAction & notes <>~ diffNote "the given page" , extraInfo (Proxy :: Proxy ("history" :> "revert" :> ReqBody '[FormUrlEncoded, JSON] RevReq :> Post '[HTML, JSON] PrettyPage)) $ defAction & notes <>~ revertNote "the `Main_Page`" , extraInfo (Proxy :: Proxy ("history" :> "diff" :> QueryParam "from" Version :> QueryParam "to" Version :> Get '[HTML,JSON] DiffPage)) $ defAction & notes <>~ diffNote "the `Main_Page`" , extraInfo (Proxy :: Proxy (Capture "page" Key :> "history" :> "revert" :> ReqBody '[FormUrlEncoded, JSON] RevReq :> Post '[HTML, JSON] PrettyPage)) $ defAction & notes <>~ revertNote "the given page" , extraInfo (Proxy :: Proxy (Capture "page" Key :> "history" :> Get '[HTML, JSON] History)) $ defAction & notes <>~ historyNote "the given page" , extraInfo (Proxy :: Proxy ("history" :> Get '[HTML, JSON] History)) $ defAction & notes <>~ historyNote "the page entitled `Main_Page`" , extraInfo (Proxy :: Proxy (Capture "page" Key :> "history" :> Capture "version" Version :> Get '[HTML, JSON] PrettyPage)) $ defAction & notes <>~ prettyNote "given version" "given page" , extraInfo (Proxy :: Proxy ("history" :> Capture "version" Version :> Get '[HTML, JSON] PrettyPage)) $ defAction & notes <>~ prettyNote "given version" "page entitled `Main_Page`" , extraInfo (Proxy :: Proxy (Get '[HTML, JSON] PrettyPage)) $ defAction & notes <>~ prettyNote "latest version" "page entitled `Main_Page`" , extraInfo (Proxy :: Proxy (Capture "page" Key :> Get '[HTML, JSON] PrettyPage)) $ defAction & notes <>~ prettyNote "latest version" "given page" , extraInfo (Proxy :: Proxy (Capture "page" Key :> "history" :> Capture "version" Version :> "raw" :> Get '[HTML, JSON] RawPage)) $ defAction & notes <>~ rawNote "given version" "given page" , extraInfo (Proxy :: Proxy ("history" :> Capture "version" Version :> "raw" :> Get '[HTML, JSON] RawPage)) $ defAction & notes <>~ rawNote "given version" "page entitled `Main_Page`" , extraInfo (Proxy :: Proxy ("raw" :> Get '[HTML, JSON] RawPage)) $ defAction & notes <>~ rawNote "latest version" "page entitled `Main_Page`" , extraInfo (Proxy :: Proxy (Capture "page" Key :> "raw" :> Get '[HTML, JSON] RawPage)) $ defAction & notes <>~ rawNote "latest version" "given page" , extraInfo (Proxy :: Proxy (Capture "page" Key :> "history" :> Capture "version" Version :> ReqBody '[FormUrlEncoded, JSON] NewBody :> Post '[HTML, JSON] PrettyPage)) $ defAction & notes <>~ amendNote "given page" , extraInfo (Proxy :: Proxy ("history" :> Capture "version" Version :> ReqBody '[FormUrlEncoded, JSON] NewBody :> Post '[HTML, JSON] PrettyPage)) $ defAction & notes <>~ amendNote "`Main_Page`" ]