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  }