diff --git a/notes-service/src/main/java/org/exoplatform/wiki/service/ExportThread.java b/notes-service/src/main/java/org/exoplatform/wiki/service/ExportThread.java index c7527a616f..b40602c180 100644 --- a/notes-service/src/main/java/org/exoplatform/wiki/service/ExportThread.java +++ b/notes-service/src/main/java/org/exoplatform/wiki/service/ExportThread.java @@ -51,6 +51,8 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; +import org.exoplatform.wiki.service.plugin.WikiPageAttachmentPlugin; +import org.exoplatform.wiki.utils.Utils; import org.springframework.util.MimeTypeUtils; import com.fasterxml.jackson.databind.ObjectMapper; @@ -508,7 +510,7 @@ public List getFilesfromContent(NoteToExport note, List files) throw } /** - * Process images by creting images found in the content + * Process images by creating images found in the content * * @param note * @return content @@ -535,6 +537,32 @@ public String processImagesForExport(Page note) throws WikiException, IOExceptio break; } } + + List contentImageIds = Utils.getContentImagesIds(content, note.getAttachmentObjectType(), note.getId()); + if (!contentImageIds.isEmpty()) { + String noteAttachmentRestUrl = new StringBuilder("/portal/rest/v1/social/attachments/") + .append(note.getAttachmentObjectType()) + .append("/") + .append(note.getId()) + .append("/") + .toString(); + contentImageIds.forEach((fileId) -> { + try { + FileItem imageFile = fileService.getFile(Long.parseLong(fileId)); + if (imageFile != null && imageFile.getFileInfo() != null) { + FileInfo fileInfo = imageFile.getFileInfo(); + String extension = "." + MimeTypeUtils.parseMimeType(fileInfo.getMimetype()).getSubtype(); + String filePath = System.getProperty(TEMP_DIRECTORY_PATH) + File.separator + fileId + extension; + File file = new File(filePath); + FileUtils.copyInputStreamToFile(imageFile.getAsStream(), file); + urlToReplaces.put(noteAttachmentRestUrl.concat(fileId), IMAGE_URL_REPLACEMENT_PREFIX.concat(file.getName()).concat(IMAGE_URL_REPLACEMENT_SUFFIX)); + } + } catch (Exception exception) { + log.error("Error when processing note content image", exception); + } + }); + } + if (!urlToReplaces.isEmpty()) { content = replaceUrl(note.getContent(), urlToReplaces); } diff --git a/notes-service/src/main/java/org/exoplatform/wiki/service/impl/NoteServiceImpl.java b/notes-service/src/main/java/org/exoplatform/wiki/service/impl/NoteServiceImpl.java index 09fcc9ab84..14ec431562 100644 --- a/notes-service/src/main/java/org/exoplatform/wiki/service/impl/NoteServiceImpl.java +++ b/notes-service/src/main/java/org/exoplatform/wiki/service/impl/NoteServiceImpl.java @@ -43,7 +43,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; import org.exoplatform.social.attachment.AttachmentService; @@ -129,6 +128,13 @@ public class NoteServiceImpl implements NoteService { private static final String FILE_NAME_SPACE = "wiki"; + private static final String IMAGE_URL_REPLACEMENT_PREFIX = "//-"; + + private static final String IMAGE_URL_REPLACEMENT_SUFFIX = "-//"; + + private static final Pattern IMAGES_IMPORT_PATTERN = + Pattern.compile("src=\"//-(.*?)-//\""); + private static final Log log = ExoLogger.getLogger(NoteServiceImpl.class); @@ -190,8 +196,6 @@ public class NoteServiceImpl implements NoteService { private final AttachmentService attachmentService; - private final HTMLUploadImageProcessor htmlUploadImageProcessor; - public NoteServiceImpl(DataStorage dataStorage, CacheService cacheService, WikiService wikiService, @@ -217,38 +221,7 @@ public NoteServiceImpl(DataStorage dataStorage, this.metadataService = metadataService; this.imageThumbnailService = imageThumbnailService; this.attachmentService = attachmentService; - this.htmlUploadImageProcessor = null; } - - public NoteServiceImpl(DataStorage dataStorage, - CacheService cacheService, - WikiService wikiService, - IdentityManager identityManager, - SpaceService spaceService, - CMSService cmsService, - ListenerService listenerService, - FileService fileService, - UploadService uploadService, - MetadataService metadataService, - ImageThumbnailService imageThumbnailService, - AttachmentService attachmentService, - HTMLUploadImageProcessor htmlUploadImageProcessor) { - this.dataStorage = dataStorage; - this.wikiService = wikiService; - this.identityManager = identityManager; - this.renderingCache = cacheService.getCacheInstance(CACHE_NAME); - this.attachmentCountCache = cacheService.getCacheInstance(ATT_CACHE_NAME); - this.spaceService = spaceService; - this.listenerService = listenerService; - this.cmsService = cmsService; - this.fileService = fileService; - this.uploadService = uploadService; - this.metadataService = metadataService; - this.imageThumbnailService = imageThumbnailService; - this.attachmentService = attachmentService; - this.htmlUploadImageProcessor = htmlUploadImageProcessor; - } - /** * {@inheritDoc} */ @@ -367,10 +340,7 @@ public Page updateNote(Page note) throws WikiException { * {@inheritDoc} */ @Override - public Page updateNote(Page note, PageUpdateType type, Identity userIdentity) throws WikiException, - IllegalAccessException, - EntityNotFoundException, - Exception { + public Page updateNote(Page note, PageUpdateType type, Identity userIdentity) throws Exception { Page existingNote = getNoteById(note.getId()); if (existingNote == null) { throw new EntityNotFoundException("Note to update not found"); @@ -1366,9 +1336,7 @@ public void importNotes(String zipLocation, Page parent, String conflict, Identi * {@inheritDoc} */ @Override - public void importNotes(List files, Page parent, String conflict, Identity userIdentity) throws WikiException, - IllegalAccessException, - IOException, Exception { + public void importNotes(List files, Page parent, String conflict, Identity userIdentity) throws Exception { Map featuredImages = new HashMap<>(); String notesFilePath = ""; @@ -2041,28 +2009,16 @@ private void importNote(Page note, note.setId(null); Page note_2 = getNoteOfNoteBookByName(wiki.getType(), wiki.getOwner(), note.getName()); if (note_2 == null) { - String processedContent = htmlUploadImageProcessor.processSpaceImages(note.getContent(), - wiki.getOwner(), - imagesSubLocationPath); - note.setContent(processedContent); note_ = createNote(wiki, parent_.getName(), note, userIdentity, false); targetNote = note_; } else { if (StringUtils.isNotEmpty(conflict)) { if (conflict.equals("overwrite") || conflict.equals("replaceAll")) { deleteNote(wiki.getType(), wiki.getOwner(), note.getName()); - String processedContent = htmlUploadImageProcessor.processSpaceImages(note.getContent(), - wiki.getOwner(), - imagesSubLocationPath); - note.setContent(processedContent); note_ = createNote(wiki, parent_.getName(), note, userIdentity, false); targetNote = note_; } if (conflict.equals("duplicate")) { - String processedContent = htmlUploadImageProcessor.processSpaceImages(note.getContent(), - wiki.getOwner(), - imagesSubLocationPath); - note.setContent(processedContent); note_ = createNote(wiki, parent_.getName(), note, userIdentity); targetNote = note_; } @@ -2070,10 +2026,6 @@ private void importNote(Page note, if (!note_2.getTitle().equals(note.getTitle()) || !note_2.getContent().equals(note.getContent()) || !Objects.equals(note_2.getProperties(), note.getProperties())) { note_2.setTitle(note.getTitle()); - String processedContent = htmlUploadImageProcessor.processSpaceImages(note.getContent(), - wiki.getOwner(), - imagesSubLocationPath); - note_2.setContent(processedContent); note_2 = updateNote(note_2, PageUpdateType.EDIT_PAGE_CONTENT, userIdentity); createVersionOfNote(note_2, userIdentity.getUserId()); targetNote = note_2; @@ -2086,11 +2038,7 @@ private void importNote(Page note, && (conflict.equals("update") || conflict.equals("overwrite") || conflict.equals("replaceAll"))) { Page note_1 = getNoteOfNoteBookByName(wiki.getType(), wiki.getOwner(), note.getName()); if (!note.getContent().equals(note_1.getContent()) || !Objects.equals(note_1.getProperties(), note.getProperties())) { - String processedContent = htmlUploadImageProcessor.processSpaceImages(note.getContent(), - wiki.getOwner(), - imagesSubLocationPath); - note.setContent(processedContent); - note_1.setContent(processedContent); + note_1.setContent(note.getContent()); note_1 = updateNote(note_1, PageUpdateType.EDIT_PAGE_CONTENT, userIdentity); createVersionOfNote(note_1, userIdentity.getUserId()); targetNote = note_1; @@ -2426,11 +2374,24 @@ private String processImagesOnDraftUpdate(DraftPage draftPage, long userIdentity } private Page processImagesOnNoteCreation(Page note, String draftId, long userIdentityId) throws WikiException { - String sourceObjectType = WikiDraftPageAttachmentPlugin.OBJECT_TYPE; - attachmentService.moveAttachments(sourceObjectType, draftId, note.getAttachmentObjectType(), note.getId(), null, userIdentityId); - String newContent = note.getContent() - .replaceAll("/attachments/" + sourceObjectType + "/" + draftId, - "/attachments/" + note.getAttachmentObjectType() + "/" + note.getId()); + String newContent = note.getContent(); + if (StringUtils.isNotEmpty(draftId) && !draftId.equals("null")) { + String sourceObjectType = WikiDraftPageAttachmentPlugin.OBJECT_TYPE; + attachmentService.moveAttachments(sourceObjectType, + draftId, + note.getAttachmentObjectType(), + note.getId(), + null, + userIdentityId); + newContent = note.getContent() + .replaceAll("/attachments/" + sourceObjectType + "/" + draftId, + "/attachments/" + note.getAttachmentObjectType() + "/" + note.getId()); + } + + if (IMAGES_IMPORT_PATTERN.matcher(newContent).find()) { + // process imported images + newContent = processImportedNoteImages(note, userIdentityId); + } if (!newContent.equals(note.getContent())) { return updateNoteContent(note, newContent); } @@ -2470,17 +2431,28 @@ private String saveUploadedContentImages(String content, String objectType, Stri } private String updateNoteContentImages(Page note) { + String processedContent = note.getContent(); if (note.getContent().contains("cke_upload_id=")) { - long userIdentityId = Long.parseLong(identityManager.getOrCreateUserIdentity(Utils.getCurrentUser()).getId()); - return saveUploadedContentImages(note.getContent(), note.getAttachmentObjectType(), note.getId(), userIdentityId); + processedContent = saveUploadedContentImages(note.getContent(), + note.getAttachmentObjectType(), + note.getId(), + Long.parseLong(identityManager.getOrCreateUserIdentity(Utils.getCurrentUser()) + .getId())); + } + + if (IMAGES_IMPORT_PATTERN.matcher(processedContent).find()) { + // process imported images + processedContent = processImportedNoteImages(note, + Long.parseLong(identityManager.getOrCreateUserIdentity(Utils.getCurrentUser()) + .getId())); } - return note.getContent(); + return processedContent; } private void updateVersionContentImages(PageVersion pageVersion) throws WikiException { - List fileIds = getContentImagesIds(pageVersion.getContent(), - pageVersion.getAttachmentObjectType(), - pageVersion.getParentPageId()); + List fileIds = Utils.getContentImagesIds(pageVersion.getContent(), + pageVersion.getAttachmentObjectType(), + pageVersion.getParentPageId()); List existingFiles = attachmentService.getAttachmentFileIds(pageVersion.getAttachmentObjectType(), pageVersion.getParentPageId()); List removedFiles = existingFiles.stream().filter(item -> !fileIds.contains(item)).toList(); @@ -2498,19 +2470,7 @@ private void updateVersionContentImages(PageVersion pageVersion) throws WikiExce pageVersion.getParentPageId(), fileId)); } - private List getContentImagesIds(String content, String objectType, String objectId) { - String existingIdRegex = String.format("src=\"/portal/rest/v1/social/attachments/%s/%s/([^\"]+)\"", objectType, objectId); - Pattern existingPattern = Pattern.compile(existingIdRegex); - Matcher existingMatcher = existingPattern.matcher(content); - - List existingFileIds = new ArrayList<>(); - while (existingMatcher.find()) { - String fileId = existingMatcher.group(1); - existingFileIds.add(fileId); - } - return existingFileIds; - } - + private DraftPage updateDraftPageContent(long draftId, String content) throws WikiException { return dataStorage.updateDraftContent(draftId, content); } @@ -2519,4 +2479,46 @@ private Page updateNoteContent(Page note, String content) throws WikiException { return dataStorage.updatePageContent(note, content); } + private String processImportedNoteImages(Page note, long userIdentityId) { + String processedContent = note.getContent(); + Matcher matcher = IMAGES_IMPORT_PATTERN.matcher(processedContent); + while (matcher.find()) { + String fileName = processedContent.split("src=\"//-")[1].split("-//")[0]; + File file = new File(System.getProperty(TEMP_DIRECTORY_PATH) + File.separator + fileName); + try (InputStream inputStream = new FileInputStream(file)) { + String mimeType = Files.probeContentType(file.toPath()); + FileItem fileItem = new FileItem(0L, + fileName, + mimeType, + "attachment", + inputStream.available(), + new Date(), + null, + false, + inputStream); + fileItem = fileService.writeFile(fileItem); + if (fileItem.getFileInfo().getId() != null) { + attachmentService.createAttachment(String.valueOf(fileItem.getFileInfo().getId()), + note.getAttachmentObjectType(), + note.getId(), + null, + userIdentityId, + new HashMap()); + String urlToReplace = IMAGE_URL_REPLACEMENT_PREFIX + fileName + IMAGE_URL_REPLACEMENT_SUFFIX; + String newImageUrl = new StringBuilder("/portal/rest/v1/social/attachments/").append(note.getAttachmentObjectType()) + .append("/") + .append(note.getId()) + .append("/") + .append(fileItem.getFileInfo().getId()) + .toString(); + processedContent = processedContent.replace(urlToReplace, newImageUrl); + + } + } catch (Exception exception) { + log.error("Error while processing note images"); + } + } + return processedContent; + } + } diff --git a/notes-service/src/main/java/org/exoplatform/wiki/utils/Utils.java b/notes-service/src/main/java/org/exoplatform/wiki/utils/Utils.java index 956a0b71d3..a101fb5f0e 100644 --- a/notes-service/src/main/java/org/exoplatform/wiki/utils/Utils.java +++ b/notes-service/src/main/java/org/exoplatform/wiki/utils/Utils.java @@ -40,6 +40,7 @@ import java.util.Objects; import java.util.ResourceBundle; import java.util.Set; +import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.zip.ZipEntry; @@ -794,4 +795,17 @@ public static void sendMentionInNoteNotification(Page note, Page originalNote, S .execute(mentionNotificationCtx); } + public static List getContentImagesIds(String content, String objectType, String objectId) { + String existingIdRegex = String.format("src=\"/portal/rest/v1/social/attachments/%s/%s/([^\"]+)\"", objectType, objectId); + Pattern existingPattern = Pattern.compile(existingIdRegex); + Matcher existingMatcher = existingPattern.matcher(content); + + List existingFileIds = new ArrayList<>(); + while (existingMatcher.find()) { + String fileId = existingMatcher.group(1); + existingFileIds.add(fileId); + } + return existingFileIds; + } + } diff --git a/notes-service/src/test/java/org/exoplatform/wiki/service/TestNoteService.java b/notes-service/src/test/java/org/exoplatform/wiki/service/TestNoteService.java index 7414429a7b..58068805ca 100644 --- a/notes-service/src/test/java/org/exoplatform/wiki/service/TestNoteService.java +++ b/notes-service/src/test/java/org/exoplatform/wiki/service/TestNoteService.java @@ -510,6 +510,7 @@ public void testGetNoteOfNoteBookByName() throws WikiException, IllegalAccessExc public void testExportNotes() throws Exception { Identity root = new Identity("root"); + startSessionAs("root"); Wiki portalWiki = getOrCreateWiki(wService, PortalConfig.PORTAL_TYPE, "exportPortal"); Page page1 = new Page("exported1", "exported1"); page1.setContent("
"); @@ -523,9 +524,14 @@ public void testExportNotes() throws Exception { page3.setContent("Home"); Page note3 = noteService.createNote(portalWiki, "Home", page3, root); + bindMockedUploadService(); + note3.setContent(note3.getContent().concat("")); + noteService.updateNote(note3); + assertNotNull(noteService.getNoteOfNoteBookByName(PortalConfig.PORTAL_TYPE, "exportPortal", note1.getName())); assertNotNull(noteService.getNoteOfNoteBookByName(PortalConfig.PORTAL_TYPE, "exportPortal", note2.getName())); assertNotNull(noteService.getNoteOfNoteBookByName(PortalConfig.PORTAL_TYPE, "exportPortal", note3.getName())); + assertTrue(note3.getContent().contains("src=\"/portal/rest/v1/social/attachments/wikiPage/")); String[] notes = new String[3]; notes[0] = note1.getId(); @@ -1073,4 +1079,46 @@ public void testProcessingNoteContentImages() throws Exception { assertTrue(draftForExistingPage.getContent().contains(imageSrcTagSuffix.concat(WikiPageAttachmentPlugin.OBJECT_TYPE).concat("/".concat(note.getId())))); } + public void testProcessingNoteImportedContentImages() throws Exception { + + String fileName = "pexels-nout-gons-80280-378570(1).png"; + File file = new File(System.getProperty("java.io.tmpdir") + File.separator + fileName); + file.createNewFile(); + this.bindMockedUploadService(); + String imageSrcTagSuffix = "src=\"/portal/rest/v1/social/attachments/"; + // + Page note = new Page(); + note.setTitle("imported note title"); + note.setContent("content include imported image matcher "); + Identity root = new Identity("root"); + startSessionAs("root"); + Wiki portalWiki = getOrCreateWiki(wService, PortalConfig.PORTAL_TYPE, "classic"); + note = noteService.createNote(portalWiki, "Home",note ,root); + // + assertNotNull(note); + assertNotNull(note.getId()); + assertTrue(note.getContent().contains(imageSrcTagSuffix.concat(WikiPageAttachmentPlugin.OBJECT_TYPE).concat("/").concat(note.getId()))); + file.delete(); + + String file1Name = "importedImage.png"; + File file1 = new File(System.getProperty("java.io.tmpdir") + File.separator + file1Name); + file1.createNewFile(); + // + + note.setContent(note.getContent().concat("")); + note = noteService.updateNote(note); + // + assertNotNull(note); + assertNotNull(note.getId()); + assertTrue(note.getContent().contains(imageSrcTagSuffix.concat(WikiPageAttachmentPlugin.OBJECT_TYPE).concat("/").concat(note.getId()))); + + String content = note.getContent(); + // remove the first image src url + content = content.substring(content.indexOf(imageSrcTagSuffix.concat(WikiPageAttachmentPlugin.OBJECT_TYPE).concat("/").concat(note.getId()))); + // assert that the note content contains the second image src url + assertTrue(content.contains(imageSrcTagSuffix.concat(WikiPageAttachmentPlugin.OBJECT_TYPE).concat("/").concat(note.getId()))); + + file1.delete(); + } + }