/** * Copyright © 2014 Instituto Superior Técnico * * This file is part of FenixEdu CMS. * * FenixEdu CMS is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * FenixEdu CMS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with FenixEdu CMS. If not, see <http://www.gnu.org/licenses/>. */ package org.fenixedu.cms.domain; import static java.nio.charset.Charset.defaultCharset; import static java.util.Optional.ofNullable; import static java.util.stream.Collectors.toList; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.apache.tika.io.FilenameUtils; import org.fenixedu.bennu.core.groups.Group; import org.fenixedu.bennu.io.domain.GroupBasedFile; import org.fenixedu.bennu.io.servlets.FileDownloadServlet; import org.fenixedu.cms.domain.component.Component; import org.fenixedu.commons.i18n.LocalizedString; import org.joda.time.DateTime; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; /** * Created by borgez-dsi on 24-06-2015. */ public class SiteExporter { private final Site site; public SiteExporter(Site site) { this.site = site; } public ByteArrayOutputStream export() { try { ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream(); ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(byteArrayStream)); addToZipFile("site.json", export(site), zipOutputStream); for (Page page : getSite().getPagesSet()) { addToZipFile("pages/" + page.getSlug() + ".json", export(page), zipOutputStream); } for (Post post : getSite().getPostSet()) { addToZipFile("posts/" + post.getSlug() + ".json", export(post), zipOutputStream); } for (Category category : getSite().getCategoriesSet()) { addToZipFile("categories/" + category.getSlug() + ".json", export(category), zipOutputStream); } for (Menu menu : getSite().getMenusSet()) { addToZipFile("menus/" + menu.getSlug() + ".json", export(menu), zipOutputStream); } for (GroupBasedFile file : getSite().getPostSet().stream() .flatMap(post -> post.getFilesSet().stream()).map(PostFile::getFiles).distinct().collect(toList())) { addToZipFile("files/" + file.getExternalId(), file.getStream(), zipOutputStream); } zipOutputStream.close(); return byteArrayStream; } catch (IOException e) { throw new RuntimeException("Error exporting site " + site.getSlug(), e); } } public static void addToZipFile(String filename, JsonObject jsonObject, ZipOutputStream zos) throws IOException { addToZipFile(filename, new ByteArrayInputStream(jsonObject.toString().getBytes(defaultCharset())), zos); } public static void addToZipFile(String filename, InputStream content, ZipOutputStream zos) throws IOException { ZipEntry zipEntry = new ZipEntry(FilenameUtils.normalize(filename)); zos.putNextEntry(zipEntry); byte[] bytes = new byte[1024]; int length; while ((length = content.read(bytes)) >= 0) { zos.write(bytes, 0, length); } zos.closeEntry(); content.close(); } protected JsonObject export(Site site) { JsonObject siteJson = new JsonObject(); siteJson.addProperty("slug", site.getSlug()); siteJson.add("name", site.getName().json()); siteJson.add("description", site.getDescription().json()); siteJson.add("canViewGroup", export(site.getCanViewGroup())); siteJson.addProperty("themeType", site.getThemeType()); siteJson.addProperty("embedded", site.getEmbedded()); siteJson.addProperty("analyticsCode", site.getAnalyticsCode()); siteJson.add("creationDate", toJson(site.getCreationDate())); siteJson.addProperty("createdBy", site.getCreatedBy().getUsername()); siteJson.addProperty("folder", ofNullable(site.getFolder()).map(CMSFolder::getExternalId).orElse(null)); siteJson.addProperty("published", site.getPublished()); siteJson.addProperty("initialPage", ofNullable(site.getInitialPage()).map(Page::getSlug).orElse(null)); siteJson.add("menus", toArray(site.getMenusSet().stream().map(Menu::getSlug))); siteJson.add("posts", toArray(site.getPostSet().stream().map(Post::getSlug))); siteJson.add("pages", toArray(site.getPagesSet().stream().map(Page::getSlug))); siteJson.add("categories", toArray(site.getCategoriesSet().stream().map(Category::getSlug))); return siteJson; } protected JsonObject export(Page page) { JsonObject pageJson = new JsonObject(); pageJson.addProperty("slug", page.getSlug()); pageJson.add("name", page.getName().json()); pageJson.addProperty("site", page.getSite().getSlug()); pageJson.add("canViewGroup", export(page.getCanViewGroup())); pageJson.addProperty("templateType", page.getTemplateType()); pageJson.addProperty("createdBy", page.getCreatedBy().getUsername()); pageJson.add("creationDate", toJson(page.getCreationDate())); pageJson.addProperty("published", page.getPublished()); pageJson.add("modificationDate", toJson(page.getModificationDate())); pageJson.addProperty("published", page.getPublished()); pageJson.add("menuItems", toArray(page.getMenuItemsSet().stream().map(MenuItem::getExternalId))); pageJson.add("components", toJsonArray(page.getComponentsSet().stream().map(this::export))); return pageJson; } protected JsonObject export(Menu menu) { JsonObject json = new JsonObject(); json.addProperty("slug", menu.getSlug()); json.addProperty("site", menu.getSite().getSlug()); json.add("creationDate", toJson(menu.getCreationDate())); json.addProperty("createdBy", menu.getCreatedBy().getUsername()); json.addProperty("order", menu.getOrder()); json.add("name", menu.getName().json()); json.add("topLevelItems", toJsonArray(menu.getToplevelItemsSet().stream().map(this::export))); return json; } protected JsonObject export(MenuItem menuItem) { JsonObject json = new JsonObject(); json.add("name", menuItem.getName().json()); json.addProperty("slug", menuItem.getExternalId()); json.addProperty("menu", ofNullable(menuItem.getMenu()).map(Menu::getSlug).orElse(null)); json.addProperty("top", ofNullable(menuItem.getTop()).map(Menu::getSlug).orElse(null)); json.addProperty("parent", ofNullable(menuItem.getParent()).map(MenuItem::getExternalId).orElse(null)); json.addProperty("position", ofNullable(menuItem.getPosition()).orElse(0)); json.addProperty("isFolder", menuItem.getFolder()); json.addProperty("page", ofNullable(menuItem.getPage()).map(Page::getSlug).orElse(null)); json.addProperty("createdBy", menuItem.getCreatedBy().getUsername()); json.add("creationDate", toJson(menuItem.getCreationDate())); json.add("children", toJsonArray(menuItem.getChildrenSet().stream().map(this::export))); return json; } protected JsonObject export(Post post) { JsonObject json = new JsonObject(); json.addProperty("slug", post.getSlug()); json.addProperty("site", post.getSite().getSlug()); json.add("name", post.getName().json()); json.add("body", post.getBody().json()); json.addProperty("createdBy", post.getCreatedBy().getUsername()); json.add("creationDate", toJson(post.getCreationDate())); json.add("canViewGroup", export(post.getCanViewGroup())); json.add("categories", toArray(post.getCategoriesSet().stream().map(Category::getSlug))); json.addProperty("active", post.getActive()); json.add("location", ofNullable(post.getLocation()).map(LocalizedString::json).orElse(JsonNull.INSTANCE)); json.add("metadata", ofNullable(post.getMetadata()).map(PostMetadata::json).orElse(JsonNull.INSTANCE)); json.add("modificationDate", toJson(post.getModificationDate())); json.add("publicationBegin", toJson(post.getPublicationBegin())); json.add("publicationEnd", toJson(post.getPublicationEnd())); json.add("files", toJsonArray(post.getFilesSet().stream().map(this::export))); return json; } protected JsonObject export(Category category) { JsonObject json = new JsonObject(); json.addProperty("slug", category.getSlug()); json.addProperty("site", category.getSite().getSlug()); json.add("creationDate", toJson(category.getCreationDate())); json.addProperty("createdBy", category.getCreatedBy().getUsername()); json.add("name", category.getName().json()); json.add("posts", toArray(category.getPostsSet().stream().map(Post::getSlug))); json.add("components", toJsonArray(category.getComponentsSet().stream().map(this::export))); return json; } protected JsonObject export(PostFile postFile) { JsonObject json = new JsonObject(); json.addProperty("slug", postFile.getExternalId()); json.addProperty("index", postFile.getIndex()); json.addProperty("isEmbedded", postFile.getIsEmbedded()); json.addProperty("post", postFile.getPost().getSlug()); json.add("viewGroup", export(postFile.getFiles().getAccessGroup())); json.addProperty("displayName", postFile.getFiles().getDisplayName()); json.addProperty("fileName", postFile.getFiles().getFilename()); json.addProperty("url", FileDownloadServlet.getDownloadUrl(postFile.getFiles())); json.addProperty("file", postFile.getFiles().getExternalId()); return json; } protected JsonObject export(Component component) { return component.json(); } private JsonElement export(Group group) { return group != null ? new JsonPrimitive(group.getExpression()) : JsonNull.INSTANCE; } private JsonElement toJson(DateTime date) { return date != null ? new JsonPrimitive(date.toDateTimeISO().toString()) : JsonNull.INSTANCE; } private JsonArray toArray(Stream<String> strStream) { return toJsonArray(strStream.map(JsonPrimitive::new)); } private JsonArray toJsonArray(Stream<JsonElement> jsonElementStream) { JsonArray jsonArray = new JsonArray(); jsonElementStream.forEach(jsonArray::add); return jsonArray; } public Site getSite() { return site; } }