From db919b890287b5ca49d41fce4c75853cf2cb0e36 Mon Sep 17 00:00:00 2001 From: Lensors Date: Fri, 2 May 2025 18:34:45 +0200 Subject: [PATCH] Export : OK !! --- Projet/.classpath | 2 + .../main/java/projet/BlocCollaborative.java | 57 ++- Projet/src/main/java/projet/BlocRenderer.java | 41 +- Projet/src/main/java/projet/Export.java | 95 +++++ .../main/java/projet/HtmlBlocRenderer.java | 69 ++++ .../src/main/java/projet/HtmlPageRender.java | 21 + .../main/java/projet/LatexBlocRenderer.java | 71 ++++ .../src/main/java/projet/LatexPageRender.java | 17 + .../java/projet/MarkdownBlocRenderer.java | 55 +++ .../main/java/projet/MarkdownPageRender.java | 14 + Projet/src/main/java/projet/Page.java | 4 +- Projet/src/main/java/projet/PageRender.java | 19 + .../src/main/webapp/WEB-INF/AfficherPage.jsp | 57 ++- Projet/src/main/webapp/WEB-INF/Header.jsp | 12 + .../webapp/WEB-INF/lib/javax.json-1.1.4.jar | Bin 0 -> 128770 bytes .../WEB-INF/lib/javax.json-api-1.1.4.jar | Bin 0 -> 31095 bytes Projet/src/main/webapp/js/bloc.js | 364 +++++------------- Projet/src/main/webapp/js/collagePropre.js | 22 ++ Projet/src/main/webapp/js/drag-and-drop.js | 114 ------ Projet/src/main/webapp/js/functionsBloc.js | 271 +++++++++++++ Projet/src/main/webapp/js/main.js | 5 +- Projet/src/main/webapp/js/socket-bloc.js | 95 ++++- Projet/src/main/webapp/js/utils.js | 50 +++ Projet/src/main/webapp/styles.css | 17 +- 24 files changed, 1037 insertions(+), 435 deletions(-) create mode 100644 Projet/src/main/java/projet/Export.java create mode 100644 Projet/src/main/java/projet/HtmlBlocRenderer.java create mode 100644 Projet/src/main/java/projet/HtmlPageRender.java create mode 100644 Projet/src/main/java/projet/LatexBlocRenderer.java create mode 100644 Projet/src/main/java/projet/LatexPageRender.java create mode 100644 Projet/src/main/java/projet/MarkdownBlocRenderer.java create mode 100644 Projet/src/main/java/projet/MarkdownPageRender.java create mode 100644 Projet/src/main/java/projet/PageRender.java create mode 100644 Projet/src/main/webapp/WEB-INF/lib/javax.json-1.1.4.jar create mode 100644 Projet/src/main/webapp/WEB-INF/lib/javax.json-api-1.1.4.jar create mode 100644 Projet/src/main/webapp/js/collagePropre.js create mode 100644 Projet/src/main/webapp/js/functionsBloc.js diff --git a/Projet/.classpath b/Projet/.classpath index b2da0f7..6e63adc 100644 --- a/Projet/.classpath +++ b/Projet/.classpath @@ -14,5 +14,7 @@ + + diff --git a/Projet/src/main/java/projet/BlocCollaborative.java b/Projet/src/main/java/projet/BlocCollaborative.java index be2ea27..04c1fef 100644 --- a/Projet/src/main/java/projet/BlocCollaborative.java +++ b/Projet/src/main/java/projet/BlocCollaborative.java @@ -1,10 +1,13 @@ package projet; +import java.io.StringReader; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; + +import javax.json.Json; +import javax.json.JsonArrayBuilder; +import javax.json.JsonObject; import jakarta.websocket.*; import jakarta.websocket.server.ServerEndpoint; @@ -14,6 +17,8 @@ import jakarta.websocket.server.ServerEndpoint; public class BlocCollaborative { private static final Map> sessionsParPage = new ConcurrentHashMap<>(); + private static final Map> utilisateursParPage = new ConcurrentHashMap<>(); + @OnOpen public void onOpen(Session session) { @@ -28,18 +33,22 @@ public class BlocCollaborative { public void onMessage(String message, Session session) { String pageId = (String) session.getUserProperties().get("pageId"); Set sessions = sessionsParPage.get(pageId); + Map utilisateurs = utilisateursParPage.computeIfAbsent(pageId, k -> new ConcurrentHashMap<>()); - Lock sessionLock = new ReentrantLock(); + JsonObject json = Json.createReader(new StringReader(message)).readObject(); + + if ("nouvelleConnexion".equals(json.getString("action", ""))) { + String login = json.getString("utilisateur", "Anonyme"); + utilisateurs.put(session, login); + + envoiUtilisateursParPage(pageId); + return; + } synchronized (sessions) { for (Session s : sessions) { if (s.isOpen() && !s.equals(session)) { - sessionLock.lock(); - try { - s.getAsyncRemote().sendText(message); - } finally { - sessionLock.unlock(); - } + s.getAsyncRemote().sendText(message); } } } @@ -50,12 +59,18 @@ public class BlocCollaborative { String pageId = (String) session.getUserProperties().get("pageId"); if (pageId != null) { Set sessions = sessionsParPage.get(pageId); + Map utilisateurs = utilisateursParPage.get(pageId); if (sessions != null) { sessions.remove(session); if (sessions.isEmpty()) { sessionsParPage.remove(pageId); + utilisateursParPage.remove(pageId); } } + if (utilisateurs != null) { + utilisateurs.remove(session); + envoiUtilisateursParPage(pageId); + } } } @@ -73,4 +88,28 @@ public class BlocCollaborative { } return "default"; } + + private void envoiUtilisateursParPage(String pageId) { + Set sessions = sessionsParPage.get(pageId); + Map utilisateurs = utilisateursParPage.get(pageId); + + if (utilisateurs == null || sessions == null) return; + + JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); + for (String utilisateur : utilisateurs.values()) { + arrayBuilder.add(utilisateur); + } + + + JsonObject json = Json.createObjectBuilder() + .add("action", "users") + .add("users", arrayBuilder) + .build(); + + for (Session s : sessions) { + if (s.isOpen()) { + s.getAsyncRemote().sendText(json.toString()); + } + } + } } diff --git a/Projet/src/main/java/projet/BlocRenderer.java b/Projet/src/main/java/projet/BlocRenderer.java index 49e2dd2..c55eee3 100644 --- a/Projet/src/main/java/projet/BlocRenderer.java +++ b/Projet/src/main/java/projet/BlocRenderer.java @@ -1,31 +1,50 @@ package projet; -public interface BlocRenderer { +import java.io.StringReader; +import javax.json.Json; +import javax.json.JsonObject; +import javax.json.JsonReader; + +public interface BlocRenderer { + String renderTexte(String contenu); - String renderListe(String contenu); - String renderTitre(String contenu); - String renderCode(String contenu); - String renderPage(String contenu); + String renderListe(String contenu, String style); + String renderTitre(String contenu, int level); + String renderCode(String contenu, String language); + String renderPage(String title, String from); String renderSeparateur(); - String renderCitation(String contenu); + String renderCitation(String contenu, String type); + + default JsonObject parseMetadata(String metadata) { + try (JsonReader reader = Json.createReader(new StringReader(metadata))) { + return reader.readObject(); + } + } default String render(Bloc bloc) { + JsonObject metadata = parseMetadata(bloc.getMetadata()); switch (bloc.getType()) { case TEXTE: return renderTexte(bloc.getContenu()); case LISTE: - return renderListe(bloc.getContenu()); + String style = metadata.getString("style", "bullet"); + return renderListe(bloc.getContenu(), style); case TITRE: - return renderTitre(bloc.getContenu()); + int level = metadata.getInt("level", 1); + return renderTitre(bloc.getContenu(), level); case CODE: - return renderCode(bloc.getContenu()); + String language = metadata.getString("language", ""); + return renderCode(bloc.getContenu(), language); case PAGE: - return renderPage(bloc.getContenu()); + String title = metadata.getString("title", "Page"); + String from = metadata.getString("from", ""); + return renderPage(title, from); case SEPARATEUR: return renderSeparateur(); case CITATION: - return renderCitation(bloc.getContenu()); + String type = metadata.getString("type", "normal"); + return renderCitation(bloc.getContenu(), type); default: throw new IllegalArgumentException("Type de bloc inconnu : " + bloc.getType()); } diff --git a/Projet/src/main/java/projet/Export.java b/Projet/src/main/java/projet/Export.java new file mode 100644 index 0000000..5f46e91 --- /dev/null +++ b/Projet/src/main/java/projet/Export.java @@ -0,0 +1,95 @@ +package projet; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; + +import java.io.IOException; +import java.util.ArrayList; + +@WebServlet("/Export") +public class Export extends HttpServlet { + private static final long serialVersionUID = 1L; + + public Export() { + super(); + } + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + HttpSession session = request.getSession(); + Utilisateur u = (Utilisateur) session.getAttribute("utilisateur"); + + String idStr = request.getParameter("id"); + String type = request.getParameter("type"); + + if(u != null && idStr != null && type != null) { + u.chargerPages(); + u.chargerPagesPartagees(); + ArrayList listePages = u.getListePages(); + listePages.addAll(u.getListePagesPartagees()); + + try { + int id = Integer.parseInt(idStr); + Boolean estDans = false; + for (Page page : listePages) { + if (page.getId() == id) { + estDans = true; + break; + } + } + + if (!estDans) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, "Page introuvable."); + return; + } + + Page pageToExport = Page.getPageById(u.getId(), id); + BlocRenderer blocRenderer; + PageRender pageRender; + String filename; + switch (type.toLowerCase()) { + case "html": + blocRenderer = new HtmlBlocRenderer(); + pageRender = new HtmlPageRender(); + response.setContentType("text/html"); + filename = pageToExport.getTitre() + ".html"; + break; + case "latex": + blocRenderer = new LatexBlocRenderer(); + pageRender = new LatexPageRender(); + response.setContentType("application/x-latex"); + filename = pageToExport.getTitre() + ".tex"; + break; + case "markdown": + blocRenderer = new MarkdownBlocRenderer(); + pageRender = new MarkdownPageRender(); + response.setContentType("text/markdown"); + filename = pageToExport.getTitre() + ".md"; + break; + default: + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Type de format non pris en charge."); + return; + } + + String exportContent = pageRender.render(blocRenderer, pageToExport.getListeBlocs()); + response.setCharacterEncoding("UTF-8"); + response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\""); + response.getWriter().write(exportContent); + return; + + } catch (NumberFormatException e) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "ID invalide"); + return; + } + } else { + response.sendRedirect("/Projet/"); + } + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + } + +} diff --git a/Projet/src/main/java/projet/HtmlBlocRenderer.java b/Projet/src/main/java/projet/HtmlBlocRenderer.java new file mode 100644 index 0000000..92ab6ad --- /dev/null +++ b/Projet/src/main/java/projet/HtmlBlocRenderer.java @@ -0,0 +1,69 @@ +package projet; + +public class HtmlBlocRenderer implements BlocRenderer { + + @Override + public String renderTexte(String contenu) { + contenu = escapeHtml(contenu); + return "

" + contenu + "

\n"; + } + + @Override + public String renderListe(String contenu, String style) { + contenu = escapeHtml(contenu); + + StringBuilder sb = new StringBuilder(); + String[] items = contenu.split("\n"); + String tag = "bullet".equals(style) ? "ul" : "ol"; + sb.append("<").append(tag).append(">\n"); + for (String item : items) { + sb.append("
  • ").append(item).append("
  • \n"); + } + sb.append("\n"); + return sb.toString(); + } + + @Override + public String renderTitre(String contenu, int level) { + contenu = escapeHtml(contenu); + + level = Math.max(1, Math.min(level, 6)); + return "" + contenu + "\n"; + } + + @Override + public String renderCode(String contenu, String language) { + contenu = escapeHtml(contenu); + + return "
    \n" + contenu + "\n
    \n"; + } + + @Override + public String renderPage(String title, String from) { + return "" + title + "\n"; + } + + @Override + public String renderSeparateur() { + return "
    \n"; + } + + @Override + public String renderCitation(String contenu, String type) { + contenu = escapeHtml(contenu); + + return "
    \n" + contenu + "\n
    \n"; + } + + public static String escapeHtml(String content) { + if (content == null) return null; + + content = content.replaceAll("\n", "
    "); + content = content.replaceAll("\\*\\*(.*?)\\*\\*", "$1"); + content = content.replaceAll("\\*(.*?)\\*", "$1"); + content = content.replaceAll("`(.*?)`", "$1"); + + return content; + } + +} diff --git a/Projet/src/main/java/projet/HtmlPageRender.java b/Projet/src/main/java/projet/HtmlPageRender.java new file mode 100644 index 0000000..a49fae7 --- /dev/null +++ b/Projet/src/main/java/projet/HtmlPageRender.java @@ -0,0 +1,21 @@ +package projet; + +public class HtmlPageRender implements PageRender { + + @Override + public String getHeader() { + return "\n" + + "\n" + + "\n" + + "\n" + + "Page\n" + + "\n" + + "\n"; + } + + @Override + public String getFooter() { + return "\n" + + "\n"; + } +} diff --git a/Projet/src/main/java/projet/LatexBlocRenderer.java b/Projet/src/main/java/projet/LatexBlocRenderer.java new file mode 100644 index 0000000..82d00f2 --- /dev/null +++ b/Projet/src/main/java/projet/LatexBlocRenderer.java @@ -0,0 +1,71 @@ +package projet; + +public class LatexBlocRenderer implements BlocRenderer { + + @Override + public String renderTexte(String contenu) { + contenu = escapeLatex(contenu); + + return contenu + "\n\n"; + } + + @Override + public String renderListe(String contenu, String style) { + + StringBuilder sb = new StringBuilder(); + String env = "bullet".equals(style) ? "itemize" : "enumerate"; + sb.append("\\begin{").append(env).append("}\n"); + for (String item : contenu.split("\n")) { + sb.append(" \\item ").append(item).append("\n"); + } + sb.append("\\end{").append(env).append("}\n\n"); + return sb.toString(); + } + + @Override + public String renderTitre(String contenu, int level) { + contenu = escapeLatex(contenu); + + switch (level) { + case 1: return "\\section{" + contenu + "}\n\n"; + case 2: return "\\subsection{" + contenu + "}\n\n"; + case 3: return "\\subsubsection{" + contenu + "}\n\n"; + default: return "\\paragraph{" + contenu + "}\n\n"; + } + } + + @Override + public String renderCode(String contenu, String language) { + contenu = escapeLatex(contenu); + + return "\\begin{verbatim}\n" + contenu + "\n\\end{verbatim}\n\n"; + } + + @Override + public String renderPage(String title, String from) { + return "\\href{page:" + from + "}{" + title + "}\n\n"; + } + + @Override + public String renderSeparateur() { + return "\\noindent\\rule{\\linewidth}{0.4pt}\n\n"; + } + + @Override + public String renderCitation(String contenu, String type) { + contenu = escapeLatex(contenu); + + return "\\begin{quote}\n" + contenu + "\n\\end{quote}\n\n"; + } + + public static String escapeLatex(String content) { + if (content == null) return null; + + content = content.replaceAll("\n", "\\\\\\\\ \n"); + content = content.replaceAll("\\*\\*(.*?)\\*\\*", "\\\\textbf{$1}"); + content = content.replaceAll("\\*(.*?)\\*", "\\\\textit{$1}"); + content = content.replaceAll("`(.*?)`", "\\\\texttt{$1}"); + + return content; + } +} diff --git a/Projet/src/main/java/projet/LatexPageRender.java b/Projet/src/main/java/projet/LatexPageRender.java new file mode 100644 index 0000000..d4749a0 --- /dev/null +++ b/Projet/src/main/java/projet/LatexPageRender.java @@ -0,0 +1,17 @@ +package projet; + +public class LatexPageRender implements PageRender { + + @Override + public String getHeader() { + return "\\documentclass{article}\n" + + "\\usepackage[utf8]{inputenc}\n" + + "\\usepackage{hyperref}\n" + + "\\begin{document}\n"; + } + + @Override + public String getFooter() { + return "\\end{document}\n"; + } +} diff --git a/Projet/src/main/java/projet/MarkdownBlocRenderer.java b/Projet/src/main/java/projet/MarkdownBlocRenderer.java new file mode 100644 index 0000000..bfaaf41 --- /dev/null +++ b/Projet/src/main/java/projet/MarkdownBlocRenderer.java @@ -0,0 +1,55 @@ +package projet; + +public class MarkdownBlocRenderer implements BlocRenderer { + + @Override + public String renderTexte(String contenu) { + return contenu + "\n"; + } + + @Override + public String renderListe(String contenu, String style) { + String[] items = contenu.split("\n"); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < items.length; i++) { + if ("number".equals(style)) { + sb.append(i + 1).append(". ").append(items[i]).append("\n"); + } else { + sb.append("- ").append(items[i]).append("\n"); + } + } + return sb.toString(); + } + + @Override + public String renderTitre(String contenu, int level) { + return "#".repeat(Math.max(1, level)) + " " + contenu + "\n"; + } + + @Override + public String renderCode(String contenu, String language) { + return "```" + language + "\n" + contenu + "\n```\n"; + } + + @Override + public String renderPage(String title, String from) { + return "[" + title + "](page:" + from + ")\n"; + } + + @Override + public String renderSeparateur() { + return "---\n"; + } + + @Override + public String renderCitation(String contenu, String type) { + StringBuilder result = new StringBuilder(); + String[] lignes = contenu.split("\n"); + for (String ligne : lignes) { + result.append("> ").append(ligne).append("\n"); + } + return result.toString(); + } + + +} diff --git a/Projet/src/main/java/projet/MarkdownPageRender.java b/Projet/src/main/java/projet/MarkdownPageRender.java new file mode 100644 index 0000000..773dd60 --- /dev/null +++ b/Projet/src/main/java/projet/MarkdownPageRender.java @@ -0,0 +1,14 @@ +package projet; + +public class MarkdownPageRender implements PageRender { + + @Override + public String getHeader() { + return ""; + } + + @Override + public String getFooter() { + return ""; + } +} diff --git a/Projet/src/main/java/projet/Page.java b/Projet/src/main/java/projet/Page.java index cc931c2..f29c857 100644 --- a/Projet/src/main/java/projet/Page.java +++ b/Projet/src/main/java/projet/Page.java @@ -9,9 +9,7 @@ import java.sql.Statement; import java.time.LocalDate; import java.sql.Date; import java.util.ArrayList; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import projet.Bloc.Type; @@ -198,11 +196,13 @@ public class Page extends ParamBD { + " FROM partage" + " JOIN page ON partage.page_id = page.id" + " WHERE partage.utilisateur_id = ?" + + " AND page.id = ?" + ";"; pst = connexion.prepareStatement(sql); pst.setInt(1, id); pst.setInt(2, idU); pst.setInt(3, idU); + pst.setInt(4, id); rs = pst.executeQuery(); while(rs.next()) { titre = rs.getString("titre"); diff --git a/Projet/src/main/java/projet/PageRender.java b/Projet/src/main/java/projet/PageRender.java new file mode 100644 index 0000000..082bf6b --- /dev/null +++ b/Projet/src/main/java/projet/PageRender.java @@ -0,0 +1,19 @@ +package projet; + +import java.util.List; + +public interface PageRender { + + String getHeader(); + String getFooter(); + + default String render(BlocRenderer blocRenderer, List blocs) { + StringBuilder sb = new StringBuilder(); + sb.append(getHeader()); + for (Bloc bloc : blocs) { + sb.append(blocRenderer.render(bloc)).append("\n"); + } + sb.append(getFooter()); + return sb.toString(); + } +} diff --git a/Projet/src/main/webapp/WEB-INF/AfficherPage.jsp b/Projet/src/main/webapp/WEB-INF/AfficherPage.jsp index 7f80e5a..bfad927 100644 --- a/Projet/src/main/webapp/WEB-INF/AfficherPage.jsp +++ b/Projet/src/main/webapp/WEB-INF/AfficherPage.jsp @@ -18,31 +18,50 @@
    -
    +

    ${entry.value} > ${page.titre}

    -
    diff --git a/Projet/src/main/webapp/WEB-INF/Header.jsp b/Projet/src/main/webapp/WEB-INF/Header.jsp index 82cd7d3..4c0a9ff 100644 --- a/Projet/src/main/webapp/WEB-INF/Header.jsp +++ b/Projet/src/main/webapp/WEB-INF/Header.jsp @@ -22,6 +22,18 @@