PlantillaService.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. package es.uv.saic.service;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.io.PrintWriter;
  6. import java.io.Reader;
  7. import java.io.UncheckedIOException;
  8. import java.math.BigInteger;
  9. import java.nio.file.Files;
  10. import java.text.DecimalFormat;
  11. import java.util.Base64;
  12. import java.util.List;
  13. import java.util.Optional;
  14. import java.util.regex.Matcher;
  15. import java.util.regex.Pattern;
  16. import org.jsoup.Jsoup;
  17. import org.jsoup.nodes.Document;
  18. import org.jsoup.nodes.Element;
  19. import org.springframework.beans.factory.annotation.Autowired;
  20. import org.springframework.beans.factory.annotation.Value;
  21. import org.springframework.core.io.DefaultResourceLoader;
  22. import org.springframework.core.io.Resource;
  23. import org.springframework.core.io.ResourceLoader;
  24. import org.springframework.stereotype.Service;
  25. import org.springframework.util.FileCopyUtils;
  26. import com.fasterxml.jackson.core.JsonParseException;
  27. import com.fasterxml.jackson.core.type.TypeReference;
  28. import com.fasterxml.jackson.databind.JsonMappingException;
  29. import com.fasterxml.jackson.databind.ObjectMapper;
  30. import es.uv.saic.shared.domain.Plantilla;
  31. import es.uv.saic.shared.domain.PlantillaComentario;
  32. import es.uv.saic.shared.domain.PlantillaConversation;
  33. import es.uv.saic.shared.domain.PlantillaRepository;
  34. import es.uv.saic.shared.dto.InstanciaTascaDTO;
  35. import es.uv.saic.shared.feign.IndicadorClient;
  36. import es.uv.saic.shared.feign.OrganClient;
  37. import es.uv.saic.shared.feign.ProceduresClient;
  38. import es.uv.saic.shared.feign.TascaClient;
  39. @Service
  40. public class PlantillaService {
  41. @Autowired
  42. private PlantillaRepository r;
  43. @Value("${saic.data.filePath}")
  44. private String filePath;
  45. @Value("${saic.data.tmpPath}")
  46. private String tmpPath;
  47. @Value("${saic.data.templates.fileNotFound}")
  48. private String fileNotFound;
  49. @Value("${saic.data.templates.filePath}")
  50. private String templatePath;
  51. @Value("${saic.data.templates.logoPath}")
  52. private String logoPath;
  53. @Autowired
  54. private TascaClient tc;
  55. @Autowired
  56. private OrganClient oc;
  57. @Autowired
  58. private ProceduresClient pc;
  59. @Autowired
  60. private IndicadorClient ic;
  61. private static final DecimalFormat df = new DecimalFormat("0.00");
  62. public List<Plantilla> findAll(){
  63. return this.r.findAll();
  64. }
  65. public Plantilla findByID(Integer id) {
  66. return this.r.findByIdPlantilla(id);
  67. }
  68. public Plantilla findByVersioCodiAmbit(Integer versio, String codi, String ambit) {
  69. return this.r.findByVersioCodiAmbit(versio, codi, ambit);
  70. }
  71. public void save(Plantilla p) {
  72. this.r.save(p);
  73. this.r.flush();
  74. }
  75. public void delete(Plantilla p) {
  76. this.r.delete(p);
  77. }
  78. public boolean isUsed(Integer idPlantilla) {
  79. List<Plantilla> l = this.r.findUsedByIdPlantilla(idPlantilla);
  80. if(l.size() > 0) {
  81. return true;
  82. }
  83. return false;
  84. }
  85. public Plantilla findEvidencia(Integer codiEvidencia, Integer titulacio, String tambit) {
  86. Plantilla p = this.findByID(codiEvidencia);
  87. Plantilla p2 = null;
  88. if(titulacio > 0) {
  89. if(!p.getAmbit().equals(tambit)) {
  90. p2 = this.findByVersioCodiAmbit(p.getVersio(), p.getCodi(), tambit);
  91. }
  92. }
  93. if(p2 != null) {
  94. p = p2;
  95. }
  96. return p;
  97. }
  98. public String savePDF(String content, BigInteger idtascai) throws IOException, InterruptedException {
  99. content = content.replace("<p><!-- pagebreak --></p>", "<p class=\"pagebreak\"><!-- pagebreak --></p>");
  100. Document d = Jsoup.parse(content, "UTF8");
  101. d.head().append("<style>"
  102. + "@page{size: 297mm 210mm;} "
  103. + "html{ max-width:297mm; max-height:210mm; margin:0; padding:0; transform:scale(0.925); transform-origin:left top; } "
  104. + "table { padding:2px !important; }"
  105. + "th, td { padding:2px !important; }"
  106. + ".pagebreak { page-break-before:always; }"
  107. + "</style>");
  108. List<Element> trs = d.getElementsByTag("tr");
  109. for(Element t : trs) {
  110. if(t.hasAttr("height")) {
  111. t.removeAttr("height");
  112. }
  113. if(t.hasAttr("style")) {
  114. String style = t.attr("style");
  115. style = style.replaceAll("height:[ \\d.pxcmin]{1,};", "");
  116. t.attr("style", style);
  117. }
  118. }
  119. List<Element> tds = d.getElementsByTag("td");
  120. for(Element t : tds) {
  121. if(t.hasAttr("height")) {
  122. t.removeAttr("height");
  123. }
  124. if(t.hasAttr("style")) {
  125. String style = t.attr("style");
  126. style = style.replaceAll("height:[ \\d.pxcmin]{1,};", "");
  127. t.attr("style", style);
  128. }
  129. }
  130. List<Element> ignore = d.getElementsByClass("pdfignore");
  131. for(Element e: ignore) {
  132. e.remove();
  133. }
  134. InstanciaTascaDTO ita = tc.findInstanciaTascaById(idtascai);
  135. if(ita.getTasca().getNomRol().equals("u_uq")) {
  136. d.body().append(this.parseComments(d.html()));
  137. }
  138. String basecommand = "google-chrome --headless --disable-gpu --no-pdf-header-footer --run-all-compositor-stages-before-draw --no-sandbox";
  139. String dst = idtascai.toString()+".pdf";
  140. File src = File.createTempFile("saic-pdfexport-", ".tmp.html", new File(tmpPath));
  141. src.deleteOnExit();
  142. PrintWriter out = new PrintWriter(src.getAbsolutePath());
  143. out.println(d.html());
  144. out.flush();
  145. out.close();
  146. System.out.println(basecommand+" --print-to-pdf='"+filePath+dst+"' "+src.getAbsolutePath());
  147. ProcessBuilder pb = new ProcessBuilder("bash", "-c", basecommand+" --print-to-pdf='"+filePath+dst+"' "+src.getAbsolutePath());
  148. Process pr = pb.start();
  149. pr.waitFor();
  150. src.delete();
  151. return dst;
  152. }
  153. public byte[] toPDF(String content, Optional<BigInteger> idtascai) throws IOException, InterruptedException {
  154. content = content.replace("<p><!-- pagebreak --></p>", "<p class=\"pagebreak\"><!-- pagebreak --></p>");
  155. Document d = Jsoup.parse(content, "UTF8");
  156. d.head().append("<style>"
  157. + "@page{size: 297mm 210mm;} "
  158. + "html{ max-width:297mm; max-height:210mm; margin:0; padding:0; transform:scale(0.925); transform-origin:left top; } "
  159. + "table { padding:2px !important; }"
  160. + "th, td { padding:2px !important; }"
  161. + ".pagebreak { page-break-before:always; }"
  162. + "</style>");
  163. List<Element> trs = d.getElementsByTag("tr");
  164. for(Element t : trs) {
  165. if(t.hasAttr("height")) {
  166. t.removeAttr("height");
  167. }
  168. if(t.hasAttr("style")) {
  169. String style = t.attr("style");
  170. style = style.replaceAll("height:[ \\d.pxcmin]{1,};", "");
  171. t.attr("style", style);
  172. }
  173. }
  174. List<Element> tds = d.getElementsByTag("td");
  175. for(Element t : tds) {
  176. if(t.hasAttr("height")) {
  177. t.removeAttr("height");
  178. }
  179. if(t.hasAttr("style")) {
  180. String style = t.attr("style");
  181. style = style.replaceAll("height:[ \\d.pxcmin]{1,};", "");
  182. t.attr("style", style);
  183. }
  184. }
  185. List<Element> ignore = d.getElementsByClass("pdfignore");
  186. for(Element e: ignore) {
  187. e.remove();
  188. }
  189. if(idtascai.isPresent()) {
  190. InstanciaTascaDTO ita = tc.findInstanciaTascaById(idtascai.get());
  191. if(ita.getTasca().getNomRol().equals("u_uq")) {
  192. d.body().append(this.parseComments(d.html()));
  193. }
  194. }
  195. d.body().append(this.parseComments(d.html()));
  196. String basecommand = "google-chrome --headless --disable-gpu --no-pdf-header-footer --run-all-compositor-stages-before-draw --no-sandbox";
  197. File dst = File.createTempFile("saic-pdfpreview-", ".tmp.pdf", new File(tmpPath));
  198. File src = File.createTempFile("saic-pdfpreview-", ".tmp.html", new File(tmpPath));
  199. src.deleteOnExit();
  200. dst.deleteOnExit();
  201. PrintWriter out = new PrintWriter(src.getAbsolutePath());
  202. out.println(d.html());
  203. out.flush();
  204. out.close();
  205. ProcessBuilder pb = new ProcessBuilder("bash", "-c", basecommand+" --print-to-pdf='"+dst+"' "+src.getAbsolutePath());
  206. Process pr = pb.start();
  207. pr.waitFor();
  208. byte[] bytes = Files.readAllBytes(dst.toPath());
  209. src.delete();
  210. dst.delete();
  211. return bytes;
  212. }
  213. private String parseComments(String content) throws JsonParseException, JsonMappingException, IOException {
  214. // <!--tinycomments\|2\.1\|data:application\/json;base64,([A-Za-z0-9]*)=-->
  215. Pattern pattern = Pattern.compile("\\<\\!\\-\\-tinycomments\\|2\\.1\\|data\\:application\\/json\\;base64\\,([A-Za-z0-9\\/\\+\\\\]*)\\=*\\-\\-\\>");
  216. Matcher matcher = pattern.matcher(content);
  217. String rawComments = "";
  218. if(matcher.find()) {
  219. byte[] decoded = Base64.getDecoder().decode(matcher.group(1));
  220. rawComments = new String(decoded, "UTF-8");
  221. if(rawComments.length() < 10) {
  222. return "";
  223. }
  224. rawComments = rawComments.replaceAll("^.", "[");
  225. rawComments = rawComments.replaceAll(".$", "]");
  226. rawComments = rawComments.replaceAll("\"mce-conversation\\_\\d*\":", "");
  227. ObjectMapper mapper = new ObjectMapper();
  228. List<PlantillaConversation> comments = mapper.readValue(rawComments, new TypeReference<List<PlantillaConversation>>(){});
  229. String tabComments = "<p class=\"pagebreak\"><!-- pagebreak --></p>"
  230. + "<h3>COMENTARIOS GENERADOS DURANTE LA REVISIÓN DEL DOCUMENTO</h3>"
  231. + "<h3><small>Nota: Esta página no será visible en la versión final publicada del documento.</small></h3>"
  232. + "<table style=\"border-collapse: collapse; width: 297mm; border-width: 1px; border-spacing: 0px; border-color: rgb(149, 165, 166); margin-left: 0px; margin-right: auto;\" border=\"1\" width=\"297mm\" cellspacing=\"0\" cellpadding=\"8\">"
  233. + "<thead>"
  234. + " <tr style=\"padding: 0px; border-width: 1px; border-color: rgb(149, 165, 166);\" bgcolor=\"#153d63\">"
  235. + " <th style=\"padding: 0px; border-width: 1px; border-color: rgb(149, 165, 166); color:white;\" scope=\"col\">Usuario</th>"
  236. + " <th style=\"padding: 0px; border-width: 1px; border-color: rgb(149, 165, 166); color:white;\" scope=\"col\">Nombre</th>"
  237. + " <th style=\"padding: 0px; border-width: 1px; border-color: rgb(149, 165, 166); color:white;\" scope=\"col\">Comentario</th>"
  238. + " </tr>"
  239. + " </thead>"
  240. + "<tbody>";
  241. for(PlantillaConversation conv: comments) {
  242. for(PlantillaComentario c: conv.getComments()) {
  243. tabComments += ("<tr style=\"padding: 0px; border-width: 1px; border-color: rgb(149, 165, 166);\"> "
  244. + " <td style=\"padding: 0px; border-width: 1px; border-color: rgb(149, 165, 166);\">"+c.getAuthor()+"</td>"
  245. + " <td style=\"padding: 0px; border-width: 1px; border-color: rgb(149, 165, 166);\">"+c.getAuthorName()+"</td>"
  246. + " <td style=\"padding: 0px; border-width: 1px; border-color: rgb(149, 165, 166);\">"+c.getContent()+"</td>"
  247. + "</tr> ");
  248. }
  249. }
  250. tabComments += "</tbody></table>";
  251. return tabComments;
  252. }
  253. return "";
  254. }
  255. public static String asString(Resource resource) {
  256. try (Reader reader = new InputStreamReader(resource.getInputStream(), "UTF-8")) {
  257. return FileCopyUtils.copyToString(reader);
  258. } catch (IOException e) {
  259. throw new UncheckedIOException(e);
  260. }
  261. }
  262. public static String readFileToString(String path) {
  263. ResourceLoader resourceLoader = new DefaultResourceLoader();
  264. Resource resource = resourceLoader.getResource(path);
  265. return asString(resource);
  266. }
  267. }