From ff734ed153edf6ec4282b51f7079e0501bba9fc6 Mon Sep 17 00:00:00 2001 From: Wh1te Date: Sun, 25 Oct 2020 21:23:14 +0800 Subject: [PATCH] feat: support automatic cleaning recycled posts. #1031 (#1114) --- src/main/java/run/halo/app/Application.java | 2 + .../run/halo/app/model/enums/TimeUnit.java | 35 ++++++++ .../app/model/properties/PostProperties.java | 19 ++++- .../app/task/RecycledPostCleaningTask.java | 82 +++++++++++++++++++ 4 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 src/main/java/run/halo/app/model/enums/TimeUnit.java create mode 100644 src/main/java/run/halo/app/task/RecycledPostCleaningTask.java diff --git a/src/main/java/run/halo/app/Application.java b/src/main/java/run/halo/app/Application.java index 786423c9d..31ad6f417 100755 --- a/src/main/java/run/halo/app/Application.java +++ b/src/main/java/run/halo/app/Application.java @@ -7,6 +7,7 @@ import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; import run.halo.app.repository.base.BaseRepositoryImpl; /** @@ -17,6 +18,7 @@ import run.halo.app.repository.base.BaseRepositoryImpl; */ @SpringBootApplication(exclude = { MultipartAutoConfiguration.class }) @EnableAsync +@EnableScheduling @EnableJpaRepositories(basePackages = "run.halo.app.repository", repositoryBaseClass = BaseRepositoryImpl.class) public class Application extends SpringBootServletInitializer { diff --git a/src/main/java/run/halo/app/model/enums/TimeUnit.java b/src/main/java/run/halo/app/model/enums/TimeUnit.java new file mode 100644 index 000000000..f4a62ae62 --- /dev/null +++ b/src/main/java/run/halo/app/model/enums/TimeUnit.java @@ -0,0 +1,35 @@ +package run.halo.app.model.enums; + +/** + * @author Wh1te + * @date 2020-10-19 + */ +public enum TimeUnit implements ValueEnum { + + /** + * 天 + */ + DAY(0), + + /** + * 小时 + */ + HOUR(1); + + private final Integer value; + + TimeUnit(Integer value) { + this.value = value; + } + + /** + * Get enum value. + * + * @return enum value + */ + @Override + public Integer getValue() { + return value; + } +} + diff --git a/src/main/java/run/halo/app/model/properties/PostProperties.java b/src/main/java/run/halo/app/model/properties/PostProperties.java index 854ef95d9..b1280737f 100644 --- a/src/main/java/run/halo/app/model/properties/PostProperties.java +++ b/src/main/java/run/halo/app/model/properties/PostProperties.java @@ -1,5 +1,7 @@ package run.halo.app.model.properties; +import run.halo.app.model.enums.TimeUnit; + /** * Post properties. * @@ -37,7 +39,22 @@ public enum PostProperties implements PropertyEnum { /** * Post index sort. */ - INDEX_SORT("post_index_sort", String.class, "createTime"); + INDEX_SORT("post_index_sort", String.class, "createTime"), + + /** + * Enable auto cleaning recycled post. + */ + RECYCLED_POST_CLEANING_ENABLED("recycled_post_cleaning_enabled", Boolean.class, "false"), + + /** + * Recycled post retention time + */ + RECYCLED_POST_RETENTION_TIME("recycled_post_retention_time", Integer.class, "30"), + + /** + * Recycled post retention time unit. + */ + RECYCLED_POST_RETENTION_TIMEUNIT("recycled_post_retention_timeunit", TimeUnit.class, TimeUnit.DAY.name()); private final String value; diff --git a/src/main/java/run/halo/app/task/RecycledPostCleaningTask.java b/src/main/java/run/halo/app/task/RecycledPostCleaningTask.java new file mode 100644 index 000000000..da17e640c --- /dev/null +++ b/src/main/java/run/halo/app/task/RecycledPostCleaningTask.java @@ -0,0 +1,82 @@ +package run.halo.app.task; + +import cn.hutool.core.date.DateUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import run.halo.app.model.entity.BasePost; +import run.halo.app.model.entity.Post; +import run.halo.app.model.enums.PostStatus; +import run.halo.app.model.enums.TimeUnit; +import run.halo.app.model.properties.PostProperties; +import run.halo.app.service.OptionService; +import run.halo.app.service.PostService; + +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * @author Wh1te + * @date 2020-10-19 + */ +@Slf4j +@Component +public class RecycledPostCleaningTask { + + private final OptionService optionService; + + private final PostService postService; + + public RecycledPostCleaningTask(OptionService optionService, PostService postService) { + this.optionService = optionService; + this.postService = postService; + } + + /** + * Clean recycled posts if RECYCLED_POST_CLEANING_ENABLED is true + */ + @Scheduled(cron = "0 0 */1 * * *") + public synchronized void run() { + Boolean recycledPostCleaningEnabled = optionService.getByPropertyOrDefault(PostProperties.RECYCLED_POST_CLEANING_ENABLED, Boolean.class, false); + log.debug("{} = {}", PostProperties.RECYCLED_POST_CLEANING_ENABLED.getValue(), recycledPostCleaningEnabled); + if (!recycledPostCleaningEnabled) { + return; + } + + Integer recycledPostRetentionTime = optionService.getByPropertyOrDefault(PostProperties.RECYCLED_POST_RETENTION_TIME, Integer.class, PostProperties.RECYCLED_POST_RETENTION_TIME.defaultValue(Integer.class)); + TimeUnit timeUnit = optionService.getEnumByPropertyOrDefault(PostProperties.RECYCLED_POST_RETENTION_TIMEUNIT, TimeUnit.class, TimeUnit.DAY); + log.debug("{} = {}", PostProperties.RECYCLED_POST_RETENTION_TIME.getValue(), recycledPostRetentionTime); + log.debug("{} = {}", PostProperties.RECYCLED_POST_RETENTION_TIMEUNIT.getValue(), Objects.requireNonNull(timeUnit).name()); + + long expiredIn; + switch (timeUnit) { + case HOUR: + expiredIn = recycledPostRetentionTime; + break; + case DAY: + default: + expiredIn = recycledPostRetentionTime * 24; + break; + } + List recyclePost = postService.listAllBy(PostStatus.RECYCLE); + LocalDateTime now = LocalDateTime.now(); + List ids = recyclePost.stream().filter(post -> { + LocalDateTime updateTime = DateUtil.toLocalDateTime(post.getUpdateTime()); + long until = updateTime.until(now, ChronoUnit.HOURS); + return until >= expiredIn; + }).map(BasePost::getId).collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(ids)) { + return; + } + + log.info("Start cleaning recycled posts"); + List posts = postService.removeByIds(ids); + log.info("Recycled posts cleaning has been completed, {} posts has been permanently deleted", posts.size()); + } + +}