From c37f36f61edfad131008a9c6520387e32b32aa74 Mon Sep 17 00:00:00 2001 From: ruibaby Date: Thu, 26 Dec 2019 20:17:03 +0800 Subject: [PATCH] feat: support deploy static page in netlify. --- src/main/java/run/halo/app/Application.java | 1 + .../admin/api/StaticPageController.java | 57 +++++++++++++++++-- .../migrate/CnBlogsMigrateHandler.java | 4 ++ .../app/handler/migrate/MigrateHandlers.java | 4 +- .../NetlifyStaticDeployHandler.java | 36 +++++++++++- .../staticdeploy/StaticDeployHandlers.java | 7 ++- .../run/halo/app/model/enums/MigrateType.java | 2 +- .../app/model/enums/StaticDeployType.java | 4 +- .../run/halo/app/model/support/HaloConst.java | 5 ++ .../halo/app/model/support/StaticFile.java | 2 + .../app/model/support/StaticPageFile.java | 2 + .../halo/app/service/StaticPageService.java | 17 ++++++ .../service/impl/StaticPageServiceImpl.java | 56 +++++++++++++++++- .../impl/StaticStorageServiceImpl.java | 2 + 14 files changed, 185 insertions(+), 14 deletions(-) diff --git a/src/main/java/run/halo/app/Application.java b/src/main/java/run/halo/app/Application.java index 037fe8ff9..efb1f5a1d 100755 --- a/src/main/java/run/halo/app/Application.java +++ b/src/main/java/run/halo/app/Application.java @@ -35,6 +35,7 @@ public class Application extends SpringBootServletInitializer { // Run application context = SpringApplication.run(Application.class, args); + } /** diff --git a/src/main/java/run/halo/app/controller/admin/api/StaticPageController.java b/src/main/java/run/halo/app/controller/admin/api/StaticPageController.java index 0e2b6b985..2a0b95a6f 100644 --- a/src/main/java/run/halo/app/controller/admin/api/StaticPageController.java +++ b/src/main/java/run/halo/app/controller/admin/api/StaticPageController.java @@ -1,26 +1,55 @@ package run.halo.app.controller.admin.api; +import cn.hutool.core.io.FileUtil; import io.swagger.annotations.ApiOperation; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; +import run.halo.app.model.properties.NetlifyStaticDeployProperties; import run.halo.app.model.support.StaticPageFile; +import run.halo.app.service.OptionService; import run.halo.app.service.StaticPageService; +import java.io.FileNotFoundException; +import java.nio.file.Path; +import java.util.Collections; import java.util.List; /** - * @author ryan0up - * @date 2019/12/25 + * Static page controller. + * + * @author ryanwang + * @date 2019-12-25 */ @RestController @RequestMapping("/api/admin/static_page") public class StaticPageController { + private final static String DEPLOY_API = "https://api.netlify.com/api/v1/sites/%s/deploys"; + + private final OptionService optionService; + + private final RestTemplate httpsRestTemplate; + private final StaticPageService staticPageService; - public StaticPageController(StaticPageService staticPageService) { + public StaticPageController(StaticPageService staticPageService, + OptionService optionService, + RestTemplate httpsRestTemplate) { this.staticPageService = staticPageService; + this.optionService = optionService; + this.httpsRestTemplate = httpsRestTemplate; + + MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(); + mappingJackson2HttpMessageConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL)); + this.httpsRestTemplate.getMessageConverters().add(mappingJackson2HttpMessageConverter); } @GetMapping @@ -35,9 +64,29 @@ public class StaticPageController { staticPageService.generate(); } - @GetMapping("deploy") + @PostMapping("deploy") @ApiOperation("Deploy static page to remove platform") public void deploy() { staticPageService.deploy(); } + + @GetMapping("netlify") + public void testNetlify() throws FileNotFoundException { + String domain = optionService.getByPropertyOfNonNull(NetlifyStaticDeployProperties.NETLIFY_DOMAIN).toString(); + String siteId = optionService.getByPropertyOfNonNull(NetlifyStaticDeployProperties.NETLIFY_SITE_ID).toString(); + String token = optionService.getByPropertyOfNonNull(NetlifyStaticDeployProperties.NETLIFY_TOKEN).toString(); + + HttpHeaders headers = new HttpHeaders(); + + headers.set("Content-Type", "application/zip"); + headers.set(HttpHeaders.AUTHORIZATION, "Bearer " + token); + + Path path = staticPageService.zipStaticPagesDirectory(); + + byte[] bytes = FileUtil.readBytes(path.toFile()); + + HttpEntity httpEntity = new HttpEntity<>(bytes, headers); + + ResponseEntity responseEntity = httpsRestTemplate.postForEntity(String.format(DEPLOY_API, siteId), httpEntity, Object.class); + } } diff --git a/src/main/java/run/halo/app/handler/migrate/CnBlogsMigrateHandler.java b/src/main/java/run/halo/app/handler/migrate/CnBlogsMigrateHandler.java index bdd512d6d..55f4f6930 100644 --- a/src/main/java/run/halo/app/handler/migrate/CnBlogsMigrateHandler.java +++ b/src/main/java/run/halo/app/handler/migrate/CnBlogsMigrateHandler.java @@ -1,5 +1,7 @@ package run.halo.app.handler.migrate; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; import run.halo.app.model.enums.MigrateType; @@ -9,6 +11,8 @@ import run.halo.app.model.enums.MigrateType; * @author ryanwang * @date 2019-10-30 */ +@Slf4j +@Component public class CnBlogsMigrateHandler implements MigrateHandler { @Override diff --git a/src/main/java/run/halo/app/handler/migrate/MigrateHandlers.java b/src/main/java/run/halo/app/handler/migrate/MigrateHandlers.java index e7ac60f11..325c8fe92 100644 --- a/src/main/java/run/halo/app/handler/migrate/MigrateHandlers.java +++ b/src/main/java/run/halo/app/handler/migrate/MigrateHandlers.java @@ -31,7 +31,7 @@ public class MigrateHandlers { public MigrateHandlers(ApplicationContext applicationContext) { // Add all migrate handler - addFileHandlers(applicationContext.getBeansOfType(MigrateHandler.class).values()); + addMigrateHandlers(applicationContext.getBeansOfType(MigrateHandler.class).values()); } @NonNull @@ -56,7 +56,7 @@ public class MigrateHandlers { * @return current migrate handlers */ @NonNull - private MigrateHandlers addFileHandlers(@Nullable Collection migrateHandlers) { + private MigrateHandlers addMigrateHandlers(@Nullable Collection migrateHandlers) { if (!CollectionUtils.isEmpty(migrateHandlers)) { this.migrateHandlers.addAll(migrateHandlers); } diff --git a/src/main/java/run/halo/app/handler/staticdeploy/NetlifyStaticDeployHandler.java b/src/main/java/run/halo/app/handler/staticdeploy/NetlifyStaticDeployHandler.java index f493bc486..dddad86e1 100644 --- a/src/main/java/run/halo/app/handler/staticdeploy/NetlifyStaticDeployHandler.java +++ b/src/main/java/run/halo/app/handler/staticdeploy/NetlifyStaticDeployHandler.java @@ -1,9 +1,18 @@ package run.halo.app.handler.staticdeploy; +import cn.hutool.core.io.FileUtil; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; import run.halo.app.model.enums.StaticDeployType; +import run.halo.app.model.properties.NetlifyStaticDeployProperties; import run.halo.app.service.OptionService; +import run.halo.app.service.StaticPageService; + +import java.nio.file.Path; /** * Netlify deploy handler. @@ -15,15 +24,40 @@ import run.halo.app.service.OptionService; @Component public class NetlifyStaticDeployHandler implements StaticDeployHandler { + private final static String DEPLOY_API = "https://api.netlify.com/api/v1/sites/%s/deploys"; + private final OptionService optionService; - public NetlifyStaticDeployHandler(OptionService optionService) { + private final RestTemplate httpsRestTemplate; + + private final StaticPageService staticPageService; + + public NetlifyStaticDeployHandler(OptionService optionService, + RestTemplate httpsRestTemplate, + StaticPageService staticPageService) { this.optionService = optionService; + this.httpsRestTemplate = httpsRestTemplate; + this.staticPageService = staticPageService; } @Override public void deploy() { + String domain = optionService.getByPropertyOfNonNull(NetlifyStaticDeployProperties.NETLIFY_DOMAIN).toString(); + String siteId = optionService.getByPropertyOfNonNull(NetlifyStaticDeployProperties.NETLIFY_SITE_ID).toString(); + String token = optionService.getByPropertyOfNonNull(NetlifyStaticDeployProperties.NETLIFY_TOKEN).toString(); + HttpHeaders headers = new HttpHeaders(); + + headers.set("Content-Type", "application/zip"); + headers.set(HttpHeaders.AUTHORIZATION, "Bearer " + token); + + Path path = staticPageService.zipStaticPagesDirectory(); + + byte[] bytes = FileUtil.readBytes(path.toFile()); + + HttpEntity httpEntity = new HttpEntity<>(bytes, headers); + + ResponseEntity responseEntity = httpsRestTemplate.postForEntity(String.format(DEPLOY_API, siteId), httpEntity, Object.class); } @Override diff --git a/src/main/java/run/halo/app/handler/staticdeploy/StaticDeployHandlers.java b/src/main/java/run/halo/app/handler/staticdeploy/StaticDeployHandlers.java index 22ece8fa2..4a8b8138f 100644 --- a/src/main/java/run/halo/app/handler/staticdeploy/StaticDeployHandlers.java +++ b/src/main/java/run/halo/app/handler/staticdeploy/StaticDeployHandlers.java @@ -26,8 +26,8 @@ public class StaticDeployHandlers { private final Collection staticDeployHandlers = new LinkedList<>(); public StaticDeployHandlers(ApplicationContext applicationContext) { - // Add all file handler - addFileHandlers(applicationContext.getBeansOfType(StaticDeployHandler.class).values()); + // Add all static deploy handler + addStaticDeployHandlers(applicationContext.getBeansOfType(StaticDeployHandler.class).values()); } @@ -42,6 +42,7 @@ public class StaticDeployHandlers { for (StaticDeployHandler staticDeployHandler : staticDeployHandlers) { if (staticDeployHandler.supportType(staticDeployType)) { staticDeployHandler.deploy(); + return; } } @@ -55,7 +56,7 @@ public class StaticDeployHandlers { * @return current file handlers */ @NonNull - public StaticDeployHandlers addFileHandlers(@Nullable Collection staticDeployHandlers) { + public StaticDeployHandlers addStaticDeployHandlers(@Nullable Collection staticDeployHandlers) { if (!CollectionUtils.isEmpty(staticDeployHandlers)) { this.staticDeployHandlers.addAll(staticDeployHandlers); } diff --git a/src/main/java/run/halo/app/model/enums/MigrateType.java b/src/main/java/run/halo/app/model/enums/MigrateType.java index 975e55c51..74a952cc8 100644 --- a/src/main/java/run/halo/app/model/enums/MigrateType.java +++ b/src/main/java/run/halo/app/model/enums/MigrateType.java @@ -4,7 +4,7 @@ package run.halo.app.model.enums; * Migrate type. * * @author ryanwang - * @date : 2019-03-12 + * @date 2019-03-12 */ public enum MigrateType implements ValueEnum { diff --git a/src/main/java/run/halo/app/model/enums/StaticDeployType.java b/src/main/java/run/halo/app/model/enums/StaticDeployType.java index 79de7687b..4dcd9a50d 100644 --- a/src/main/java/run/halo/app/model/enums/StaticDeployType.java +++ b/src/main/java/run/halo/app/model/enums/StaticDeployType.java @@ -11,12 +11,12 @@ public enum StaticDeployType implements ValueEnum { /** * Deploy static pages in remote git repository, such as github pages,gitee pages,coding pages.etc. */ - GIT(1), + GIT(0), /** * Deploy static pages in netlify. */ - NETLIFY(2); + NETLIFY(1); private Integer value; diff --git a/src/main/java/run/halo/app/model/support/HaloConst.java b/src/main/java/run/halo/app/model/support/HaloConst.java index 18bd89d58..b728af898 100644 --- a/src/main/java/run/halo/app/model/support/HaloConst.java +++ b/src/main/java/run/halo/app/model/support/HaloConst.java @@ -30,6 +30,11 @@ public class HaloConst { */ public final static String HALO_BACKUP_PREFIX = "halo-backup-"; + /** + * Static pages pack prefix. + */ + public final static String STATIC_PAGE_PACK_PREFIX = "static-pages-"; + /** * Default theme name. */ diff --git a/src/main/java/run/halo/app/model/support/StaticFile.java b/src/main/java/run/halo/app/model/support/StaticFile.java index e1de4146a..c7f05e693 100644 --- a/src/main/java/run/halo/app/model/support/StaticFile.java +++ b/src/main/java/run/halo/app/model/support/StaticFile.java @@ -16,6 +16,8 @@ import java.util.List; @ToString public class StaticFile implements Comparator { + private String id; + private String name; private String path; diff --git a/src/main/java/run/halo/app/model/support/StaticPageFile.java b/src/main/java/run/halo/app/model/support/StaticPageFile.java index 240db30b6..f92139d1a 100644 --- a/src/main/java/run/halo/app/model/support/StaticPageFile.java +++ b/src/main/java/run/halo/app/model/support/StaticPageFile.java @@ -14,6 +14,8 @@ import java.util.List; @Data public class StaticPageFile implements Comparator { + private String id; + private String name; private Boolean isFile; diff --git a/src/main/java/run/halo/app/service/StaticPageService.java b/src/main/java/run/halo/app/service/StaticPageService.java index fc40e2a9c..72afcafed 100644 --- a/src/main/java/run/halo/app/service/StaticPageService.java +++ b/src/main/java/run/halo/app/service/StaticPageService.java @@ -2,8 +2,13 @@ package run.halo.app.service; import run.halo.app.model.support.StaticPageFile; +import java.nio.file.Path; import java.util.List; +import static run.halo.app.model.support.HaloConst.FILE_SEPARATOR; +import static run.halo.app.model.support.HaloConst.TEMP_DIR; +import static run.halo.app.utils.HaloUtils.ensureSuffix; + /** * Static Page service interface. * @@ -17,6 +22,11 @@ public interface StaticPageService { */ String PAGES_FOLDER = "static_pages"; + + String STATIC_PAGE_PACK_DIR = ensureSuffix(TEMP_DIR, FILE_SEPARATOR) + "static-pages-pack" + FILE_SEPARATOR; + + String[] USELESS_FILE_SUFFIX = {"ftl", "md", "yaml", "yml", "gitignore"}; + /** * Generate pages. */ @@ -27,6 +37,13 @@ public interface StaticPageService { */ void deploy(); + /** + * Zip static pages directory. + * + * @return zip path + */ + Path zipStaticPagesDirectory(); + /** * List file of generated static page. * diff --git a/src/main/java/run/halo/app/service/impl/StaticPageServiceImpl.java b/src/main/java/run/halo/app/service/impl/StaticPageServiceImpl.java index 0d1824e04..88f2e81fa 100644 --- a/src/main/java/run/halo/app/service/impl/StaticPageServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/StaticPageServiceImpl.java @@ -1,6 +1,8 @@ package run.halo.app.service.impl; +import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.file.FileWriter; +import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.PageUtil; import freemarker.template.Template; import freemarker.template.TemplateException; @@ -42,6 +44,8 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.LinkedList; import java.util.List; import java.util.stream.Stream; @@ -123,6 +127,7 @@ public class StaticPageServiceImpl implements StaticPageService { pagesDir = Paths.get(haloProperties.getWorkDir(), PAGES_FOLDER); FileUtils.createIfAbsent(pagesDir); + Files.createDirectories(Paths.get(STATIC_PAGE_PACK_DIR)); } @Override @@ -158,6 +163,22 @@ public class StaticPageServiceImpl implements StaticPageService { staticDeployHandlers.deploy(type); } + @Override + public Path zipStaticPagesDirectory() { + try { + String staticPagePackName = HaloConst.STATIC_PAGE_PACK_PREFIX + + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss-")) + + IdUtil.simpleUUID().hashCode() + ".zip"; + Path staticPageZipPath = Files.createFile(Paths.get(STATIC_PAGE_PACK_DIR, staticPagePackName)); + + FileUtils.zip(pagesDir, staticPageZipPath); + + return staticPageZipPath; + } catch (IOException e) { + throw new ServiceException("Failed to zip static pages directory", e); + } + } + @Override public List listFile() { return listStaticPageFileTree(pagesDir); @@ -176,6 +197,7 @@ public class StaticPageServiceImpl implements StaticPageService { pathStream.forEach(path -> { StaticPageFile staticPageFile = new StaticPageFile(); + staticPageFile.setId(IdUtil.fastSimpleUUID()); staticPageFile.setName(path.getFileName().toString()); staticPageFile.setIsFile(Files.isRegularFile(path)); if (Files.isDirectory(path)) { @@ -708,9 +730,41 @@ public class StaticPageServiceImpl implements StaticPageService { */ private void copyThemeFolder() throws IOException { ThemeProperty activatedTheme = themeService.getActivatedTheme(); - Path path = Paths.get(pagesDir.toString(), activatedTheme.getId()); + Path path = Paths.get(pagesDir.toString(), activatedTheme.getFolderName()); FileUtils.createIfAbsent(path); FileUtils.copyFolder(Paths.get(activatedTheme.getThemePath()), path); + cleanThemeFolder(Paths.get(pagesDir.toString(), activatedTheme.getFolderName())); + } + + private void cleanThemeFolder(Path themePath) { + if (!Files.isDirectory(themePath)) { + return; + } + + try (Stream pathStream = Files.list(themePath)) { + + pathStream.forEach(path -> { + if (!Files.isDirectory(path)) { + for (String suffix : USELESS_FILE_SUFFIX) { + if (suffix.contains(FileUtil.extName(path.toFile()))) { + try { + Files.delete(path); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } else { + if (path.getFileName().toString().contains(".git")) { + FileUtils.deleteFolderQuietly(path); + } else { + cleanThemeFolder(path); + } + } + }); + } catch (IOException e) { + throw new ServiceException("Failed to list sub files", e); + } } /** diff --git a/src/main/java/run/halo/app/service/impl/StaticStorageServiceImpl.java b/src/main/java/run/halo/app/service/impl/StaticStorageServiceImpl.java index 40ea905b4..8f16c4262 100644 --- a/src/main/java/run/halo/app/service/impl/StaticStorageServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/StaticStorageServiceImpl.java @@ -1,5 +1,6 @@ package run.halo.app.service.impl; +import cn.hutool.core.util.IdUtil; import org.apache.commons.lang3.StringUtils; import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; @@ -59,6 +60,7 @@ public class StaticStorageServiceImpl implements StaticStorageService { pathStream.forEach(path -> { StaticFile staticFile = new StaticFile(); + staticFile.setId(IdUtil.fastSimpleUUID()); staticFile.setName(path.getFileName().toString()); staticFile.setPath(path.toString()); staticFile.setRelativePath(StringUtils.removeStart(path.toString(), staticDir.toString()));