From 8649f81a70fd6b8b26132a203f03eaf570581ade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?REBUILD=20=E4=BC=81=E4=B8=9A=E7=AE=A1=E7=90=86=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F?= <42044143+getrebuild@users.noreply.github.com> Date: Fri, 22 Dec 2023 16:45:00 +0800 Subject: [PATCH] Fix 3.5.3 (#699) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update @rbv * be: 通知邮件保持 html * feat: report nref * be: Bad JSONArray format * out API Filter * pageSize max=1000 * fix: DATE DATETIME 比较 * fix: SafeObservable * v3.5.3 --- @rbv | 2 +- pom.xml | 2 +- .../java/com/rebuild/core/Application.java | 8 ++-- .../rebuild/core/service/CommonsService.java | 2 +- .../rebuild/core/service/SafeObservable.java | 45 +++++++++++++++++++ .../rebuild/core/service/SafeObserver.java | 21 +++++++++ .../datareport/EasyExcelGenerator33.java | 10 ++++- .../service/datareport/FixsMergeStrategy.java | 1 + .../core/service/feeds/FeedsService.java | 3 +- .../files/AttachmentAwareObserver.java | 5 ++- .../service/general/GeneralEntityService.java | 20 ++------- .../service/general/ObservableService.java | 30 ++++--------- .../service/general/OperatingObserver.java | 9 ++-- .../service/general/RecordDifference.java | 12 +++++ .../general/RevisionHistoryObserver.java | 5 +++ .../notification/NotificationObserver.java | 5 +++ .../service/project/ProjectTaskService.java | 3 +- .../service/trigger/RobotTriggerObserver.java | 9 +++- .../trigger/impl/SendNotification.java | 4 +- .../support/general/FieldValueHelper.java | 9 +++- .../core/support/general/QueryParser.java | 5 ++- .../core/support/integration/SMSender.java | 29 ++++++++---- .../java/com/rebuild/utils/MarkdownUtils.java | 14 +++--- .../com/rebuild/web/RebuildWebConfigurer.java | 2 +- src/main/resources/web/assets/css/rb-page.css | 6 ++- .../resources/web/assets/css/view-page.css | 2 +- .../web/assets/js/admin/apis-manager.js | 2 +- .../web/assets/js/rb-datalist.common.js | 4 ++ 28 files changed, 189 insertions(+), 80 deletions(-) create mode 100644 src/main/java/com/rebuild/core/service/SafeObservable.java create mode 100644 src/main/java/com/rebuild/core/service/SafeObserver.java diff --git a/@rbv b/@rbv index fecdd9ab1..d3707a301 160000 --- a/@rbv +++ b/@rbv @@ -1 +1 @@ -Subproject commit fecdd9ab1897c92ab4a7b5cd1f2d83d197597e7f +Subproject commit d3707a301a97a0b18e6428607ac836c796b01685 diff --git a/pom.xml b/pom.xml index 866495241..53db1ab98 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.rebuild rebuild - 3.5.2 + 3.5.3 rebuild Building your business-systems freely! https://getrebuild.com/ diff --git a/src/main/java/com/rebuild/core/Application.java b/src/main/java/com/rebuild/core/Application.java index d9bacd39e..50b7d7172 100644 --- a/src/main/java/com/rebuild/core/Application.java +++ b/src/main/java/com/rebuild/core/Application.java @@ -74,11 +74,11 @@ public class Application implements ApplicationListener /** * Rebuild Version */ - public static final String VER = "3.5.2"; + public static final String VER = "3.5.3"; /** * Rebuild Build [MAJOR]{1}[MINOR]{2}[PATCH]{2}[BUILD]{2} */ - public static final int BUILD = 3050207; + public static final int BUILD = 3050308; static { // Driver for DB @@ -373,11 +373,11 @@ public static EntityService getEntityService(int entityCode) { } public static GeneralEntityService getGeneralEntityService() { - return (GeneralEntityService) getContext().getBean("generalEntityService"); + return (GeneralEntityService) getContext().getBean("rbGeneralEntityService"); } public static CommonsService getCommonsService() { - return getBean(CommonsService.class); + return (CommonsService) getContext().getBean("rbCommonsService"); } /** diff --git a/src/main/java/com/rebuild/core/service/CommonsService.java b/src/main/java/com/rebuild/core/service/CommonsService.java index 9324eca30..dfcaaeeda 100644 --- a/src/main/java/com/rebuild/core/service/CommonsService.java +++ b/src/main/java/com/rebuild/core/service/CommonsService.java @@ -27,7 +27,7 @@ * @author Zixin (RB) * @since 11/06/2019 */ -@Service +@Service("rbCommonsService") public class CommonsService extends InternalPersistService { protected CommonsService(PersistManagerFactory aPMFactory) { diff --git a/src/main/java/com/rebuild/core/service/SafeObservable.java b/src/main/java/com/rebuild/core/service/SafeObservable.java new file mode 100644 index 000000000..15feba193 --- /dev/null +++ b/src/main/java/com/rebuild/core/service/SafeObservable.java @@ -0,0 +1,45 @@ +/*! +Copyright (c) REBUILD and/or its owners. All rights reserved. + +rebuild is dual-licensed under commercial and open source licenses (GPLv3). +See LICENSE and COMMERCIAL in the project root for license information. +*/ + +package com.rebuild.core.service; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +/** + * Thread-Safe Observable + * + * @author devezhao + * @since 2023/12/22 + */ +public class SafeObservable { + + final private List obs; + + public SafeObservable() { + obs = new ArrayList<>(); + } + + public void addObserver(SafeObserver o) { + if (o == null) throw new NullPointerException(); + if (!obs.contains(o)) { + obs.add(o); + obs.sort(Comparator.comparingInt(SafeObserver::getOrder)); + } + } + + public void notifyObservers(Object arg) { + for (SafeObserver o : obs) { + o.update(this, arg); + } + } + + public int countObservers() { + return obs.size(); + } +} diff --git a/src/main/java/com/rebuild/core/service/SafeObserver.java b/src/main/java/com/rebuild/core/service/SafeObserver.java new file mode 100644 index 000000000..23c52482c --- /dev/null +++ b/src/main/java/com/rebuild/core/service/SafeObserver.java @@ -0,0 +1,21 @@ +/*! +Copyright (c) REBUILD and/or its owners. All rights reserved. + +rebuild is dual-licensed under commercial and open source licenses (GPLv3). +See LICENSE and COMMERCIAL in the project root for license information. +*/ + +package com.rebuild.core.service; + +/** + * Thread-Safe Observer + * + * @author devezhao + * @since 2023/12/22 + */ +public interface SafeObserver { + + void update(SafeObservable o, Object arg); + + int getOrder(); +} diff --git a/src/main/java/com/rebuild/core/service/datareport/EasyExcelGenerator33.java b/src/main/java/com/rebuild/core/service/datareport/EasyExcelGenerator33.java index fc31cf9a9..cc44fc2e7 100644 --- a/src/main/java/com/rebuild/core/service/datareport/EasyExcelGenerator33.java +++ b/src/main/java/com/rebuild/core/service/datareport/EasyExcelGenerator33.java @@ -17,6 +17,7 @@ import com.rebuild.core.metadata.MetadataHelper; import com.rebuild.core.privileges.UserService; import com.rebuild.core.service.approval.ApprovalHelper; +import com.rebuild.core.support.general.ProtocolFilterParser; import com.rebuild.core.support.general.RecordBuilder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; @@ -88,10 +89,11 @@ protected List> buildData() { } else if (varName.startsWith(DETAIL_PREFIX)) { refName = DETAIL_PREFIX; } else { + // 在客户中导出订单(下列 AccountId 为订单中引用客户的引用字段) // .AccountId.SalesOrder.SalesOrderName String[] split = varName.substring(1).split("\\."); if (split.length < 2) throw new ReportsException("Bad REF (Miss .detail prefix?) : " + varName); - + String refName2 = split[0] + split[1]; refName = varName.substring(0, refName2.length() + 2 /* dots */); } @@ -169,8 +171,12 @@ protected List> buildData() { String sortField = templateExtractor33.getSortField(refName); querySql += " order by " + StringUtils.defaultIfBlank(sortField, "createdOn asc"); + String relatedExpr = split[1] + "." + split[0]; + String where = new ProtocolFilterParser(null).parseRelated(relatedExpr, recordId); + querySql = querySql.replace("%s = ?", where); + querySql = String.format(querySql, StringUtils.join(e.getValue(), ","), - ref2Entity.getPrimaryField().getName(), ref2Entity.getName(), split[0]); + ref2Entity.getPrimaryField().getName(), ref2Entity.getName()); } log.info("SQL of template : {}", querySql); diff --git a/src/main/java/com/rebuild/core/service/datareport/FixsMergeStrategy.java b/src/main/java/com/rebuild/core/service/datareport/FixsMergeStrategy.java index c2ad640e4..da888a471 100644 --- a/src/main/java/com/rebuild/core/service/datareport/FixsMergeStrategy.java +++ b/src/main/java/com/rebuild/core/service/datareport/FixsMergeStrategy.java @@ -36,6 +36,7 @@ protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex int colIndex = cell.getColumnIndex(); sheet = cell.getSheet(); Row prevRow = sheet.getRow(rowIndex - 1); + if (prevRow == null) return; Cell prevCell = prevRow.getCell(colIndex); List craList = sheet.getMergedRegions(); CellStyle cs = cell.getCellStyle(); diff --git a/src/main/java/com/rebuild/core/service/feeds/FeedsService.java b/src/main/java/com/rebuild/core/service/feeds/FeedsService.java index 84a96dbf8..73b2c18ea 100644 --- a/src/main/java/com/rebuild/core/service/feeds/FeedsService.java +++ b/src/main/java/com/rebuild/core/service/feeds/FeedsService.java @@ -57,8 +57,9 @@ public int delete(ID recordId) { "select commentId from FeedsComment where feedsId = ?") .setParameter(1, recordId) .array(); + FeedsCommentService fcs = Application.getBean(FeedsCommentService.class); for (Object[] c : comments) { - Application.getBean(FeedsCommentService.class).delete((ID) c[0]); + fcs.delete((ID) c[0]); } // 只有动态本身可以恢复 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 cdaaf63e8..2bf449757 100644 --- a/src/main/java/com/rebuild/core/service/files/AttachmentAwareObserver.java +++ b/src/main/java/com/rebuild/core/service/files/AttachmentAwareObserver.java @@ -37,8 +37,9 @@ @Slf4j public class AttachmentAwareObserver extends OperatingObserver { - public AttachmentAwareObserver() { - super(); + @Override + public int getOrder() { + return 1; } @Override diff --git a/src/main/java/com/rebuild/core/service/general/GeneralEntityService.java b/src/main/java/com/rebuild/core/service/general/GeneralEntityService.java index 16ba6545b..0d9d6c302 100644 --- a/src/main/java/com/rebuild/core/service/general/GeneralEntityService.java +++ b/src/main/java/com/rebuild/core/service/general/GeneralEntityService.java @@ -52,7 +52,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang3.ArrayUtils; import org.springframework.stereotype.Service; import org.springframework.util.Assert; @@ -63,7 +62,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Observer; import java.util.Set; import java.util.TreeMap; @@ -79,7 +77,7 @@ * @since 11/06/2019 */ @Slf4j -@Service +@Service("rbGeneralEntityService") public class GeneralEntityService extends ObservableService implements EntityService { // 有明细 @@ -87,18 +85,9 @@ public class GeneralEntityService extends ObservableService implements EntitySer protected GeneralEntityService(PersistManagerFactory aPMFactory) { super(aPMFactory); - } - @Override - protected Observer[] getOrderObservers() { - Observer[] obs = new Observer[] { - // 触发器 - new RobotTriggerObserver(), - // 通知 - new NotificationObserver(), - }; - obs = ArrayUtils.addAll(obs, super.getOrderObservers()); - return obs; + addObserver(new NotificationObserver()); + addObserver(new RobotTriggerObserver()); } @Override @@ -375,7 +364,6 @@ record = QueryHelper.getMainIdByDetail(record); } if (countObservers() > 0 && assignBefore != null) { - setChanged(); notifyObservers(OperatingContext.create(UserContextHolder.getUser(), BizzPermission.ASSIGN, assignBefore, assignAfter)); } return affected; @@ -454,7 +442,6 @@ record = QueryHelper.getMainIdByDetail(record); } if (countObservers() > 0 && shareChange) { - setChanged(); notifyObservers(OperatingContext.create(currentUser, BizzPermission.SHARE, null, sharedAfter)); } return affected; @@ -476,7 +463,6 @@ public int unshare(ID record, ID accessId) { delegateService.delete(accessId); if (countObservers() > 0) { - setChanged(); notifyObservers(OperatingContext.create(currentUser, InternalPermission.UNSHARE, unsharedBefore, null)); } return 1; diff --git a/src/main/java/com/rebuild/core/service/general/ObservableService.java b/src/main/java/com/rebuild/core/service/general/ObservableService.java index d03a9dac5..421e5ea1c 100644 --- a/src/main/java/com/rebuild/core/service/general/ObservableService.java +++ b/src/main/java/com/rebuild/core/service/general/ObservableService.java @@ -16,6 +16,8 @@ import com.rebuild.core.metadata.EntityHelper; import com.rebuild.core.privileges.bizz.InternalPermission; import com.rebuild.core.service.BaseService; +import com.rebuild.core.service.SafeObservable; +import com.rebuild.core.service.SafeObserver; import com.rebuild.core.service.ServiceSpec; import com.rebuild.core.service.files.AttachmentAwareObserver; import com.rebuild.core.service.general.recyclebin.RecycleBinCleanerJob; @@ -24,9 +26,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.util.Assert; -import java.util.Observable; -import java.util.Observer; - /** * 可注入观察者的服务 * @@ -35,7 +34,7 @@ * @since 12/28/2018 */ @Slf4j -public abstract class ObservableService extends Observable implements ServiceSpec { +public abstract class ObservableService extends SafeObservable implements ServiceSpec { final protected ServiceSpec delegateService; @@ -45,21 +44,14 @@ public abstract class ObservableService extends Observable implements ServiceSpe protected ObservableService(PersistManagerFactory aPMFactory) { this.delegateService = new BaseService(aPMFactory); - for (Observer o : getOrderObservers()) { - log.info("Add observer : {} for [ {} ] ", o, getEntityCode()); - addObserver(o); - } + addObserver(new AttachmentAwareObserver()); + addObserver(new RevisionHistoryObserver()); } - /** - * @return - */ - protected Observer[] getOrderObservers() { - // 默认监听者 - return new Observer[] { - new RevisionHistoryObserver(), // 2 - new AttachmentAwareObserver(), // 1 - }; + @Override + public void addObserver(SafeObserver o) { + log.info("Add observer : {} for [ {} ] ", o, getEntityCode()); + super.addObserver(o); } @Override @@ -72,7 +64,6 @@ public Record create(Record record) { record = delegateService.create(record); if (countObservers() > 0) { - setChanged(); notifyObservers(OperatingContext.create(UserContextHolder.getUser(), BizzPermission.CREATE, null, record)); } return record; @@ -85,7 +76,6 @@ public Record update(Record record) { record = delegateService.update(record); if (countObservers() > 0) { - setChanged(); notifyObservers(OperatingContext.create(UserContextHolder.getUser(), BizzPermission.UPDATE, before, record)); } return record; @@ -102,14 +92,12 @@ public int delete(ID recordId) { deleted = recordSnap(deleted, true); // 删除前触发,做一些状态保持 - setChanged(); notifyObservers(OperatingContext.create(currentUser, InternalPermission.DELETE_BEFORE, deleted, deleted)); } int affected = delegateService.delete(recordId); if (countObservers() > 0) { - setChanged(); notifyObservers(OperatingContext.create(currentUser, BizzPermission.DELETE, deleted, null)); } return affected; diff --git a/src/main/java/com/rebuild/core/service/general/OperatingObserver.java b/src/main/java/com/rebuild/core/service/general/OperatingObserver.java index 431bfd358..9982fff77 100644 --- a/src/main/java/com/rebuild/core/service/general/OperatingObserver.java +++ b/src/main/java/com/rebuild/core/service/general/OperatingObserver.java @@ -10,11 +10,10 @@ import cn.devezhao.bizz.privileges.impl.BizzPermission; import cn.devezhao.commons.ThreadPool; import com.rebuild.core.privileges.bizz.InternalPermission; +import com.rebuild.core.service.SafeObservable; +import com.rebuild.core.service.SafeObserver; import lombok.extern.slf4j.Slf4j; -import java.util.Observable; -import java.util.Observer; - /** * 记录操作观察者。子类复写需要关注的操作即可,**注意实现必须是无状态的** * @@ -23,14 +22,14 @@ * @since 10/31/2018 */ @Slf4j -public abstract class OperatingObserver implements Observer { +public abstract class OperatingObserver implements SafeObserver { protected OperatingObserver() { super(); } @Override - public void update(final Observable o, final Object arg) { + public void update(final SafeObservable o, final Object arg) { final OperatingContext ctx = (OperatingContext) arg; if (isAsync()) { ThreadPool.exec(() -> { diff --git a/src/main/java/com/rebuild/core/service/general/RecordDifference.java b/src/main/java/com/rebuild/core/service/general/RecordDifference.java index bf93f309f..e6393b9d5 100644 --- a/src/main/java/com/rebuild/core/service/general/RecordDifference.java +++ b/src/main/java/com/rebuild/core/service/general/RecordDifference.java @@ -7,6 +7,7 @@ package com.rebuild.core.service.general; +import cn.devezhao.commons.CalendarUtils; import cn.devezhao.persist4j.Entity; import cn.devezhao.persist4j.Field; import cn.devezhao.persist4j.Record; @@ -22,6 +23,7 @@ import com.rebuild.utils.JSONUtils; import org.apache.commons.collections4.map.CaseInsensitiveMap; +import java.util.Date; import java.util.Map; /** @@ -80,6 +82,11 @@ protected JSON diffMerge(Record after, boolean diffCommons) { Object beforeVal = e.getValue(); if (NullValue.is(beforeVal)) beforeVal = null; + // v3.5.3 + if (beforeVal instanceof Date && entity.getField(fieldName).getType() == FieldType.DATE) { + beforeVal = CalendarUtils.clearTime((Date) beforeVal); + } + merged.put(fieldName, new Object[]{beforeVal, null}); } } @@ -94,6 +101,11 @@ protected JSON diffMerge(Record after, boolean diffCommons) { Object afterVal = e.getValue(); if (NullValue.is(afterVal)) continue; + // v3.5.3 + if (afterVal instanceof Date && entity.getField(fieldName).getType() == FieldType.DATE) { + afterVal = CalendarUtils.clearTime((Date) afterVal); + } + Object[] mergedValue = merged.computeIfAbsent(fieldName, k -> new Object[]{null, null}); mergedValue[1] = afterVal; } diff --git a/src/main/java/com/rebuild/core/service/general/RevisionHistoryObserver.java b/src/main/java/com/rebuild/core/service/general/RevisionHistoryObserver.java index 218c9679c..d64088f9e 100644 --- a/src/main/java/com/rebuild/core/service/general/RevisionHistoryObserver.java +++ b/src/main/java/com/rebuild/core/service/general/RevisionHistoryObserver.java @@ -33,6 +33,11 @@ @Slf4j public class RevisionHistoryObserver extends OperatingObserver { + @Override + public int getOrder() { + return 2; + } + @Override protected void updateByAction(OperatingContext ctx) { if (isIgnore(ctx)) return; diff --git a/src/main/java/com/rebuild/core/service/notification/NotificationObserver.java b/src/main/java/com/rebuild/core/service/notification/NotificationObserver.java index 53f994897..79f366899 100644 --- a/src/main/java/com/rebuild/core/service/notification/NotificationObserver.java +++ b/src/main/java/com/rebuild/core/service/notification/NotificationObserver.java @@ -27,6 +27,11 @@ */ public class NotificationObserver extends OperatingObserver { + @Override + public int getOrder() { + return 3; + } + @Override protected boolean isAsync() { // NOTE 异步无法使用 NotificationOnce 功能 diff --git a/src/main/java/com/rebuild/core/service/project/ProjectTaskService.java b/src/main/java/com/rebuild/core/service/project/ProjectTaskService.java index b96163b25..da00ec759 100644 --- a/src/main/java/com/rebuild/core/service/project/ProjectTaskService.java +++ b/src/main/java/com/rebuild/core/service/project/ProjectTaskService.java @@ -126,8 +126,9 @@ public int delete(ID taskId) { "select commentId from ProjectTaskComment where taskId = ?") .setParameter(1, taskId) .array(); + ProjectCommentService pcs = Application.getBean(ProjectCommentService.class); for (Object[] c : comments) { - Application.getBean(ProjectCommentService.class).delete((ID) c[0]); + pcs.delete((ID) c[0]); } // 只有任务本身可以恢复 diff --git a/src/main/java/com/rebuild/core/service/trigger/RobotTriggerObserver.java b/src/main/java/com/rebuild/core/service/trigger/RobotTriggerObserver.java index 6242403e1..f13b7cc17 100644 --- a/src/main/java/com/rebuild/core/service/trigger/RobotTriggerObserver.java +++ b/src/main/java/com/rebuild/core/service/trigger/RobotTriggerObserver.java @@ -8,6 +8,7 @@ package com.rebuild.core.service.trigger; import cn.devezhao.persist4j.engine.ID; +import com.rebuild.core.service.SafeObservable; import com.rebuild.core.service.general.OperatingContext; import com.rebuild.core.service.general.OperatingObserver; import com.rebuild.core.service.general.RepeatedRecordsException; @@ -21,7 +22,6 @@ import org.springframework.core.NamedThreadLocal; import java.util.Map; -import java.util.Observable; import java.util.concurrent.ConcurrentHashMap; import static com.rebuild.core.support.CommonsLog.TYPE_TRIGGER; @@ -40,7 +40,12 @@ public class RobotTriggerObserver extends OperatingObserver { private static final ThreadLocal SKIP_TRIGGERS = new NamedThreadLocal<>("Skip triggers"); @Override - public void update(final Observable o, Object arg) { + public int getOrder() { + return 4; + } + + @Override + public void update(final SafeObservable o, Object arg) { if (isSkipTriggers(false)) return; super.update(o, arg); } diff --git a/src/main/java/com/rebuild/core/service/trigger/impl/SendNotification.java b/src/main/java/com/rebuild/core/service/trigger/impl/SendNotification.java index da9c4e6ba..24f304e47 100644 --- a/src/main/java/com/rebuild/core/service/trigger/impl/SendNotification.java +++ b/src/main/java/com/rebuild/core/service/trigger/impl/SendNotification.java @@ -123,7 +123,7 @@ private Set sendToUsers(OperatingContext operatingContext) { if (msgType == MTYPE_MAIL) { String emailAddr = Application.getUserStore().getUser(user).getEmail(); if (RegexUtils.isEMail(emailAddr)) { - String mdHtml = MarkdownUtils.render(message[0]); + String mdHtml = MarkdownUtils.render(message[0], false, true); SMSender.sendMailAsync(emailAddr, message[1], mdHtml); send.add(emailAddr); } @@ -198,7 +198,7 @@ private Set sendToAccounts(OperatingContext operatingContext, int userTy } if (msgType == MTYPE_MAIL && RegexUtils.isEMail(mobileOrEmail)) { - String mdHtml = MarkdownUtils.render(message[0]); + String mdHtml = MarkdownUtils.render(message[0], false, true); SMSender.sendMailAsync(mobileOrEmail, message[1], mdHtml); send.add(mobileOrEmail); } diff --git a/src/main/java/com/rebuild/core/support/general/FieldValueHelper.java b/src/main/java/com/rebuild/core/support/general/FieldValueHelper.java index b416a1111..a6ecfc808 100644 --- a/src/main/java/com/rebuild/core/support/general/FieldValueHelper.java +++ b/src/main/java/com/rebuild/core/support/general/FieldValueHelper.java @@ -15,6 +15,7 @@ import cn.devezhao.persist4j.metadata.MetadataException; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.JSONObject; import com.rebuild.core.Application; import com.rebuild.core.configuration.general.ClassificationManager; @@ -121,7 +122,13 @@ public static Object wrapFieldValue(Object value, EasyField field) { value = N2NReferenceSupport.items(field.getRawMeta(), (ID) value); } - return field.wrapValue(value); + try { + return field.wrapValue(value); + } catch (JSONException ex) { + log.error("Bad JSONArray format : {} < {}", value, field.getRawMeta()); + return JSONUtils.EMPTY_ARRAY; +// throw new RebuildException("BAD VALUE FORMAT:" + value); + } } /** diff --git a/src/main/java/com/rebuild/core/support/general/QueryParser.java b/src/main/java/com/rebuild/core/support/general/QueryParser.java index ff76252bf..07f3e7b2b 100644 --- a/src/main/java/com/rebuild/core/support/general/QueryParser.java +++ b/src/main/java/com/rebuild/core/support/general/QueryParser.java @@ -239,8 +239,11 @@ private void doParseIfNeed() { this.countSql = this.buildCountSql(pkName) + sqlWhere; int pageNo = NumberUtils.toInt(queryExpr.getString("pageNo"), 1); - int pageSize = NumberUtils.toInt(queryExpr.getString("pageSize"), 20); + int pageSize = NumberUtils.toInt(queryExpr.getString("pageSize"), 40); + pageNo = Math.max(pageNo, 1); + pageSize = Math.max(Math.min(pageSize, 1000), 1); this.limit = new int[] { pageSize, pageNo * pageSize - pageSize }; + this.reload = limit[1] == 0; if (!reload) { reload = BooleanUtils.toBoolean(queryExpr.getString("reload")); diff --git a/src/main/java/com/rebuild/core/support/integration/SMSender.java b/src/main/java/com/rebuild/core/support/integration/SMSender.java index 7056a2e2a..091d39252 100644 --- a/src/main/java/com/rebuild/core/support/integration/SMSender.java +++ b/src/main/java/com/rebuild/core/support/integration/SMSender.java @@ -22,7 +22,11 @@ import com.rebuild.core.support.License; import com.rebuild.core.support.RebuildConfiguration; import com.rebuild.core.support.i18n.Language; -import com.rebuild.utils.*; +import com.rebuild.utils.AppUtils; +import com.rebuild.utils.CommonsUtils; +import com.rebuild.utils.JSONUtils; +import com.rebuild.utils.MarkdownUtils; +import com.rebuild.utils.OkHttpUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.apache.commons.mail.EmailException; @@ -85,13 +89,17 @@ public static String sendMail(String to, String subject, String content) { * @throws ConfigurationException If mail-account unset */ public static String sendMail(String to, String subject, String content, boolean useTemplate, String[] specAccount) throws ConfigurationException { - if (Application.devMode()) return null; if (specAccount == null || specAccount.length < 5 || StringUtils.isBlank(specAccount[0]) || StringUtils.isBlank(specAccount[1]) || StringUtils.isBlank(specAccount[2]) || StringUtils.isBlank(specAccount[3])) { throw new ConfigurationException(Language.L("邮件账户未配置或配置错误")); } + if (Application.devMode()) { + log.info("[dev] Fake send email to : {} / {} / {}", to, subject, content); + return null; + } + // 使用邮件模板 if (useTemplate) { Element mailbody = getMailTemplate(); @@ -132,7 +140,7 @@ public static String sendMail(String to, String subject, String content, boolean return emailId; } catch (EmailException ex) { - log.error("SMTP failed to send : {} | {} | {}", to, subject, content, ex); + log.error("SMTP failed to send : {} / {} / {}", to, subject, content, ex); return null; } } @@ -158,7 +166,7 @@ public static String sendMail(String to, String subject, String content, boolean String r = OkHttpUtils.post("https://api-v4.mysubmail.com/mail/send.json", params); rJson = JSON.parseObject(r); } catch (Exception ex) { - log.error("Submail failed to send : {} | {} | {}", to, subject, content, ex); + log.error("Submail failed to send : {} / {} / {}", to, subject, content, ex); return null; } @@ -169,7 +177,7 @@ public static String sendMail(String to, String subject, String content, boolean return sendId; } - log.error("Submail failed to send : {} | {} | {}\nError : {}", to, subject, content, rJson); + log.error("Submail failed to send : {} / {} / {}\nError : {}", to, subject, content, rJson); createLog(to, logContent, TYPE_EMAIL, null, rJson.getString("msg")); return null; } @@ -185,7 +193,6 @@ public static String sendMail(String to, String subject, String content, boolean * @throws ConfigurationException */ protected static String sendMailViaSmtp(String to, String subject, String htmlContent, String[] specAccount) throws EmailException { - if (Application.devMode()) return null; HtmlEmail email = new HtmlEmail(); email.addTo(to); if (StringUtils.isNotBlank(specAccount[4])) email.addCc(specAccount[4]); @@ -260,13 +267,17 @@ public static String sendSMS(String to, String content) throws ConfigurationExce * @throws ConfigurationException If sms-account unset */ public static String sendSMS(String to, String content, String[] specAccount) throws ConfigurationException { - if (Application.devMode()) return null; if (specAccount == null || specAccount.length < 3 || StringUtils.isBlank(specAccount[0]) || StringUtils.isBlank(specAccount[1]) || StringUtils.isBlank(specAccount[2])) { throw new ConfigurationException(Language.L("短信账户未配置或配置错误")); } + if (Application.devMode()) { + log.warn("[dev] Fake send sms to : {} / {}", to, content); + return null; + } + Map params = new HashMap<>(); params.put("appid", specAccount[0]); params.put("signature", specAccount[1]); @@ -283,7 +294,7 @@ public static String sendSMS(String to, String content, String[] specAccount) th String r = OkHttpUtils.post("https://api-v4.mysubmail.com/sms/send.json", params); rJson = JSON.parseObject(r); } catch (Exception ex) { - log.error("Subsms failed to send : {} | {}", to, content, ex); + log.error("Subsms failed to send : {} / {}", to, content, ex); return null; } finally { HeavyStopWatcher.clean(); @@ -295,7 +306,7 @@ public static String sendSMS(String to, String content, String[] specAccount) th return sendId; } - log.error("Subsms failed to send : {} | {}\nError : {}", to, content, rJson); + log.error("Subsms failed to send : {} / {}\nError : {}", to, content, rJson); createLog(to, content, TYPE_SMS, null, rJson.getString("msg")); return null; } diff --git a/src/main/java/com/rebuild/utils/MarkdownUtils.java b/src/main/java/com/rebuild/utils/MarkdownUtils.java index c17edffd5..bec688b3b 100644 --- a/src/main/java/com/rebuild/utils/MarkdownUtils.java +++ b/src/main/java/com/rebuild/utils/MarkdownUtils.java @@ -51,21 +51,25 @@ public class MarkdownUtils { * * @param md * @return + * @see #render(String, boolean, boolean) */ public static String render(String md) { - return render(md, false); + return render(md, false, false); } /** - * MD 渲染,支持表格,HTML 代码会转义 + * MD 渲染,支持表格 * * @param md * @param targetBlank + * @param keepHtml HTML 代码保持 * @return */ - public static String render(String md, boolean targetBlank) { - md = CommonsUtils.escapeHtml(md); - md = md.replace("> ", "> "); // for MD quote + public static String render(String md, boolean targetBlank, boolean keepHtml) { + if (!keepHtml) { + md = CommonsUtils.escapeHtml(md); + md = md.replace("> ", "> "); // for MD quote + } if (targetBlank) { Node document = PARSER2.parse(md); diff --git a/src/main/java/com/rebuild/web/RebuildWebConfigurer.java b/src/main/java/com/rebuild/web/RebuildWebConfigurer.java index 8bebf0d5a..5ce88a014 100644 --- a/src/main/java/com/rebuild/web/RebuildWebConfigurer.java +++ b/src/main/java/com/rebuild/web/RebuildWebConfigurer.java @@ -89,7 +89,7 @@ public void init() { if (StringUtils.isBlank(pageFooter)) { pageFooterHtml = null; } else { - pageFooterHtml = MarkdownUtils.render(pageFooter, true); + pageFooterHtml = MarkdownUtils.render(pageFooter, true, false); } thymeleafViewResolver.addStaticVariable(WebConstants.PAGE_FOOTER, pageFooterHtml); diff --git a/src/main/resources/web/assets/css/rb-page.css b/src/main/resources/web/assets/css/rb-page.css index 699e54b90..10903171a 100644 --- a/src/main/resources/web/assets/css/rb-page.css +++ b/src/main/resources/web/assets/css/rb-page.css @@ -1326,6 +1326,10 @@ a.link.link-icon::after { top: 119px; } +.rbform .type-NTEXT .CodeMirror { + padding: 8px; +} + .editor-toolbar.fullscreen::before, .editor-toolbar.fullscreen::after { display: none; @@ -4982,7 +4986,7 @@ pre.unstyle { } .dropdown-menu.entity-switch { - min-width: 220px; + width: 235px; } .dropdown-menu.entity-switch .dropdown-item.current, diff --git a/src/main/resources/web/assets/css/view-page.css b/src/main/resources/web/assets/css/view-page.css index 431ed2905..e424a56ca 100644 --- a/src/main/resources/web/assets/css/view-page.css +++ b/src/main/resources/web/assets/css/view-page.css @@ -590,7 +590,7 @@ body { .mdedit-content p, .editor-preview p { margin-bottom: 0.75em !important; - line-height: 1.6 !important; + line-height: 1.428571 !important; } /* over Feeds */ diff --git a/src/main/resources/web/assets/js/admin/apis-manager.js b/src/main/resources/web/assets/js/admin/apis-manager.js index 3d09f02b3..c458c8258 100644 --- a/src/main/resources/web/assets/js/admin/apis-manager.js +++ b/src/main/resources/web/assets/js/admin/apis-manager.js @@ -299,7 +299,7 @@ class AppLogsViewer extends RbModal { return resp.error_code === 0 } catch (err) { try { - return resp.includes('调用成功') || resp.length > 9999 + return resp.includes('调用成功') || resp.length >= 32767 } catch (ignored) { // ignored } diff --git a/src/main/resources/web/assets/js/rb-datalist.common.js b/src/main/resources/web/assets/js/rb-datalist.common.js index be755e888..19fb866da 100644 --- a/src/main/resources/web/assets/js/rb-datalist.common.js +++ b/src/main/resources/web/assets/js/rb-datalist.common.js @@ -1048,6 +1048,10 @@ class RbList extends React.Component { this.setState({ inLoad: true }, () => this._$wrapper.addClass('rb-loading-active')) }, 400) + if (query.filter && (query.filter.items || []).length > 0) { + console.log('API Filter :\n', JSON.stringify(query.filter)) + } + $.post(`/app/${this._entity}/data-list`, JSON.stringify(RbList.queryBefore(query)), (res) => { if (res.error_code === 0) { this.setState({ rowsData: res.data.data || [], inLoad: false }, () => {