diff --git a/src/main/java/com/rebuild/core/service/files/AttachmentAwareObserver.java b/src/main/java/com/rebuild/core/service/files/AttachmentAwareObserver.java index 942a10487..826a75073 100644 --- a/src/main/java/com/rebuild/core/service/files/AttachmentAwareObserver.java +++ b/src/main/java/com/rebuild/core/service/files/AttachmentAwareObserver.java @@ -7,6 +7,7 @@ See LICENSE and COMMERCIAL in the project root for license information. package com.rebuild.core.service.files; +import cn.devezhao.commons.CalendarUtils; import cn.devezhao.persist4j.Field; import cn.devezhao.persist4j.Record; import cn.devezhao.persist4j.engine.ID; @@ -19,7 +20,6 @@ import com.rebuild.core.metadata.easymeta.DisplayType; import com.rebuild.core.privileges.UserService; import com.rebuild.core.service.general.OperatingContext; import com.rebuild.core.service.general.OperatingObserver; -import com.rebuild.core.service.general.recyclebin.RecycleBinCleanerJob; import com.rebuild.utils.JSONUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; @@ -53,9 +53,9 @@ public class AttachmentAwareObserver extends OperatingObserver { if (record.hasValue(field.getName(), false)) { JSONArray files = parseFilesJson(record.getObjectValue(field.getName())); for (Object file : files) { - Record add = createAttachment( + Record c = buildAttachment( field, context.getAfterRecord().getPrimary(), (String) file, context.getOperator()); - creates.add(add); + creates.add(c); } } } @@ -72,8 +72,8 @@ public class AttachmentAwareObserver extends OperatingObserver { Record before = context.getBeforeRecord(); - List creates = new ArrayList<>(); - List deletes = new ArrayList<>(); + // 4.2 标记删除 + List createsAndUpdates = new ArrayList<>(); for (Field field : fileFields) { String fieldName = field.getName(); if (record.hasValue(fieldName)) { @@ -101,21 +101,24 @@ public class AttachmentAwareObserver extends OperatingObserver { .setParameter(3, o) .unique(); if (delete != null) { - deletes.add((ID) delete[0]); + Record d = EntityHelper.forUpdate((ID) delete[0], UserService.SYSTEM_USER, false); + d.setBoolean(EntityHelper.IsDeleted, true); + d.setDate(EntityHelper.ModifiedOn, CalendarUtils.now()); + createsAndUpdates.add(d); } } for (Object o : afterFiles) { - Record add = createAttachment( + Record c = buildAttachment( field, context.getAfterRecord().getPrimary(), (String) o, context.getOperator()); - creates.add(add); + createsAndUpdates.add(c); } } } - if (creates.isEmpty() && deletes.isEmpty()) return; + if (createsAndUpdates.isEmpty()) return; - Application.getCommonsService().createOrUpdateAndDelete( - creates.toArray(new Record[0]), deletes.toArray(new ID[0]), false); + Application.getCommonsService() + .createOrUpdate(createsAndUpdates.toArray(new Record[0]), false); } @Override @@ -130,23 +133,17 @@ public class AttachmentAwareObserver extends OperatingObserver { .array(); if (array.length == 0) return; - // 标记删除,以便记录从回收站恢复后可用 - final boolean rbEnable = RecycleBinCleanerJob.isEnableRecycleBin(); - + // 4.2 标记删除 List updates = new ArrayList<>(); - List deletes = new ArrayList<>(); for (Object[] o : array) { - if (rbEnable) { - Record upt = EntityHelper.forUpdate((ID) o[0], UserService.SYSTEM_USER, false); - upt.setBoolean(EntityHelper.IsDeleted, true); - updates.add(upt); - } else { - deletes.add((ID) o[0]); - } + Record d = EntityHelper.forUpdate((ID) o[0], UserService.SYSTEM_USER, false); + d.setBoolean(EntityHelper.IsDeleted, true); + d.setDate(EntityHelper.ModifiedOn, CalendarUtils.now()); + updates.add(d); } - Application.getCommonsService().createOrUpdateAndDelete( - updates.toArray(new Record[0]), deletes.toArray(new ID[0]), false); + Application.getCommonsService() + .createOrUpdate(updates.toArray(new Record[0]), false); } private JSONArray parseFilesJson(Object files) { @@ -155,7 +152,7 @@ public class AttachmentAwareObserver extends OperatingObserver { else return JSON.parseArray(files.toString()); } - private Record createAttachment(Field field, ID recordId, String filePath, ID user) { + private Record buildAttachment(Field field, ID recordId, String filePath, ID user) { Record attach = FilesHelper.createAttachment(filePath, user); attach.setInt("belongEntity", field.getOwnEntity().getEntityCode()); attach.setString("belongField", field.getName()); diff --git a/src/main/java/com/rebuild/core/service/general/recyclebin/RecycleBinCleanerJob.java b/src/main/java/com/rebuild/core/service/general/recyclebin/RecycleBinCleanerJob.java index 51e1dc809..0e8b57e56 100644 --- a/src/main/java/com/rebuild/core/service/general/recyclebin/RecycleBinCleanerJob.java +++ b/src/main/java/com/rebuild/core/service/general/recyclebin/RecycleBinCleanerJob.java @@ -8,21 +8,27 @@ See LICENSE and COMMERCIAL in the project root for license information. package com.rebuild.core.service.general.recyclebin; import cn.devezhao.commons.CalendarUtils; +import cn.devezhao.commons.ObjectUtils; import cn.devezhao.persist4j.Entity; +import cn.devezhao.persist4j.engine.ID; import com.rebuild.core.Application; import com.rebuild.core.metadata.EntityHelper; import com.rebuild.core.metadata.MetadataHelper; import com.rebuild.core.support.ConfigurationItem; import com.rebuild.core.support.RebuildConfiguration; import com.rebuild.core.support.distributed.DistributedJobLock; +import com.rebuild.core.support.integration.QiniuCloud; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; import org.springframework.core.NamedThreadLocal; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.Date; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * 回收站/变更历史清理 @@ -40,6 +46,7 @@ public class RecycleBinCleanerJob extends DistributedJobLock { // 回收站 + final Set deletePaths42 = new HashSet<>(); final int rbDays = RebuildConfiguration.getInt(ConfigurationItem.RecycleBinKeepingDays); if (rbDays > 0) { log.info("RecycleBin clean running ... {}d", rbDays); @@ -71,6 +78,15 @@ public class RecycleBinCleanerJob extends DistributedJobLock { refEntity.getField(refRecordIdName).getPhysicalName(), recordIdName, commonFrom); dels.add(delRef); + + // 4.2 删除附件 + if ("Attachment".equals(refName)) { + String sql = "select FILE_PATH " + delRef.substring(7); + Object[][] array = Application.getQueryFactory().createNativeQuery(sql).array(); + for (Object[] o : array) { + deletePaths42.add((String) o[0]); + } + } } String delSql = "delete " + commonFrom; @@ -99,15 +115,53 @@ public class RecycleBinCleanerJob extends DistributedJobLock { log.warn("RevisionHistory cleaned : {}", del); } - // CommonLog 保留6个月 + // CommonLog 保留 180d Entity entity = MetadataHelper.getEntity(EntityHelper.CommonsLog); String delSql = String.format( "delete from `%s` where `%s` < '%s 00:00:00'", entity.getPhysicalName(), entity.getField("logTime").getPhysicalName(), - CalendarUtils.getUTCDateFormat().format(CalendarUtils.addMonth(-6))); + CalendarUtils.getUTCDateFormat().format(CalendarUtils.addDay(-180))); Application.getSqlExecutor().execute(delSql, 60 * 3); + + // 4.2 已删除附件最少保留 180d + + List deletesAuto42 = new ArrayList<>(); + Object[][] array = Application.createQueryNoFilter( + "select attachmentId,filePath from Attachment where isDeleted = 'T' and modifiedOn < ?") + .setParameter(1, CalendarUtils.addDay(-Math.max(rbDays, 180))) + .array(); + for (Object[] o : array) { + deletesAuto42.add((ID) o[0]); + deletePaths42.add((String) o[1]); + } + + // 删记录 + if (!deletesAuto42.isEmpty()) { + Application.getCommonsService().delete(deletesAuto42.toArray(new ID[0]), false); + } + // 删文件 + int del = 0; + for (String path : deletePaths42) { + Object[] o = Application.createQueryNoFilter( + "select count(filePath) from Attachment where filePath = ?") + .setParameter(1, path) + .unique(); + // 检查附件是否有其他字段使用(例如记录转换、触发器处理的) + if (o != null && ObjectUtils.toInt(o[0]) > 0) continue; + + if (QiniuCloud.instance().available()) { + try { + boolean s = QiniuCloud.instance().delete(path); + del += s ? 1 : 0; + } catch (Exception ignored) {} + } else { + boolean s = FileUtils.deleteQuietly(RebuildConfiguration.getFileOfData(path)); + del += s ? 1 : 0; + } + } + log.warn("File/Attachment deleted : {}", del); } // --