From b391459734bd6555972e4fea29dcb4a693d94710 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Mon, 7 Nov 2016 19:34:56 +0100 Subject: [PATCH 01/11] WIP estimate pdf --- Yavsc/ApiControllers/PdfEstimateController.cs | 37 ++++ .../estimate-3.pdf | Bin 0 -> 16587 bytes .../tmpestimtex-3.pdf | Bin 0 -> 16587 bytes Yavsc/Bills/estimate-3.pdf | Bin 0 -> 16587 bytes Yavsc/Controllers/FrontOfficeController.cs | 191 ++++++++++++++---- Yavsc/Settings/SiteSettings.cs | 19 +- Yavsc/Startup/Startup.FileServer.cs | 1 + Yavsc/Startup/Startup.cs | 8 + Yavsc/Temp/estimate-8.tex | 146 +++++++++++++ Yavsc/Views/Estimate/Details.cshtml | 2 +- Yavsc/Views/FrontOffice/Estimate.pdf.cshtml | 48 ++--- Yavsc/estimate-3.t2d/pdf/bak/estimate-3.aux | 9 + .../pdf/bak/tmpestimtex-3.aux | 9 + 13 files changed, 407 insertions(+), 63 deletions(-) create mode 100644 Yavsc/ApiControllers/PdfEstimateController.cs create mode 100644 Yavsc/Bills/a94433b4-f11f-4a4b-8066-b32c1ab1103d/estimate-3.pdf create mode 100644 Yavsc/Bills/a94433b4-f11f-4a4b-8066-b32c1ab1103d/tmpestimtex-3.pdf create mode 100644 Yavsc/Bills/estimate-3.pdf create mode 100644 Yavsc/Temp/estimate-8.tex create mode 100644 Yavsc/estimate-3.t2d/pdf/bak/estimate-3.aux create mode 100644 Yavsc/tmpestimtex-3.t2d/pdf/bak/tmpestimtex-3.aux diff --git a/Yavsc/ApiControllers/PdfEstimateController.cs b/Yavsc/ApiControllers/PdfEstimateController.cs new file mode 100644 index 00000000..08428c38 --- /dev/null +++ b/Yavsc/ApiControllers/PdfEstimateController.cs @@ -0,0 +1,37 @@ +using System; +using System.IO; +using System.Security.Claims; +using Microsoft.AspNet.Authorization; +using Microsoft.AspNet.Mvc; + +namespace Yavsc.ApiControllers +{ + [Route("api/pdfestimate"), Authorize] + public class PdfEstimateController : Controller + { + [HttpGet("{id}", Name = "Get")] + public IActionResult Get(long id) + { + var filename = $"estimate-{id}.pdf"; + + var cd = new System.Net.Mime.ContentDisposition + { + // for example foo.bak + FileName = filename, + + // always prompt the user for downloading, set to true if you want + // the browser to try to show the file inline + Inline = false, + }; + + FileInfo fi = new FileInfo(Path.Combine(Startup.UserBillsDirName,filename)); + + FileStreamResult result = null; + var s = fi.OpenRead(); + + result = File(s,"application/x-pdf",filename); + + return result; + } + } +} \ No newline at end of file diff --git a/Yavsc/Bills/a94433b4-f11f-4a4b-8066-b32c1ab1103d/estimate-3.pdf b/Yavsc/Bills/a94433b4-f11f-4a4b-8066-b32c1ab1103d/estimate-3.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ba625e66d4ad364d87a7c12eaa903b5c63101c96 GIT binary patch literal 16587 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 literal 0 HcmV?d00001 diff --git a/Yavsc/Controllers/FrontOfficeController.cs b/Yavsc/Controllers/FrontOfficeController.cs index a7b8fb8c..8eed5407 100644 --- a/Yavsc/Controllers/FrontOfficeController.cs +++ b/Yavsc/Controllers/FrontOfficeController.cs @@ -8,10 +8,20 @@ using Microsoft.Extensions.Logging; using Yavsc.Models.Booking; using Yavsc.Helpers; using System; +using System.IO; +using System.Diagnostics; +using System.Text; +using Microsoft.AspNet.Mvc.ViewFeatures; +using Microsoft.AspNet.Razor; +using Microsoft.AspNet.Mvc.ViewEngines; +using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.Extensions.OptionsModel; +using System.Threading.Tasks; +using System.Security.Claims; namespace Yavsc.Controllers { - [ServiceFilter(typeof(LanguageActionFilter)), + [ServiceFilter(typeof(LanguageActionFilter)), Route("do")] public class FrontOfficeController : Controller { @@ -35,44 +45,45 @@ namespace Yavsc.Controllers return View(latestPosts); } - [Route("Book/{id?}"),HttpGet] - + [Route("Book/{id?}"), HttpGet] public ActionResult Book(string id) { - if (id == null) { + if (id == null) + { throw new NotImplementedException("No Activity code"); } - + ViewBag.Activities = _context.ActivityItems(id); - ViewBag.Activity = _context.Activities.FirstOrDefault( - a => a.Code == id ); + ViewBag.Activity = _context.Activities.FirstOrDefault( + a => a.Code == id); return View( - _context.Performers.Include(p=>p.Performer).Where + _context.Performers.Include(p => p.Performer).Where (p => p.ActivityCode == id && p.Active).OrderBy( - x=>x.MinDailyCost + x => x.MinDailyCost ) ); } - [Route("Book/{id}"),HttpPost] - + [Route("Book/{id}"), HttpPost] public ActionResult Book(BookQuery bookQuery) { - if (ModelState.IsValid) { + if (ModelState.IsValid) + { var pro = _context.Performers.Include( pr => pr.Performer ).FirstOrDefault( - x=>x.PerformerId == bookQuery.PerformerId + x => x.PerformerId == bookQuery.PerformerId ); - if (pro==null) + if (pro == null) return HttpNotFound(); // Let's create a command - if (bookQuery.Id==0) + if (bookQuery.Id == 0) { _context.BookQueries.Add(bookQuery); } - else { + else + { _context.BookQueries.Update(bookQuery); } _context.SaveChanges(); @@ -81,36 +92,146 @@ namespace Yavsc.Controllers return View("Index"); } ViewBag.Activities = _context.ActivityItems(null); - return View( _context.Performers.Include(p=>p.Performer).Where + return View(_context.Performers.Include(p => p.Performer).Where (p => p.Active).OrderBy( - x=>x.MinDailyCost + x => x.MinDailyCost )); } [Produces("text/x-tex"), Authorize, Route("estimate-{id}.tex")] public ViewResult EstimateTex(long id) { - var estimate = _context.Estimates.Include(x=>x.Query) - .Include(x=>x.Query.Client) - .Include(x=>x.Query.PerformerProfile) - .Include(x=>x.Query.PerformerProfile.OrganizationAddress) - .Include(x=>x.Query.PerformerProfile.Performer) - .Include(e=>e.Bill).FirstOrDefault(x=>x.Id==id); + var estimate = _context.Estimates.Include(x => x.Query) + .Include(x => x.Query.Client) + .Include(x => x.Query.PerformerProfile) + .Include(x => x.Query.PerformerProfile.OrganizationAddress) + .Include(x => x.Query.PerformerProfile.Performer) + .Include(e => e.Bill).FirstOrDefault(x => x.Id == id); Response.ContentType = "text/x-tex"; return View("Estimate.tex", estimate); } - - - [Produces("application/x-pdf"), Authorize, Route("estimate-{id}.pdf")] - public ViewResult EstimatePdf(long id) + + class TeOtions : IOptions + { + public MvcViewOptions Value + { + get + { + return new MvcViewOptions(); + } + } + } + + [Authorize,Route("Estimate-{id}.pdf")] + public async Task EstimatePdf(long id) { - var estimate = _context.Estimates.Include(x=>x.Query) - .Include(x=>x.Query.Client) - .Include(x=>x.Query.PerformerProfile) - .Include(x=>x.Query.PerformerProfile.OrganizationAddress) - .Include(x=>x.Query.PerformerProfile.Performer) - .Include(e=>e.Bill).FirstOrDefault(x=>x.Id==id); - return View("Estimate.pdf", estimate); + ViewBag.TempDir = Startup.SiteSetup.TempDir; + ViewBag.BillsDir = Startup.UserBillsDirName; + + var estimate = _context.Estimates.Include(x => x.Query) + .Include(x => x.Query.Client) + .Include(x => x.Query.PerformerProfile) + .Include(x => x.Query.PerformerProfile.OrganizationAddress) + .Include(x => x.Query.PerformerProfile.Performer) + .Include(e => e.Bill).FirstOrDefault(x => x.Id == id); + if (estimate==null) + throw new Exception("No data"); + + return View("Estimate.pdf",estimate); + /* + await result.ExecuteResultAsync(ActionContext); + var cd = new System.Net.Mime.ContentDisposition + { + // for example foo.bak + FileName = $"estimate-{id}.pdf", + + // always prompt the user for downloading, set to true if you want + // the browser to try to show the file inline + Inline = false, + }; + Response.Headers.Add("Content-Disposition", cd.ToString()); + return File((Byte[])ViewData["Pdf"], "application/x-pdf"); */ } + /* + + [Produces("application/x-pdf"), Authorize, Route("testimate-{id}.pdf")] + public async Task BadEstimatePdf(long id) + { + + var tempDir = Startup.SiteSetup.TempDir; + + string name = $"tmpestimtex-{id}"; + string fullname = new FileInfo( + System.IO.Path.Combine(tempDir, name)).FullName; + var writer = new System.IO.StringWriter(); + try + { + using (StringWriter sw = new StringWriter()) + { + Microsoft.AspNet.Mvc.ViewEngines.CompositeViewEngine ve = new CompositeViewEngine( + new TeOtions {} + ); + + ViewEngineResult viewResult = ve.FindPartialView(ActionContext, $"estimate-{id}.tex"); + ViewContext viewContext = new ViewContext(); // ActionContext, viewResult.View, ViewData, TempData, sw); + await viewResult.View.RenderAsync(viewContext); + } + } catch (Exception ex) + { + } + + + + + FileInfo fo = new FileInfo(fullname + ".pdf"); + if (!fi.Exists) + { + throw new Exception("Source write failed"); + } + using (Process p = new Process()) + { + p.StartInfo.WorkingDirectory = tempDir; + p.StartInfo = new ProcessStartInfo(); + p.StartInfo.UseShellExecute = false; + p.StartInfo.FileName = "/usr/bin/texi2pdf"; + p.StartInfo.Arguments = $"--batch --build-dir=."; + + p.Start(); + + using (p.StandardInput) + { + + } + p.WaitForExit(); + if (p.ExitCode != 0) + { + throw new Exception("Pdf generation failed with exit code:" + p.ExitCode); + } + } + byte[] pdf = null; + if (fo.Exists) + { + using (StreamReader sr = new StreamReader(fo.FullName)) + { + pdf = System.IO.File.ReadAllBytes(fo.FullName); + } + fo.Delete(); + } + fi.Delete(); + + + var cd = new System.Net.Mime.ContentDisposition + { + // for example foo.bak + FileName = $"estimate-{id}.pdf", + + // always prompt the user for downloading, set to true if you want + // the browser to try to show the file inline + Inline = false, + }; + Response.Headers.Add("Content-Disposition", cd.ToString()); + return File(pdf, "application/x-pdf"); + } */ + } } \ No newline at end of file diff --git a/Yavsc/Settings/SiteSettings.cs b/Yavsc/Settings/SiteSettings.cs index 03cc63ee..7801060f 100644 --- a/Yavsc/Settings/SiteSettings.cs +++ b/Yavsc/Settings/SiteSettings.cs @@ -16,15 +16,32 @@ namespace Yavsc /// /// public string Authority { get; set; } + /// + /// Owner's email + /// + /// public EmailEntry Owner { get; set; } + /// + /// Administrator's email + /// + /// public EmailEntry Admin { get; set; } + /// + /// User's files directory + /// + /// public ThirdPartyFiles UserFiles { get; set; } public string BusinessName { get; set; } public string Street { get; set; } public string PostalCode { get; set; } public string CountryCode { get; set; } - + /// + /// Specifies the directory where should be + /// generated pdf files using pandoc + /// + /// The temporary directory to use + public string TempDir { get; set; } = "Temp"; } } diff --git a/Yavsc/Startup/Startup.FileServer.cs b/Yavsc/Startup/Startup.FileServer.cs index 2f66ed44..d9012fb0 100644 --- a/Yavsc/Startup/Startup.FileServer.cs +++ b/Yavsc/Startup/Startup.FileServer.cs @@ -12,6 +12,7 @@ namespace Yavsc { public static string UserFilesDirName { get; private set; } public static FileServerOptions UserFilesOptions { get; private set; } + public void ConfigureFileServerApp(IApplicationBuilder app, SiteSettings siteSettings, IHostingEnvironment env) { diff --git a/Yavsc/Startup/Startup.cs b/Yavsc/Startup/Startup.cs index f409d99c..bcd7ffe0 100755 --- a/Yavsc/Startup/Startup.cs +++ b/Yavsc/Startup/Startup.cs @@ -1,6 +1,7 @@ using System; using System.Globalization; +using System.IO; using System.Reflection; using System.Threading.Tasks; using System.Web.Optimization; @@ -32,8 +33,11 @@ namespace Yavsc public partial class Startup { public static string ConnectionString { get; private set; } + public static string UserBillsDirName { private set; get; } public static string Authority { get; private set; } public static string Audience { get; private set; } + public static SiteSettings SiteSetup { get; private set; } + private static ILogger logger; public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv) { @@ -225,7 +229,11 @@ namespace Yavsc RoleManager roleManager, ILoggerFactory loggerFactory) { + SiteSetup = siteSettings.Value; + var tempdi = new DirectoryInfo(SiteSetup.TempDir); + if (!tempdi.Exists) tempdi.Create(); Startup.UserFilesDirName = siteSettings.Value.UserFiles.DirName; + Startup.UserBillsDirName = siteSettings.Value.UserFiles.Bills; loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); logger = loggerFactory.CreateLogger(); diff --git a/Yavsc/Temp/estimate-8.tex b/Yavsc/Temp/estimate-8.tex new file mode 100644 index 00000000..82c06f27 --- /dev/null +++ b/Yavsc/Temp/estimate-8.tex @@ -0,0 +1,146 @@ +\documentclass[french,11pt]{article} +\usepackage{babel} +\usepackage[T1]{fontenc} +\usepackage[utf8]{inputenc} +\usepackage[a4paper]{geometry} +\usepackage{units} +\usepackage{bera} +\usepackage{graphicx} +\usepackage{fancyhdr} +\usepackage{fp} + +\def\TVA{20} % Taux de la TVA + +\def\TotalHT{0} +\def\TotalTVA{0} + +\newcommand{\AjouterService}[3]{% Arguments : Désignation, quantité, prix + \FPround{\prix}{#3}{2} + \FPeval{\montant}{#2 * #3} + \FPround{\montant}{\montant}{2} + \FPadd{\TotalHT}{\TotalHT}{\montant} + + \eaddto\ListeProduits{#1 & \prix & #2 & \montant \cr} +} + + +\newcommand{\AfficheResultat}{% + \ListeProduits + + \FPeval{\TotalTVA}{\TotalHT * \TVA / 100} + \FPadd{\TotalTTC}{\TotalHT}{\TotalTVA} + \FPround{\TotalHT}{\TotalHT}{2} + \FPround{\TotalTVA}{\TotalTVA}{2} + \FPround{\TotalTTC}{\TotalTTC}{2} + \global\let\TotalHT\TotalHT + \global\let\TotalTVA\TotalTVA + \global\let\TotalTTC\TotalTTC + + + \cr + \hline + \textbf{Total} & & & \TotalHT +} + +\newcommand*\eaddto[2]{% version développée de \addto + \edef\tmp{#2}% + \expandafter\addto + \expandafter#1% + \expandafter{\tmp}% +} + +\newcommand{\ListeProduits}{} + +%%%%%%%%%%%%%%%%%%%%% A MODIFIER DANS LA FACTURE %%%%%%%%%%%%%%%%%%%%% + +\def\FactureNum {8} % Numéro de facture +\def\FactureAcquittee {non} % Facture acquittée : oui/non +\def\FactureLieu {2 Boulevard Aristide Briand, 92150 Suresnes, France} % Lieu de l'édition de la facture +\def\FactureObjet {Facture : } % Objet du document +% Description de la facture +\def\FactureDescr { + # **Hello Estimate!** coup blah +} + +% Infos Client +\def\ClientNom{Paul} % Nom du client + +\def\ClientAdresse{ +% Adresse du client + E-mail: redienhcs.luap@gmail.com +} + +% Liste des produits facturés : Désignation, prix + + +\AjouterService {une première} {3} {121,6000} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\geometry{verbose,tmargin=4em,bmargin=8em,lmargin=6em,rmargin=6em} +\setlength{\parindent}{0pt} +\setlength{\parskip}{1ex plus 0.5ex minus 0.2ex} + +\thispagestyle{fancy} +\pagestyle{fancy} +\setlength{\parindent}{0pt} + +\renewcommand{\headrulewidth}{0pt} +\cfoot{ Paul - 2 Boulevard Aristide Briand, 92150 Suresnes, France \newline + \small{ E-mail: redienhcs.luap@gmail.com + } +} + +\begin{document} + +% Logo de la société + +%\includegraphics{logo.png} +% Nom et adresse de la société + Paul \\ + 2 Boulevard Aristide Briand, 92150 Suresnes, France + +Facture n°\FactureNum + + +{\addtolength{\leftskip}{10.5cm} %in ERT + \textbf{\ClientNom} \\ + \ClientAdresse \\ + +} %in ERT + + +\hspace*{10.5cm} +\FactureLieu, le \today + +~\\~\\ + +\textbf{Objet : \FactureObjet \\} + +\textnormal{\FactureDescr} + +~\\ + +\begin{center} + \begin{tabular}{lrrr} + \textbf{Désignation ~~~~~~} & \textbf{Prix unitaire} & \textbf{Quantité} & \textbf{Montant (EUR)} \\ + \hline + \AfficheResultat{} + \end{tabular} +\end{center} + +\begin{flushright} +\textit{Auto entreprise en franchise de TVA}\\ + +\end{flushright} +~\\ + +\ifthenelse{\equal{\FactureAcquittee}{oui}}{ + Facture acquittée. +}{ + +} +\end{document} diff --git a/Yavsc/Views/Estimate/Details.cshtml b/Yavsc/Views/Estimate/Details.cshtml index ae367964..87afc47b 100644 --- a/Yavsc/Views/Estimate/Details.cshtml +++ b/Yavsc/Views/Estimate/Details.cshtml @@ -40,5 +40,5 @@ @{ var filenametex = $"estimate-{Model.Id}.tex" ; var filenamepdf = $"estimate-{Model.Id}.pdf" ;} Export au format LaTeX - Export au format LaTeX + Export au format Pdf

diff --git a/Yavsc/Views/FrontOffice/Estimate.pdf.cshtml b/Yavsc/Views/FrontOffice/Estimate.pdf.cshtml index a8bb2b06..aefd3826 100644 --- a/Yavsc/Views/FrontOffice/Estimate.pdf.cshtml +++ b/Yavsc/Views/FrontOffice/Estimate.pdf.cshtml @@ -1,26 +1,27 @@ - -@using System.Reflection -@using System.IO -@using Microsoft.Extensions.WebEncoders -@using System.Diagnostics -@using System.Text -@using Yavsc.Formatters - +@using System.Reflection; +@using System.IO; +@using Microsoft.Extensions.WebEncoders; +@using System.Diagnostics; +@using System.Text; +@using Yavsc.Formatters; @model Estimate @{ - Layout = null; - ViewBag.Pdf = ""; - ViewBag.TeX = ""; - var writer = new System.IO.StringWriter(); - var content = await Html.PartialAsync("Estimate.tex", Model ); + if (ViewBag.TempDir==null) { throw new InvalidOperationException(); } + + ViewBag.Pdf = ""; + ViewBag.TeX = ""; + var writer = new System.IO.StringWriter(); + var content = await Html.PartialAsync("Estimate.tex", Model ); content.WriteTo(writer, new TexEncoder()); var contentStr = writer.ToString(); - string name = $"tmpestimtex-{Model.Id}"; - string fullname = new FileInfo( + string name = $"estimate-{Model.Id}"; + string fullname = new FileInfo( System.IO.Path.Combine(ViewBag.TempDir,name)).FullName; + string ofullname = new FileInfo( + System.IO.Path.Combine(ViewBag.BillsDir,name)).FullName; FileInfo fi = new FileInfo(fullname + ".tex"); - FileInfo fo = new FileInfo(fullname + ".pdf"); + FileInfo fo = new FileInfo(ofullname + ".pdf"); using (StreamWriter sw = new StreamWriter (fi.FullName)) { sw.Write (contentStr); @@ -41,15 +42,10 @@ throw new Exception ("Pdf generation failed with exit code:" + p.ExitCode); } } - if (fo.Exists) { - UTF8Encoding utf8 = new UTF8Encoding(); - - using (StreamReader sr = new StreamReader (fo.FullName)) { - byte[] buffer = File.ReadAllBytes (fo.FullName); - ViewBag.Pdf = utf8.GetString(buffer,0,buffer.Length); - } - fo.Delete(); - } + ViewBag.Success = fo.Exists; fi.Delete(); + var uri = $"~/api/pdfestimate/{Model.Id}"; + } -@ViewBag.Pdf + +@uri \ No newline at end of file diff --git a/Yavsc/estimate-3.t2d/pdf/bak/estimate-3.aux b/Yavsc/estimate-3.t2d/pdf/bak/estimate-3.aux new file mode 100644 index 00000000..2398624f --- /dev/null +++ b/Yavsc/estimate-3.t2d/pdf/bak/estimate-3.aux @@ -0,0 +1,9 @@ +\relax +\catcode `:\active +\catcode `;\active +\catcode `!\active +\catcode `?\active +\select@language{french} +\@writefile{toc}{\select@language{french}} +\@writefile{lof}{\select@language{french}} +\@writefile{lot}{\select@language{french}} diff --git a/Yavsc/tmpestimtex-3.t2d/pdf/bak/tmpestimtex-3.aux b/Yavsc/tmpestimtex-3.t2d/pdf/bak/tmpestimtex-3.aux new file mode 100644 index 00000000..2398624f --- /dev/null +++ b/Yavsc/tmpestimtex-3.t2d/pdf/bak/tmpestimtex-3.aux @@ -0,0 +1,9 @@ +\relax +\catcode `:\active +\catcode `;\active +\catcode `!\active +\catcode `?\active +\select@language{french} +\@writefile{toc}{\select@language{french}} +\@writefile{lof}{\select@language{french}} +\@writefile{lot}{\select@language{french}} From fc0e71cac12bf1667a77ad48995b95312b70f977 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Tue, 8 Nov 2016 14:53:32 +0100 Subject: [PATCH 02/11] ignore .gitignore --- .gitignore | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 80039ef9..00000000 --- a/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ - -.gitignore -appsettings.*.json -.idea/ -.vscode/ -.vs/ -YavscWeb.userprefs -bin/ -obj/ -bower_components/ -node_modules/ -docfx_project/ -debugcmd -undefined/ -debugcode/ -kestrel*.pid -kestrel*.log -scaffold.cmds -DataProtection-Keys -RSA-Params.json -Components/ -packages/ -build/ -*.user -*.bak -*~ - From 2e631a331431598042e2c0f6f7f691b8bb902b88 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Tue, 8 Nov 2016 14:55:21 +0100 Subject: [PATCH 03/11] Use an euro sign, fixes decimal --- Yavsc/Views/FrontOffice/Estimate.tex.cshtml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Yavsc/Views/FrontOffice/Estimate.tex.cshtml b/Yavsc/Views/FrontOffice/Estimate.tex.cshtml index 9633eba9..5b807102 100644 --- a/Yavsc/Views/FrontOffice/Estimate.tex.cshtml +++ b/Yavsc/Views/FrontOffice/Estimate.tex.cshtml @@ -1,5 +1,6 @@ @model Estimate @using Yavsc.Helpers +@using System.Globalization @{ Layout = null; var pro = Model.Query.PerformerProfile; @@ -11,6 +12,7 @@ var proaddrm = (proaddr!=null) ? proaddr.NewLinesWith(" - ") : null ; } \documentclass[french,11pt]{article} +\usepackage{eurosym} \usepackage{babel} \usepackage[T1]{fontenc} \usepackage[utf8]{inputenc} @@ -88,13 +90,9 @@ } % Liste des produits facturés : Désignation, prix - -@if (Model.Bill!=null) {  - foreach (CommandLine line in Model.Bill) { - -\AjouterService {@line.Description} {@line.Count} {@line.UnitaryCost} - -} } +@if (Model.Bill!=null) { foreach (CommandLine line in Model.Bill) { +\AjouterService{@line.Description}{@line.Count}{@line.UnitaryCost.ToString("F2",CultureInfo.InvariantCulture)} +} } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -151,7 +149,7 @@ Facture n°\FactureNum \begin{center} \begin{tabular}{lrrr} - \textbf{Désignation ~~~~~~} & \textbf{Prix unitaire} & \textbf{Quantité} & \textbf{Montant (EUR)} \\ + \textbf{Désignation ~~~~~~} & \textbf{Prix unitaire} & \textbf{Quantité} & \textbf{Montant (\euro)} \\ \hline \AfficheResultat{} \end{tabular} From d8895f0887a99565cce7f2bf3fa038a420a36b47 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Tue, 8 Nov 2016 14:56:38 +0100 Subject: [PATCH 04/11] Fixes Html special chars, and spaces --- Yavsc/wwwroot/js/to-markdown.js | 673 +++++++++++++++++--------------- 1 file changed, 351 insertions(+), 322 deletions(-) diff --git a/Yavsc/wwwroot/js/to-markdown.js b/Yavsc/wwwroot/js/to-markdown.js index ca2372d1..b81025ed 100644 --- a/Yavsc/wwwroot/js/to-markdown.js +++ b/Yavsc/wwwroot/js/to-markdown.js @@ -2,204 +2,151 @@ /* * to-markdown - an HTML to Markdown converter * - * Copyright 2011-15, Dom Christie + * Copyright 2011+, Dom Christie * Licenced under the MIT licence * */ -'use strict'; - -var toMarkdown; -var converters; -var mdConverters = require('./lib/md-converters'); -var gfmConverters = require('./lib/gfm-converters'); -var collapse = require('collapse-whitespace'); +'use strict' -/* - * Set up window and document for Node.js - */ - -var _window = (typeof window !== 'undefined' ? window : this), _document; -if (typeof document === 'undefined') { - _document = require('jsdom').jsdom(); -} -else { - _document = document; -} +var toMarkdown +var converters +var mdConverters = require('./lib/md-converters') +var gfmConverters = require('./lib/gfm-converters') +var HtmlParser = require('./lib/html-parser') +var collapse = require('collapse-whitespace') /* * Utilities */ -function trim(string) { - return string.replace(/^[ \r\n\t]+|[ \r\n\t]+$/g, ''); -} - var blocks = ['address', 'article', 'aside', 'audio', 'blockquote', 'body', 'canvas', 'center', 'dd', 'dir', 'div', 'dl', 'dt', 'fieldset', 'figcaption', - 'figure', 'footer', 'form', 'frameset', 'h1', 'h2', 'h3', 'h4','h5', 'h6', + 'figure', 'footer', 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'html', 'isindex', 'li', 'main', 'menu', 'nav', 'noframes', 'noscript', 'ol', 'output', 'p', 'pre', 'section', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'ul' -]; +] -function isBlock(node) { - return blocks.indexOf(node.nodeName.toLowerCase()) !== -1; +function isBlock (node) { + return blocks.indexOf(node.nodeName.toLowerCase()) !== -1 } var voids = [ 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr' -]; - -function isVoid(node) { - return voids.indexOf(node.nodeName.toLowerCase()) !== -1; -} - -/* - * Parsing HTML strings - */ - -function canParseHtml() { - var Parser = _window.DOMParser, canParse = false; - - // Adapted from https://gist.github.com/1129031 - // Firefox/Opera/IE throw errors on unsupported types - try { - // WebKit returns null on unsupported types - if (new Parser().parseFromString('', 'text/html')) { - canParse = true; - } - } catch (e) {} - return canParse; -} - -function createHtmlParser() { - var Parser = function () {}; +] - Parser.prototype.parseFromString = function (string) { - var newDoc = _document.implementation.createHTMLDocument(''); - - if (string.toLowerCase().indexOf(' -1) { - newDoc.documentElement.innerHTML = string; - } - else { - newDoc.body.innerHTML = string; - } - return newDoc; - }; - return Parser; +function isVoid (node) { + return voids.indexOf(node.nodeName.toLowerCase()) !== -1 } -var HtmlParser = canParseHtml() ? _window.DOMParser : createHtmlParser(); - -function htmlToDom(string) { - var tree = new HtmlParser().parseFromString(string, 'text/html'); - collapse(tree, isBlock); - return tree; +function htmlToDom (string) { + var tree = new HtmlParser().parseFromString(string, 'text/html') + collapse(tree.documentElement, isBlock) + return tree } /* * Flattens DOM tree into single array */ -function bfsOrder(node) { - var inqueue = [node], - outqueue = [], - elem, children, i; +function bfsOrder (node) { + var inqueue = [node] + var outqueue = [] + var elem + var children + var i while (inqueue.length > 0) { - elem = inqueue.shift(); - outqueue.push(elem); - children = elem.childNodes; - for (i = 0 ; i < children.length; i++) { - if (children[i].nodeType === 1) { inqueue.push(children[i]); } + elem = inqueue.shift() + outqueue.push(elem) + children = elem.childNodes + for (i = 0; i < children.length; i++) { + if (children[i].nodeType === 1) inqueue.push(children[i]) } } - outqueue.shift(); - return outqueue; + outqueue.shift() + return outqueue } /* * Contructs a Markdown string of replacement text for a given node */ -function getContent(node) { - var text = ''; +function getContent (node) { + var text = '' for (var i = 0; i < node.childNodes.length; i++) { if (node.childNodes[i].nodeType === 1) { - text += node.childNodes[i]._replacement; - } - else if (node.childNodes[i].nodeType === 3) { - text += node.childNodes[i].data; - } - else { continue; } + text += node.childNodes[i]._replacement + } else if (node.childNodes[i].nodeType === 3) { + text += node.childNodes[i].data + } else continue } - return text; + return text } /* * Returns the HTML string of an element with its contents converted */ -function outer(node, content) { - return node.cloneNode(false).outerHTML.replace('><', '>'+ content +'<'); +function outer (node, content) { + return node.cloneNode(false).outerHTML.replace('><', '>' + content + '<') } -function canConvert(node, filter) { +function canConvert (node, filter) { if (typeof filter === 'string') { - return filter === node.nodeName.toLowerCase(); + return filter === node.nodeName.toLowerCase() } if (Array.isArray(filter)) { - return filter.indexOf(node.nodeName.toLowerCase()) !== -1; - } - else if (typeof filter === 'function') { - return filter.call(toMarkdown, node); - } - else { - throw new TypeError('`filter` needs to be a string, array, or function'); + return filter.indexOf(node.nodeName.toLowerCase()) !== -1 + } else if (typeof filter === 'function') { + return filter.call(toMarkdown, node) + } else { + throw new TypeError('`filter` needs to be a string, array, or function') } } -function isFlankedByWhitespace(side, node) { - var sibling, regExp, isFlanked; +function isFlankedByWhitespace (side, node) { + var sibling + var regExp + var isFlanked if (side === 'left') { - sibling = node.previousSibling; - regExp = / $/; - } - else { - sibling = node.nextSibling; - regExp = /^ /; + sibling = node.previousSibling + regExp = / $/ + } else { + sibling = node.nextSibling + regExp = /^ / } if (sibling) { if (sibling.nodeType === 3) { - isFlanked = regExp.test(sibling.nodeValue); - } - else if(sibling.nodeType === 1 && !isBlock(sibling)) { - isFlanked = regExp.test(sibling.textContent); + isFlanked = regExp.test(sibling.nodeValue) + } else if (sibling.nodeType === 1 && !isBlock(sibling)) { + isFlanked = regExp.test(sibling.textContent) } } - return isFlanked; + return isFlanked } -function flankingWhitespace(node) { - var leading = '', trailing = ''; +function flankingWhitespace (node, content) { + var leading = '' + var trailing = '' if (!isBlock(node)) { - var hasLeading = /^[ \r\n\t]/.test(node.innerHTML), - hasTrailing = /[ \r\n\t]$/.test(node.innerHTML); + var hasLeading = /^[ \r\n\t]/.test(content) + var hasTrailing = /[ \r\n\t]$/.test(content) if (hasLeading && !isFlankedByWhitespace('left', node)) { - leading = ' '; + leading = ' ' } if (hasTrailing && !isFlankedByWhitespace('right', node)) { - trailing = ' '; + trailing = ' ' } } - return { leading: leading, trailing: trailing }; + return { leading: leading, trailing: trailing } } /* @@ -207,154 +154,158 @@ function flankingWhitespace(node) { * `_replacement` */ -function process(node) { - var replacement, content = getContent(node); +function process (node) { + var replacement + var content = getContent(node) // Remove blank nodes - if (!isVoid(node) && !/A/.test(node.nodeName) && /^\s*$/i.test(content)) { - node._replacement = ''; - return; + if (!isVoid(node) && !/A|TH|TD/.test(node.nodeName) && /^\s*$/i.test(content)) { + node._replacement = '' + return } for (var i = 0; i < converters.length; i++) { - var converter = converters[i]; + var converter = converters[i] if (canConvert(node, converter.filter)) { if (typeof converter.replacement !== 'function') { throw new TypeError( '`replacement` needs to be a function that returns a string' - ); + ) } - var whitespace = flankingWhitespace(node); + var whitespace = flankingWhitespace(node, content) if (whitespace.leading || whitespace.trailing) { - content = trim(content); + content = content.trim() } replacement = whitespace.leading + - converter.replacement.call(toMarkdown, content, node) + - whitespace.trailing; - break; + converter.replacement.call(toMarkdown, content, node) + + whitespace.trailing + break } } - node._replacement = replacement; + node._replacement = replacement } toMarkdown = function (input, options) { - options = options || {}; + options = options || {} if (typeof input !== 'string') { - throw new TypeError(input + ' is not a string'); + throw new TypeError(input + ' is not a string') + } + + if (input === '') { + return '' } // Escape potential ol triggers - input = input.replace(/(\d+)\. /g, '$1\\. '); + input = input.replace(/(\d+)\. /g, '$1\\. ') - var clone = htmlToDom(input).body, - nodes = bfsOrder(clone), - output; + var clone = htmlToDom(input).body + var nodes = bfsOrder(clone) + var output - converters = mdConverters.slice(0); + converters = mdConverters.slice(0) if (options.gfm) { - converters = gfmConverters.concat(converters); + converters = gfmConverters.concat(converters) } if (options.converters) { - converters = options.converters.concat(converters); + converters = options.converters.concat(converters) } // Process through nodes in reverse (so deepest child elements are first). for (var i = nodes.length - 1; i >= 0; i--) { - process(nodes[i]); + process(nodes[i]) } - output = getContent(clone); + output = getContent(clone) return output.replace(/^[\t\r\n]+|[\t\r\n\s]+$/g, '') - .replace(/\n\s+\n/g, '\n\n') - .replace(/\n{3,}/g, '\n\n'); -}; + .replace(/\n\s+\n/g, '\n\n') + .replace(/\n{3,}/g, '\n\n') +} -toMarkdown.isBlock = isBlock; -toMarkdown.isVoid = isVoid; -toMarkdown.trim = trim; -toMarkdown.outer = outer; +toMarkdown.isBlock = isBlock +toMarkdown.isVoid = isVoid +toMarkdown.outer = outer -module.exports = toMarkdown; +module.exports = toMarkdown -},{"./lib/gfm-converters":2,"./lib/md-converters":3,"collapse-whitespace":4,"jsdom":7}],2:[function(require,module,exports){ -'use strict'; +},{"./lib/gfm-converters":2,"./lib/html-parser":3,"./lib/md-converters":4,"collapse-whitespace":7}],2:[function(require,module,exports){ +'use strict' -function cell(content, node) { - var index = Array.prototype.indexOf.call(node.parentNode.childNodes, node); - var prefix = ' '; - if (index === 0) { prefix = '| '; } - return prefix + content + ' |'; +function cell (content, node) { + var index = Array.prototype.indexOf.call(node.parentNode.childNodes, node) + var prefix = ' ' + if (index === 0) prefix = '| ' + return prefix + content + ' |' } -var highlightRegEx = /highlight highlight-(\S+)/; +var highlightRegEx = /highlight highlight-(\S+)/ module.exports = [ { filter: 'br', replacement: function () { - return '\n'; + return '\n' } }, { filter: ['del', 's', 'strike'], replacement: function (content) { - return '~~' + content + '~~'; + return '~~' + content + '~~' } }, { filter: function (node) { - return node.type === 'checkbox' && node.parentNode.nodeName === 'LI'; + return node.type === 'checkbox' && node.parentNode.nodeName === 'LI' }, replacement: function (content, node) { - return (node.checked ? '[x]' : '[ ]') + ' '; + return (node.checked ? '[x]' : '[ ]') + ' ' } }, { filter: ['th', 'td'], replacement: function (content, node) { - return cell(content, node); + return cell(content, node) } }, { filter: 'tr', replacement: function (content, node) { - var borderCells = ''; - var alignMap = { left: ':--', right: '--:', center: ':-:' }; + var borderCells = '' + var alignMap = { left: ':--', right: '--:', center: ':-:' } if (node.parentNode.nodeName === 'THEAD') { for (var i = 0; i < node.childNodes.length; i++) { - var align = node.childNodes[i].attributes.align; - var border = '---'; + var align = node.childNodes[i].attributes.align + var border = '---' - if (align) { border = alignMap[align.value] || border; } + if (align) border = alignMap[align.value] || border - borderCells += cell(border, node.childNodes[i]); + borderCells += cell(border, node.childNodes[i]) } } - return '\n' + content + (borderCells ? '\n' + borderCells : ''); + return '\n' + content + (borderCells ? '\n' + borderCells : '') } }, { filter: 'table', replacement: function (content) { - return '\n\n' + content + '\n\n'; + return '\n\n' + content + '\n\n' } }, { filter: ['thead', 'tbody', 'tfoot'], replacement: function (content) { - return content; + return content } }, @@ -362,11 +313,11 @@ module.exports = [ { filter: function (node) { return node.nodeName === 'PRE' && - node.firstChild && - node.firstChild.nodeName === 'CODE'; + node.firstChild && + node.firstChild.nodeName === 'CODE' }, - replacement: function(content, node) { - return '\n\n```\n' + node.firstChild.textContent + '\n```\n\n'; + replacement: function (content, node) { + return '\n\n```\n' + node.firstChild.textContent + '\n```\n\n' } }, @@ -374,233 +325,357 @@ module.exports = [ { filter: function (node) { return node.nodeName === 'PRE' && - node.parentNode.nodeName === 'DIV' && - highlightRegEx.test(node.parentNode.className); + node.parentNode.nodeName === 'DIV' && + highlightRegEx.test(node.parentNode.className) }, replacement: function (content, node) { - var language = node.parentNode.className.match(highlightRegEx)[1]; - return '\n\n```' + language + '\n' + node.textContent + '\n```\n\n'; + var language = node.parentNode.className.match(highlightRegEx)[1] + return '\n\n```' + language + '\n' + node.textContent + '\n```\n\n' } }, { filter: function (node) { return node.nodeName === 'DIV' && - highlightRegEx.test(node.className); + highlightRegEx.test(node.className) }, replacement: function (content) { - return '\n\n' + content + '\n\n'; + return '\n\n' + content + '\n\n' } } -]; +] },{}],3:[function(require,module,exports){ -'use strict'; +/* + * Set up window for Node.js + */ + +var _window = (typeof window !== 'undefined' ? window : this) + +/* + * Parsing HTML strings + */ + +function canParseHtmlNatively () { + var Parser = _window.DOMParser + var canParse = false + + // Adapted from https://gist.github.com/1129031 + // Firefox/Opera/IE throw errors on unsupported types + try { + // WebKit returns null on unsupported types + if (new Parser().parseFromString('', 'text/html')) { + canParse = true + } + } catch (e) {} + + return canParse +} + +function createHtmlParser () { + var Parser = function () {} + + // For Node.js environments + if (typeof document === 'undefined') { + var jsdom = require('jsdom') + Parser.prototype.parseFromString = function (string) { + return jsdom.jsdom(string, { + features: { + FetchExternalResources: [], + ProcessExternalResources: false + } + }) + } + } else { + if (!shouldUseActiveX()) { + Parser.prototype.parseFromString = function (string) { + var doc = document.implementation.createHTMLDocument('') + doc.open() + doc.write(string) + doc.close() + return doc + } + } else { + Parser.prototype.parseFromString = function (string) { + var doc = new window.ActiveXObject('htmlfile') + doc.designMode = 'on' // disable on-page scripts + doc.open() + doc.write(string) + doc.close() + return doc + } + } + } + return Parser +} + +function shouldUseActiveX () { + var useActiveX = false + + try { + document.implementation.createHTMLDocument('').open() + } catch (e) { + if (window.ActiveXObject) useActiveX = true + } + + return useActiveX +} + +module.exports = canParseHtmlNatively() ? _window.DOMParser : createHtmlParser() + +},{"jsdom":6}],4:[function(require,module,exports){ +'use strict' module.exports = [ { filter: 'p', replacement: function (content) { - return '\n\n' + content + '\n\n'; - } - }, - { - filter: 'div', - replacement: function (content) { - return content + '\n'; + return '\n\n' + content + '\n\n' } }, + { filter: 'br', replacement: function () { - return ' \n'; + return ' \n' } }, { - filter: ['h1', 'h2', 'h3', 'h4','h5', 'h6'], - replacement: function(content, node) { - var hLevel = node.nodeName.charAt(1); - var hPrefix = ''; - for(var i = 0; i < hLevel; i++) { - hPrefix += '#'; + filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'], + replacement: function (content, node) { + var hLevel = node.nodeName.charAt(1) + var hPrefix = '' + for (var i = 0; i < hLevel; i++) { + hPrefix += '#' } - return '\n\n' + hPrefix + ' ' + content + '\n\n'; + return '\n\n' + hPrefix + ' ' + content + '\n\n' } }, { filter: 'hr', replacement: function () { - return '\n\n* * *\n\n'; + return '\n\n* * *\n\n' } }, { filter: ['em', 'i'], replacement: function (content) { - return '*' + content + '*'; + return '_' + content + '_' + } + }, + + { + filter: ['strong', 'b'], + replacement: function (content) { + return '**' + content + '**' } }, { filter: ['u'], replacement: function (content) { - return '_' + content + '_'; + return '_' + content + '_' } }, { - filter: ['strong', 'b'], + filter: ['del', 's', 'strike'], replacement: function (content) { - return '**' + content + '**'; + return '~~' + content + '~~' } }, { - filter: ['strike','s'], + filter: 'div', replacement: function (content) { - return '~~' + content + '~~'; + return content + '\n\n' } }, + // Inline code { filter: function (node) { - var hasSiblings = node.previousSibling || node.nextSibling; - var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings; + var hasSiblings = node.previousSibling || node.nextSibling + var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings - return node.nodeName === 'CODE' && !isCodeBlock; + return node.nodeName === 'CODE' && !isCodeBlock }, - replacement: function(content) { - return '`' + content + '`'; + replacement: function (content) { + return '`' + content + '`' } }, + { filter: function (node) { - return node.nodeName === 'A' && node.getAttribute('href'); + return node.nodeName === 'A' && node.getAttribute('href') }, - replacement: function(content, node) { - var titlePart = node.title ? ' "'+ node.title +'"' : ''; - return '[' + content + '](' + node.getAttribute('href') + titlePart + ')'; + replacement: function (content, node) { + var titlePart = node.title ? ' "' + node.title + '"' : '' + return '[' + content + '](' + node.getAttribute('href') + titlePart + ')' } }, - { filter: 'video', - replacement: function(content, node) { - var alt = node.getAttribute("alt") || ''; - var src ; - for (var i = 0; i < node.childNodes.length; i++) - { - if (node.childNodes[i].localName == 'source') { - src = node.childNodes[i].getAttribute('src') ; - break; - } - } - var title = node.title || ''; - var titlePart = title ? ' "'+ title +'"' : ''; - return src ? '![video:' + alt + ']' + '(' + src + titlePart + ')' : ''; + replacement: function (content, node) { + var alt = node.getAttribute('alt') || '' + var src + for (var i = 0; i < node.childNodes.length; i++) { + if (node.childNodes[i].localName === 'source') { + src = node.childNodes[i].getAttribute('src') + break + } } + var title = node.title || '' + var titlePart = title ? ' "' + title + '"' : '' + return src ? '![video:' + alt + ']' + '(' + src + titlePart + ')' : '' } }, { filter: 'audio', - replacement: function(content, node) { - var alt = node.getAttribute("alt") || ''; - var src = node.getAttribute('src') || ''; - if (!src) - for (var i = 0; i < node.childNodes.length; i++) - { - if (node.childNodes[i].localName == 'source') { - src = node.childNodes[i].getAttribute('src') ; - break; - } - } - var title = node.title || ''; - var titlePart = title ? ' "'+ title +'"' : ''; - return src ? '![audio:' + alt + ']' + '(' + src + titlePart + ')' : ''; + replacement: function (content, node) { + var alt = node.getAttribute('alt') || '' + var src = node.getAttribute('src') || '' + if (!src) { + for (var i = 0; i < node.childNodes.length; i++) { + if (node.childNodes[i].localName === 'source') { + src = node.childNodes[i].getAttribute('src') + break + } } } + var title = node.title || '' + var titlePart = title ? ' "' + title + '"' : '' + return src ? '![audio:' + alt + ']' + '(' + src + titlePart + ')' : '' } }, + { filter: 'img', - replacement: function(content, node) { - var alt = node.getAttribute("alt") || ''; - var src = node.getAttribute('src') || ''; - var title = node.getAttribute('title') || ''; - var titlePart = title ? ' "'+ title +'"' : ''; - return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : ''; + replacement: function (content, node) { + var alt = node.alt || '' + var src = node.getAttribute('src') || '' + var title = node.title || '' + var titlePart = title ? ' "' + title + '"' : '' + return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : '' } }, // Code blocks { filter: function (node) { - return node.nodeName === 'PRE' && node.firstChild.nodeName === 'CODE'; + return node.nodeName === 'PRE' && node.firstChild.nodeName === 'CODE' }, - replacement: function(content, node) { - return '\n\n ' + node.firstChild.textContent.replace(/\n/g, '\n ') + '\n\n'; + replacement: function (content, node) { + return '\n\n ' + node.firstChild.textContent.replace(/\n/g, '\n ') + '\n\n' } }, { filter: 'blockquote', replacement: function (content) { - content = this.trim(content); - content = content.replace(/\n{3,}/g, '\n\n'); - content = content.replace(/^/gm, '> '); - return '\n\n' + content + '\n\n'; + content = content.trim() + content = content.replace(/\n{3,}/g, '\n\n') + content = content.replace(/^/gm, '> ') + return '\n\n' + content + '\n\n' } }, { filter: 'li', replacement: function (content, node) { - content = content.replace(/^\s+/, '').replace(/\n/gm, '\n '); - var prefix = '* '; - var parent = node.parentNode; - var index = Array.prototype.indexOf.call(parent.children, node) + 1; + content = content.replace(/^\s+/, '').replace(/\n/gm, '\n ') + var prefix = '* ' + var parent = node.parentNode + var index = Array.prototype.indexOf.call(parent.children, node) + 1 - prefix = /ol/i.test(parent.nodeName) ? index + '. ' : '* '; - return prefix + content; + prefix = /ol/i.test(parent.nodeName) ? index + '. ' : '* ' + return prefix + content } }, { filter: ['ul', 'ol'], replacement: function (content, node) { - var strings = []; + var strings = [] for (var i = 0; i < node.childNodes.length; i++) { - strings.push(node.childNodes[i]._replacement); + strings.push(node.childNodes[i]._replacement) } if (/li/i.test(node.parentNode.nodeName)) { - return '\n' + strings.join('\n'); + return '\n' + strings.join('\n') } - return '\n\n' + strings.join('\n') + '\n\n'; + return '\n\n' + strings.join('\n') + '\n\n' } }, { filter: function (node) { - return this.isBlock(node); + return this.isBlock(node) }, replacement: function (content, node) { - return '\n\n' + this.outer(node, content) + '\n\n'; + return '\n\n' + this.outer(node, content) + '\n\n' } }, // Anything else! { filter: function () { - return true; + return true }, replacement: function (content, node) { - return this.outer(node, content); + return this.outer(node, content) } } +] + +},{}],5:[function(require,module,exports){ +/** + * This file automatically generated from `build.js`. + * Do not manually edit. + */ + +module.exports = [ + "address", + "article", + "aside", + "audio", + "blockquote", + "canvas", + "dd", + "div", + "dl", + "fieldset", + "figcaption", + "figure", + "footer", + "form", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "header", + "hgroup", + "hr", + "main", + "nav", + "noscript", + "ol", + "output", + "p", + "pre", + "section", + "table", + "tfoot", + "ul", + "video" ]; -},{}],4:[function(require,module,exports){ +},{}],6:[function(require,module,exports){ + +},{}],7:[function(require,module,exports){ 'use strict'; var voidElements = require('void-elements'); @@ -738,51 +813,7 @@ function next(prev, current) { module.exports = collapseWhitespace; -},{"block-elements":5,"void-elements":6}],5:[function(require,module,exports){ -/** - * This file automatically generated from `build.js`. - * Do not manually edit. - */ - -module.exports = [ - "address", - "article", - "aside", - "audio", - "blockquote", - "canvas", - "dd", - "div", - "dl", - "fieldset", - "figcaption", - "figure", - "footer", - "form", - "h1", - "h2", - "h3", - "h4", - "h5", - "h6", - "header", - "hgroup", - "hr", - "main", - "nav", - "noscript", - "ol", - "output", - "p", - "pre", - "section", - "table", - "tfoot", - "ul", - "video" -]; - -},{}],6:[function(require,module,exports){ +},{"block-elements":5,"void-elements":8}],8:[function(require,module,exports){ /** * This file automatically generated from `pre-publish.js`. * Do not manually edit. @@ -807,7 +838,5 @@ module.exports = { "wbr": true }; -},{}],7:[function(require,module,exports){ - },{}]},{},[1])(1) }); \ No newline at end of file From a0ad5225e80c74c87f34f5fb975f8e2512c89b44 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Wed, 9 Nov 2016 11:21:00 +0100 Subject: [PATCH 05/11] cleaning --- Yavsc/Temp/estimate-8.tex | 146 -------------------------------------- 1 file changed, 146 deletions(-) delete mode 100644 Yavsc/Temp/estimate-8.tex diff --git a/Yavsc/Temp/estimate-8.tex b/Yavsc/Temp/estimate-8.tex deleted file mode 100644 index 82c06f27..00000000 --- a/Yavsc/Temp/estimate-8.tex +++ /dev/null @@ -1,146 +0,0 @@ -\documentclass[french,11pt]{article} -\usepackage{babel} -\usepackage[T1]{fontenc} -\usepackage[utf8]{inputenc} -\usepackage[a4paper]{geometry} -\usepackage{units} -\usepackage{bera} -\usepackage{graphicx} -\usepackage{fancyhdr} -\usepackage{fp} - -\def\TVA{20} % Taux de la TVA - -\def\TotalHT{0} -\def\TotalTVA{0} - -\newcommand{\AjouterService}[3]{% Arguments : Désignation, quantité, prix - \FPround{\prix}{#3}{2} - \FPeval{\montant}{#2 * #3} - \FPround{\montant}{\montant}{2} - \FPadd{\TotalHT}{\TotalHT}{\montant} - - \eaddto\ListeProduits{#1 & \prix & #2 & \montant \cr} -} - - -\newcommand{\AfficheResultat}{% - \ListeProduits - - \FPeval{\TotalTVA}{\TotalHT * \TVA / 100} - \FPadd{\TotalTTC}{\TotalHT}{\TotalTVA} - \FPround{\TotalHT}{\TotalHT}{2} - \FPround{\TotalTVA}{\TotalTVA}{2} - \FPround{\TotalTTC}{\TotalTTC}{2} - \global\let\TotalHT\TotalHT - \global\let\TotalTVA\TotalTVA - \global\let\TotalTTC\TotalTTC - - - \cr - \hline - \textbf{Total} & & & \TotalHT -} - -\newcommand*\eaddto[2]{% version développée de \addto - \edef\tmp{#2}% - \expandafter\addto - \expandafter#1% - \expandafter{\tmp}% -} - -\newcommand{\ListeProduits}{} - -%%%%%%%%%%%%%%%%%%%%% A MODIFIER DANS LA FACTURE %%%%%%%%%%%%%%%%%%%%% - -\def\FactureNum {8} % Numéro de facture -\def\FactureAcquittee {non} % Facture acquittée : oui/non -\def\FactureLieu {2 Boulevard Aristide Briand, 92150 Suresnes, France} % Lieu de l'édition de la facture -\def\FactureObjet {Facture : } % Objet du document -% Description de la facture -\def\FactureDescr { - # **Hello Estimate!** coup blah -} - -% Infos Client -\def\ClientNom{Paul} % Nom du client - -\def\ClientAdresse{ -% Adresse du client - E-mail: redienhcs.luap@gmail.com -} - -% Liste des produits facturés : Désignation, prix - - -\AjouterService {une première} {3} {121,6000} - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - - -\geometry{verbose,tmargin=4em,bmargin=8em,lmargin=6em,rmargin=6em} -\setlength{\parindent}{0pt} -\setlength{\parskip}{1ex plus 0.5ex minus 0.2ex} - -\thispagestyle{fancy} -\pagestyle{fancy} -\setlength{\parindent}{0pt} - -\renewcommand{\headrulewidth}{0pt} -\cfoot{ Paul - 2 Boulevard Aristide Briand, 92150 Suresnes, France \newline - \small{ E-mail: redienhcs.luap@gmail.com - } -} - -\begin{document} - -% Logo de la société - -%\includegraphics{logo.png} -% Nom et adresse de la société - Paul \\ - 2 Boulevard Aristide Briand, 92150 Suresnes, France - -Facture n°\FactureNum - - -{\addtolength{\leftskip}{10.5cm} %in ERT - \textbf{\ClientNom} \\ - \ClientAdresse \\ - -} %in ERT - - -\hspace*{10.5cm} -\FactureLieu, le \today - -~\\~\\ - -\textbf{Objet : \FactureObjet \\} - -\textnormal{\FactureDescr} - -~\\ - -\begin{center} - \begin{tabular}{lrrr} - \textbf{Désignation ~~~~~~} & \textbf{Prix unitaire} & \textbf{Quantité} & \textbf{Montant (EUR)} \\ - \hline - \AfficheResultat{} - \end{tabular} -\end{center} - -\begin{flushright} -\textit{Auto entreprise en franchise de TVA}\\ - -\end{flushright} -~\\ - -\ifthenelse{\equal{\FactureAcquittee}{oui}}{ - Facture acquittée. -}{ - -} -\end{document} From bd39e900ef4e336f2bf86ccb6b8f40e3dd834af8 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Wed, 9 Nov 2016 11:22:28 +0100 Subject: [PATCH 06/11] cleaning --- .../estimate-3.pdf | Bin 16587 -> 0 bytes .../tmpestimtex-3.pdf | Bin 16587 -> 0 bytes Yavsc/Bills/estimate-3.pdf | Bin 16587 -> 0 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Yavsc/Bills/a94433b4-f11f-4a4b-8066-b32c1ab1103d/estimate-3.pdf delete mode 100644 Yavsc/Bills/a94433b4-f11f-4a4b-8066-b32c1ab1103d/tmpestimtex-3.pdf delete mode 100644 Yavsc/Bills/estimate-3.pdf diff --git a/Yavsc/Bills/a94433b4-f11f-4a4b-8066-b32c1ab1103d/estimate-3.pdf b/Yavsc/Bills/a94433b4-f11f-4a4b-8066-b32c1ab1103d/estimate-3.pdf deleted file mode 100644 index ba625e66d4ad364d87a7c12eaa903b5c63101c96..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16587 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 From 207b0e86646c7142d3dfacd310e5748238d2a8fc Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Wed, 9 Nov 2016 14:03:57 +0100 Subject: [PATCH 07/11] A view component --- Yavsc/ApiControllers/PdfEstimateController.cs | 101 +++++++++++++-- Yavsc/Controllers/FrontOfficeController.cs | 121 +----------------- Yavsc/Helpers/TagHelpers.cs | 1 - Yavsc/Helpers/TeXHelpers.cs | 35 +++++ Yavsc/ViewComponents/EstimateViewComponent.cs | 58 +++++++++ .../ViewModels/Gen/PdfGenerationViewModel.cs | 14 ++ Yavsc/Views/Estimate/Details.cshtml | 9 +- Yavsc/Views/FrontOffice/Estimate.pdf.cshtml | 51 -------- .../Components/Estimate/Estimate_pdf.cshtml | 50 ++++++++ .../Components/Estimate/Estimate_tex.cshtml} | 5 +- Yavsc/project.json | 3 +- 11 files changed, 258 insertions(+), 190 deletions(-) create mode 100644 Yavsc/ViewComponents/EstimateViewComponent.cs create mode 100644 Yavsc/ViewModels/Gen/PdfGenerationViewModel.cs delete mode 100644 Yavsc/Views/FrontOffice/Estimate.pdf.cshtml create mode 100644 Yavsc/Views/Shared/Components/Estimate/Estimate_pdf.cshtml rename Yavsc/Views/{FrontOffice/Estimate.tex.cshtml => Shared/Components/Estimate/Estimate_tex.cshtml} (99%) diff --git a/Yavsc/ApiControllers/PdfEstimateController.cs b/Yavsc/ApiControllers/PdfEstimateController.cs index 08428c38..3ace640d 100644 --- a/Yavsc/ApiControllers/PdfEstimateController.cs +++ b/Yavsc/ApiControllers/PdfEstimateController.cs @@ -1,19 +1,66 @@ -using System; using System.IO; -using System.Security.Claims; using Microsoft.AspNet.Authorization; using Microsoft.AspNet.Mvc; +using System.Threading.Tasks; +using System.Web.Routing; +using Microsoft.AspNet.Mvc.ViewComponents; +using Microsoft.AspNet.Razor; namespace Yavsc.ApiControllers { + using Models; + [Route("api/pdfestimate"), Authorize] public class PdfEstimateController : Controller { - [HttpGet("{id}", Name = "Get")] + ApplicationDbContext dbContext; + DefaultViewComponentHelper helper; + IViewComponentDescriptorCollectionProvider provider; + IViewComponentInvokerFactory factory; + RazorEngineHost host; + RazorTemplateEngine engine; + IViewComponentSelector selector; + + + public PdfEstimateController( + IViewComponentDescriptorCollectionProvider provider, + IViewComponentSelector selector, + IViewComponentInvokerFactory factory, + ApplicationDbContext context) + { + + this.selector = selector; + this.provider = provider; + this.factory = factory; + helper = new DefaultViewComponentHelper(provider, selector, factory); + dbContext = context; + + var language = new CSharpRazorCodeLanguage(); + host = new RazorEngineHost(language) + { + DefaultBaseClass = "RazorPage", + DefaultClassName = "Estimate", + DefaultNamespace = "Yavsc", + }; + + // Everyone needs the System namespace, right? + host.NamespaceImports.Add("System"); + engine = new RazorTemplateEngine(host); + + + /* + GeneratorResults razorResult = + engine.GenerateCode( + + ) */ + } + + + [HttpGet("get/{id}", Name = "Get"), Authorize] public IActionResult Get(long id) { var filename = $"estimate-{id}.pdf"; - + var cd = new System.Net.Mime.ContentDisposition { // for example foo.bak @@ -23,15 +70,43 @@ namespace Yavsc.ApiControllers // the browser to try to show the file inline Inline = false, }; - - FileInfo fi = new FileInfo(Path.Combine(Startup.UserBillsDirName,filename)); - - FileStreamResult result = null; - var s = fi.OpenRead(); - - result = File(s,"application/x-pdf",filename); - - return result; + + FileInfo fi = new FileInfo(Path.Combine(Startup.UserBillsDirName, filename)); + if (!fi.Exists) return Ok(new { Error = "Not generated" }); + return File(fi.OpenRead(), "application/x-pdf", filename); ; + } + + [HttpGet("GetComponents", Name = "GetComponents")] + public IActionResult GetComponents() + { + return Ok(provider); + } + + [HttpGet("estimate-{id}.tex", Name = "GetTex"), Authorize] + public IActionResult GetTex(long id) + { + Response.ContentType = "text/x-tex"; + + return ViewComponent("Estimate",new object[] { id, false }); + } + + [HttpGet("gen/{id}")] + public async Task GeneratePdf(long id) + { + /* + + using (TextWriter wr = new StringWriter()) { + ViewComponentContext ctx = new ViewComponentContext( + selector.SelectComponent("Estimate"), new object[]{id}, + new ViewContext(), + wr + ); + + } + + */ + + return ViewComponent("Estimate",new object[] { id, true } ); } } } \ No newline at end of file diff --git a/Yavsc/Controllers/FrontOfficeController.cs b/Yavsc/Controllers/FrontOfficeController.cs index 8eed5407..e3a0959f 100644 --- a/Yavsc/Controllers/FrontOfficeController.cs +++ b/Yavsc/Controllers/FrontOfficeController.cs @@ -8,16 +8,6 @@ using Microsoft.Extensions.Logging; using Yavsc.Models.Booking; using Yavsc.Helpers; using System; -using System.IO; -using System.Diagnostics; -using System.Text; -using Microsoft.AspNet.Mvc.ViewFeatures; -using Microsoft.AspNet.Razor; -using Microsoft.AspNet.Mvc.ViewEngines; -using Microsoft.AspNet.Mvc.Rendering; -using Microsoft.Extensions.OptionsModel; -using System.Threading.Tasks; -using System.Security.Claims; namespace Yavsc.Controllers { @@ -111,23 +101,11 @@ namespace Yavsc.Controllers return View("Estimate.tex", estimate); } - class TeOtions : IOptions - { - public MvcViewOptions Value - { - get - { - return new MvcViewOptions(); - } - } - } - [Authorize,Route("Estimate-{id}.pdf")] - public async Task EstimatePdf(long id) + public IActionResult EstimatePdf(long id) { ViewBag.TempDir = Startup.SiteSetup.TempDir; ViewBag.BillsDir = Startup.UserBillsDirName; - var estimate = _context.Estimates.Include(x => x.Query) .Include(x => x.Query.Client) .Include(x => x.Query.PerformerProfile) @@ -136,102 +114,7 @@ namespace Yavsc.Controllers .Include(e => e.Bill).FirstOrDefault(x => x.Id == id); if (estimate==null) throw new Exception("No data"); - return View("Estimate.pdf",estimate); - /* - await result.ExecuteResultAsync(ActionContext); - var cd = new System.Net.Mime.ContentDisposition - { - // for example foo.bak - FileName = $"estimate-{id}.pdf", - - // always prompt the user for downloading, set to true if you want - // the browser to try to show the file inline - Inline = false, - }; - Response.Headers.Add("Content-Disposition", cd.ToString()); - return File((Byte[])ViewData["Pdf"], "application/x-pdf"); */ } - /* - - [Produces("application/x-pdf"), Authorize, Route("testimate-{id}.pdf")] - public async Task BadEstimatePdf(long id) - { - - var tempDir = Startup.SiteSetup.TempDir; - - string name = $"tmpestimtex-{id}"; - string fullname = new FileInfo( - System.IO.Path.Combine(tempDir, name)).FullName; - var writer = new System.IO.StringWriter(); - try - { - using (StringWriter sw = new StringWriter()) - { - Microsoft.AspNet.Mvc.ViewEngines.CompositeViewEngine ve = new CompositeViewEngine( - new TeOtions {} - ); - - ViewEngineResult viewResult = ve.FindPartialView(ActionContext, $"estimate-{id}.tex"); - ViewContext viewContext = new ViewContext(); // ActionContext, viewResult.View, ViewData, TempData, sw); - await viewResult.View.RenderAsync(viewContext); - } - } catch (Exception ex) - { - - } - - - - - FileInfo fo = new FileInfo(fullname + ".pdf"); - if (!fi.Exists) - { - throw new Exception("Source write failed"); - } - using (Process p = new Process()) - { - p.StartInfo.WorkingDirectory = tempDir; - p.StartInfo = new ProcessStartInfo(); - p.StartInfo.UseShellExecute = false; - p.StartInfo.FileName = "/usr/bin/texi2pdf"; - p.StartInfo.Arguments = $"--batch --build-dir=."; - - p.Start(); - - using (p.StandardInput) - { - - } - p.WaitForExit(); - if (p.ExitCode != 0) - { - throw new Exception("Pdf generation failed with exit code:" + p.ExitCode); - } - } - byte[] pdf = null; - if (fo.Exists) - { - using (StreamReader sr = new StreamReader(fo.FullName)) - { - pdf = System.IO.File.ReadAllBytes(fo.FullName); - } - fo.Delete(); - } - fi.Delete(); - - - var cd = new System.Net.Mime.ContentDisposition - { - // for example foo.bak - FileName = $"estimate-{id}.pdf", - - // always prompt the user for downloading, set to true if you want - // the browser to try to show the file inline - Inline = false, - }; - Response.Headers.Add("Content-Disposition", cd.ToString()); - return File(pdf, "application/x-pdf"); - } */ } -} \ No newline at end of file +} diff --git a/Yavsc/Helpers/TagHelpers.cs b/Yavsc/Helpers/TagHelpers.cs index fca20b37..974cbaa7 100644 --- a/Yavsc/Helpers/TagHelpers.cs +++ b/Yavsc/Helpers/TagHelpers.cs @@ -68,7 +68,6 @@ namespace Yavsc.Helpers /// /// Transforms a string of Markdown into HTML. /// - /// HtmlHelper - Not used, but required to make this an extension method. /// The Markdown that should be transformed. /// The url Base Location. /// The HTML representation of the supplied Markdown. diff --git a/Yavsc/Helpers/TeXHelpers.cs b/Yavsc/Helpers/TeXHelpers.cs index 2157520a..0c1d82e9 100644 --- a/Yavsc/Helpers/TeXHelpers.cs +++ b/Yavsc/Helpers/TeXHelpers.cs @@ -1,4 +1,12 @@ +using System; +using System.IO; using System.Linq; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Mvc; +using Microsoft.AspNet.Mvc.ModelBinding; +using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.AspNet.Mvc.ViewEngines; +using Microsoft.AspNet.Mvc.ViewFeatures; namespace Yavsc.Helpers { @@ -11,5 +19,32 @@ namespace Yavsc.Helpers return string.Join(separator, items); } + public static string RenderViewToString( + this Controller controller, IViewEngine engine, + IHttpContextAccessor httpContextAccessor, + string viewName, object model) +{ + using (var sw = new StringWriter()) + { + if (engine == null) + throw new InvalidOperationException("no engine"); + + // try to find the specified view + controller.TryValidateModel(model); + ViewEngineResult viewResult = engine.FindPartialView(controller.ActionContext, viewName); + // create the associated context + ViewContext viewContext = new ViewContext(); + viewContext.ActionDescriptor = controller.ActionContext.ActionDescriptor; + viewContext.HttpContext = controller.ActionContext.HttpContext; + viewContext.TempData = controller.TempData; + viewContext.View = viewResult.View; + viewContext.Writer = sw; + + // write the render view with the given context to the stringwriter + viewResult.View.RenderAsync(viewContext); + viewResult.EnsureSuccessful(); + return sw.GetStringBuilder().ToString(); + } +} } } \ No newline at end of file diff --git a/Yavsc/ViewComponents/EstimateViewComponent.cs b/Yavsc/ViewComponents/EstimateViewComponent.cs new file mode 100644 index 00000000..720bc2f1 --- /dev/null +++ b/Yavsc/ViewComponents/EstimateViewComponent.cs @@ -0,0 +1,58 @@ +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNet.Mvc; +using Microsoft.Data.Entity; +using Yavsc.Models; +using Yavsc.Models.Billing; +using Yavsc.ViewModels.Gen; + +namespace Yavsc.ViewComponents +{ + public class EstimateViewComponent : ViewComponent + { + ApplicationDbContext dbContext; + public EstimateViewComponent(ApplicationDbContext dbContext) + { + this.dbContext = dbContext; + } + public async Task InvokeAsync(long id, bool toPdf = false) + { + Estimate estimate = + dbContext.Estimates.Include(x => x.Query) + .Include(x => x.Query.Client) + .Include(x => x.Query.PerformerProfile) + .Include(x => x.Query.PerformerProfile.OrganizationAddress) + .Include(x => x.Query.PerformerProfile.Performer) + .Include(e => e.Bill).FirstOrDefault(x => x.Id == id); + if (estimate == null) + throw new Exception("No data"); + if (toPdf) + { + string tex = null; + var oldWriter = ViewComponentContext.ViewContext.Writer; + + using (var writer = new StringWriter()) + { + this.ViewComponentContext.ViewContext.Writer = writer; + + var resultTex = View("Estimate_tex", estimate); + resultTex.Execute(this.ViewComponentContext); + tex = writer.ToString(); + + } + ViewComponentContext.ViewContext.Writer = oldWriter; + + return this.View("Estimate_pdf", + new PdfGenerationViewModel{ + TeXSource = tex, + DestDir = Startup.UserBillsDirName, + BaseFileName = $"estimate-{id}" + } ); + } + return this.View("Estimate_tex", estimate); + } + + } +} \ No newline at end of file diff --git a/Yavsc/ViewModels/Gen/PdfGenerationViewModel.cs b/Yavsc/ViewModels/Gen/PdfGenerationViewModel.cs new file mode 100644 index 00000000..6c193de4 --- /dev/null +++ b/Yavsc/ViewModels/Gen/PdfGenerationViewModel.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; + +namespace Yavsc.ViewModels.Gen +{ + public class PdfGenerationViewModel + { + [Required] + public string TeXSource { get; set; } + [Required] + public string BaseFileName { get; set; } + [Required] + public string DestDir { get; set; } + } +} \ No newline at end of file diff --git a/Yavsc/Views/Estimate/Details.cshtml b/Yavsc/Views/Estimate/Details.cshtml index 87afc47b..696398ab 100644 --- a/Yavsc/Views/Estimate/Details.cshtml +++ b/Yavsc/Views/Estimate/Details.cshtml @@ -39,6 +39,11 @@ @SR["Back to List"] | @{ var filenametex = $"estimate-{Model.Id}.tex" ; var filenamepdf = $"estimate-{Model.Id}.pdf" ;} - Export au format LaTeX - Export au format Pdf + Export au format LaTeX | + + +
+ +
+

diff --git a/Yavsc/Views/FrontOffice/Estimate.pdf.cshtml b/Yavsc/Views/FrontOffice/Estimate.pdf.cshtml deleted file mode 100644 index aefd3826..00000000 --- a/Yavsc/Views/FrontOffice/Estimate.pdf.cshtml +++ /dev/null @@ -1,51 +0,0 @@ -@using System.Reflection; -@using System.IO; -@using Microsoft.Extensions.WebEncoders; -@using System.Diagnostics; -@using System.Text; -@using Yavsc.Formatters; -@model Estimate -@{ - if (ViewBag.TempDir==null) { throw new InvalidOperationException(); } - - ViewBag.Pdf = ""; - ViewBag.TeX = ""; - var writer = new System.IO.StringWriter(); - var content = await Html.PartialAsync("Estimate.tex", Model ); - content.WriteTo(writer, new TexEncoder()); - var contentStr = writer.ToString(); - string name = $"estimate-{Model.Id}"; - string fullname = new FileInfo( - System.IO.Path.Combine(ViewBag.TempDir,name)).FullName; - string ofullname = new FileInfo( - System.IO.Path.Combine(ViewBag.BillsDir,name)).FullName; - - FileInfo fi = new FileInfo(fullname + ".tex"); - FileInfo fo = new FileInfo(ofullname + ".pdf"); - using (StreamWriter sw = new StreamWriter (fi.FullName)) - { - sw.Write (contentStr); - } - if (!fi.Exists) - { - throw new Exception ("Source write failed"); - } - using (Process p = new Process ()) { - p.StartInfo.WorkingDirectory = ViewBag.TempDir; - p.StartInfo = new ProcessStartInfo (); - p.StartInfo.UseShellExecute = false; - p.StartInfo.FileName = "/usr/bin/texi2pdf"; - p.StartInfo.Arguments = $"--batch --build-dir=. -o {fo.FullName} {fi.FullName}"; - p.Start (); - p.WaitForExit (); - if (p.ExitCode != 0) { - throw new Exception ("Pdf generation failed with exit code:" + p.ExitCode); - } - } - ViewBag.Success = fo.Exists; - fi.Delete(); - var uri = $"~/api/pdfestimate/{Model.Id}"; - -} - -@uri \ No newline at end of file diff --git a/Yavsc/Views/Shared/Components/Estimate/Estimate_pdf.cshtml b/Yavsc/Views/Shared/Components/Estimate/Estimate_pdf.cshtml new file mode 100644 index 00000000..08664810 --- /dev/null +++ b/Yavsc/Views/Shared/Components/Estimate/Estimate_pdf.cshtml @@ -0,0 +1,50 @@ +@using System.Reflection +@using System.IO +@using Microsoft.Extensions.WebEncoders +@using System.Diagnostics +@using System.Text +@using Yavsc.Formatters +@model Yavsc.ViewModels.Gen.PdfGenerationViewModel +@{ + string errorMsg = null; + var billdir = Model.DestDir; + var tempdir = Startup.SiteSetup.TempDir; + string name = Model.BaseFileName; + string fullname = new FileInfo( + System.IO.Path.Combine(tempdir,name)).FullName; + string ofullname = new FileInfo( + System.IO.Path.Combine(billdir,name)).FullName; + + FileInfo fi = new FileInfo(fullname + ".tex"); + FileInfo fo = new FileInfo(ofullname + ".pdf"); + using (StreamWriter sw = new StreamWriter (fi.FullName)) + { + sw.Write (Model.TeXSource); + } + if (!fi.Exists) + { + errorMsg = "Source write failed"; + } + else { + using (Process p = new Process ()) { + p.StartInfo.WorkingDirectory = tempdir; + p.StartInfo = new ProcessStartInfo (); + p.StartInfo.UseShellExecute = false; + p.StartInfo.FileName = "/usr/bin/texi2pdf"; + p.StartInfo.Arguments = $"--batch --build-dir=. -o {fo.FullName} {fi.FullName}"; + p.Start (); + p.WaitForExit (); + if (p.ExitCode != 0) { + errorMsg = $"Pdf generation failed with exit code: {p.ExitCode}"; + } + } + fi.Delete(); + } + ViewBag.GenSuccess = fo.Exists; +} +@if (ViewBag.GenSuccess) { + @($"{name}.pdf") +} else { + @errorMsg + Something went wrong ... +} \ No newline at end of file diff --git a/Yavsc/Views/FrontOffice/Estimate.tex.cshtml b/Yavsc/Views/Shared/Components/Estimate/Estimate_tex.cshtml similarity index 99% rename from Yavsc/Views/FrontOffice/Estimate.tex.cshtml rename to Yavsc/Views/Shared/Components/Estimate/Estimate_tex.cshtml index 5b807102..142f19cf 100644 --- a/Yavsc/Views/FrontOffice/Estimate.tex.cshtml +++ b/Yavsc/Views/Shared/Components/Estimate/Estimate_tex.cshtml @@ -1,6 +1,6 @@ -@model Estimate @using Yavsc.Helpers @using System.Globalization +@model Estimate @{ Layout = null; var pro = Model.Query.PerformerProfile; @@ -10,8 +10,7 @@ var proaddr = Model.Query?.PerformerProfile.OrganizationAddress.Address; var proaddrn = (proaddr!=null) ? proaddr.NewLinesWith("\\\\\n") : null ; var proaddrm = (proaddr!=null) ? proaddr.NewLinesWith(" - ") : null ; -} -\documentclass[french,11pt]{article} +}\documentclass[french,11pt]{article} \usepackage{eurosym} \usepackage{babel} \usepackage[T1]{fontenc} diff --git a/Yavsc/project.json b/Yavsc/project.json index e8fd7ef1..96bcff9c 100755 --- a/Yavsc/project.json +++ b/Yavsc/project.json @@ -140,5 +140,6 @@ "postrestore": "echo after restoring packages", "prepublish": "gulp min", "postpublish": "echo \" . ./contrib/postPublish.sh # to push in prod.\"" - } + }, + "embed": "Views/**/*.cshtml" } \ No newline at end of file From 78cda657426c316b856eb4654495f20065d86791 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Thu, 10 Nov 2016 01:02:26 +0100 Subject: [PATCH 08/11] =?UTF-8?q?Fixe=20la=20cr=C3=A9ation=20des=20dossier?= =?UTF-8?q?s=20manquants?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit à l'installation, le dossier des fichiers temporaires, ou autres sont créés si inéxistant au démarrage --- Yavsc/Startup/Startup.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Yavsc/Startup/Startup.cs b/Yavsc/Startup/Startup.cs index bcd7ffe0..e06782e9 100755 --- a/Yavsc/Startup/Startup.cs +++ b/Yavsc/Startup/Startup.cs @@ -230,10 +230,17 @@ namespace Yavsc ILoggerFactory loggerFactory) { SiteSetup = siteSettings.Value; - var tempdi = new DirectoryInfo(SiteSetup.TempDir); - if (!tempdi.Exists) tempdi.Create(); Startup.UserFilesDirName = siteSettings.Value.UserFiles.DirName; Startup.UserBillsDirName = siteSettings.Value.UserFiles.Bills; + + // TODO implement an installation & upgrade procedure + // Create required directories + foreach (string dir in new string[] { Startup.UserFilesDirName, Startup.UserBillsDirName, SiteSetup.TempDir }) + { + DirectoryInfo di = new DirectoryInfo(dir); + if (!di.Exists) di.Create(); + } + loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); logger = loggerFactory.CreateLogger(); From aa966aaa83855037fbae4f4e984030d40375c0b3 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Thu, 10 Nov 2016 01:02:57 +0100 Subject: [PATCH 09/11] POST required to generate the Pdf resource --- Yavsc/ApiControllers/PdfEstimateController.cs | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/Yavsc/ApiControllers/PdfEstimateController.cs b/Yavsc/ApiControllers/PdfEstimateController.cs index 3ace640d..10ba682e 100644 --- a/Yavsc/ApiControllers/PdfEstimateController.cs +++ b/Yavsc/ApiControllers/PdfEstimateController.cs @@ -76,36 +76,16 @@ namespace Yavsc.ApiControllers return File(fi.OpenRead(), "application/x-pdf", filename); ; } - [HttpGet("GetComponents", Name = "GetComponents")] - public IActionResult GetComponents() - { - return Ok(provider); - } - [HttpGet("estimate-{id}.tex", Name = "GetTex"), Authorize] public IActionResult GetTex(long id) { Response.ContentType = "text/x-tex"; - return ViewComponent("Estimate",new object[] { id, false }); } - [HttpGet("gen/{id}")] + [HttpPost("gen/{id}")] public async Task GeneratePdf(long id) { - /* - - using (TextWriter wr = new StringWriter()) { - ViewComponentContext ctx = new ViewComponentContext( - selector.SelectComponent("Estimate"), new object[]{id}, - new ViewContext(), - wr - ); - - } - - */ - return ViewComponent("Estimate",new object[] { id, true } ); } } From c174187b9fa0065829b62278c42b20f5920875ec Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Thu, 10 Nov 2016 01:03:49 +0100 Subject: [PATCH 10/11] =?UTF-8?q?Fixe=20la=20g=C3=A9n=C3=A9ration=20du=20c?= =?UTF-8?q?ode=20LaTeX?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Yavsc/Helpers/TeXHelpers.cs | 60 +++++++++++++++++++ .../Components/Estimate/Estimate_tex.cshtml | 34 +++++------ 2 files changed, 77 insertions(+), 17 deletions(-) diff --git a/Yavsc/Helpers/TeXHelpers.cs b/Yavsc/Helpers/TeXHelpers.cs index 0c1d82e9..3f5860f9 100644 --- a/Yavsc/Helpers/TeXHelpers.cs +++ b/Yavsc/Helpers/TeXHelpers.cs @@ -10,6 +10,59 @@ using Microsoft.AspNet.Mvc.ViewFeatures; namespace Yavsc.Helpers { + public class TeXString { + + public class Replacement { + string target; + string replacement; + public Replacement(string target, string replacement){ + this.target=target; + this.replacement=replacement; + } + public string Execute(string source) + { + return source.Replace(target,replacement); + } + } + + public readonly static Replacement[] SpecialCharsToCommands = + { + new Replacement("<","\\textless"), + new Replacement(">","\\textgreater"), + new Replacement("©","\\copyright"), + new Replacement("®","\\textregistered"), + new Replacement("\\","\\textbackslash"), + new Replacement("™","\\texttrademark"), + new Replacement("¶","\\P"), + new Replacement("|","\\textbar"), + new Replacement("%","\\%"), + new Replacement("{","\\{"), + new Replacement("}","\\}"), + new Replacement("_","\\_"), + new Replacement("#","\\#"), + new Replacement("$","\\$"), + new Replacement("_","\\_"), + new Replacement("¿","\\textquestiondown"), + new Replacement("§","\\S"), + new Replacement("£","\\pounds"), + new Replacement("&","\\&"), + new Replacement("¡","\\textexclamdown"), + new Replacement("†","\\dag"), + new Replacement("–","\\textendash") + }; + string data; + public TeXString(string str) { + data = str; + foreach (var r in SpecialCharsToCommands) { + data = r.Execute(data); + } + } + + override public string ToString() + { + return data; + } + } public static class TeXHelpers { public static string NewLinesWith(this string target, string separator) @@ -19,6 +72,13 @@ namespace Yavsc.Helpers return string.Join(separator, items); } + + public static TeXString ToTeX(string target, string lineSeparator="\n\\\\") + { + if (target==null) return null; + return new TeXString(target.NewLinesWith(lineSeparator)); + } + public static string RenderViewToString( this Controller controller, IViewEngine engine, IHttpContextAccessor httpContextAccessor, diff --git a/Yavsc/Views/Shared/Components/Estimate/Estimate_tex.cshtml b/Yavsc/Views/Shared/Components/Estimate/Estimate_tex.cshtml index 142f19cf..5f8c9d89 100644 --- a/Yavsc/Views/Shared/Components/Estimate/Estimate_tex.cshtml +++ b/Yavsc/Views/Shared/Components/Estimate/Estimate_tex.cshtml @@ -69,28 +69,28 @@ \def\FactureNum {@Model.Id.ToString()} % Numéro de facture \def\FactureAcquittee {non} % Facture acquittée : oui/non \def\FactureLieu {@proaddrn} % Lieu de l'édition de la facture -\def\FactureObjet {Facture : @Model.Title} % Objet du document +\def\FactureObjet {Facture : @TeXHelpers.ToTeX(Model.Title)} % Objet du document % Description de la facture \def\FactureDescr { - @Model.Description + @TeXHelpers.ToTeX(Model.Description) } % Infos Client -\def\ClientNom{@to.UserName} % Nom du client +\def\ClientNom{@TeXHelpers.ToTeX(to.UserName)} % Nom du client \def\ClientAdresse{ % Adresse du client @if (!string.IsNullOrWhiteSpace(PostalAddress)) { - @PostalAddress\\ } + @TeXHelpers.ToTeX(PostalAddress)\\ } @if (!string.IsNullOrWhiteSpace(to.PhoneNumber)) { - @to.PhoneNumber \\ + @TeXHelpers.ToTeX(to.PhoneNumber)\\ } - E-mail: @to.Email + E-mail: @TeXHelpers.ToTeX(to.Email) } % Liste des produits facturés : Désignation, prix @if (Model.Bill!=null) { foreach (CommandLine line in Model.Bill) { -\AjouterService{@line.Description}{@line.Count}{@line.UnitaryCost.ToString("F2",CultureInfo.InvariantCulture)} +\AjouterService{@TeXHelpers.ToTeX(line.Description)}{@line.Count}{@line.UnitaryCost.ToString("F2",CultureInfo.InvariantCulture)} } } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -106,24 +106,24 @@ \setlength{\parindent}{0pt} \renewcommand{\headrulewidth}{0pt} -\cfoot{ @if (!string.IsNullOrWhiteSpace(from.UserName)) { @from.UserName } - @if (!string.IsNullOrWhiteSpace(proaddrm)) { - @proaddrm } \newline - \small{ E-mail: @from.Email - @if (!string.IsNullOrWhiteSpace(from.PhoneNumber)) { - Téléphone fixe: @from.PhoneNumber } +\cfoot{ @TeXHelpers.ToTeX(from.UserName) @if (!string.IsNullOrWhiteSpace(proaddrm)) { - @TeXHelpers.ToTeX(proaddrm) } \newline + \small{ E-mail: @TeXHelpers.ToTeX(from.Email) @if (!string.IsNullOrWhiteSpace(from.PhoneNumber)) { - Téléphone fixe: @TeXHelpers.ToTeX(from.PhoneNumber) } } } \begin{document} % Logo de la société -@if (from.Avatar != null) { -\includegraphics{@from.Avatar} -} else { -%\includegraphics{logo.png} +@if (from.Avatar != null) { +\includegraphics{@from.Avatar} + +} else { +%\includegraphics{logo.png} + } % Nom et adresse de la société - @from.UserName \\ - @proaddrn + @TeXHelpers.ToTeX(from.UserName) \\ + @TeXHelpers.ToTeX(proaddrn) Facture n°\FactureNum From 5734e680faf455da0decdf12f869c411905d0519 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Thu, 10 Nov 2016 01:04:06 +0100 Subject: [PATCH 11/11] MAJ des liens --- Yavsc/Views/Estimate/Details.cshtml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Yavsc/Views/Estimate/Details.cshtml b/Yavsc/Views/Estimate/Details.cshtml index 696398ab..a838acf4 100644 --- a/Yavsc/Views/Estimate/Details.cshtml +++ b/Yavsc/Views/Estimate/Details.cshtml @@ -39,11 +39,12 @@ @SR["Back to List"] | @{ var filenametex = $"estimate-{Model.Id}.tex" ; var filenamepdf = $"estimate-{Model.Id}.pdf" ;} - Export au format LaTeX | + Export au format LaTeX -
+
+ Télécharger le document