refactor(letter): i18n renewal letter templating

This commit is contained in:
Steffen Jost 2022-07-07 18:56:10 +02:00
parent a6782d8637
commit d078257a70
7 changed files with 71 additions and 76 deletions

View File

@ -133,7 +133,7 @@ MenuLmsUpload: Hochladen
MenuLmsDirect: Direkter Upload MenuLmsDirect: Direkter Upload
MenuAvs: Schnittstelle AVS MenuAvs: Schnittstelle AVS
MenuApc: Schnittstelle Druckerei MenuApc: Druckerei
MenuPrintSend: Manueller Briefversand MenuPrintSend: Manueller Briefversand
MenuApiDocs: API-Dokumentation (Englisch) MenuApiDocs: API-Dokumentation (Englisch)

View File

@ -134,7 +134,7 @@ MenuLmsUpload: Upload
MenuLmsDirect: Direct Upload MenuLmsDirect: Direct Upload
MenuAvs: AVS Interface MenuAvs: AVS Interface
MenuApc: Print Center Interface MenuApc: Printing
MenuPrintSend: Send Letter MenuPrintSend: Send Letter
MenuApiDocs: API documentation MenuApiDocs: API documentation

View File

@ -4,8 +4,8 @@ module Handler.Admin.Test
, getAdminTestPdfR , getAdminTestPdfR
) where ) where
import Import import Import
import Utils.Print import Utils.Print
import Handler.Utils import Handler.Utils
import Jobs import Jobs
@ -279,15 +279,15 @@ postAdminTestR = do
getAdminTestPdfR :: Handler TypedContent getAdminTestPdfR :: Handler TypedContent
getAdminTestPdfR = do getAdminTestPdfR = do
-- uUser <- maybeAuth -- to determine language for test -- uUser <- maybeAuth -- to determine language for test
templates <- liftIO $ do templates <- liftIO $ do
letter_tp <- P.compileTemplate "" templateRenewal letter_tp <- P.compileTemplate "" templateRenewal
din5008 <- P.compileTemplate "" templateDIN5008 din5008 <- P.compileTemplate "" templateDIN5008
now <- getCurrentTime now <- getCurrentTime
return (now, letter_tp, din5008) return (now, letter_tp, din5008)
case templates of case templates of
(_,Left err,_) -> sendResponseStatus internalServerError500 $ tshow err (_,Left err,_) -> sendResponseStatus internalServerError500 $ "Markdown template error: \n" <> err
(_,_,Left err) -> sendResponseStatus internalServerError500 $ tshow err (_,_,Left err) -> sendResponseStatus internalServerError500 $ "LaTeX template error: \n" <> err
(now, Right templ, Right latex) -> do (now, Right templ, Right latex) -> do
content <- liftIO . P.runIO $ do content <- liftIO . P.runIO $ do
let texopts = [] let texopts = []
@ -305,5 +305,5 @@ getAdminTestPdfR = do
Right (Right bs) -> do Right (Right bs) -> do
liftIO $ L.writeFile "/tmp/generated.pdf" bs liftIO $ L.writeFile "/tmp/generated.pdf" bs
sendByteStringAsFile "demoPDF.pdf" (L.toStrict bs) now sendByteStringAsFile "demoPDF.pdf" (L.toStrict bs) now
Right (Left err) -> sendResponseStatus internalServerError500 $ tshow err Right (Left err) -> sendResponseStatus internalServerError500 $ decodeUtf8 $ L.toStrict $ "LaTeX compile error: \n" <> err
Left err -> sendResponseStatus internalServerError500 $ P.renderError err Left err -> sendResponseStatus internalServerError500 $ "Pandoc error: \n" <> P.renderError err

View File

@ -21,9 +21,7 @@ import qualified Control.Monad.State.Class as State
import Handler.Utils import Handler.Utils
data MetaPinRenewal = MetaPinRenewal data MetaPinRenewal = MetaPinRenewal
{ mppOpening :: Maybe Text { mppDate :: Maybe Text
, mppClosing :: Maybe Text
, mppDate :: Maybe Text
, mppURL :: Maybe Text , mppURL :: Maybe Text
, mppLogin :: Text , mppLogin :: Text
, mppPin :: Text , mppPin :: Text
@ -35,9 +33,7 @@ data MetaPinRenewal = MetaPinRenewal
formToMetaValues :: MetaPinRenewal -> P.Meta formToMetaValues :: MetaPinRenewal -> P.Meta
formToMetaValues MetaPinRenewal{..} = P.Meta $ mconcat formToMetaValues MetaPinRenewal{..} = P.Meta $ mconcat
[ mbMeta "opening" mppOpening [ mbMeta "date" mppDate
, mbMeta "closing" mppClosing
, mbMeta "date" mppDate
, mbMeta "url" mppURL , mbMeta "url" mppURL
, toMeta "login" mppLogin , toMeta "login" mppLogin
, toMeta "pin" mppPin , toMeta "pin" mppPin
@ -51,13 +47,10 @@ formToMetaValues MetaPinRenewal{..} = P.Meta $ mconcat
html2textlines :: StoredMarkup -> [Text] html2textlines :: StoredMarkup -> [Text]
html2textlines sm = T.lines . LT.toStrict $ markupInput sm html2textlines sm = T.lines . LT.toStrict $ markupInput sm
makeRenewalForm :: Maybe MetaPinRenewal -> Form MetaPinRenewal makeRenewalForm :: Maybe MetaPinRenewal -> Form MetaPinRenewal
makeRenewalForm tmpl = identifyForm FIDLmsLetter . validateForm validateMetaPinRenewal $ \html -> makeRenewalForm tmpl = identifyForm FIDLmsLetter . validateForm validateMetaPinRenewal $ \html ->
flip (renderAForm FormStandard) html $ MetaPinRenewal flip (renderAForm FormStandard) html $ MetaPinRenewal
<$> aopt textField (fslI MsgMppOpening) (mppOpening <$> tmpl) <$> aopt textField (fslI MsgMppDate) (mppDate <$> tmpl)
<*> aopt textField (fslI MsgMppClosing) (mppClosing <$> tmpl)
<*> aopt textField (fslI MsgMppDate) (mppDate <$> tmpl)
<*> aopt textField (fslI MsgMppURL) (mppURL <$> tmpl) <*> aopt textField (fslI MsgMppURL) (mppURL <$> tmpl)
<*> areq textField (fslI MsgMppLogin) (mppLogin <$> tmpl) <*> areq textField (fslI MsgMppLogin) (mppLogin <$> tmpl)
<*> areq textField (fslI MsgMppPin) (mppPin <$> tmpl) <*> areq textField (fslI MsgMppPin) (mppPin <$> tmpl)

View File

@ -4,7 +4,7 @@ import Import.NoModel
-- import qualified Data.Foldable as Fold -- import qualified Data.Foldable as Fold
-- hiding (foldr) import Data.Foldable (foldr) -- hiding (foldr) import Data.Foldable (foldr)
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy as L
import Control.Monad.Except import Control.Monad.Except
import Import hiding (embedFile) import Import hiding (embedFile)
@ -35,23 +35,23 @@ templateDIN5008 = decodeUtf8 $(Data.FileEmbed.embedFile "templates/letter/din500
---------------------- ----------------------
-- Pandoc Functions -- -- Pandoc Functions --
---------------------- ----------------------
-- Either I don't understand how pandoc works or -- Either I don't understand how pandoc works or
-- I don't understand why these are not included -- I don't understand why these are not included
compileTemplate :: (P.PandocMonad m) => Text -> m (P.Template Text) compileTemplate :: (P.PandocMonad m) => Text -> m (P.Template Text)
compileTemplate tmpl = do compileTemplate tmpl = do
let partialPath = "" -- no partials used, see Text.DocTemplates let partialPath = "" -- no partials used, see Text.DocTemplates
mbTemplate <- P.runWithDefaultPartials $ P.compileTemplate partialPath tmpl mbTemplate <- P.runWithDefaultPartials $ P.compileTemplate partialPath tmpl
liftEither $ str2pandocError mbTemplate liftEither $ str2pandocError mbTemplate
where where
str2pandocError = over _Left $ P.PandocTemplateError . pack str2pandocError = over _Left $ P.PandocTemplateError . pack
makePDF :: P.WriterOptions -> P.Pandoc -> P.PandocIO L.ByteString makePDF :: P.WriterOptions -> P.Pandoc -> P.PandocIO L.ByteString
-- makePDF :: (PandocMonad m, MonadIO m, MonadMask m) => P.WriterOptions -> P.Pandoc -> m L.ByteString -- only pandoc >= 2.18 -- makePDF :: (PandocMonad m, MonadIO m, MonadMask m) => P.WriterOptions -> P.Pandoc -> m L.ByteString -- only pandoc >= 2.18
makePDF wopts doc = do makePDF wopts doc = do
mbPdf <- P.makePDF "lualatex" texopts P.writeLaTeX wopts doc mbPdf <- P.makePDF "lualatex" texopts P.writeLaTeX wopts doc
liftEither $ bs2pandocError mbPdf liftEither $ bs2pandocError mbPdf
where where
texopts = [] texopts = []
bs2pandocError = over _Left (P.PandocMakePDFError . decodeUtf8 . L.toStrict) bs2pandocError = over _Left (P.PandocMakePDFError . decodeUtf8 . L.toStrict)
@ -59,7 +59,7 @@ makePDF wopts doc = do
appMeta :: (P.Meta -> P.Meta) -> P.Pandoc -> P.Pandoc appMeta :: (P.Meta -> P.Meta) -> P.Pandoc -> P.Pandoc
appMeta f (P.Pandoc m bs) = P.Pandoc (f m) bs appMeta f (P.Pandoc m bs) = P.Pandoc (f m) bs
-- applyMetas :: (P.HasMeta p, Foldable t, P.ToMetaValue a) => t (Text, a) -> p -> p -- applyMetas :: (P.HasMeta p, Foldable t, P.ToMetaValue a) => t (Text, a) -> p -> p
-- applyMetas metas doc = Fold.foldr (uncurry P.setMeta) doc metas -- applyMetas metas doc = Fold.foldr (uncurry P.setMeta) doc metas
-- | Add meta to pandoc. Existing variables will be overwritten. -- | Add meta to pandoc. Existing variables will be overwritten.
@ -70,15 +70,15 @@ addMeta m = appMeta (m <>)
-- | Pandoc conditionals only test if a variable is set or isn't set. -- | Pandoc conditionals only test if a variable is set or isn't set.
-- Variable "is-de" will be set to True if the "lang" variable starts with "de" -- Variable "is-de" will be set to True if the "lang" variable starts with "de"
-- and will be unset otherwise -- and will be unset otherwise
setIsDeFromLang :: P.Meta -> P.Meta setIsDeFromLang :: P.Meta -> P.Meta
setIsDeFromLang m setIsDeFromLang m
| (Just (P.MetaString t)) <- P.lookupMeta "lang" m | (Just (P.MetaString t)) <- P.lookupMeta "lang" m
, T.isPrefixOf "de" t , T.isPrefixOf "de" t
= P.setMeta isde True m = P.setMeta isde True m
| otherwise = P.deleteMeta isde m | otherwise = P.deleteMeta isde m
where where
isde = "is-de" isde = "is-de"
@ -92,31 +92,31 @@ setIsDeFromLang m
-- An alternative Route would be to use Builders, but this prevents User-edited Markup Templates -- An alternative Route would be to use Builders, but this prevents User-edited Markup Templates
reTemplateLetter :: P.PandocMonad m => P.Meta -> StoredMarkup -> m Text reTemplateLetter :: P.PandocMonad m => P.Meta -> StoredMarkup -> m Text
reTemplateLetter meta StoredMarkup{..} = do reTemplateLetter meta StoredMarkup{..} = do
tmpl <- compileTemplate strictMarkupInput tmpl <- compileTemplate strictMarkupInput
-- TODO: write cacheHere Version using DB Key of StoredMarkup with Unique DB Argument instead of StoredMarkup -- TODO: write cacheHere Version using DB Key of StoredMarkup with Unique DB Argument instead of StoredMarkup
doc1 <- areader readerOpts strictMarkupInput doc1 <- areader readerOpts strictMarkupInput
let writerOpts = def { P.writerTemplate = Just tmpl } let writerOpts = def { P.writerTemplate = Just tmpl }
P.writeMarkdown writerOpts P.writeMarkdown writerOpts
$ appMeta setIsDeFromLang $ appMeta setIsDeFromLang
$ addMeta meta doc1 $ addMeta meta doc1
where where
strictMarkupInput = toStrict markupInput strictMarkupInput = toStrict markupInput
readerOpts = def { P.readerExtensions = P.pandocExtensions readerOpts = def { P.readerExtensions = P.pandocExtensions
, P.readerStripComments = True , P.readerStripComments = True
} }
-- reader :: (P.PandocMonad m, P.ToSources a) => P.ReaderOptions -> a -> m P.Pandoc -- reader :: (P.PandocMonad m, P.ToSources a) => P.ReaderOptions -> a -> m P.Pandoc
areader = case markupInputFormat of areader = case markupInputFormat of
MarkupHtml -> P.readHtml MarkupHtml -> P.readHtml
MarkupMarkdown -> P.readMarkdown MarkupMarkdown -> P.readMarkdown
MarkupPlaintext -> P.readMarkdown MarkupPlaintext -> P.readMarkdown
--pdfDIN5008 :: P.PandocMonad m => Text -> m L.ByteString -- for pandoc > 2.18 --pdfDIN5008 :: P.PandocMonad m => Text -> m L.ByteString -- for pandoc > 2.18
pdfDIN5008 :: Text -> P.PandocIO L.ByteString pdfDIN5008 :: Text -> P.PandocIO L.ByteString
pdfDIN5008 md = do pdfDIN5008 md = do
tmpl <- compileTemplate templateDIN5008 tmpl <- compileTemplate templateDIN5008
let readerOpts = def { P.readerExtensions = P.pandocExtensions } let readerOpts = def { P.readerExtensions = P.pandocExtensions }
writerOpts = def { P.writerTemplate = Just tmpl } writerOpts = def { P.writerTemplate = Just tmpl }
doc <- P.readMarkdown readerOpts md doc <- P.readMarkdown readerOpts md
makePDF writerOpts doc makePDF writerOpts doc
@ -125,9 +125,9 @@ pdfDIN5008' md = do
etmpl <- $cachedHereBinary ("din5008"::Text) (liftIO . P.runIO $ compileTemplate templateDIN5008) etmpl <- $cachedHereBinary ("din5008"::Text) (liftIO . P.runIO $ compileTemplate templateDIN5008)
case etmpl of case etmpl of
Left err -> return $ Left err Left err -> return $ Left err
Right tmpl -> liftIO . P.runIO $ do Right tmpl -> liftIO . P.runIO $ do
let readerOpts = def { P.readerExtensions = P.pandocExtensions } let readerOpts = def { P.readerExtensions = P.pandocExtensions }
writerOpts = def { P.writerTemplate = Just tmpl } writerOpts = def { P.writerTemplate = Just tmpl }
doc <- P.readMarkdown readerOpts md doc <- P.readMarkdown readerOpts md
makePDF writerOpts doc makePDF writerOpts doc

View File

@ -8,7 +8,7 @@
fromlogo=false, % don't show logo in letter head fromlogo=false, % don't show logo in letter head
version=last, % latest version of KOMA letter version=last, % latest version of KOMA letter
pagenumber=botright, % show pagenumbers on bottom right pagenumber=botright, % show pagenumbers on bottom right
firstfoot=true % first-page footer firstfoot=false % first-page footer
]{scrlttr2} ]{scrlttr2}
\PassOptionsToPackage{hyphens}{url} \PassOptionsToPackage{hyphens}{url}
@ -76,6 +76,7 @@ $endif$
\usepackage{parskip} \usepackage{parskip}
\usepackage{graphics} \usepackage{graphics}
\usepackage{xcolor}
\usepackage{booktabs} \usepackage{booktabs}
\usepackage{longtable} \usepackage{longtable}
@ -123,16 +124,28 @@ $endif$
$endfor$ $endfor$
} }
\opening{$opening$} $if(is-de)$
\opening{$de-opening$}
$else$
\opening{$en-opening$}
$endif$
\begin{textblock}{13}(15,45) \begin{textblock}{13}(15,45)
$pin$ \textcolor{gray}{
\begin{labeling}{Login:x}
\item[Login:] $login$
\item[Pin:] $pin$
\end{labeling}
~}
\end{textblock} \end{textblock}
$body$ $body$
\vspace{1.2cm} $if(is-de)$
\closing{$closing$} \closing{$de-closing$}
$else$
\closing{$en-closing$}
$endif$
%\ps $postskriptum$ %\ps $postskriptum$

View File

@ -5,13 +5,18 @@ subject: Verlängerung Vorfeldführerschein
author: Fraport AG - Fahrerausbildung (AVN-AR) author: Fraport AG - Fahrerausbildung (AVN-AR)
phone: +49 69 690-30306 phone: +49 69 690-30306
email: fahrerausbildung@fraport.de email: fahrerausbildung@fraport.de
url: <http://www.fraport.de/fahrerausbildung>
place: Frankfurt/Main place: Frankfurt/Main
return-address: return-address:
- 60547 Frankfurt - 60547 Frankfurt
opening: Sehr geehrte Damen und Herren, de-opening: Sehr geehrte Damen und Herren,
closing: | en-opening: Dear driver,
de-closing: |
Mit freundlichen Grüßen, Mit freundlichen Grüßen,
Ihre Fahrerausbildung. Ihre Fahrerausbildung.
en-closing: |
Best wishes,
Your fraport driving instructors from "Fahrerausbildung".
encludes: encludes:
hyperrefoptions: hidelinks hyperrefoptions: hidelinks
@ -36,21 +41,13 @@ Durch die erfolgreiche Teilnahme an einem E-Lernen können Sie
die Gültigkeit um 2 Jahre verlängern. Verwenden Sie dazu folgende die Gültigkeit um 2 Jahre verlängern. Verwenden Sie dazu folgende
Login-Daten. Login-Daten.
URL Name
: <http://www.fraport.de/fahrerausbildung>
Name:
: $recipient$ : $recipient$
Login URL
: $login$ : $url$
Pin
: $pin$
Sobald die Frist abgelaufen ist, muss zur Wiedererlangung des Vorfeldführerscheins Sobald die Frist abgelaufen ist, muss zur Wiedererlangung des Vorfeldführerscheins
@ -66,21 +63,13 @@ your apron diving licence is about to expire soon.
You may renew your apron driving licence by two years through successfully You may renew your apron driving licence by two years through successfully
completing an e-learning course. Please use the following login data. completing an e-learning course. Please use the following login data.
URL Name
: <http://www.fraport.de/fahrerausbildung>
Name:
: $recipient$ : $recipient$
Login URL
: $login$ : $url$
Pin
: $pin$
Should your apron driving licence expire before completing this Should your apron driving licence expire before completing this