diff --git a/backend/pom.xml b/backend/pom.xml
index 690751235..f5baba6cb 100644
--- a/backend/pom.xml
+++ b/backend/pom.xml
@@ -1,5 +1,6 @@
-
4.0.0
@@ -37,6 +38,9 @@
6.4.0
0.10.2
2.2.2
+ 5.2.3
+ 1.18.3
+ 0.4.20
@@ -117,5 +121,30 @@
${toolsVersion}
test
+
+ org.apache.poi
+ poi
+ ${apachePoiVersion}
+
+
+ org.apache.poi
+ poi-ooxml
+ ${apachePoiVersion}
+
+
+ org.apache.poi
+ poi-ooxml-full
+ ${apachePoiVersion}
+
+
+ org.jsoup
+ jsoup
+ ${jsoupVersion}
+
+
+ net.coobird
+ thumbnailator
+ ${thumbnailatorVersion}
+
diff --git a/backend/src/main/java/fr/cgi/magneto/Magneto.java b/backend/src/main/java/fr/cgi/magneto/Magneto.java
index b4b17bccc..44ad24fa1 100644
--- a/backend/src/main/java/fr/cgi/magneto/Magneto.java
+++ b/backend/src/main/java/fr/cgi/magneto/Magneto.java
@@ -50,6 +50,7 @@ public void start(Promise startPromise) throws Exception {
addController(new CommentController(serviceFactory));
addController(new BoardAccessController(serviceFactory));
addController(new WorkspaceController(serviceFactory));
+ addController(new ExportController(serviceFactory));
final EventBus eb = getEventBus(vertx);
diff --git a/backend/src/main/java/fr/cgi/magneto/controller/ExportController.java b/backend/src/main/java/fr/cgi/magneto/controller/ExportController.java
new file mode 100644
index 000000000..0b26a53ed
--- /dev/null
+++ b/backend/src/main/java/fr/cgi/magneto/controller/ExportController.java
@@ -0,0 +1,39 @@
+package fr.cgi.magneto.controller;
+
+import fr.cgi.magneto.core.constants.Field;
+import fr.cgi.magneto.helper.I18nHelper;
+import fr.cgi.magneto.service.ExportService;
+import fr.cgi.magneto.service.ServiceFactory;
+import fr.wseduc.rs.ApiDoc;
+import fr.wseduc.rs.Get;
+import fr.wseduc.webutils.I18n;
+import io.vertx.core.buffer.Buffer;
+import io.vertx.core.http.HttpServerRequest;
+import org.entcore.common.controller.ControllerHelper;
+import org.entcore.common.user.UserUtils;
+
+public class ExportController extends ControllerHelper {
+ private final ExportService exportService;
+
+ public ExportController(ServiceFactory serviceFactory) {
+ this.exportService = serviceFactory.exportService();
+ }
+
+ @Get("/export/slide/:boardId")
+ @ApiDoc("Export board to PPTX")
+ public void exportBoardToPPTX(HttpServerRequest request) {
+ String boardId = request.getParam(Field.BOARDID);
+ UserUtils.getUserInfos(eb, request, user -> {
+ I18nHelper i18nHelper = new I18nHelper(getHost(request), I18n.acceptLanguage(request));
+ exportService.exportBoardToArchive(boardId, user, i18nHelper)
+ .onFailure(err -> renderError(request))
+ .onSuccess(zip -> {
+ request.response()
+ .putHeader("Content-Type", "application/zip")
+ .putHeader("Content-Disposition", "attachment; filename=\"board.zip\"");
+
+ request.response().end(Buffer.buffer(zip.toByteArray()));
+ });
+ });
+ }
+}
\ No newline at end of file
diff --git a/backend/src/main/java/fr/cgi/magneto/core/constants/CollectionsConstant.java b/backend/src/main/java/fr/cgi/magneto/core/constants/CollectionsConstant.java
index 7c0d4ab18..7d585a4f6 100644
--- a/backend/src/main/java/fr/cgi/magneto/core/constants/CollectionsConstant.java
+++ b/backend/src/main/java/fr/cgi/magneto/core/constants/CollectionsConstant.java
@@ -6,6 +6,12 @@ public class CollectionsConstant {
public static final String CARD_COLLECTION = "magneto.cards";
public static final String SECTION_COLLECTION = "magneto.sections";
public static final String BOARD_VIEW_COLLECTION = "magneto.boards.access";
+ public static final String I18N_SLIDESHOW_OWNER = "magneto.slideshow.owner";
+ public static final String I18N_SLIDESHOW_UPDATED = "magneto.slideshow.updated.the";
+ public static final String I18N_SLIDESHOW_MAGNETS = "magneto.slideshow.magnets";
+ public static final String I18N_SLIDESHOW_SHARED = "magneto.slideshow.shared";
+ public static final String I18N_SLIDESHOW_PLATFORM = "magneto.slideshow.platform";
+ public static final String I18N_SLIDESHOW_FILENAME = "magneto.slideshow.filename";
public static final String WORKSPACE_DOCUMENTS = "documents";
}
diff --git a/backend/src/main/java/fr/cgi/magneto/core/constants/Field.java b/backend/src/main/java/fr/cgi/magneto/core/constants/Field.java
index e4659d0e6..630f6cbf5 100644
--- a/backend/src/main/java/fr/cgi/magneto/core/constants/Field.java
+++ b/backend/src/main/java/fr/cgi/magneto/core/constants/Field.java
@@ -89,7 +89,6 @@ public class Field {
public static final String CURSOR = "cursor";
public static final String FIRSTBATCH = "firstBatch";
-
// CARD FIELD
public static final String BOARDID = "boardId";
@@ -102,6 +101,7 @@ public class Field {
public static final String RESOURCE_MAGNET = "magnet";
public static final String RESOURCE_SECTION = "section";
public static final String RESOURCEURL = "resourceUrl";
+ public static final String MAGNET_NUMBER = "magnetNumber";
public static final String LASTMODIFIERID = "lastModifierId";
public static final String LASTMODIFIERNAME = "lastModifierName";
public static final String LASTCOMMENT = "lastComment";
@@ -124,7 +124,6 @@ public class Field {
public static final String NUMBER = "number";
-
// METADATA FIELD
public static final String NAME = "name";
@@ -134,6 +133,7 @@ public class Field {
public static final String CHARSET = "charset";
public static final String SIZE = "size";
public static final String METADATA = "metadata";
+ public static final String CONTENTTYPE = "contentType";
public static final String INDEX = "index";
public static final String PROFILURI = "profilUri";
@@ -187,7 +187,7 @@ public class Field {
public static final String BOARDURL = "boardUrl";
- //Import Export
+ // Import Export
public static final String RAPPORT = "rapport";
public static final String RESSOURCE_NUMBER = "resourcesNumber";
@@ -210,7 +210,7 @@ public class Field {
public static final String USER_2 = "User";
public static final String USERIDS = "userIds";
- //FAVORITE
+ // FAVORITE
public static final String FAVORITE = "favorite";
public static final String FAVORITE_LIST = "favoriteList";
public static final String ISFAVORITE = "isFavorite";
@@ -230,8 +230,14 @@ public class Field {
public static final String GROUP_TYPE = "groupType";
public static final String GROUP = "Group";
public static final String MEMBERS = "members";
- //notification Folder
+ // notification Folder
public static final String FOLDERTITLE = "folderTitle";
public static final String FOLDERURL = "folderUrl";
public static final String BOARDNAME = "boardName";
+
+ // EXPORT SLIDE
+ public static final String SLIDE_OBJECTS = "slideObjects";
+ public static final String BOARD_IMAGE_ID = "boardImageId";
+ public static final String BUFFER = "buffer";
+ public static final String FILE = "file";
}
diff --git a/backend/src/main/java/fr/cgi/magneto/core/constants/MagnetoPaths.java b/backend/src/main/java/fr/cgi/magneto/core/constants/MagnetoPaths.java
new file mode 100644
index 000000000..cee46195f
--- /dev/null
+++ b/backend/src/main/java/fr/cgi/magneto/core/constants/MagnetoPaths.java
@@ -0,0 +1,6 @@
+package fr.cgi.magneto.core.constants;
+
+public class MagnetoPaths {
+ public static final String MAGNETO_BOARD = "magneto#/board/";
+ public static final String VIEW = "/view";
+}
diff --git a/backend/src/main/java/fr/cgi/magneto/core/constants/Slideshow.java b/backend/src/main/java/fr/cgi/magneto/core/constants/Slideshow.java
new file mode 100644
index 000000000..8ba56cde6
--- /dev/null
+++ b/backend/src/main/java/fr/cgi/magneto/core/constants/Slideshow.java
@@ -0,0 +1,223 @@
+package fr.cgi.magneto.core.constants;
+
+import java.awt.*;
+
+public class Slideshow {
+ // Constantes de mise en page générales
+ public static final int MARGIN_LEFT = 80;
+ public static final int MARGIN_TOP_TITLE = 40;
+ public static final int WIDTH = 1120;
+ public static final String DEFAULT_FONT = "Roboto";
+ public static final int SLIDE_HEIGHT = 720;
+ public static final int SLIDE_WIDTH = 1280;
+
+ // Constantes pour les titres
+ public static final int TITLE_HEIGHT = 70;
+ public static final Double TITLE_FONT_SIZE = 44.0;
+ public static final int DESCRIPTION_TITLE_HEIGHT = 75;
+ public static final Double DESCRIPTION_TITLE_FONT_SIZE = 55.0;
+ public static final int MAIN_TITLE_HEIGHT = 100;
+ public static final Double MAIN_TITLE_FONT_SIZE = 100.0;
+
+ // Constantes pour les légendes
+ public static final int LEGEND_HEIGHT = 70;
+ public static final int LEGEND_MARGIN_BOTTOM = 20;
+ public static final Double LEGEND_FONT_SIZE = 16.0;
+ public static final String LEGEND_FONT_FAMILY = "Roboto";
+
+ // Constantes pour le contenu
+ public static final int CONTENT_HEIGHT = 520;
+ public static final int CONTENT_MARGIN_TOP = 140;
+ public static final int MAIN_CONTENT_MARGIN_TOP = 300;
+ public static final Double CONTENT_FONT_SIZE = 36.0;
+ public static final int SLIDE_BOARD_CONTENT_MARGIN_TOP = 450;
+ public static final Double DESCRIPTION_FONT_SIZE = 24.0;
+ public static final int BOARD_TEXT_WIDTH = 500;
+
+ // Constantes pour les images
+ public static final int MAIN_IMAGE_CONTENT_HEIGHT = 400;
+ public static final int IMAGE_CONTENT_HEIGHT = 480;
+ public static final int BOARD_IMAGE_CONTENT_HEIGHT = 250;
+ public static final int SVG_CONTENT_HEIGHT = 250;
+ public static final int SVG_CONTENT_WIDTH = 175;
+
+ // Constantes content_type prefixes
+ public static final String CONTENT_TYPE_AUDIO = "audio/";
+ public static final String CONTENT_TYPE_VIDEO = "video/";
+
+ // Constantes content_type audio
+ public static final String CONTENT_TYPE_AUDIO_MPEG = "audio/mpeg";
+ public static final String CONTENT_TYPE_AUDIO_MP3 = "audio/mp3";
+ public static final String CONTENT_TYPE_AUDIO_WAV = "audio/wav";
+ public static final String CONTENT_TYPE_AUDIO_X_WAV = "audio/x-wav";
+ public static final String CONTENT_TYPE_AUDIO_MP4 = "audio/mp4";
+ public static final String CONTENT_TYPE_AUDIO_X_M4A = "audio/x-m4a";
+ public static final String CONTENT_TYPE_AUDIO_OGG = "audio/ogg";
+
+ // Constantes content_type vidéo
+ public static final String CONTENT_TYPE_VIDEO_MP4 = "video/mp4";
+ public static final String CONTENT_TYPE_VIDEO_MPEG = "video/mpeg";
+ public static final String CONTENT_TYPE_VIDEO_X_MS_WMV = "video/x-ms-wmv";
+ public static final String CONTENT_TYPE_VIDEO_QUICKTIME = "video/quicktime";
+ public static final String CONTENT_TYPE_VIDEO_X_MATROSKA = "video/x-matroska";
+ public static final String CONTENT_TYPE_VIDEO_WEBM = "video/webm";
+ public static final String CONTENT_TYPE_VIDEO_X_FLV = "video/x-flv";
+ public static final String CONTENT_TYPE_VIDEO_3GPP = "video/3gpp";
+ public static final String CONTENT_TYPE_VIDEO_AVI = "video/avi";
+ public static final String CONTENT_TYPE_VIDEO_X_MSVIDEO = "video/x-msvideo";
+
+ // Constantes content_type image
+ public static final String CONTENT_TYPE_IMAGE_JPEG = "image/jpeg";
+ public static final String CONTENT_TYPE_IMAGE_JPG = "image/jpg";
+ public static final String CONTENT_TYPE_IMAGE_PNG = "image/png";
+ public static final String CONTENT_TYPE_IMAGE_GIF = "image/gif";
+ public static final String CONTENT_TYPE_IMAGE_TIFF = "image/tiff";
+ public static final String CONTENT_TYPE_IMAGE_X_EMF = "image/x-emf";
+ public static final String CONTENT_TYPE_IMAGE_X_WMF = "image/x-wmf";
+ public static final String CONTENT_TYPE_IMAGE_X_PICT = "image/x-pict";
+ public static final String CONTENT_TYPE_IMAGE_DIB = "image/dib";
+ public static final String CONTENT_TYPE_IMAGE_X_EPS = "image/x-eps";
+ public static final String CONTENT_TYPE_IMAGE_X_MS_BMP = "image/x-ms-bmp";
+ public static final String CONTENT_TYPE_IMAGE_BMP = "image/bmp";
+ public static final String CONTENT_TYPE_IMAGE_X_WPG = "image/x-wpg";
+ public static final String CONTENT_TYPE_IMAGE_VND_MS_PHOTO = "image/vnd.ms-photo";
+ public static final String CONTENT_TYPE_IMAGE_SVG_XML = "image/svg+xml";
+ public static final String CONTENT_TYPE_IMAGE_PREFIX = "image/";
+
+ // Constantes pour le formatage de texte
+ public static final Double H1_FONT_SIZE = 20.0;
+ public static final Double H2_FONT_SIZE = 18.0;
+ public static final Double H3_FONT_SIZE = 16.0;
+ public static final int H1_INDENT_LEVEL = 0;
+ public static final int H2_INDENT_LEVEL = 1;
+ public static final int H3_INDENT_LEVEL = 2;
+ public static final int LIST_INDENT_LEVEL = 1;
+
+ // Constantes pour l'espacement des paragraphes
+ public static final Double PARAGRAPH_SPACE_BEFORE = 10.0;
+ public static final Double PARAGRAPH_SPACE_AFTER = 10.0;
+
+ // Constantes pour les styles CSS
+ public static final String CSS_STYLE = "style";
+ public static final String CSS_COLOR = "color";
+ public static final String CSS_FONT_SIZE = "font-size";
+ public static final String CSS_TEXT_DECORATION = "text-decoration";
+ public static final String CSS_FONT_WEIGHT = "font-weight";
+ public static final String CSS_FONT_STYLE = "font-style";
+
+ // Constantes pour les valeurs de style
+ public static final String VALUE_UNDERLINE = "underline";
+ public static final String VALUE_BOLD = "bold";
+ public static final String VALUE_BOLD_WEIGHT = "700";
+ public static final String VALUE_ITALIC = "italic";
+
+ // Constantes pour les préfixes de noms de fichiers médias
+ public static final String MEDIA_TYPE_AUDIO = "audio";
+ public static final String MEDIA_TYPE_VIDEO = "video";
+
+ // Constantes pour les chemins et relations
+ public static final String MEDIA_PATH_PREFIX = "/ppt/media/";
+ public static final String RELATIONSHIP_MEDIA = "http://schemas.microsoft.com/office/2007/relationships/media";
+ public static final String RELATIONSHIP_AUDIO = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/audio";
+ public static final String RELATIONSHIP_VIDEO = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/video";
+ public static final String ACTION_MEDIA = "ppaction://media";
+ public static final String EXTENSION_URI_MEDIA = "{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}";
+ public static final String NAMESPACE_POWERPOINT_2010 = "http://schemas.microsoft.com/office/powerpoint/2010/main";
+
+ // Constantes pour les paramètres de timing
+ public static final int TIMING_ROOT_ID = 1;
+ public static final int TIMING_MEDIA_ID = 2;
+ public static final int MEDIA_VOLUME = 80000;
+
+ // Constantes pour les balises HTML
+ public static final String TAG_H1 = "h1";
+ public static final String TAG_H2 = "h2";
+ public static final String TAG_H3 = "h3";
+ public static final String TAG_BOLD = "b";
+ public static final String TAG_STRONG = "strong";
+ public static final String TAG_ITALIC = "i";
+ public static final String TAG_EM = "em";
+ public static final String TAG_UNDERLINE = "u";
+ public static final String TAG_PARAGRAPH = "p";
+ public static final String TAG_UNORDERED_LIST = "ul";
+ public static final String TAG_ORDERED_LIST = "ol";
+ public static final String TAG_LIST_ITEM = "li";
+
+ // Constantes pour les extensions de fichiers
+ public static final String EXT_MP3 = "mp3";
+ public static final String EXT_WAV = "wav";
+ public static final String EXT_M4A = "m4a";
+ public static final String EXT_OGG = "ogg";
+ public static final String EXT_MP4 = "mp4";
+ public static final String EXT_MPG = "mpg";
+ public static final String EXT_WMV = "wmv";
+ public static final String EXT_MOV = "mov";
+ public static final String EXT_MKV = "mkv";
+ public static final String EXT_WEBM = "webm";
+ public static final String EXT_FLV = "flv";
+ public static final String EXT_3GP = "3gp";
+ public static final String EXT_AVI = "avi";
+
+ // Constantes pour les valeurs par défaut
+ public static final String DEFAULT_VIDEO_EXTENSION = EXT_MP4;
+ public static final String DEFAULT_AUDIO_EXTENSION = EXT_MP3;
+
+ // Constantes pour les vignettes par défaut
+ public static final int THUMBNAIL_WIDTH = 320;
+ public static final int THUMBNAIL_HEIGHT = 180;
+ public static final String THUMBNAIL_FORMAT = "png";
+ public static final String THUMBNAIL_FONT = "Arial";
+ public static final int THUMBNAIL_FONT_STYLE = java.awt.Font.BOLD;
+ public static final int THUMBNAIL_FONT_SIZE = 18;
+ public static final String THUMBNAIL_DEFAULT_TEXT = "Video Preview";
+ public static final int THUMBNAIL_TEXT_X = 100;
+ public static final int THUMBNAIL_TEXT_Y = 90;
+ public static final int VIDEO_THUMBNAIL_WIDTH = 640;
+ public static final int VIDEO_THUMBNAIL_HEIGHT = 360;
+ public static final String VIDEO_THUMBNAIL_FORMAT = "png";
+ public static final String VIDEO_THUMBNAIL_FONT = "Arial";
+ public static final int VIDEO_THUMBNAIL_FONT_STYLE = java.awt.Font.BOLD;
+ public static final int VIDEO_THUMBNAIL_FONT_SIZE = 24;
+ public static final String VIDEO_THUMBNAIL_TEXT = "VIDÉO";
+ public static final int VIDEO_PLAY_BUTTON_RADIUS = 50;
+ public static final int VIDEO_TEXT_Y_OFFSET = 80;
+ public static final int VIDEO_PLAY_TRIANGLE_OFFSET_X = 15;
+ public static final int VIDEO_PLAY_TRIANGLE_OFFSET_Y = 25;
+ public static final int VIDEO_PLAY_TRIANGLE_OFFSET_X2 = 25;
+
+ // Constantes pour les couleurs
+ public static final Color VIDEO_BACKGROUND_COLOR = new Color(20, 20, 50);
+ public static final Color VIDEO_PLAY_BUTTON_COLOR = new Color(255, 255, 255, 180);
+ public static final Color VIDEO_TEXT_COLOR = Color.WHITE;
+
+ // Constantes pour les dimensions d'icônes standard
+ public static final int ICON_WIDTH = 150;
+ public static final int ICON_HEIGHT = 150;
+
+ // Constantes pour les dimensions vidéo standard (16:9)
+ public static final int VIDEO_DISPLAY_WIDTH = 640;
+ public static final int VIDEO_DISPLAY_HEIGHT = 360;
+
+ // Constantes pour l'icône audio
+ public static final int AUDIO_ICON_WIDTH = 100;
+ public static final int AUDIO_ICON_HEIGHT = 100;
+ public static final int AUDIO_ICON_CIRCLE_X = 5;
+ public static final int AUDIO_ICON_CIRCLE_Y = 5;
+ public static final int AUDIO_ICON_CIRCLE_WIDTH = 90;
+ public static final int AUDIO_ICON_CIRCLE_HEIGHT = 90;
+ public static final String AUDIO_ICON_FORMAT = "png";
+ public static final Color AUDIO_ICON_BACKGROUND_COLOR = new Color(0, 120, 215, 240);
+ public static final Color AUDIO_ICON_PLAY_COLOR = Color.WHITE;
+ public static final int[] AUDIO_ICON_TRIANGLE_X = { 35, 70, 35 };
+ public static final int[] AUDIO_ICON_TRIANGLE_Y = { 30, 50, 70 };
+ // Constantes pour l'image de secours (bytecode PNG vide 1x1)
+ public static final byte[] FALLBACK_PNG = new byte[] {
+ (byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,
+ 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08,
+ 0x02, 0x00, 0x00, 0x00, (byte) 0x90, 0x77, 0x53, (byte) 0xDE, 0x00, 0x00, 0x00,
+ 0x0C, 0x49, 0x44, 0x41, 0x54, 0x08, (byte) 0xD7, 0x63, (byte) 0xF8, (byte) 0xCF,
+ (byte) 0xC0, 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, (byte) 0x18, (byte) 0xDD, (byte) 0x8D,
+ (byte) 0xB0, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, (byte) 0xAE, 0x42,
+ 0x60, (byte) 0x82
+ };
+}
\ No newline at end of file
diff --git a/backend/src/main/java/fr/cgi/magneto/core/enums/FileFormatManager.java b/backend/src/main/java/fr/cgi/magneto/core/enums/FileFormatManager.java
new file mode 100644
index 000000000..fa2b7bd01
--- /dev/null
+++ b/backend/src/main/java/fr/cgi/magneto/core/enums/FileFormatManager.java
@@ -0,0 +1,121 @@
+package fr.cgi.magneto.core.enums;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Stream;
+
+public class FileFormatManager {
+
+ /**
+ * Obtient le type de format pour une extension donnée
+ */
+ public static FileFormat getFormatFromExtension(String extension) {
+ return FileFormat.fromExtension(extension);
+ }
+
+ /**
+ * Vérifie si une extension appartient à un format spécifique
+ */
+ public static boolean isExtensionOfFormat(FileFormat format, String extension) {
+ return format != null && format.hasExtension(extension);
+ }
+
+ /**
+ * Charge une ressource appropriée en fonction de l'extension fournie
+ *
+ * @param extension l'extension de fichier pour déterminer la ressource à charger
+ * @return le contenu de la ressource sous forme de byte[]
+ * @throws IOException si une erreur se produit lors du chargement
+ */
+ public static String loadResourceForExtension(String extension) throws IOException {
+ if (extension == null || extension.isEmpty()) {
+ throw new IllegalArgumentException("L'extension ne peut pas être null ou vide");
+ }
+
+ // Déterminer le format à partir de l'extension
+ FileFormat format = FileFormat.fromExtension(extension);
+
+ // Déterminer le chemin de la ressource en fonction du format
+ String resourcePath;
+ switch (format) {
+ case IMAGE:
+ resourcePath = "img/extension/image.svg";
+ break;
+ case VIDEO:
+ resourcePath = "img/extension/video.svg";
+ break;
+ case AUDIO:
+ resourcePath = "img/extension/audio.svg";
+ break;
+ case SHEET:
+ resourcePath = "img/extension/sheet.svg";
+ break;
+ case PDF:
+ resourcePath = "img/extension/pdf.svg";
+ break;
+ case TEXT:
+ default:
+ resourcePath = "img/extension/default.svg";
+ break;
+ }
+
+ return resourcePath;
+ }
+
+ /**
+ * Enum représentant les différents formats de fichiers
+ * avec leurs extensions associées
+ */
+ public enum FileFormat {
+ TEXT(Arrays.asList("doc", "docx", "odt", "rtf", "tex", "txt", "wpd", "md")),
+ IMAGE(Arrays.asList("tif", "tiff", "bmp", "gif", "jpg", "jpeg", "png", "eps", "raw")),
+ VIDEO(Arrays.asList("3g2", "3gp", "avi", "flv", "h264", "m4v", "mkv", "mov", "mp4",
+ "mpg", "mpeg", "rm", "swf", "vob", "wmv")),
+ AUDIO(Arrays.asList("aif", "cda", "mid", "midi", "mp3", "mpa", "ogg", "wav", "wma", "wpl")),
+ SHEET(Arrays.asList("xlsx", "xls", "xlsm", "xlt", "xltx", "xltm", "ods", "csv", "tsv", "tab")),
+ PDF(Arrays.asList("pdf"));
+
+ private final List extensions;
+
+ FileFormat(List extensions) {
+ this.extensions = extensions;
+ }
+
+ /**
+ * Trouve le format correspondant à une extension donnée
+ */
+ /**
+ * Trouve le format correspondant à une extension donnée
+ * Retourne TEXT par défaut si l'extension n'est pas reconnue
+ */
+ public static FileFormat fromExtension(String extension) {
+ if (extension == null) {
+ return FileFormat.TEXT;
+ }
+
+ String lowerExt = extension.toLowerCase();
+
+ return Stream.of(FileFormat.values())
+ .filter(format -> format.hasExtension(lowerExt))
+ .findFirst()
+ .orElse(FileFormat.TEXT);
+ }
+
+ public List getExtensions() {
+ return extensions;
+ }
+
+ /**
+ * Vérifie si cette extension appartient à ce format
+ */
+ public boolean hasExtension(String extension) {
+ if (extension == null) {
+ return false;
+ }
+ return extensions.contains(extension.toLowerCase());
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/backend/src/main/java/fr/cgi/magneto/core/enums/SlideResourceType.java b/backend/src/main/java/fr/cgi/magneto/core/enums/SlideResourceType.java
new file mode 100644
index 000000000..c1044e903
--- /dev/null
+++ b/backend/src/main/java/fr/cgi/magneto/core/enums/SlideResourceType.java
@@ -0,0 +1,37 @@
+package fr.cgi.magneto.core.enums;
+
+public enum SlideResourceType {
+ TITLE("title"),
+ DESCRIPTION("description"),
+ TEXT("text"),
+ IMAGE("image"),
+ VIDEO("video"),
+ AUDIO("audio"),
+ PDF("pdf"),
+ SHEET("sheet"),
+ FILE("file"),
+ LINK("link"),
+ BOARD("board"),
+ EMBEDDER("embedder"),
+ HYPERLINK("hyperlink"),
+ DEFAULT("default");
+
+ private final String value;
+
+ SlideResourceType(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public static SlideResourceType fromString(String text) {
+ for (SlideResourceType type : SlideResourceType.values()) {
+ if (type.value.equalsIgnoreCase(text)) {
+ return type;
+ }
+ }
+ return DEFAULT;
+ }
+}
\ No newline at end of file
diff --git a/backend/src/main/java/fr/cgi/magneto/factory/SlideFactory.java b/backend/src/main/java/fr/cgi/magneto/factory/SlideFactory.java
new file mode 100644
index 000000000..b35c181c0
--- /dev/null
+++ b/backend/src/main/java/fr/cgi/magneto/factory/SlideFactory.java
@@ -0,0 +1,50 @@
+package fr.cgi.magneto.factory;
+
+import fr.cgi.magneto.core.enums.SlideResourceType;
+import fr.cgi.magneto.model.properties.SlideProperties;
+import fr.cgi.magneto.model.slides.*;
+
+public class SlideFactory {
+
+ public Slide createSlide(SlideResourceType type, SlideProperties properties) {
+ if (!properties.isValidForType(type)) {
+ throw new IllegalArgumentException("Invalid properties for slide type: " + type);
+ }
+
+ switch (type) {
+ case TITLE:
+ return new SlideTitle(properties.getTitle(), properties.getDescription(), properties.getOwnerName(),
+ properties.getModificationDate(), properties.getResourceData(), properties.getContentType());
+ case DESCRIPTION:
+ return new SlideDescription(properties.getTitle(), properties.getDescription());
+ case TEXT:
+ return new SlideText(properties.getTitle(), properties.getDescription());
+ case FILE:
+ case PDF:
+ return new SlideFile(properties.getTitle(), properties.getDescription(), properties.getFileNameString(), properties.getCaption(), properties.getResourceData(), properties.getContentType());
+ case LINK:
+ case HYPERLINK:
+ case EMBEDDER:
+ return new SlideLink(properties.getTitle(), properties.getDescription(), properties.getResourceUrl(), properties.getCaption(), properties.getResourceData(), properties.getContentType());
+ case IMAGE:
+ case VIDEO:
+ case AUDIO:
+ return new SlideMedia(properties.getTitle(), properties.getCaption(),
+ properties.getResourceData(), properties.getContentType());
+ case BOARD:
+ return new SlideBoard(
+ properties.getTitle(), properties.getDescription(),
+ properties.getOwnerName(),
+ properties.getModificationDate(),
+ properties.getResourceNumber(),
+ properties.getIsShare(),
+ properties.getIsPublic(),
+ properties.getCaption(),
+ properties.getLink(),
+ properties.getContentType(), properties.getResourceData(), properties.getI18ns());
+
+ default:
+ throw new IllegalArgumentException("Unsupported slide type: " + type);
+ }
+ }
+}
\ No newline at end of file
diff --git a/backend/src/main/java/fr/cgi/magneto/helper/SlideHelper.java b/backend/src/main/java/fr/cgi/magneto/helper/SlideHelper.java
new file mode 100644
index 000000000..94622b915
--- /dev/null
+++ b/backend/src/main/java/fr/cgi/magneto/helper/SlideHelper.java
@@ -0,0 +1,649 @@
+package fr.cgi.magneto.helper;
+
+import fr.cgi.magneto.core.constants.CollectionsConstant;
+import fr.cgi.magneto.core.constants.Slideshow;
+import fr.cgi.magneto.model.slides.SlideMedia;
+import io.vertx.core.json.JsonObject;
+import org.apache.poi.openxml4j.opc.*;
+import org.apache.poi.sl.usermodel.PictureData.PictureType;
+import org.apache.poi.sl.usermodel.Placeholder;
+import org.apache.poi.sl.usermodel.PlaceholderDetails;
+import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
+import org.apache.poi.xslf.usermodel.*;
+import org.apache.xmlbeans.XmlCursor;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink;
+import org.openxmlformats.schemas.presentationml.x2006.main.*;
+
+import javax.imageio.ImageIO;
+import javax.xml.namespace.QName;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Set;
+
+import static org.apache.poi.openxml4j.opc.PackageRelationshipTypes.CORE_PROPERTIES_ECMA376_NS;
+
+public class SlideHelper {
+
+ public static XSLFTextBox createTitle(XSLFSlide slide, String title, int titleHeight, Double titleFontSize,
+ TextAlign titleTextAlign) {
+ XSLFTextShape titleShape = slide.createTextBox();
+ titleShape.setAnchor(
+ new Rectangle(Slideshow.MARGIN_LEFT, Slideshow.MARGIN_TOP_TITLE, Slideshow.WIDTH, titleHeight));
+
+ PlaceholderDetails phDetails = titleShape.getPlaceholderDetails();
+ if (phDetails != null) {
+ phDetails.setPlaceholder(Placeholder.TITLE);
+ }
+
+ titleShape.clearText();
+ titleShape.setText(title);
+
+ XSLFTextParagraph para = titleShape.getTextParagraphs().get(0);
+ para.setTextAlign(titleTextAlign);
+
+ XSLFTextRun run = para.getTextRuns().get(0);
+ run.setFontSize(titleFontSize);
+
+ return (XSLFTextBox) titleShape;
+ }
+
+ public static void addNotes(XSLFSlide newSlide, String description) {
+ Document doc = Jsoup.parse(description);
+ doc.select("style").remove();
+ String text = doc.text();
+
+ XSLFNotes note = newSlide.getSlideShow().getNotesSlide(newSlide);
+
+ // insert text
+ for (XSLFTextShape shape : note.getPlaceholders()) {
+ if (shape.getTextType() == Placeholder.BODY) {
+ shape.setText(text);
+ break;
+ }
+ }
+ }
+
+ public static XSLFTextBox createLegend(XSLFSlide slide, String legendText) {
+ XSLFTextBox legendShape = slide.createTextBox();
+
+ int slideHeight = slide.getSlideShow().getPageSize().height;
+ int legendY = slideHeight - Slideshow.LEGEND_HEIGHT - Slideshow.LEGEND_MARGIN_BOTTOM;
+
+ legendShape.setAnchor(new Rectangle(Slideshow.MARGIN_LEFT, legendY, Slideshow.WIDTH, Slideshow.LEGEND_HEIGHT));
+
+ legendShape.clearText();
+ legendShape.setText(legendText);
+
+ XSLFTextParagraph para = legendShape.getTextParagraphs().get(0);
+ para.setTextAlign(TextAlign.LEFT);
+
+ XSLFTextRun run = para.getTextRuns().get(0);
+ run.setFontSize(Slideshow.LEGEND_FONT_SIZE);
+ run.setFontFamily(Slideshow.LEGEND_FONT_FAMILY);
+
+ return legendShape;
+ }
+
+ public static XSLFTextBox createContent(XSLFSlide slide) {
+ XSLFTextBox contentBox = slide.createTextBox();
+ contentBox.setAnchor(new Rectangle(Slideshow.MARGIN_LEFT, Slideshow.CONTENT_MARGIN_TOP, Slideshow.WIDTH,
+ Slideshow.CONTENT_HEIGHT));
+ return contentBox;
+ }
+
+ public static XSLFPictureShape createImage(XSLFSlide slide, byte[] pictureData, String fileContentType,
+ int contentMarginTop, int imageContentHeight, Boolean alignLeft) {
+ XMLSlideShow ppt = slide.getSlideShow();
+
+ XSLFPictureData pic = ppt.addPicture(pictureData, getPictureTypeFromContentType(fileContentType));
+
+ java.awt.Dimension imgSize = pic.getImageDimension();
+
+ int availableWidth = Slideshow.WIDTH;
+
+ // Calculer les dimensions tout en préservant le ratio
+ double scaleFactor = Math.min(
+ (double) availableWidth / imgSize.width,
+ (double) imageContentHeight / imgSize.height
+ );
+
+ int newWidth = (int) (imgSize.width * scaleFactor);
+ int newHeight = (int) (imgSize.height * scaleFactor);
+
+ // Calculer la position X en fonction de l'alignement
+ int x = alignLeft ?
+ Slideshow.MARGIN_LEFT :
+ Slideshow.MARGIN_LEFT + (availableWidth - newWidth) / 2;
+
+ // Centrer verticalement dans l'espace alloué
+ int y = contentMarginTop + (imageContentHeight - newHeight) / 2;
+
+ XSLFPictureShape shape = slide.createPicture(pic);
+ shape.setAnchor(new Rectangle(x, y, newWidth, newHeight));
+
+ return shape;
+ }
+
+ public static XSLFPictureShape createImageWidthHeight(XSLFSlide slide, byte[] pictureData, String fileContentType,
+ int contentMarginTop, int imageContentHeight, int imageContentWidth, Boolean alignLeft) {
+ XMLSlideShow ppt = slide.getSlideShow();
+
+ XSLFPictureData pic = ppt.addPicture(pictureData, getPictureTypeFromContentType(fileContentType));
+
+ int x = alignLeft ? Slideshow.MARGIN_LEFT : Slideshow.MARGIN_LEFT + (Slideshow.WIDTH - imageContentWidth) / 2;
+
+ XSLFPictureShape shape = slide.createPicture(pic);
+ shape.setAnchor(new Rectangle(x, contentMarginTop, imageContentWidth, imageContentHeight));
+
+ return shape;
+ }
+
+ public static XSLFTextBox createLink(XSLFSlide slide, String url) {
+ // Créer une zone de texte pour le lien
+ XSLFTextBox linkBox = slide.createTextBox();
+ int linkPositionY = Slideshow.MARGIN_TOP_TITLE + Slideshow.TITLE_HEIGHT + 10;
+ // Positionner la zone de texte en utilisant les constantes existantes
+
+ linkBox.setAnchor(new Rectangle(
+ Slideshow.MARGIN_LEFT,
+ linkPositionY,
+ Slideshow.WIDTH,
+ 50));
+
+ // Créer un paragraphe pour le texte du lien
+ XSLFTextParagraph paragraph = linkBox.addNewTextParagraph();
+ paragraph.setTextAlign(TextAlign.LEFT);
+
+ // Créer un TextRun avec l'URL comme texte affiché
+ XSLFTextRun textRun = paragraph.addNewTextRun();
+ textRun.setText(url);
+ textRun.setFontSize(Slideshow.CONTENT_FONT_SIZE);
+ textRun.setFontColor(new Color(0, 0, 255)); // Bleu pour indiquer un lien
+ textRun.setUnderlined(true); // Souligné pour indiquer un lien
+
+ // Utiliser XSLFHyperlink pour créer le lien
+ XSLFHyperlink hyperlink = textRun.createHyperlink();
+ hyperlink.setAddress(url);
+
+ return linkBox;
+ }
+
+ public static XSLFTextBox createBoardInfoList(XSLFSlide slide, String ownerName, String modificationDate,
+ int resourceNumber,
+ boolean isShare, boolean isPublic, JsonObject i18ns) {
+ // Créer une zone de texte pour la liste
+ XSLFTextBox infoBox = slide.createTextBox();
+
+ int listPositionY = Slideshow.MAIN_CONTENT_MARGIN_TOP;
+ infoBox.setAnchor(
+ new Rectangle(Slideshow.WIDTH - Slideshow.MARGIN_LEFT * 5, listPositionY, Slideshow.BOARD_TEXT_WIDTH, 200));
+
+ XSLFTextParagraph paragraph1 = infoBox.addNewTextParagraph();
+ paragraph1.setSpaceBefore(0.0);
+ XSLFTextRun textRun1 = paragraph1.addNewTextRun();
+ textRun1.setText("• " + i18ns.getString(CollectionsConstant.I18N_SLIDESHOW_OWNER) + ownerName);
+ textRun1.setFontSize(Slideshow.CONTENT_FONT_SIZE);
+
+ if (modificationDate != null && !modificationDate.isEmpty()) {
+ XSLFTextParagraph paragraphDate = infoBox.addNewTextParagraph();
+ XSLFTextRun textRunDate = paragraphDate.addNewTextRun();
+ textRunDate.setText(
+ "• " + i18ns.getString(CollectionsConstant.I18N_SLIDESHOW_UPDATED) + formatDate(modificationDate));
+ textRunDate.setFontSize(Slideshow.CONTENT_FONT_SIZE);
+ }
+
+ XSLFTextParagraph paragraph2 = infoBox.addNewTextParagraph();
+ XSLFTextRun textRun2 = paragraph2.addNewTextRun();
+ textRun2.setText("• " + resourceNumber + " " + i18ns.getString(CollectionsConstant.I18N_SLIDESHOW_MAGNETS));
+ textRun2.setFontSize(Slideshow.CONTENT_FONT_SIZE);
+
+ // 3. Tableau partagé (si applicable)
+ if (isShare) {
+ XSLFTextParagraph paragraph3 = infoBox.addNewTextParagraph();
+ XSLFTextRun textRun3 = paragraph3.addNewTextRun();
+ textRun3.setText("• " + i18ns.getString(CollectionsConstant.I18N_SLIDESHOW_SHARED));
+ textRun3.setFontSize(Slideshow.CONTENT_FONT_SIZE);
+ }
+
+ // 4. Tableau de la plateforme
+ if (isPublic) {
+ XSLFTextParagraph paragraph4 = infoBox.addNewTextParagraph();
+ XSLFTextRun textRun4 = paragraph4.addNewTextRun();
+ textRun4.setText("• " + i18ns.getString(CollectionsConstant.I18N_SLIDESHOW_PLATFORM));
+ textRun4.setFontSize(Slideshow.CONTENT_FONT_SIZE);
+ }
+
+ return infoBox;
+ }
+
+ public static XSLFPictureShape createMedia(XSLFSlide slide, byte[] mediaData, String fileContentType,
+ SlideMedia.MediaType mediaType) {
+
+ if (mediaType != SlideMedia.MediaType.AUDIO && mediaType != SlideMedia.MediaType.VIDEO) {
+ throw new IllegalArgumentException("Type de média non supporté: " + mediaType);
+ }
+
+ boolean isAudio = mediaType == SlideMedia.MediaType.AUDIO;
+ String extension = getExtensionFromContentType(fileContentType);
+
+ try {
+ // Générer un nom pour le fichier média
+ String mediaTypeStr = isAudio ? Slideshow.MEDIA_TYPE_AUDIO : Slideshow.MEDIA_TYPE_VIDEO;
+ String mediaFileName = mediaTypeStr + "_" + System.currentTimeMillis() + "." + extension;
+
+ // Créer et stocker le fichier média
+ XMLSlideShow ppt = slide.getSlideShow();
+ OPCPackage opcPackage = ppt.getPackage();
+
+ PackagePartName mediaPartName = PackagingURIHelper
+ .createPartName(Slideshow.MEDIA_PATH_PREFIX + mediaFileName);
+ PackagePart mediaPart = opcPackage.createPart(mediaPartName, fileContentType);
+
+ try (OutputStream out = mediaPart.getOutputStream()) {
+ out.write(mediaData);
+ }
+
+ // Obtenir la partie du slide
+ PackagePart pp = slide.getPackagePart();
+
+ // Créer deux relations vers le fichier média
+ PackageRelationship prsEmbed = pp.addRelationship(
+ mediaPart.getPartName(), TargetMode.INTERNAL,
+ Slideshow.RELATIONSHIP_MEDIA);
+
+ String execRelationship = isAudio ? Slideshow.RELATIONSHIP_AUDIO : Slideshow.RELATIONSHIP_VIDEO;
+ PackageRelationship prsExec = pp.addRelationship(
+ mediaPart.getPartName(), TargetMode.INTERNAL,
+ execRelationship);
+
+ // Créer l'icône ou la miniature
+ byte[] iconData = isAudio ? getAudioIcon() : getVideoThumbnail(mediaData, extension);
+ XSLFPictureData snap = ppt.addPicture(iconData, PictureType.PNG);
+
+ XSLFPictureShape pic = isAudio ? createAndPositionMediaIcon(slide, iconData)
+ : createAndPositionVideoThumbnail(slide, iconData);
+
+ // Configurer les propriétés de l'image pour le média
+ CTPicture xpic = (CTPicture) pic.getXmlObject();
+
+ CTHyperlink link = xpic.getNvPicPr().getCNvPr().addNewHlinkClick();
+ link.setId("");
+ link.setAction(Slideshow.ACTION_MEDIA);
+
+ // Ajouter les propriétés au média
+ CTApplicationNonVisualDrawingProps nvPr = xpic.getNvPicPr().getNvPr();
+ if (isAudio) {
+ nvPr.addNewAudioFile().setLink(prsExec.getId());
+ } else {
+ nvPr.addNewVideoFile().setLink(prsExec.getId());
+ }
+
+ // Ajouter l'extension média
+ CTExtension ext = nvPr.addNewExtLst().addNewExt();
+ ext.setUri(Slideshow.EXTENSION_URI_MEDIA);
+
+ // Configurer l'élément p14:media
+ try (XmlCursor cur = ext.newCursor()) {
+ cur.toEndToken();
+ cur.beginElement(new QName(Slideshow.NAMESPACE_POWERPOINT_2010, "media", "p14"));
+ cur.insertNamespace("p14", Slideshow.NAMESPACE_POWERPOINT_2010);
+ cur.insertNamespace("r", CORE_PROPERTIES_ECMA376_NS);
+ cur.insertAttributeWithValue(
+ new QName(CORE_PROPERTIES_ECMA376_NS, "embed"),
+ prsEmbed.getId());
+ }
+
+ // S'assurer que le blipFill utilise le bon ID pour l'image
+ String imageRelId = slide.getRelationId(snap);
+ if (imageRelId != null) {
+ xpic.getBlipFill().getBlip().setEmbed(imageRelId);
+ }
+
+ // Ajouter la section timing - CRUCIAL
+ CTSlide xslide = slide.getXmlObject();
+ CTTimeNodeList ctnl;
+
+ if (!xslide.isSetTiming()) {
+ CTTLCommonTimeNodeData ctn = xslide.addNewTiming().addNewTnLst().addNewPar().addNewCTn();
+ ctn.setId(Slideshow.TIMING_ROOT_ID);
+ ctn.setDur(STTLTimeIndefinite.INDEFINITE);
+ ctn.setRestart(STTLTimeNodeRestartType.NEVER);
+ ctn.setNodeType(STTLTimeNodeType.TM_ROOT);
+ ctnl = ctn.addNewChildTnLst();
+ } else {
+ ctnl = xslide.getTiming().getTnLst().getParArray(0).getCTn().getChildTnLst();
+ }
+
+ // Ajouter le nœud média approprié (audio ou vidéo)
+ CTTLCommonMediaNodeData cmedia = isAudio ? ctnl.addNewAudio().addNewCMediaNode()
+ : ctnl.addNewVideo().addNewCMediaNode();
+ cmedia.setVol(Slideshow.MEDIA_VOLUME);
+
+ CTTLCommonTimeNodeData ctn = cmedia.addNewCTn();
+ ctn.setId(Slideshow.TIMING_MEDIA_ID);
+ ctn.setFill(STTLTimeNodeFillType.HOLD);
+ ctn.setDisplay(false);
+
+ ctn.addNewStCondLst().addNewCond().setDelay(STTLTimeIndefinite.INDEFINITE);
+
+ cmedia.addNewTgtEl().addNewSpTgt().setSpid(pic.getShapeId());
+
+ return pic;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ private static PictureType getPictureTypeFromContentType(String contentType) {
+ if (contentType == null) {
+ return PictureType.PNG;
+ }
+
+ String lowerContentType = contentType.toLowerCase();
+
+ switch (lowerContentType) {
+ case Slideshow.CONTENT_TYPE_IMAGE_JPEG:
+ case Slideshow.CONTENT_TYPE_IMAGE_JPG:
+ return PictureType.JPEG;
+ case Slideshow.CONTENT_TYPE_IMAGE_PNG:
+ return PictureType.PNG;
+ case Slideshow.CONTENT_TYPE_IMAGE_GIF:
+ return PictureType.GIF;
+ case Slideshow.CONTENT_TYPE_IMAGE_TIFF:
+ return PictureType.TIFF;
+ case Slideshow.CONTENT_TYPE_IMAGE_X_EMF:
+ return PictureType.EMF;
+ case Slideshow.CONTENT_TYPE_IMAGE_X_WMF:
+ return PictureType.WMF;
+ case Slideshow.CONTENT_TYPE_IMAGE_X_PICT:
+ return PictureType.PICT;
+ case Slideshow.CONTENT_TYPE_IMAGE_DIB:
+ return PictureType.DIB;
+ case Slideshow.CONTENT_TYPE_IMAGE_X_EPS:
+ return PictureType.EPS;
+ case Slideshow.CONTENT_TYPE_IMAGE_X_MS_BMP:
+ case Slideshow.CONTENT_TYPE_IMAGE_BMP:
+ return PictureType.BMP;
+ case Slideshow.CONTENT_TYPE_IMAGE_X_WPG:
+ return PictureType.WPG;
+ case Slideshow.CONTENT_TYPE_IMAGE_VND_MS_PHOTO:
+ return PictureType.WDP;
+ case Slideshow.CONTENT_TYPE_IMAGE_SVG_XML:
+ return PictureType.SVG;
+ default:
+ return PictureType.PNG;
+ }
+ }
+
+ private static XSLFPictureShape createAndPositionMediaIcon(XSLFSlide slide, byte[] iconData) {
+
+ XMLSlideShow ppt = slide.getSlideShow();
+ XSLFPictureData snap = ppt.addPicture(iconData, PictureType.PNG);
+
+ XSLFPictureShape pic = slide.createPicture(snap);
+
+ // Définir une taille plus grande
+ int iconWidth = Slideshow.ICON_WIDTH;
+ int iconHeight = Slideshow.ICON_HEIGHT;
+
+ // Calculer la position verticale centrée
+ int y = (Slideshow.SLIDE_HEIGHT - iconHeight) / 2; // Centre vertical
+
+ // Utiliser le MARGIN_LEFT existant pour l'alignement horizontal
+ pic.setAnchor(new Rectangle(Slideshow.MARGIN_LEFT, y, iconWidth, iconHeight));
+
+ return pic;
+ }
+
+ private static byte[] getAudioIcon() {
+ try {
+ BufferedImage image = new BufferedImage(
+ Slideshow.AUDIO_ICON_WIDTH,
+ Slideshow.AUDIO_ICON_HEIGHT,
+ BufferedImage.TYPE_INT_ARGB);
+
+ Graphics2D g2d = image.createGraphics();
+
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+
+ g2d.setColor(Slideshow.AUDIO_ICON_BACKGROUND_COLOR);
+ g2d.fillOval(
+ Slideshow.AUDIO_ICON_CIRCLE_X,
+ Slideshow.AUDIO_ICON_CIRCLE_Y,
+ Slideshow.AUDIO_ICON_CIRCLE_WIDTH,
+ Slideshow.AUDIO_ICON_CIRCLE_HEIGHT);
+
+ g2d.setColor(Slideshow.AUDIO_ICON_PLAY_COLOR);
+ g2d.fillPolygon(
+ Slideshow.AUDIO_ICON_TRIANGLE_X,
+ Slideshow.AUDIO_ICON_TRIANGLE_Y,
+ Slideshow.AUDIO_ICON_TRIANGLE_X.length);
+
+ // Libérer les ressources
+ g2d.dispose();
+
+ // Convertir l'image en tableau de bytes (PNG)
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ImageIO.write(image, Slideshow.AUDIO_ICON_FORMAT, baos);
+ return baos.toByteArray();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ return Slideshow.FALLBACK_PNG;
+ }
+ }
+
+ private static XSLFPictureShape createAndPositionVideoThumbnail(XSLFSlide slide, byte[] thumbnailData) {
+
+ XMLSlideShow ppt = slide.getSlideShow();
+ XSLFPictureData snap = ppt.addPicture(thumbnailData, PictureType.PNG);
+
+ XSLFPictureShape pic = slide.createPicture(snap);
+
+ int videoWidth = Slideshow.VIDEO_DISPLAY_WIDTH;
+ int videoHeight = Slideshow.VIDEO_DISPLAY_HEIGHT;
+
+ int x = (Slideshow.SLIDE_WIDTH - videoWidth) / 2; // Centre horizontal
+ int y = (Slideshow.SLIDE_HEIGHT - videoHeight) / 2; // Centre vertical
+
+ pic.setAnchor(new Rectangle(x, y, videoWidth, videoHeight));
+
+ return pic;
+ }
+
+ private static byte[] getVideoThumbnail(byte[] videoData, String extension) {
+ try {
+ // Dans un cas réel, on extrairait une image de la vidéo ici
+ // Pour cet exemple, nous allons simplement créer une vignette générique
+
+ // Créer une image au format 16:9
+ BufferedImage image = new BufferedImage(
+ Slideshow.VIDEO_THUMBNAIL_WIDTH,
+ Slideshow.VIDEO_THUMBNAIL_HEIGHT,
+ BufferedImage.TYPE_INT_RGB);
+
+ // Obtenir le contexte graphique
+ Graphics2D g2d = image.createGraphics();
+
+ // Activer l'antialiasing pour des bords plus lisses
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+
+ // Remplir le fond avec un dégradé bleu foncé
+ g2d.setColor(Slideshow.VIDEO_BACKGROUND_COLOR);
+ g2d.fillRect(0, 0, Slideshow.VIDEO_THUMBNAIL_WIDTH, Slideshow.VIDEO_THUMBNAIL_HEIGHT);
+
+ // Dessiner un symbole de lecture au centre
+ g2d.setColor(Slideshow.VIDEO_PLAY_BUTTON_COLOR);
+ int centerX = Slideshow.VIDEO_THUMBNAIL_WIDTH / 2;
+ int centerY = Slideshow.VIDEO_THUMBNAIL_HEIGHT / 2;
+ int radius = Slideshow.VIDEO_PLAY_BUTTON_RADIUS;
+ g2d.fillOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
+
+ // Triangle de lecture
+ g2d.setColor(Slideshow.VIDEO_BACKGROUND_COLOR);
+ int[] xPoints = {
+ centerX - Slideshow.VIDEO_PLAY_TRIANGLE_OFFSET_X,
+ centerX + Slideshow.VIDEO_PLAY_TRIANGLE_OFFSET_X2,
+ centerX - Slideshow.VIDEO_PLAY_TRIANGLE_OFFSET_X
+ };
+ int[] yPoints = {
+ centerY - Slideshow.VIDEO_PLAY_TRIANGLE_OFFSET_Y,
+ centerY,
+ centerY + Slideshow.VIDEO_PLAY_TRIANGLE_OFFSET_Y
+ };
+ g2d.fillPolygon(xPoints, yPoints, 3);
+
+ // Ajouter le texte "VIDÉO"
+ g2d.setColor(Slideshow.VIDEO_TEXT_COLOR);
+ g2d.setFont(new java.awt.Font(
+ Slideshow.VIDEO_THUMBNAIL_FONT,
+ Slideshow.VIDEO_THUMBNAIL_FONT_STYLE,
+ Slideshow.VIDEO_THUMBNAIL_FONT_SIZE));
+ java.awt.FontMetrics fm = g2d.getFontMetrics();
+ String text = Slideshow.VIDEO_THUMBNAIL_TEXT;
+ int textWidth = fm.stringWidth(text);
+ g2d.drawString(text, centerX - textWidth / 2, centerY + Slideshow.VIDEO_TEXT_Y_OFFSET);
+
+ // Libérer les ressources
+ g2d.dispose();
+
+ // Convertir l'image en tableau de bytes (PNG)
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ImageIO.write(image, Slideshow.VIDEO_THUMBNAIL_FORMAT, baos);
+ return baos.toByteArray();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ return getDefaultThumbnail();
+ }
+ }
+
+ private static byte[] getDefaultThumbnail() {
+ try {
+ // Créer une image simple par défaut
+ BufferedImage image = new BufferedImage(Slideshow.THUMBNAIL_WIDTH, Slideshow.THUMBNAIL_HEIGHT,
+ BufferedImage.TYPE_INT_RGB);
+ Graphics2D g2d = image.createGraphics();
+ g2d.setColor(Color.DARK_GRAY);
+ g2d.fillRect(0, 0, Slideshow.THUMBNAIL_WIDTH, Slideshow.THUMBNAIL_HEIGHT);
+ g2d.setColor(Color.WHITE);
+ g2d.setFont(new java.awt.Font(Slideshow.THUMBNAIL_FONT, Slideshow.THUMBNAIL_FONT_STYLE,
+ Slideshow.THUMBNAIL_FONT_SIZE));
+ g2d.drawString(Slideshow.THUMBNAIL_DEFAULT_TEXT, Slideshow.THUMBNAIL_TEXT_X, Slideshow.THUMBNAIL_TEXT_Y);
+ g2d.dispose();
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ImageIO.write(image, Slideshow.THUMBNAIL_FORMAT, baos);
+ return baos.toByteArray();
+ } catch (IOException e) {
+ e.printStackTrace();
+ return new byte[0];
+ }
+ }
+
+ private static String getExtensionFromContentType(String contentType) {
+ if (contentType == null) {
+ return Slideshow.DEFAULT_VIDEO_EXTENSION;
+ }
+
+ String lowerContentType = contentType.toLowerCase();
+
+ switch (lowerContentType) {
+ // Types audio
+ case Slideshow.CONTENT_TYPE_AUDIO_MPEG:
+ case Slideshow.CONTENT_TYPE_AUDIO_MP3:
+ return Slideshow.EXT_MP3;
+ case Slideshow.CONTENT_TYPE_AUDIO_WAV:
+ case Slideshow.CONTENT_TYPE_AUDIO_X_WAV:
+ return Slideshow.EXT_WAV;
+ case Slideshow.CONTENT_TYPE_AUDIO_MP4:
+ case Slideshow.CONTENT_TYPE_AUDIO_X_M4A:
+ return Slideshow.EXT_M4A;
+ case Slideshow.CONTENT_TYPE_AUDIO_OGG:
+ return Slideshow.EXT_OGG;
+
+ // Types vidéo
+ case Slideshow.CONTENT_TYPE_VIDEO_MP4:
+ return Slideshow.EXT_MP4;
+ case Slideshow.CONTENT_TYPE_VIDEO_MPEG:
+ return Slideshow.EXT_MPG;
+ case Slideshow.CONTENT_TYPE_VIDEO_X_MS_WMV:
+ return Slideshow.EXT_WMV;
+ case Slideshow.CONTENT_TYPE_VIDEO_QUICKTIME:
+ return Slideshow.EXT_MOV;
+ case Slideshow.CONTENT_TYPE_VIDEO_X_MATROSKA:
+ return Slideshow.EXT_MKV;
+ case Slideshow.CONTENT_TYPE_VIDEO_WEBM:
+ return Slideshow.EXT_WEBM;
+ case Slideshow.CONTENT_TYPE_VIDEO_X_FLV:
+ return Slideshow.EXT_FLV;
+ case Slideshow.CONTENT_TYPE_VIDEO_3GPP:
+ return Slideshow.EXT_3GP;
+ case Slideshow.CONTENT_TYPE_VIDEO_AVI:
+ case Slideshow.CONTENT_TYPE_VIDEO_X_MSVIDEO:
+ return Slideshow.EXT_AVI;
+
+ default:
+ if (lowerContentType.startsWith(Slideshow.CONTENT_TYPE_AUDIO)) {
+ return Slideshow.DEFAULT_AUDIO_EXTENSION;
+ } else if (lowerContentType.startsWith(Slideshow.CONTENT_TYPE_VIDEO)) {
+ return Slideshow.DEFAULT_VIDEO_EXTENSION;
+ } else {
+ return null;
+ }
+ }
+ }
+
+ private static String formatDate(String dateString) {
+ if (dateString == null || dateString.isEmpty()) {
+ return "";
+ }
+
+ try {
+ java.text.SimpleDateFormat inputFormat = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+ java.text.SimpleDateFormat outputFormat = new java.text.SimpleDateFormat("dd/MM/yyyy");
+
+ java.util.Date date = inputFormat.parse(dateString);
+ return outputFormat.format(date);
+ } catch (java.text.ParseException e) {
+ return dateString;
+ }
+ }
+
+ public static String generateUniqueFileName(Set usedFileNames, String originalFileName) {
+ if (!usedFileNames.contains(originalFileName)) {
+ usedFileNames.add(originalFileName);
+ return originalFileName;
+ }
+
+ String fileNameWithoutExtension = getFileNameWithoutExtension(originalFileName);
+ String extension = getFileExtension(originalFileName);
+
+ int counter = 1;
+ String uniqueFileName;
+ do {
+ uniqueFileName = fileNameWithoutExtension + " (" + counter + ")." + extension;
+ counter++;
+ } while (usedFileNames.contains(uniqueFileName));
+
+ usedFileNames.add(uniqueFileName);
+ return uniqueFileName;
+ }
+
+ private static String getFileNameWithoutExtension(String fileName) {
+ int dotIndex = fileName.lastIndexOf('.');
+ return (dotIndex == -1) ? fileName : fileName.substring(0, dotIndex);
+ }
+
+ private static String getFileExtension(String fileName) {
+ int dotIndex = fileName.lastIndexOf('.');
+ return (dotIndex == -1) ? "" : fileName.substring(dotIndex + 1);
+ }
+}
\ No newline at end of file
diff --git a/backend/src/main/java/fr/cgi/magneto/model/Section.java b/backend/src/main/java/fr/cgi/magneto/model/Section.java
index 48af01f62..351afd92b 100644
--- a/backend/src/main/java/fr/cgi/magneto/model/Section.java
+++ b/backend/src/main/java/fr/cgi/magneto/model/Section.java
@@ -1,6 +1,7 @@
package fr.cgi.magneto.model;
import fr.cgi.magneto.core.constants.Field;
+import fr.cgi.magneto.model.cards.Card;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
@@ -13,6 +14,7 @@ public class Section implements Model {
private List cardIds;
private String boardId;
private Boolean displayed;
+ private List cards;
@SuppressWarnings("unchecked")
public Section(JsonObject section) {
@@ -22,6 +24,8 @@ public Section(JsonObject section) {
this.boardId = section.getString(Field.BOARDID);
if (section.containsKey(Field.DISPLAYED))
this.displayed = section.getBoolean(Field.DISPLAYED);
+ if (section.containsKey(Field.CARDS))
+ this.cards = section.getJsonArray(Field.CARDS).getList();
}
public Section() {
@@ -87,6 +91,15 @@ public void setDisplayed(boolean displayed) {
this.displayed = displayed;
}
+ public List getCards() {
+ return cards;
+ }
+
+ public Section setCards(List cards) {
+ this.cards = cards;
+ return this;
+ }
+
@Override
public JsonObject toJson() {
JsonObject json = new JsonObject()
@@ -96,6 +109,8 @@ public JsonObject toJson() {
.put(Field.BOARDID, this.getBoardId());
if (this.displayed != null)
json.put(Field.DISPLAYED, this.getDisplayed());
+ if (this.cards != null)
+ json.put(Field.CARDS, this.getCards());
return json;
}
diff --git a/backend/src/main/java/fr/cgi/magneto/model/properties/SlideProperties.java b/backend/src/main/java/fr/cgi/magneto/model/properties/SlideProperties.java
new file mode 100644
index 000000000..61db4b618
--- /dev/null
+++ b/backend/src/main/java/fr/cgi/magneto/model/properties/SlideProperties.java
@@ -0,0 +1,261 @@
+package fr.cgi.magneto.model.properties;
+
+import fr.cgi.magneto.core.enums.SlideResourceType;
+import fr.cgi.magneto.helper.I18nHelper;
+import io.vertx.core.json.JsonObject;
+
+public class SlideProperties {
+ private String title;
+ private String description;
+ private String caption;
+ private String content;
+ private String resourceUrl;
+ private String resourceId;
+ private String fileNameString;
+ private byte[] resourceData;
+ private String contentType;
+ private String link;
+ private JsonObject i18ns;
+ private I18nHelper i18nHelper;
+
+ private String ownerName;
+ private String modificationDate;
+ private Integer resourceNumber;
+ private Boolean isShare;
+ private Boolean isPublic;
+
+ private SlideProperties() {
+ }
+
+ private boolean isValidForTitle() {
+ return title != null && description != null && ownerName != null && modificationDate != null
+ && resourceData != null && contentType != null;
+ }
+
+ private boolean isValidForFile() {
+ return fileNameString != null && resourceData != null && title != null && caption != null && contentType != null;
+ }
+
+ public boolean isValidForType(SlideResourceType type) {
+ if (type == null)
+ return false;
+
+ switch (type) {
+ case TITLE:
+ return isValidForTitle();
+ case DESCRIPTION:
+ return isValidForDescription();
+ case TEXT:
+ return isValidForText();
+ case FILE:
+ case PDF:
+ return isValidForFile();
+ case LINK:
+ case HYPERLINK:
+ case EMBEDDER:
+ return isValidForLink();
+ case IMAGE:
+ case VIDEO:
+ case AUDIO:
+ return isValidForMedia();
+ case BOARD:
+ return isValidForBoard();
+ default:
+ return false;
+ }
+ }
+
+ public I18nHelper getI18nHelper() {
+ return i18nHelper;
+ }
+
+ private boolean isValidForDescription() { return title != null; }
+
+ private boolean isValidForText() {
+ return title != null;
+ }
+
+ public String getFileNameString() {
+ return fileNameString;
+ }
+
+ private boolean isValidForLink() {
+ return resourceUrl != null && title != null && caption != null && resourceData != null && contentType != null;
+ }
+
+ private boolean isValidForMedia() {
+ return title != null && caption != null && contentType != null && resourceData != null;
+ }
+
+ private boolean isValidForBoard() {
+ return title != null && ownerName != null
+ && link != null
+ && caption != null
+ && modificationDate != null
+ && resourceNumber != null
+ && isShare != null
+ && contentType != null
+ && resourceData != null
+ && isPublic != null
+ && !i18ns.isEmpty();
+ }
+
+ // Getters
+ public String getTitle() {
+ return title;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getCaption() {
+ return caption;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public String getResourceUrl() {
+ return resourceUrl;
+ }
+
+ public String getResourceId() {
+ return resourceId;
+ }
+
+ public String getContentType() {
+ return contentType;
+ }
+
+ public String getLink() {
+ return link;
+ }
+
+ public JsonObject getI18ns() {
+ return i18ns;
+ }
+
+ public static class Builder {
+ private final SlideProperties properties;
+
+ public Builder() {
+ properties = new SlideProperties();
+ }
+
+ public Builder title(String title) {
+ properties.title = title;
+ return this;
+ }
+
+ public Builder description(String description) {
+ properties.description = description;
+ return this;
+ }
+
+ public Builder caption(String caption) {
+ properties.caption = caption;
+ return this;
+ }
+
+ public Builder content(String content) {
+ properties.content = content;
+ return this;
+ }
+
+ public Builder resourceUrl(String resourceUrl) {
+ properties.resourceUrl = resourceUrl;
+ return this;
+ }
+
+ public Builder resourceId(String resourceId) {
+ properties.resourceId = resourceId;
+ return this;
+ }
+
+ public Builder contentType(String contentType) {
+ properties.contentType = contentType;
+ return this;
+ }
+
+ public Builder fileNameString(String fileNameString) {
+ properties.fileNameString = fileNameString;
+ return this;
+ }
+
+ public Builder link(String link) {
+ properties.link = link;
+ return this;
+ }
+
+ public Builder i18ns(JsonObject i18ns) {
+ properties.i18ns = i18ns;
+ return this;
+ }
+
+ public Builder resourceData(byte[] resourceData) {
+ properties.resourceData = resourceData;
+ return this;
+ }
+
+ // Propriétés spécifiques board
+ public Builder ownerName(String ownerName) {
+ properties.ownerName = ownerName;
+ return this;
+ }
+
+ public Builder modificationDate(String modificationDate) {
+ properties.modificationDate = modificationDate;
+ return this;
+ }
+
+ public Builder resourceNumber(Integer resourceNumber) {
+ properties.resourceNumber = resourceNumber;
+ return this;
+ }
+
+ public Builder isShare(Boolean isShare) {
+ properties.isShare = isShare;
+ return this;
+ }
+
+ public Builder isPublic(Boolean isPublic) {
+ properties.isPublic = isPublic;
+ return this;
+ }
+
+ public Builder i18nHelper(I18nHelper i18nHelper) {
+ properties.i18nHelper = i18nHelper;
+ return this;
+ }
+
+ public SlideProperties build() {
+ return properties;
+ }
+ }
+
+ public byte[] getResourceData() {
+ return resourceData;
+ }
+
+ public String getOwnerName() {
+ return ownerName;
+ }
+
+ public String getModificationDate() {
+ return modificationDate;
+ }
+
+ public Integer getResourceNumber() {
+ return resourceNumber;
+ }
+
+ public Boolean getIsShare() {
+ return isShare;
+ }
+
+ public Boolean getIsPublic() {
+ return isPublic;
+ }
+}
\ No newline at end of file
diff --git a/backend/src/main/java/fr/cgi/magneto/model/slides/Slide.java b/backend/src/main/java/fr/cgi/magneto/model/slides/Slide.java
new file mode 100644
index 000000000..fb5b10f15
--- /dev/null
+++ b/backend/src/main/java/fr/cgi/magneto/model/slides/Slide.java
@@ -0,0 +1,10 @@
+package fr.cgi.magneto.model.slides;
+
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+
+public abstract class Slide {
+ protected String title;
+ protected String description = "";
+
+ public abstract Object createApacheSlide(XSLFSlide newSlide);
+}
diff --git a/backend/src/main/java/fr/cgi/magneto/model/slides/SlideBoard.java b/backend/src/main/java/fr/cgi/magneto/model/slides/SlideBoard.java
new file mode 100644
index 000000000..f46187c18
--- /dev/null
+++ b/backend/src/main/java/fr/cgi/magneto/model/slides/SlideBoard.java
@@ -0,0 +1,54 @@
+package fr.cgi.magneto.model.slides;
+
+import fr.cgi.magneto.core.constants.Slideshow;
+import fr.cgi.magneto.helper.SlideHelper;
+import io.vertx.core.json.JsonObject;
+import org.apache.poi.sl.usermodel.TextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+
+public class SlideBoard extends Slide {
+ private final String ownerName;
+ private final String link;
+ private final String modificationDate;
+ private final int resourceNumber;
+ private final boolean isShare;
+ private final boolean isPublic;
+ private final String caption;
+ private final String fileContentType;
+ private byte[] resourceData;
+ private JsonObject i18ns;
+
+ public SlideBoard(String title, String description, String ownerName, String modificationDate, int resourceNumber,
+ boolean isShare, boolean isPublic, String caption, String link, String contentType,
+ byte[] resourceData, JsonObject i18ns) {
+ this.title = title;
+ this.description = description;
+ this.ownerName = ownerName;
+ this.modificationDate = modificationDate;
+ this.resourceNumber = resourceNumber;
+ this.caption = caption;
+ this.isShare = isShare;
+ this.isPublic = isPublic;
+ this.link = link;
+ this.fileContentType = contentType;
+ this.resourceData = resourceData;
+ this.i18ns = i18ns;
+
+ }
+
+ @Override
+ public Object createApacheSlide(XSLFSlide newSlide) {
+ SlideHelper.createTitle(newSlide, title, Slideshow.TITLE_HEIGHT, Slideshow.TITLE_FONT_SIZE,
+ TextParagraph.TextAlign.LEFT);
+ SlideHelper.createLink(newSlide, link);
+ SlideHelper.createImage(newSlide, resourceData, fileContentType, Slideshow.MAIN_CONTENT_MARGIN_TOP,
+ Slideshow.BOARD_IMAGE_CONTENT_HEIGHT, true);
+ SlideHelper.createBoardInfoList(newSlide, ownerName, modificationDate, resourceNumber, isShare, isPublic,
+ i18ns);
+ SlideHelper.createLegend(newSlide, caption);
+
+ SlideHelper.addNotes(newSlide, description);
+
+ return newSlide;
+ }
+}
diff --git a/backend/src/main/java/fr/cgi/magneto/model/slides/SlideDescription.java b/backend/src/main/java/fr/cgi/magneto/model/slides/SlideDescription.java
new file mode 100644
index 000000000..d9a0e7fab
--- /dev/null
+++ b/backend/src/main/java/fr/cgi/magneto/model/slides/SlideDescription.java
@@ -0,0 +1,35 @@
+package fr.cgi.magneto.model.slides;
+
+import fr.cgi.magneto.core.constants.Slideshow;
+import fr.cgi.magneto.helper.SlideHelper;
+import org.apache.poi.sl.usermodel.TextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTextBox;
+import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFTextRun;
+
+public class SlideDescription extends Slide {
+
+ public SlideDescription(String title, String description) {
+ this.title = title;
+ this.description = description;
+ }
+
+ @Override
+ public Object createApacheSlide(XSLFSlide newSlide) {
+
+ SlideHelper.createTitle(newSlide, title,
+ Slideshow.DESCRIPTION_TITLE_HEIGHT, Slideshow.DESCRIPTION_TITLE_FONT_SIZE, TextParagraph.TextAlign.LEFT);
+
+ XSLFTextBox textBox = SlideHelper.createContent(newSlide);
+
+ XSLFTextParagraph paragraph = textBox.addNewTextParagraph();
+ paragraph.setTextAlign(TextParagraph.TextAlign.LEFT);
+ XSLFTextRun textRun = paragraph.addNewTextRun();
+ textRun.setText(description);
+ textRun.setFontSize(Slideshow.DESCRIPTION_FONT_SIZE);
+ textRun.setFontFamily(Slideshow.DEFAULT_FONT);
+
+ return newSlide;
+ }
+}
diff --git a/backend/src/main/java/fr/cgi/magneto/model/slides/SlideFile.java b/backend/src/main/java/fr/cgi/magneto/model/slides/SlideFile.java
new file mode 100644
index 000000000..6dcf2afa7
--- /dev/null
+++ b/backend/src/main/java/fr/cgi/magneto/model/slides/SlideFile.java
@@ -0,0 +1,48 @@
+package fr.cgi.magneto.model.slides;
+
+import fr.cgi.magneto.core.constants.Slideshow;
+import fr.cgi.magneto.helper.SlideHelper;
+import org.apache.poi.sl.usermodel.TextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTextBox;
+import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFTextRun;
+
+public class SlideFile extends Slide {
+ private final String filenameString;
+ private final String caption;
+ private final byte[] fileSvg;
+ private final String fileContentType;
+
+ public SlideFile(String title, String description, String filenameString, String caption, byte[] fileSvg, String fileContentType) {
+ this.title = title;
+ this.description = description;
+ this.filenameString = filenameString;
+ this.caption = caption;
+ this.fileSvg = fileSvg;
+ this.fileContentType = fileContentType;
+ }
+
+ @Override
+ public Object createApacheSlide(XSLFSlide newSlide) {
+ SlideHelper.createTitle(newSlide, title, Slideshow.TITLE_HEIGHT, Slideshow.DESCRIPTION_TITLE_FONT_SIZE,
+ TextParagraph.TextAlign.LEFT);
+
+ XSLFTextBox textBox = SlideHelper.createContent(newSlide);
+ XSLFTextParagraph paragraph = textBox.addNewTextParagraph();
+ paragraph.setTextAlign(TextParagraph.TextAlign.LEFT);
+ paragraph.setLineSpacing(175.0);
+ XSLFTextRun textRun = paragraph.addNewTextRun();
+ textRun.setText(filenameString);
+ textRun.setFontSize(Slideshow.CONTENT_FONT_SIZE);
+ textRun.setFontFamily(Slideshow.DEFAULT_FONT);
+
+ SlideHelper.createImageWidthHeight(newSlide, fileSvg, fileContentType, Slideshow.MAIN_CONTENT_MARGIN_TOP,
+ Slideshow.SVG_CONTENT_HEIGHT, Slideshow.SVG_CONTENT_WIDTH, true);
+ SlideHelper.createLegend(newSlide, caption);
+
+ SlideHelper.addNotes(newSlide, description);
+
+ return newSlide;
+ }
+}
diff --git a/backend/src/main/java/fr/cgi/magneto/model/slides/SlideLink.java b/backend/src/main/java/fr/cgi/magneto/model/slides/SlideLink.java
new file mode 100644
index 000000000..fa388eade
--- /dev/null
+++ b/backend/src/main/java/fr/cgi/magneto/model/slides/SlideLink.java
@@ -0,0 +1,37 @@
+package fr.cgi.magneto.model.slides;
+
+import fr.cgi.magneto.core.constants.Slideshow;
+import fr.cgi.magneto.helper.SlideHelper;
+import org.apache.poi.sl.usermodel.TextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+
+public class SlideLink extends Slide {
+ private final String link;
+ private final String caption;
+ private final byte[] resourceData;
+ private final String fileContentType;
+
+ public SlideLink(String title, String description, String link, String caption, byte[] resourceData, String fileContentType) {
+ this.title = title;
+ this.description = description;
+ this.link = link;
+ this.caption = caption;
+ this.resourceData = resourceData;
+ this.fileContentType = fileContentType;
+ }
+
+ @Override
+ public Object createApacheSlide(XSLFSlide newSlide) {
+
+ SlideHelper.createTitle(newSlide, title, Slideshow.TITLE_HEIGHT, Slideshow.TITLE_FONT_SIZE,
+ TextParagraph.TextAlign.LEFT);
+ SlideHelper.createLink(newSlide, link);
+ SlideHelper.createImageWidthHeight(newSlide, resourceData, fileContentType, Slideshow.MAIN_CONTENT_MARGIN_TOP,
+ Slideshow.SVG_CONTENT_HEIGHT, Slideshow.SVG_CONTENT_WIDTH, true);
+ SlideHelper.createLegend(newSlide, caption);
+
+ SlideHelper.addNotes(newSlide, description);
+
+ return newSlide;
+ }
+}
diff --git a/backend/src/main/java/fr/cgi/magneto/model/slides/SlideMedia.java b/backend/src/main/java/fr/cgi/magneto/model/slides/SlideMedia.java
new file mode 100644
index 000000000..fdce59e54
--- /dev/null
+++ b/backend/src/main/java/fr/cgi/magneto/model/slides/SlideMedia.java
@@ -0,0 +1,66 @@
+package fr.cgi.magneto.model.slides;
+
+import fr.cgi.magneto.core.constants.Slideshow;
+import fr.cgi.magneto.helper.SlideHelper;
+import org.apache.poi.sl.usermodel.TextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+
+public class SlideMedia extends Slide {
+
+ public enum MediaType {
+ IMAGE,
+ AUDIO,
+ VIDEO
+ }
+
+ private byte[] resourceData;
+ private final String fileContentType;
+ private final String caption;
+ private final MediaType mediaType;
+
+ public SlideMedia(String title, String caption, byte[] resourceData,
+ String fileContentType) {
+ this.title = title;
+ this.caption = caption;
+ this.resourceData = resourceData;
+ this.fileContentType = fileContentType;
+ this.mediaType = determineMediaType(fileContentType);
+ }
+
+ private MediaType determineMediaType(String contentType) {
+ String type = contentType.toLowerCase();
+ MediaType mediaType;
+
+ if (type.startsWith(Slideshow.CONTENT_TYPE_AUDIO)) {
+ mediaType = MediaType.AUDIO;
+ } else if (type.startsWith(Slideshow.CONTENT_TYPE_VIDEO)) {
+ mediaType = MediaType.VIDEO;
+ } else {
+ mediaType = MediaType.IMAGE;
+ }
+ return mediaType;
+ }
+
+ @Override
+ public Object createApacheSlide(XSLFSlide newSlide) {
+
+ SlideHelper.createTitle(newSlide, title, Slideshow.TITLE_HEIGHT, Slideshow.TITLE_FONT_SIZE,
+ TextParagraph.TextAlign.LEFT);
+ switch (mediaType) {
+ case AUDIO:
+ SlideHelper.createMedia(newSlide, resourceData, fileContentType, SlideMedia.MediaType.AUDIO);
+ break;
+ case VIDEO:
+ SlideHelper.createMedia(newSlide, resourceData, fileContentType, SlideMedia.MediaType.VIDEO);
+ break;
+ default:
+ SlideHelper.createImage(newSlide, resourceData, fileContentType, Slideshow.CONTENT_MARGIN_TOP,
+ Slideshow.IMAGE_CONTENT_HEIGHT, false);
+ }
+ SlideHelper.createLegend(newSlide, caption);
+
+ SlideHelper.addNotes(newSlide, description);
+
+ return newSlide;
+ }
+}
\ No newline at end of file
diff --git a/backend/src/main/java/fr/cgi/magneto/model/slides/SlideText.java b/backend/src/main/java/fr/cgi/magneto/model/slides/SlideText.java
new file mode 100644
index 000000000..4469ca1d6
--- /dev/null
+++ b/backend/src/main/java/fr/cgi/magneto/model/slides/SlideText.java
@@ -0,0 +1,173 @@
+package fr.cgi.magneto.model.slides;
+
+import fr.cgi.magneto.core.constants.Slideshow;
+import fr.cgi.magneto.helper.SlideHelper;
+import org.apache.poi.sl.usermodel.AutoNumberingScheme;
+import org.apache.poi.sl.usermodel.TextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTextBox;
+import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFTextRun;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.nodes.Node;
+
+import java.awt.*;
+
+public class SlideText extends Slide {
+
+ public SlideText(String title, String description) {
+ this.title = title;
+ this.description = description;
+ }
+
+ @Override
+ public Object createApacheSlide(XSLFSlide newSlide) {
+
+ SlideHelper.createTitle(newSlide, title, Slideshow.TITLE_HEIGHT, Slideshow.TITLE_FONT_SIZE,
+ TextParagraph.TextAlign.LEFT);
+ XSLFTextBox contentBox = SlideHelper.createContent(newSlide);
+
+ Document doc = Jsoup.parse(description);
+ processHtmlContent(contentBox, doc.body());
+
+ return newSlide;
+ }
+
+ private static boolean isBodyEmptyOrContainsEmptyParagraph(Element body) {
+ // Vérifier si le body est vide
+ if (body.children().isEmpty()) {
+ return true;
+ }
+
+ // Vérifier si le body ne contient qu'une balise vide
+ if (body.children().size() == 1) {
+ Element child = body.child(0);
+ if (child.tagName().equals("p") && child.html().trim().isEmpty()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public static boolean isDescriptionEmptyOrContainsEmptyParagraph(String description) {
+ return isBodyEmptyOrContainsEmptyParagraph(Jsoup.parse(description).body());
+ }
+
+ private void processHtmlContent(XSLFTextBox textBox, Element element) {
+ if (textBox.getTextParagraphs().isEmpty()) {
+ textBox.addNewTextParagraph();
+ }
+
+ if (!isBodyEmptyOrContainsEmptyParagraph(element)) {
+ for (Node node : element.childNodes()) {
+ if (node instanceof Element) {
+ Element elem = (Element) node;
+ XSLFTextParagraph para = textBox.addNewTextParagraph();
+ XSLFTextRun run = para.addNewTextRun();
+
+ processStyle(elem, para, run);
+
+ String text = elem.text().trim();
+ if (!text.isEmpty()) {
+ run.setText(text);
+ }
+ }
+ }
+ }
+ }
+
+ private void processInlineStyles(XSLFTextRun run, String style) {
+ String[] styles = style.split(";");
+ for (String s : styles) {
+ String[] parts = s.split(":");
+ if (parts.length == 2) {
+ String property = parts[0].trim();
+ String value = parts[1].trim();
+
+ switch (property) {
+ case Slideshow.CSS_COLOR:
+ try {
+ run.setFontColor(Color.decode(value));
+ } catch (NumberFormatException ignored) {
+ }
+ break;
+ case Slideshow.CSS_FONT_SIZE:
+ try {
+ String size = value.replaceAll("[^0-9]", "");
+ run.setFontSize(Double.parseDouble(size));
+ } catch (NumberFormatException ignored) {
+ }
+ break;
+ case Slideshow.CSS_TEXT_DECORATION:
+ if (value.contains(Slideshow.VALUE_UNDERLINE)) {
+ run.setUnderlined(true);
+ }
+ break;
+ case Slideshow.CSS_FONT_WEIGHT:
+ if (value.equals(Slideshow.VALUE_BOLD) || value.equals(Slideshow.VALUE_BOLD_WEIGHT)) {
+ run.setBold(true);
+ }
+ break;
+ case Slideshow.CSS_FONT_STYLE:
+ if (value.equals(Slideshow.VALUE_ITALIC)) {
+ run.setItalic(true);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ private void processStyle(Element elem, XSLFTextParagraph para, XSLFTextRun run) {
+ switch (elem.tagName().toLowerCase()) {
+ case Slideshow.TAG_H1:
+ run.setFontSize(Slideshow.H1_FONT_SIZE);
+ run.setBold(true);
+ para.setIndentLevel(Slideshow.H1_INDENT_LEVEL);
+ break;
+ case Slideshow.TAG_H2:
+ run.setFontSize(Slideshow.H2_FONT_SIZE);
+ run.setBold(true);
+ para.setIndentLevel(Slideshow.H2_INDENT_LEVEL);
+ break;
+ case Slideshow.TAG_H3:
+ run.setFontSize(Slideshow.H3_FONT_SIZE);
+ run.setBold(true);
+ para.setIndentLevel(Slideshow.H3_INDENT_LEVEL);
+ break;
+ case Slideshow.TAG_BOLD:
+ case Slideshow.TAG_STRONG:
+ run.setBold(true);
+ break;
+ case Slideshow.TAG_ITALIC:
+ case Slideshow.TAG_EM:
+ run.setItalic(true);
+ break;
+ case Slideshow.TAG_UNDERLINE:
+ run.setUnderlined(true);
+ break;
+ case Slideshow.TAG_PARAGRAPH:
+ para.setSpaceBefore(Slideshow.PARAGRAPH_SPACE_BEFORE);
+ para.setSpaceAfter(Slideshow.PARAGRAPH_SPACE_AFTER);
+ break;
+ case Slideshow.TAG_UNORDERED_LIST:
+ para.setIndentLevel(Slideshow.LIST_INDENT_LEVEL);
+ para.setBullet(true);
+ break;
+ case Slideshow.TAG_ORDERED_LIST:
+ para.setIndentLevel(Slideshow.LIST_INDENT_LEVEL);
+ para.setBulletAutoNumber(AutoNumberingScheme.arabicPeriod, 1);
+ break;
+ case Slideshow.TAG_LIST_ITEM:
+ para.setIndentLevel(Slideshow.LIST_INDENT_LEVEL);
+ break;
+ }
+ String style = elem.attr(Slideshow.CSS_STYLE);
+ if (!style.isEmpty()) {
+ processInlineStyles(run, style);
+ }
+ }
+}
\ No newline at end of file
diff --git a/backend/src/main/java/fr/cgi/magneto/model/slides/SlideTitle.java b/backend/src/main/java/fr/cgi/magneto/model/slides/SlideTitle.java
new file mode 100644
index 000000000..d3bcc84e0
--- /dev/null
+++ b/backend/src/main/java/fr/cgi/magneto/model/slides/SlideTitle.java
@@ -0,0 +1,55 @@
+package fr.cgi.magneto.model.slides;
+
+import fr.cgi.magneto.core.constants.Slideshow;
+import fr.cgi.magneto.helper.SlideHelper;
+import org.apache.poi.sl.usermodel.TextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTextBox;
+import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFTextRun;
+
+public class SlideTitle extends Slide {
+ private final String title;
+ private final String description;
+ private final String ownerName;
+ private final String modificationDate;
+ private final byte[] resourceData;
+ private final String contentType;
+
+ public SlideTitle(String title, String description, String ownerName, String modificationDate, byte[] resourceData,
+ String contentType) {
+ this.title = title;
+ this.description = description;
+ this.ownerName = ownerName;
+ this.modificationDate = modificationDate;
+ this.resourceData = resourceData;
+ this.contentType = contentType;
+ }
+
+ @Override
+ public Object createApacheSlide(XSLFSlide newSlide) {
+ // TITRE
+ SlideHelper.createTitle(newSlide, title, Slideshow.MAIN_TITLE_HEIGHT,
+ Slideshow.MAIN_TITLE_FONT_SIZE, TextParagraph.TextAlign.CENTER);
+
+ XSLFTextBox textBox = SlideHelper.createContent(newSlide);
+
+ XSLFTextParagraph paragraph = textBox.addNewTextParagraph();
+ paragraph.setTextAlign(TextParagraph.TextAlign.CENTER);
+ XSLFTextRun textRun = paragraph.addNewTextRun();
+ textRun.setText(ownerName);
+ textRun.setFontSize(Slideshow.CONTENT_FONT_SIZE);
+
+ XSLFTextParagraph paragraph2 = textBox.addNewTextParagraph();
+ paragraph2.setTextAlign(TextParagraph.TextAlign.CENTER);
+ XSLFTextRun textRun2 = paragraph2.addNewTextRun();
+ textRun2.setText(modificationDate);
+ textRun2.setFontSize(Slideshow.CONTENT_FONT_SIZE);
+
+ SlideHelper.createImage(newSlide, resourceData, contentType,
+ Slideshow.MAIN_CONTENT_MARGIN_TOP, Slideshow.MAIN_IMAGE_CONTENT_HEIGHT, false);
+
+ return newSlide;
+
+ }
+}
\ No newline at end of file
diff --git a/backend/src/main/java/fr/cgi/magneto/service/CardService.java b/backend/src/main/java/fr/cgi/magneto/service/CardService.java
index 9272457b0..40bec09e6 100644
--- a/backend/src/main/java/fr/cgi/magneto/service/CardService.java
+++ b/backend/src/main/java/fr/cgi/magneto/service/CardService.java
@@ -146,6 +146,16 @@ void removeCardSectionWithLocked(CardPayload updateCard, String oldBoardId, Futu
*/
Future getAllCardsBySection(Section section, Integer page, UserInfos user);
+ /**
+ * Get all cards by section, without the count and returning the list directly
+ *
+ * @param section Section object
+ * @param page Page number
+ * @param user {@link UserInfos} User info
+ * @return Future {@link Future >} containing the cards corresponding to the board identifier
+ */
+ Future> getAllCardsBySectionSimple(Section section, Integer page, UserInfos user);
+
/**
* Duplicate cards
*
diff --git a/backend/src/main/java/fr/cgi/magneto/service/ExportService.java b/backend/src/main/java/fr/cgi/magneto/service/ExportService.java
new file mode 100644
index 000000000..06bc995fa
--- /dev/null
+++ b/backend/src/main/java/fr/cgi/magneto/service/ExportService.java
@@ -0,0 +1,18 @@
+package fr.cgi.magneto.service;
+
+import fr.cgi.magneto.helper.I18nHelper;
+import io.vertx.core.Future;
+import org.entcore.common.user.UserInfos;
+
+import java.io.ByteArrayOutputStream;
+
+public interface ExportService {
+
+ /**
+ * Export board to PPTX
+ *
+ * @param boardId Board identifier
+ * @return Future {@link Future} containing board id
+ */
+ Future exportBoardToArchive(String boardId, UserInfos user, I18nHelper i18nHelper);
+}
diff --git a/backend/src/main/java/fr/cgi/magneto/service/SectionService.java b/backend/src/main/java/fr/cgi/magneto/service/SectionService.java
index 4a9b036a8..9b241baf8 100644
--- a/backend/src/main/java/fr/cgi/magneto/service/SectionService.java
+++ b/backend/src/main/java/fr/cgi/magneto/service/SectionService.java
@@ -28,9 +28,10 @@ public interface SectionService {
*/
Future> getSectionsByBoardId(String boardId);
+ Future> createSectionWithCards(Board board, UserInfos user);
+
/**
- *
- * @param board board of the sections
+ * @param board board of the sections
* @param isReadOnly
* @return
*/
diff --git a/backend/src/main/java/fr/cgi/magneto/service/ServiceFactory.java b/backend/src/main/java/fr/cgi/magneto/service/ServiceFactory.java
index e6accc5cf..34f810f22 100644
--- a/backend/src/main/java/fr/cgi/magneto/service/ServiceFactory.java
+++ b/backend/src/main/java/fr/cgi/magneto/service/ServiceFactory.java
@@ -30,6 +30,7 @@ public class ServiceFactory {
private final FolderService folderService;
private final BoardService boardService;
private final CardService cardService;
+ private final ExportService exportService;
private final Map securedActions;
private final ShareNormalizer shareNormalizer;
@@ -46,6 +47,7 @@ public ServiceFactory(Vertx vertx, Storage storage, MagnetoConfig magnetoConfig,
this.folderService = new DefaultFolderService(CollectionsConstant.FOLDER_COLLECTION, mongoDb, this);
this.cardService = new DefaultCardService(CollectionsConstant.CARD_COLLECTION, mongoDb, this);
this.boardService = new DefaultBoardService(CollectionsConstant.BOARD_COLLECTION, mongoDb, this);
+ this.exportService = new DefaultExportService(this);
}
public MagnetoService magnetoServiceExample() {
@@ -79,6 +81,11 @@ public SectionService sectionService() {
public FolderService folderService() {
return this.folderService;
}
+
+ public ExportService exportService() {
+ return this.exportService;
+ }
+
public WorkspaceService workSpaceService() {
return new DefaultWorkspaceService(vertx, mongoDb);
}
diff --git a/backend/src/main/java/fr/cgi/magneto/service/impl/DefaultCardService.java b/backend/src/main/java/fr/cgi/magneto/service/impl/DefaultCardService.java
index 203a42e28..bc76cede3 100644
--- a/backend/src/main/java/fr/cgi/magneto/service/impl/DefaultCardService.java
+++ b/backend/src/main/java/fr/cgi/magneto/service/impl/DefaultCardService.java
@@ -811,6 +811,22 @@ public Future getAllCardsBySection(Section section, Integer page, Us
return promise.future();
}
+ @Override
+ public Future> getAllCardsBySectionSimple(Section section, Integer page, UserInfos user) {
+ Promise> promise = Promise.promise();
+
+ fetchAllCardsBySection(section, page, user)
+ .compose(this::setMetadataCards)
+ .onFailure(fail -> {
+ log.error("[Magneto@%s::getAllCardsBySectionSimple] Failed to get section cards", this.getClass().getSimpleName(),
+ fail.getMessage());
+ promise.fail(fail.getMessage());
+ })
+ .onSuccess(promise::complete);
+
+ return promise.future();
+ }
+
public Future> getAllCardsByCreationDate(StatisticsPayload statisticsPayload) {
Promise> promise = Promise.promise();
diff --git a/backend/src/main/java/fr/cgi/magneto/service/impl/DefaultExportService.java b/backend/src/main/java/fr/cgi/magneto/service/impl/DefaultExportService.java
new file mode 100644
index 000000000..1ff896873
--- /dev/null
+++ b/backend/src/main/java/fr/cgi/magneto/service/impl/DefaultExportService.java
@@ -0,0 +1,595 @@
+package fr.cgi.magneto.service.impl;
+
+import fr.cgi.magneto.core.constants.CollectionsConstant;
+import fr.cgi.magneto.core.constants.Field;
+import fr.cgi.magneto.core.constants.MagnetoPaths;
+import fr.cgi.magneto.core.constants.Slideshow;
+import fr.cgi.magneto.core.enums.SlideResourceType;
+import fr.cgi.magneto.factory.SlideFactory;
+import fr.cgi.magneto.helper.I18nHelper;
+import fr.cgi.magneto.helper.SlideHelper;
+import fr.cgi.magneto.model.Section;
+import fr.cgi.magneto.model.boards.Board;
+import fr.cgi.magneto.model.cards.Card;
+import fr.cgi.magneto.model.properties.SlideProperties;
+import fr.cgi.magneto.model.slides.Slide;
+import fr.cgi.magneto.service.ExportService;
+import fr.cgi.magneto.service.ServiceFactory;
+import io.vertx.core.CompositeFuture;
+import io.vertx.core.Future;
+import io.vertx.core.Promise;
+import io.vertx.core.buffer.Buffer;
+import io.vertx.core.buffer.impl.BufferImpl;
+import io.vertx.core.json.JsonArray;
+import io.vertx.core.json.JsonObject;
+import io.vertx.core.logging.Logger;
+import io.vertx.core.logging.LoggerFactory;
+import org.apache.commons.io.IOUtils;
+import org.apache.poi.sl.usermodel.TextParagraph;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.entcore.common.user.UserInfos;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import static fr.cgi.magneto.core.enums.FileFormatManager.loadResourceForExtension;
+import static fr.cgi.magneto.helper.SlideHelper.generateUniqueFileName;
+import static fr.cgi.magneto.model.slides.SlideText.isDescriptionEmptyOrContainsEmptyParagraph;
+
+public class DefaultExportService implements ExportService {
+
+ protected static final Logger log = LoggerFactory.getLogger(DefaultExportService.class);
+ private final ServiceFactory serviceFactory;
+
+ public DefaultExportService(ServiceFactory serviceFactory) {
+ this.serviceFactory = serviceFactory;
+ }
+
+ @Override
+ public Future exportBoardToArchive(String boardId, UserInfos user, I18nHelper i18nHelper) {
+ Promise promise = Promise.promise();
+
+ serviceFactory.boardService().getBoards(Collections.singletonList(boardId))
+ .compose(boards -> {
+ if (boards.isEmpty()) {
+ String message = String.format("[Magneto@%s::exportBoardToArchive] No board found with id %s",
+ this.getClass().getSimpleName(), boardId);
+ log.error(message, new Throwable(message));
+ return Future.failedFuture(message);
+ }
+ Board board = boards.get(0);
+ JsonObject slideShow = createSlideShowObject(board);
+
+ List