Skip to content

Commit

Permalink
feat: Include inserted images in the note export/import - EXO-75694 - M…
Browse files Browse the repository at this point in the history
  • Loading branch information
sofyenne committed Dec 11, 2024
1 parent 4d667e5 commit cf2513b
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -508,7 +510,7 @@ public List<File> getFilesfromContent(NoteToExport note, List<File> files) throw
}

/**
* Process images by creting images found in the content
* Process images by creating images found in the content
*
* @param note
* @return content
Expand All @@ -535,6 +537,32 @@ public String processImagesForExport(Page note) throws WikiException, IOExceptio
break;
}
}

List<String> 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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,
Expand All @@ -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}
*/
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -1366,9 +1336,7 @@ public void importNotes(String zipLocation, Page parent, String conflict, Identi
* {@inheritDoc}
*/
@Override
public void importNotes(List<String> files, Page parent, String conflict, Identity userIdentity) throws WikiException,
IllegalAccessException,
IOException, Exception {
public void importNotes(List<String> files, Page parent, String conflict, Identity userIdentity) throws Exception {

Map<String, String> featuredImages = new HashMap<>();
String notesFilePath = "";
Expand Down Expand Up @@ -2041,39 +2009,23 @@ 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_;
}
if (conflict.equals("update")) {
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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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<String> fileIds = getContentImagesIds(pageVersion.getContent(),
pageVersion.getAttachmentObjectType(),
pageVersion.getParentPageId());
List<String> fileIds = Utils.getContentImagesIds(pageVersion.getContent(),
pageVersion.getAttachmentObjectType(),
pageVersion.getParentPageId());
List<String> existingFiles = attachmentService.getAttachmentFileIds(pageVersion.getAttachmentObjectType(),
pageVersion.getParentPageId());
List<String> removedFiles = existingFiles.stream().filter(item -> !fileIds.contains(item)).toList();
Expand All @@ -2498,19 +2470,7 @@ private void updateVersionContentImages(PageVersion pageVersion) throws WikiExce
pageVersion.getParentPageId(),
fileId));
}
private List<String> 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<String> 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);
}
Expand All @@ -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, String>());
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;
}

}
14 changes: 14 additions & 0 deletions notes-service/src/main/java/org/exoplatform/wiki/utils/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -794,4 +795,17 @@ public static void sendMentionInNoteNotification(Page note, Page originalNote, S
.execute(mentionNotificationCtx);
}

public static List<String> 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<String> existingFileIds = new ArrayList<>();
while (existingMatcher.find()) {
String fileId = existingMatcher.group(1);
existingFileIds.add(fileId);
}
return existingFileIds;
}

}
Loading

0 comments on commit cf2513b

Please sign in to comment.