github.com/benoitkugler/goacve@v0.0.0-20201217100549-151ce6e55dc8/server/core/utils/pdf/lettre_directeur.go (about) 1 package pdf 2 3 import ( 4 "bytes" 5 "encoding/base64" 6 "html/template" 7 "io" 8 "io/ioutil" 9 "net/http" 10 11 rd "github.com/benoitkugler/goACVE/server/core/rawdata" 12 13 "github.com/benoitkugler/goACVE/server/core/utils/mails" 14 ) 15 16 const ( 17 pageMargin = 0.5 18 templateLettre = ` 19 <!DOCTYPE html> 20 <html> 21 <head> 22 <meta charset="UTF-8"> 23 <style> 24 @page { 25 margin: {{ .Margin }}cm; 26 } 27 28 #infos { 29 text-align: right; 30 vertical-align: middle; 31 float: right; 32 margin-top: 10px; 33 } 34 35 #logo { 36 width: 50%; 37 text-align: left; 38 } 39 40 footer { 41 position: absolute; 42 bottom: -10px; 43 margin-left: -8px; 44 width: 100%; 45 } 46 #footer-bandeau { 47 margin: 0; 48 padding: 0; 49 border: 0px; 50 vertical-align: bottom; 51 } 52 #footer-bandeau img { 53 vertical-align: bottom; 54 float: right; 55 margin-top: -14px; 56 padding-right: 2px; 57 } 58 #status { 59 padding: 10px; 60 border: 0px; 61 text-align: left; 62 line-height: 13px; 63 background-color: #b8dbf1; 64 border-bottom-left-radius: 10px; 65 border-bottom-right-radius: 10px; 66 } 67 68 </style> 69 </head> 70 <body> 71 72 <div style="width: 100%; color: {{ .ColorCoord }};"> 73 <div id="infos"> 74 {{ if .ExpediteurDirecteur }} 75 <b>{{ .Directeur.NomPrenom }}</b><br/> 76 {{ if .ShowAdressePostale }} 77 {{ .Directeur.Adresse }}<br/> 78 {{ .Directeur.CodePostal }} {{ .Directeur.Ville }}<br/> 79 {{ end }} 80 {{ safe .Directeur.Tels }}<br/> 81 <b>Mail : </b> <a style="color: {{ .ColorCoord }};" href="mailto:{{ .Directeur.Mail }}">{{ .Directeur.Mail }}</a><br/> 82 {{ else }} 83 <b>{{ .Centre.Nom }}</b><br/> 84 <b>Tel : </b>{{ .Centre.Tel }} <br/> 85 <b>Mail : </b><a style="color: {{ .ColorCoord }};" href="mailto:{{ .Centre.Mail }}">{{ .Centre.Mail }}</a> <br/> 86 {{ end }} 87 </div> 88 <div id="logo"> 89 <img src="data:image/png;base64,{{ .IconBase64 }}"/> 90 </div> 91 </div> 92 93 {{ safe .LettreHtml }} 94 95 <footer> 96 <div id="footer-bandeau"> 97 <img src="data:image/png;base64,{{ .FooterBase64 }}"/> 98 </div> 99 <div id="status"> 100 <span style="font-size: 0.8em;">{{ safe .Footer.Title }} <br /></span> 101 <span style="font-size: 0.7em;">{{ safe .Footer.Infos}} <br /></span> 102 <span style="font-size: 0.55em;">{{ safe .Footer.Details}} </span> 103 </div> 104 </footer> 105 </body> 106 </html> 107 ` 108 ) 109 110 const ( 111 urlWeasyprint = "https://salty-plateau-05484.herokuapp.com/" 112 // urlWeasyprint = "http://localhost:5000" 113 ) 114 115 var ( 116 parsedTemplate = template.Must(template.New("lettre_directeur").Funcs(mails.FuncMap).Parse(templateLettre)) 117 iconBase64 string 118 footerBase64 string 119 ) 120 121 type Directeur struct { 122 NomPrenom string 123 Adresse string 124 CodePostal string 125 Ville string 126 Tels string 127 Mail string 128 } 129 130 type ParamsLettreDirecteur struct { 131 Margin float64 132 ExpediteurDirecteur bool 133 ShowAdressePostale bool 134 Directeur Directeur 135 ColorCoord string 136 Centre rd.Centre 137 Footer rd.InfosAsso 138 IconBase64, FooterBase64 string 139 LettreHtml string 140 } 141 142 func InitImages() error { 143 b, err := ioutil.ReadFile("ressources/images/app.png") 144 if err != nil { 145 return err 146 } 147 iconBase64 = base64.StdEncoding.EncodeToString(b) 148 149 b, err = ioutil.ReadFile("ressources/images/ronds.png") 150 if err != nil { 151 return err 152 } 153 footerBase64 = base64.StdEncoding.EncodeToString(b) 154 return nil 155 } 156 157 func TestWeasyprint() (string, error) { 158 b, err := renderHtml(rd.Lettredirecteur{}, rd.Personne{}) 159 if err != nil { 160 return "", err 161 } 162 buf := new(bytes.Buffer) 163 return urlWeasyprint, HtmlToPdf(b, buf) 164 } 165 166 func ensureHexColor(hexa string) string { 167 if len(hexa) > 7 { 168 return hexa[0:7] 169 } 170 return hexa 171 } 172 173 func renderHtml(lettre rd.Lettredirecteur, directeur rd.Personne) ([]byte, error) { 174 p := ParamsLettreDirecteur{ 175 Margin: pageMargin, 176 ExpediteurDirecteur: !lettre.UseCoordCentre, 177 ShowAdressePostale: lettre.ShowAdressePostale, 178 // weasyprint does not support AHex colors 179 ColorCoord: ensureHexColor(lettre.ColorCoord), 180 Directeur: Directeur{ 181 NomPrenom: directeur.NomPrenom().String(), 182 Adresse: string(directeur.Adresse), 183 CodePostal: string(directeur.CodePostal), 184 Ville: string(directeur.Ville), 185 Mail: string(directeur.Mail), 186 Tels: directeur.Tels.StringHTML().String(), 187 }, 188 Centre: rd.CoordonnesCentre, 189 Footer: rd.Asso, 190 LettreHtml: lettre.Html, 191 IconBase64: iconBase64, 192 FooterBase64: footerBase64, 193 } 194 b := new(bytes.Buffer) 195 if err := parsedTemplate.Execute(b, p); err != nil { 196 return nil, err 197 } 198 return b.Bytes(), nil 199 } 200 201 func HtmlToPdf(html []byte, out io.Writer) error { 202 resp, err := http.Post(urlWeasyprint, "application/octet-stream", bytes.NewReader(html)) 203 if err != nil { 204 return err 205 } 206 defer resp.Body.Close() 207 if _, err = io.Copy(out, resp.Body); err != nil { 208 return err 209 } 210 return nil 211 } 212 213 // LettreDirecteur génère le html complet puis utilise le serveur HtmlToPdf 214 // pour créé le document associé. 215 func LettreDirecteur(lettre rd.Lettredirecteur, directeur rd.Personne) ([]byte, error) { 216 fullHtml, err := renderHtml(lettre, directeur) 217 if err != nil { 218 return nil, err 219 } 220 out := new(bytes.Buffer) 221 if err = HtmlToPdf(fullHtml, out); err != nil { 222 return nil, err 223 } 224 return out.Bytes(), nil 225 }