diff --git a/@rbv b/@rbv index 017c99f74..f256231e8 160000 --- a/@rbv +++ b/@rbv @@ -1 +1 @@ -Subproject commit 017c99f7496cc86adb2e0b5cc4ca277f0dcc6d61 +Subproject commit f256231e8f0d67ee326d47b65ed9408a0ce9320f diff --git a/SECURITY.md b/SECURITY.md index 83a6fd9da..90c9c5e75 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,9 +4,10 @@ | Version | Supported | | ------- | ------------------ | -| 2.x | :white_check_mark: | +| 3.x | :white_check_mark: | | 1.x | :x: | +| 2.x | :x: | ## Reporting a Vulnerability -Please report security issues to `rebuild@ruifang-tech.com` \ No newline at end of file +Please report security issues to `rebuild@ruifang-tech.com` diff --git a/pom.xml b/pom.xml index d7b2e01bf..a1c70df9a 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.rebuild rebuild - 3.1.0 + 3.1.1 rebuild Building your business-systems freely! diff --git a/src/main/java/com/rebuild/api/ApiGateway.java b/src/main/java/com/rebuild/api/ApiGateway.java index 3025c94b9..93f9f34b6 100644 --- a/src/main/java/com/rebuild/api/ApiGateway.java +++ b/src/main/java/com/rebuild/api/ApiGateway.java @@ -156,7 +156,16 @@ public class ApiGateway extends Controller implements Initialization { final ConfigBean apiConfig = RebuildApiManager.instance.getApp(appid); if (apiConfig == null) { - throw new ApiInvokeException(ApiInvokeException.ERR_BADAUTH, "Invalid [appid] " + appid); + throw new ApiInvokeException(ApiInvokeException.ERR_BADAUTH, "Invalid [appid] : " + appid); + } + + // v3.1.1 + final String bindIps = apiConfig.getString("bindIps"); + if (StringUtils.isNotBlank(bindIps)) { + String clientIp = ServletUtils.getRemoteAddr(request); + if (!bindIps.contains(clientIp)) { + throw new ApiInvokeException(ApiInvokeException.ERR_BADAUTH, "Client ip not in whitelist : " + clientIp); + } } // 验证签名 diff --git a/src/main/java/com/rebuild/api/user/AuthTokenManager.java b/src/main/java/com/rebuild/api/user/AuthTokenManager.java index 73bea6bbc..536654125 100644 --- a/src/main/java/com/rebuild/api/user/AuthTokenManager.java +++ b/src/main/java/com/rebuild/api/user/AuthTokenManager.java @@ -61,7 +61,7 @@ public class AuthTokenManager { System.nanoTime()); String token = EncryptUtils.toSHA1Hex(desc); - Application.getCommonsCache().putx(TOKEN_PREFIX + token, desc, expires); + Application.getCommonsCache().put(TOKEN_PREFIX + token, desc, expires); return token; } diff --git a/src/main/java/com/rebuild/core/Application.java b/src/main/java/com/rebuild/core/Application.java index 702fdbdf6..ef1a7c97d 100644 --- a/src/main/java/com/rebuild/core/Application.java +++ b/src/main/java/com/rebuild/core/Application.java @@ -67,11 +67,11 @@ public class Application implements ApplicationListener /** * Rebuild Version */ - public static final String VER = "3.1.0"; + public static final String VER = "3.1.1"; /** * Rebuild Build [MAJOR]{1}[MINOR]{2}[PATCH]{2}[BUILD]{2} */ - public static final int BUILD = 3010008; + public static final int BUILD = 3010109; static { // Driver for DB diff --git a/src/main/java/com/rebuild/core/configuration/RebuildApiService.java b/src/main/java/com/rebuild/core/configuration/RebuildApiService.java index 3c9d8e5fa..34a49bc49 100644 --- a/src/main/java/com/rebuild/core/configuration/RebuildApiService.java +++ b/src/main/java/com/rebuild/core/configuration/RebuildApiService.java @@ -7,11 +7,14 @@ See LICENSE and COMMERCIAL in the project root for license information. package com.rebuild.core.configuration; +import cn.devezhao.commons.CodecUtils; import cn.devezhao.persist4j.PersistManagerFactory; +import cn.devezhao.persist4j.Record; import cn.devezhao.persist4j.engine.ID; import com.rebuild.core.Application; import com.rebuild.core.metadata.EntityHelper; import com.rebuild.core.privileges.AdminGuard; +import org.apache.commons.lang.math.RandomUtils; import org.springframework.stereotype.Service; /** @@ -32,6 +35,20 @@ public class RebuildApiService extends BaseConfigurationService implements Admin return EntityHelper.RebuildApi; } + @Override + public Record create(Record record) { + record.setString("appId", (100000000 + RandomUtils.nextInt(899999999)) + ""); + record.setString("appSecret", CodecUtils.randomCode(40)); + return super.create(record); + } + + @Override + public Record update(Record record) { + record.removeValue("appId"); + record.removeValue("appSecret"); + return super.update(record); + } + @Override protected void cleanCache(ID cfgid) { Object[] cfg = Application.createQueryNoFilter( diff --git a/src/main/java/com/rebuild/core/configuration/general/FormsBuilder.java b/src/main/java/com/rebuild/core/configuration/general/FormsBuilder.java index 2bc686967..dfb610537 100644 --- a/src/main/java/com/rebuild/core/configuration/general/FormsBuilder.java +++ b/src/main/java/com/rebuild/core/configuration/general/FormsBuilder.java @@ -678,6 +678,13 @@ public class FormsBuilder extends FormsManager { fieldParent = dtf.getName() + "." + pfs[0].split("\\.")[1]; } + // v3.1.1 父级已删除 + Entity entity = MetadataHelper.getEntity(record.getEntityCode()); + if (MetadataHelper.getLastJoinField(entity, fieldParent) == null) { + log.warn("Unknow field : {} in {}", fieldParent, entity.getName()); + return null; + } + Object[] o = Application.getQueryFactory().uniqueNoFilter(record, fieldParent); return o == null ? null : (ID) o[0]; } diff --git a/src/main/java/com/rebuild/core/metadata/EntityRecordCreator.java b/src/main/java/com/rebuild/core/metadata/EntityRecordCreator.java index 07520022b..fdcccf145 100644 --- a/src/main/java/com/rebuild/core/metadata/EntityRecordCreator.java +++ b/src/main/java/com/rebuild/core/metadata/EntityRecordCreator.java @@ -58,7 +58,7 @@ public class EntityRecordCreator extends JsonRecordCreator { final boolean isNew = record.getPrimary() == null; // 明细关联主记录 - if (isNew && isDTF(field)) return true; + if (isNew && isDtmField(field)) return true; // 公共字段前台可能会布局出来 // 此处忽略检查没问题,因为最后还会复写,即 #bindCommonsFieldsValue @@ -107,7 +107,7 @@ public class EntityRecordCreator extends JsonRecordCreator { } } else { if (field.isCreatable()) { - if (!matchsPattern(easyField, hasVal)) { + if (!patternMatches(easyField, hasVal)) { notWells.add(easyField.getLabel()); } } else { @@ -135,7 +135,7 @@ public class EntityRecordCreator extends JsonRecordCreator { } } else { if (field.isUpdatable()) { - if (!matchsPattern(easyField, hasVal)) { + if (!patternMatches(easyField, hasVal)) { notWells.add(easyField.getLabel()); } } else { @@ -157,7 +157,7 @@ public class EntityRecordCreator extends JsonRecordCreator { } // 明细关联主记录字段 - private boolean isDTF(Field field) { + private boolean isDtmField(Field field) { if (field.getType() == FieldType.REFERENCE && entity.getMainEntity() != null) { return field.equals(MetadataHelper.getDetailToMainField(entity)); } @@ -166,7 +166,7 @@ public class EntityRecordCreator extends JsonRecordCreator { // 强制可新建 private boolean isForceCreateable(Field field) { - if (isDTF(field)) return true; + if (isDtmField(field)) return true; // 自定定位 EasyField easyField = EasyMetaFactory.valueOf(field); @@ -178,7 +178,8 @@ public class EntityRecordCreator extends JsonRecordCreator { } // 正则匹配 - private boolean matchsPattern(EasyField easyField, Object val) { + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + private boolean patternMatches(EasyField easyField, Object val) { if (!(easyField instanceof EasyText)) return true; Pattern patt = ((EasyText) easyField).getPattern(); diff --git a/src/main/java/com/rebuild/core/privileges/UserHelper.java b/src/main/java/com/rebuild/core/privileges/UserHelper.java index db1d8407b..e87bdfee3 100644 --- a/src/main/java/com/rebuild/core/privileges/UserHelper.java +++ b/src/main/java/com/rebuild/core/privileges/UserHelper.java @@ -314,18 +314,17 @@ public class UserHelper { */ public static File generateAvatar(String name, boolean forceMake) { if (StringUtils.isBlank(name)) name = "RB"; - File avatarFile = RebuildConfiguration.getFileOfData("avatar-" + name + "29.jpg"); - if (avatarFile.exists()) { + + File avatar = RebuildConfiguration.getFileOfData("avatar-" + name + "29.jpg"); + if (avatar.exists()) { if (forceMake) { - FileUtils.deleteQuietly(avatarFile); + FileUtils.deleteQuietly(avatar); } else { - return avatarFile; + return avatar; } } - if (name.length() > 2) { - name = name.substring(name.length() - 2); - } + if (name.length() > 2) name = name.substring(name.length() - 2); name = name.toUpperCase(); BufferedImage bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB); @@ -347,7 +346,7 @@ public class UserHelper { g2d.drawString("wbr", 0, 62); g2d.dispose(); - try (FileOutputStream fos = new FileOutputStream(avatarFile)) { + try (FileOutputStream fos = new FileOutputStream(avatar)) { ImageIO.write(bi, "png", fos); fos.flush(); } @@ -360,7 +359,7 @@ public class UserHelper { is = CommonsUtils.getStreamOfRes("/web" + DEFAULT_AVATAR); bi = ImageIO.read(is); - try (FileOutputStream fos = new FileOutputStream(avatarFile)) { + try (FileOutputStream fos = new FileOutputStream(avatar)) { ImageIO.write(bi, "png", fos); fos.flush(); } @@ -370,7 +369,7 @@ public class UserHelper { } } - return avatarFile; + return avatar; } private static Font createFont() { @@ -408,7 +407,7 @@ public class UserHelper { * @see #sortUsers(boolean) */ public static User[] sortUsers() { - return sortUsers(false); + return sortUsers(Boolean.FALSE); } /** diff --git a/src/main/java/com/rebuild/core/service/dashboard/ChartManager.java b/src/main/java/com/rebuild/core/service/dashboard/ChartManager.java index 6cee05566..e7058e4c5 100644 --- a/src/main/java/com/rebuild/core/service/dashboard/ChartManager.java +++ b/src/main/java/com/rebuild/core/service/dashboard/ChartManager.java @@ -144,11 +144,12 @@ public class ChartManager implements ConfigManager { } ch.put("title", e.getString("title")); - ch.put("type", e.getString("type")); + String type = e.getString("type"); + ch.put("type", type); try { String c = ((JSONObject) e.getJSON("config")).getJSONObject("option").getString("useColor"); - if (StringUtils.isNotBlank(c)) ch.put("color", c); + if ("INDEX".equals(type) && StringUtils.isNotBlank(c)) ch.put("color", c); } catch (Exception ignore) {} if (user != null) { diff --git a/src/main/java/com/rebuild/core/service/dashboard/charts/TableBuilder.java b/src/main/java/com/rebuild/core/service/dashboard/charts/TableBuilder.java index 74aeb1629..ee8b2856a 100644 --- a/src/main/java/com/rebuild/core/service/dashboard/charts/TableBuilder.java +++ b/src/main/java/com/rebuild/core/service/dashboard/charts/TableBuilder.java @@ -90,33 +90,35 @@ public class TableBuilder { } // 合并纬度单元格 - for (int i = 0; i < chart.getDimensions().length; i++) { - // 行号 - if (chart.isShowLineNumber() && i == 0) continue; + if (chart.isMergeCell()) { + for (int i = 0; i < chart.getDimensions().length; i++) { + // 行号 + if (chart.isShowLineNumber() && i == 0) continue; - TD last = null; - int sumMinus = 0; // 合并的单元格 - int childrenLen = tbody.children.size(); - for (TR tr : tbody.children) { - TD current = tr.children.get(i); - if (last == null || childrenLen-- <= 1) { - last = current; - continue; + TD last = null; + int sumMinus = 0; // 合并的单元格 + int childrenLen = tbody.children.size(); + for (TR tr : tbody.children) { + TD current = tr.children.get(i); + if (last == null || childrenLen-- <= 1) { + last = current; + continue; + } + + if (last.content.equals(current.content)) { + last.rowspan++; + current.rowspan = 0; + sumMinus++; + } else { + last = current; + } } - if (last.content.equals(current.content)) { - last.rowspan++; - current.rowspan = 0; - sumMinus++; - } else { - last = current; + if (chart.isShowSums() && sumMinus > 0 && StringUtils.isNotBlank(last.content)) { + int num = ObjectUtils.toInt(last.content) - sumMinus; + last.content = String.valueOf(num); } } - - if (chart.isShowSums() && sumMinus > 0 && StringUtils.isNotBlank(last.content)) { - int num = ObjectUtils.toInt(last.content) - sumMinus; - last.content = String.valueOf(num); - } } String tClazz = (chart.isShowLineNumber() ? "line-number " : "") + (chart.isShowSums() ? "sums" : ""); diff --git a/src/main/java/com/rebuild/core/service/dashboard/charts/TableChart.java b/src/main/java/com/rebuild/core/service/dashboard/charts/TableChart.java index 3e1d260c8..a5651a060 100644 --- a/src/main/java/com/rebuild/core/service/dashboard/charts/TableChart.java +++ b/src/main/java/com/rebuild/core/service/dashboard/charts/TableChart.java @@ -28,6 +28,7 @@ public class TableChart extends ChartData { private boolean showLineNumber = false; private boolean showSums = false; + private boolean mergeCell = true; protected TableChart(JSONObject config) { super(config); @@ -36,6 +37,7 @@ public class TableChart extends ChartData { if (option != null) { this.showLineNumber = option.getBooleanValue("showLineNumber"); this.showSums = option.getBooleanValue("showSums"); + if (option.containsKey("mergeCell")) this.mergeCell = option.getBooleanValue("mergeCell"); } } @@ -96,6 +98,10 @@ public class TableChart extends ChartData { return showSums; } + protected boolean isMergeCell() { + return mergeCell; + } + protected String wrapSumValue(Axis sumAxis, Object value) { if (ChartsHelper.isZero(value)) { return ChartsHelper.VALUE_ZERO; diff --git a/src/main/java/com/rebuild/core/service/dataimport/RecordCheckout.java b/src/main/java/com/rebuild/core/service/dataimport/RecordCheckout.java index 8d4623c10..1c92014aa 100644 --- a/src/main/java/com/rebuild/core/service/dataimport/RecordCheckout.java +++ b/src/main/java/com/rebuild/core/service/dataimport/RecordCheckout.java @@ -180,11 +180,11 @@ public class RecordCheckout { // 支持ID if (ID.isId(val) && ID.valueOf(val).getEntityCode() == EntityHelper.ClassificationData) { - ID iid = ID.valueOf(val); - if (ClassificationManager.instance.getName(iid) != null) { - return iid; + ID cid = ID.valueOf(val); + if (ClassificationManager.instance.getName(cid) != null) { + return cid; } else { - log.warn("No item of Classification found by ID : " + iid); + log.warn("No item of Classification found by ID : " + cid); return null; } } else { diff --git a/src/main/java/com/rebuild/core/service/query/AdvFilterParser.java b/src/main/java/com/rebuild/core/service/query/AdvFilterParser.java index 98a7b8562..2d5ec69fb 100644 --- a/src/main/java/com/rebuild/core/service/query/AdvFilterParser.java +++ b/src/main/java/com/rebuild/core/service/query/AdvFilterParser.java @@ -486,7 +486,7 @@ public class AdvFilterParser extends SetUser { if (VF_ACU.equals(field)) { return String.format( - "(exists (select recordId from RobotApprovalStep where ^%s = recordId and state = 1 and %s) and approvalState = 2)", + "(exists (select recordId from RobotApprovalStep where ^%s = recordId and state = 1 and isCanceled = 'F' and %s) and approvalState = 2)", specRootEntity.getPrimaryField().getName(), sb.toString().replace(VF_ACU, "approver")); } else { return sb.toString(); diff --git a/src/main/java/com/rebuild/core/service/trigger/ActionContext.java b/src/main/java/com/rebuild/core/service/trigger/ActionContext.java index 0298137b3..5ddb12a99 100644 --- a/src/main/java/com/rebuild/core/service/trigger/ActionContext.java +++ b/src/main/java/com/rebuild/core/service/trigger/ActionContext.java @@ -73,4 +73,9 @@ public class ActionContext { public ID getConfigId() { return configId; } + + @Override + public String toString() { + return super.toString() + "#" + getConfigId(); + } } diff --git a/src/main/java/com/rebuild/core/service/trigger/ActionType.java b/src/main/java/com/rebuild/core/service/trigger/ActionType.java index 90a90886a..760b2e21e 100644 --- a/src/main/java/com/rebuild/core/service/trigger/ActionType.java +++ b/src/main/java/com/rebuild/core/service/trigger/ActionType.java @@ -33,6 +33,7 @@ public enum ActionType { AUTOASSIGN("自动分派", AutoAssign.class), SENDNOTIFICATION("发送通知", SendNotification.class), HOOKURL("回调 URL", "com.rebuild.rbv.trigger.HookUrl"), + PROXYTRIGGERACTION("自定义触发器", "com.rebuild.rbv.trigger.ProxyTriggerAction"), ; diff --git a/src/main/java/com/rebuild/core/service/trigger/aviator/AviatorUtils.java b/src/main/java/com/rebuild/core/service/trigger/aviator/AviatorUtils.java index 827ab591e..6b142a53a 100644 --- a/src/main/java/com/rebuild/core/service/trigger/aviator/AviatorUtils.java +++ b/src/main/java/com/rebuild/core/service/trigger/aviator/AviatorUtils.java @@ -49,9 +49,10 @@ public class AviatorUtils { addCustomFunction(new CurrentBizunitFunction()); addCustomFunction(new CurrentDateFunction()); addCustomFunction(new LocationDistanceFunction()); - addCustomFunction(new RequestFunctuin()); - addCustomFunction(new TextFunction()); addCustomFunction(new ChineseYuanFunction()); + addCustomFunction(new TextFunction()); + addCustomFunction(new RequestFunctuin()); + addCustomFunction(new SqlQueryFunction()); } /** diff --git a/src/main/java/com/rebuild/core/service/trigger/aviator/SqlQueryFunction.java b/src/main/java/com/rebuild/core/service/trigger/aviator/SqlQueryFunction.java new file mode 100644 index 000000000..89780b421 --- /dev/null +++ b/src/main/java/com/rebuild/core/service/trigger/aviator/SqlQueryFunction.java @@ -0,0 +1,101 @@ +/*! +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.trigger.aviator; + +import cn.devezhao.persist4j.Query; +import cn.devezhao.persist4j.engine.ID; +import com.googlecode.aviator.runtime.function.AbstractFunction; +import com.googlecode.aviator.runtime.type.AviatorDecimal; +import com.googlecode.aviator.runtime.type.AviatorNil; +import com.googlecode.aviator.runtime.type.AviatorObject; +import com.googlecode.aviator.runtime.type.AviatorString; +import com.rebuild.core.Application; +import lombok.extern.slf4j.Slf4j; + +import java.util.Date; +import java.util.Map; + +/** + * Usage: SQLQUERY($sql, [ $param...{5} ]) + * Return: Number|Date|String + * + * @author RB + * @since 2022/11/10 + */ +@Slf4j +public class SqlQueryFunction extends AbstractFunction { + private static final long serialVersionUID = 6408510455471045309L; + + @Override + public AviatorObject call(Map env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5, AviatorObject arg6) { + String $sql = arg1.getValue(env).toString(); + Query query = Application.createQueryNoFilter($sql); + + Object param1 = getValue(env, arg2); + if (param1 != null) query.setParameter(1, param1); + Object param2 = getValue(env, arg3); + if (param2 != null) query.setParameter(2, param2); + Object param3 = getValue(env, arg4); + if (param3 != null) query.setParameter(3, param3); + Object param4 = getValue(env, arg5); + if (param4 != null) query.setParameter(4, param4); + Object param5 = getValue(env, arg6); + if (param5 != null) query.setParameter(5, param5); + + Object[] o = query.unique(); + if (o == null || o[0] == null) return AviatorNil.NIL; + + final Object value = o[0]; + + if (value instanceof Number) { + return new AviatorDecimal((Number) value); + } else if (value instanceof Date) { + return new AviatorDate((Date) value); + } else { + return new AviatorString(value.toString()); + } + } + + private Object getValue(Map env, AviatorObject arg) { + Object value = arg.getValue(env); + if (value == null) return null; + + if (value instanceof Number || value instanceof Date || value instanceof ID) return value; + else return value.toString(); + } + + @Override + public AviatorObject call(Map env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5) { + return this.call(env, arg1, arg2, arg3, arg4, arg5, AviatorNil.NIL); + } + + @Override + public AviatorObject call(Map env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4) { + return this.call(env, arg1, arg2, arg3, arg4, AviatorNil.NIL); + } + + @Override + public AviatorObject call(Map env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3) { + return this.call(env, arg1, arg2, arg3, AviatorNil.NIL); + } + + @Override + public AviatorObject call(Map env, AviatorObject arg1, AviatorObject arg2) { + return this.call(env, arg1, arg2, AviatorNil.NIL); + } + + @Override + public AviatorObject call(Map env, AviatorObject arg1) { + return this.call(env, arg1, AviatorNil.NIL); + } + + @Override + public String getName() { + return "SQLQUERY"; + } +} diff --git a/src/main/java/com/rebuild/core/support/setup/Installer.java b/src/main/java/com/rebuild/core/support/setup/Installer.java index d2062153c..a8546c5d6 100644 --- a/src/main/java/com/rebuild/core/support/setup/Installer.java +++ b/src/main/java/com/rebuild/core/support/setup/Installer.java @@ -37,6 +37,7 @@ import org.apache.commons.lang.StringUtils; import org.springframework.util.Assert; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; +import redis.clients.jedis.args.FlushMode; import javax.sql.DataSource; import java.io.File; @@ -518,9 +519,12 @@ public class Installer implements InstallState { public static void clearAllCache() { if (isUseRedis()) { try (Jedis jedis = Application.getCommonsCache().getJedisPool().getResource()) { -// // Delete all the keys of the currently selected DB -// jedis.flushDB(FlushMode.SYNC); - jedis.flushAll(); + // https://redis.io/commands/flushdb/ + try { + jedis.flushDB(FlushMode.SYNC); // v6.2.0 + } catch (Exception v620) { + jedis.flushDB(); + } } } else { Application.getCommonsCache().getEhcacheCache().clear(); diff --git a/src/main/java/com/rebuild/utils/AppUtils.java b/src/main/java/com/rebuild/utils/AppUtils.java index c60c9dce8..b880b3cde 100644 --- a/src/main/java/com/rebuild/utils/AppUtils.java +++ b/src/main/java/com/rebuild/utils/AppUtils.java @@ -92,9 +92,7 @@ public class AppUtils { */ public static ID getRequestUser(HttpServletRequest request, boolean refreshToken) { Object user = request.getSession().getAttribute(WebUtils.CURRENT_USER); - if (user == null) { - user = getRequestUserViaToken(request, refreshToken); - } + if (user == null) user = getRequestUserViaToken(request, refreshToken); return user == null ? null : (ID) user; } diff --git a/src/main/java/com/rebuild/utils/CommonsUtils.java b/src/main/java/com/rebuild/utils/CommonsUtils.java index eb83c3ef2..15cda14e0 100644 --- a/src/main/java/com/rebuild/utils/CommonsUtils.java +++ b/src/main/java/com/rebuild/utils/CommonsUtils.java @@ -39,7 +39,7 @@ public class CommonsUtils { private static final char[] SPECIAL_CHARS = "`~!@#$%^&*()_+=-{}|[];':\",./<>?".toCharArray(); /** - * 不含特殊字符。不允许除 数字 字母 中文 及 _ - 以外的字符,包括空格 + * 不含特殊字符。不允许除 `数字` `字母` `中文` `_` `-` 及空格以外的字符 * * @param text * @return diff --git a/src/main/java/com/rebuild/web/admin/AdminCLI2.java b/src/main/java/com/rebuild/web/admin/AdminCLI2.java index 15e64a585..ea1016402 100644 --- a/src/main/java/com/rebuild/web/admin/AdminCLI2.java +++ b/src/main/java/com/rebuild/web/admin/AdminCLI2.java @@ -7,6 +7,7 @@ See LICENSE and COMMERCIAL in the project root for license information. package com.rebuild.web.admin; +import com.rebuild.core.Application; import com.rebuild.core.support.ConfigurationItem; import com.rebuild.core.support.RebuildConfiguration; import com.rebuild.core.support.setup.DatabaseBackup; @@ -64,7 +65,7 @@ public class AdminCLI2 { case C_HELP: case "?" : { result = " Usage : " + - " \ncache clean" + + " \ncache [clean|get] [KEY]" + " \nsyscfg NAME [VALUE]" + " \nsyscfg clean-qiniu|clean-sms|clean-email" + " \nbackup [database|datafile]" + @@ -108,6 +109,12 @@ public class AdminCLI2 { String name = commands[1]; if ("clean".equals(name)) { Installer.clearAllCache(); + } else if ("get".equals(name)) { + if (commands.length < 3) return "WRAN: Bad arguments"; + String key = commands[2]; + Object value = Application.getCommonsCache().getx(key); + if (value == null) result = "/NULL/"; + else result = value.toString(); } else { result = "WRAN: Bad arguments"; } diff --git a/src/main/java/com/rebuild/web/admin/ApisManagerController.java b/src/main/java/com/rebuild/web/admin/ApisManagerController.java index 3fe4dc184..54fef73ed 100644 --- a/src/main/java/com/rebuild/web/admin/ApisManagerController.java +++ b/src/main/java/com/rebuild/web/admin/ApisManagerController.java @@ -17,8 +17,8 @@ import com.rebuild.core.configuration.RebuildApiService; import com.rebuild.core.metadata.EntityHelper; import com.rebuild.core.support.i18n.I18nUtils; import com.rebuild.web.BaseController; -import org.apache.commons.lang.math.RandomUtils; 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.servlet.ModelAndView; @@ -39,10 +39,10 @@ public class ApisManagerController extends BaseController { return createModelAndView("/admin/integration/apis-manager"); } - @RequestMapping("apis-manager/app-list") + @GetMapping("apis-manager/app-list") public RespBody appList() { Object[][] apps = Application.createQueryNoFilter( - "select uniqueId,appId,appSecret,bindUser,bindUser.fullName,createdOn,appId from RebuildApi") + "select uniqueId,appId,appSecret,bindUser,bindUser.fullName,createdOn,appId,bindIps from RebuildApi order by createdOn") .array(); // 近30日用量 @@ -60,24 +60,15 @@ public class ApisManagerController extends BaseController { return RespBody.ok(apps); } - @RequestMapping("apis-manager/app-create") - public RespBody appCreate(HttpServletRequest request) { - ID user = getRequestUser(request); - ID bindUser = getIdParameter(request, "bind"); - - Record record = EntityHelper.forNew(EntityHelper.RebuildApi, user); - record.setString("appId", (100000000 + RandomUtils.nextInt(899999999)) + ""); + @PostMapping("apis-manager/reset-secret") + public RespBody resetSecret(HttpServletRequest request) { + ID appId = getIdParameterNotNull(request, "id"); + Record record = EntityHelper.forUpdate(appId, getRequestUser(request)); record.setString("appSecret", CodecUtils.randomCode(40)); - record.setID("bindUser", bindUser); - Application.getBean(RebuildApiService.class).create(record); + Application.getCommonsService().update(record, false); - return RespBody.ok(); - } - - @RequestMapping("apis-manager/app-delete") - public RespBody appDelete(HttpServletRequest request) { - ID id = getIdParameterNotNull(request, "id"); - Application.getBean(RebuildApiService.class).delete(id); + // cache + Application.getBean(RebuildApiService.class).update(record); return RespBody.ok(); } } diff --git a/src/main/java/com/rebuild/web/admin/setup/InstallController.java b/src/main/java/com/rebuild/web/admin/setup/InstallController.java index 57ed90959..132de4cf9 100644 --- a/src/main/java/com/rebuild/web/admin/setup/InstallController.java +++ b/src/main/java/com/rebuild/web/admin/setup/InstallController.java @@ -13,6 +13,7 @@ import cn.devezhao.commons.web.ServletUtils; import com.alibaba.fastjson.JSONObject; import com.rebuild.api.RespBody; import com.rebuild.core.Application; +import com.rebuild.core.RebuildException; import com.rebuild.core.support.License; import com.rebuild.core.support.i18n.Language; import com.rebuild.core.support.setup.InstallState; @@ -34,7 +35,6 @@ import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.sql.Connection; import java.sql.DatabaseMetaData; @@ -50,13 +50,17 @@ import java.sql.SQLException; @RequestMapping("/setup/") public class InstallController extends BaseController implements InstallState { - @GetMapping("install") - public ModelAndView index(HttpServletRequest request, HttpServletResponse response) throws IOException { - if (Application.isReady() && !Application.devMode()) { - response.sendError(404); - return null; + @Override + public boolean checkInstalled() { + if (InstallState.super.checkInstalled() && Application.isReady()) { + throw new RebuildException("NOT ALLOWED"); } + return false; + } + @GetMapping("install") + public ModelAndView index(HttpServletRequest request) throws IOException { + checkInstalled(); ModelAndView mv = createModelAndView("/admin/setup/install"); mv.getModel().put("Version", Application.VER); @@ -68,6 +72,7 @@ public class InstallController extends BaseController implements InstallState { @PostMapping("test-connection") public RespBody testConnection(HttpServletRequest request) { + checkInstalled(); JSONObject dbProps = (JSONObject) ServletUtils.getRequestJson(request); JSONObject props = JSONUtils.toJSONObject("databaseProps", dbProps); @@ -108,6 +113,7 @@ public class InstallController extends BaseController implements InstallState { @PostMapping("test-cache") public RespBody testCache(HttpServletRequest request) { + checkInstalled(); JSONObject cacheProps = (JSONObject) ServletUtils.getRequestJson(request); JedisPool pool = new JedisPool(new JedisPoolConfig(), @@ -133,6 +139,7 @@ public class InstallController extends BaseController implements InstallState { @PostMapping("install-rebuild") public RespBody installExec(HttpServletRequest request) { + checkInstalled(); JSONObject installProps = (JSONObject) ServletUtils.getRequestJson(request); try { @@ -146,6 +153,7 @@ public class InstallController extends BaseController implements InstallState { @GetMapping("request-sn") public RespBody requestSn() { + checkInstalled(); return RespBody.ok(License.SN()); } } diff --git a/src/main/java/com/rebuild/web/user/signup/LoginAction.java b/src/main/java/com/rebuild/web/user/signup/LoginAction.java index d48d6799a..62e919ac6 100644 --- a/src/main/java/com/rebuild/web/user/signup/LoginAction.java +++ b/src/main/java/com/rebuild/web/user/signup/LoginAction.java @@ -16,14 +16,15 @@ import cn.devezhao.persist4j.Record; import cn.devezhao.persist4j.engine.ID; import com.rebuild.api.user.AuthTokenManager; import com.rebuild.core.Application; +import com.rebuild.core.cache.CommonsCache; import com.rebuild.core.metadata.EntityHelper; import com.rebuild.core.privileges.UserService; import com.rebuild.core.privileges.bizz.User; import com.rebuild.core.support.KVStorage; import com.rebuild.core.support.License; import com.rebuild.core.support.task.TaskExecutors; -import com.rebuild.utils.AES; import com.rebuild.web.BaseController; +import com.rebuild.web.user.UserAvatar; import eu.bitwalker.useragentutils.DeviceType; import eu.bitwalker.useragentutils.OperatingSystem; import eu.bitwalker.useragentutils.UserAgent; @@ -49,7 +50,8 @@ public class LoginAction extends BaseController { protected static final String SK_NEED_VCODE = "needLoginVCode"; protected static final String SK_START_TOUR = "needStartTour"; - protected static final String PREFIX_2FA = "2FA"; + protected static final String PREFIX_2FA = "2FA:"; + protected static final String PREFIX_ALT = "ALT:"; /** * 登录成功 @@ -63,8 +65,9 @@ public class LoginAction extends BaseController { protected Integer loginSuccessed(HttpServletRequest request, HttpServletResponse response, ID user, boolean autoLogin) { // 自动登录 if (autoLogin) { - String alt = user + "," + System.currentTimeMillis() + ",v1"; - ServletUtils.addCookie(response, CK_AUTOLOGIN, AES.encrypt(alt)); + final String altToken = CodecUtils.randomCode(60); + Application.getCommonsCache().putx(PREFIX_ALT + altToken, user, CommonsCache.TS_DAY * 14); + ServletUtils.addCookie(response, CK_AUTOLOGIN, altToken); } else { ServletUtils.removeCookie(request, response, CK_AUTOLOGIN); } @@ -75,6 +78,9 @@ public class LoginAction extends BaseController { ServletUtils.setSessionAttribute(request, SK_USER_THEME, KVStorage.getCustomValue("THEME." + user)); Application.getSessionStore().storeLoginSuccessed(request); + // 头像缓存 + ServletUtils.setSessionAttribute(request, UserAvatar.SK_DAVATAR, System.currentTimeMillis()); + // TOUR 显示规则 Object[] initLoginTimes = Application.createQueryNoFilter( "select count(loginTime) from LoginLog where user = ? and loginTime > '2022-01-01'") diff --git a/src/main/java/com/rebuild/web/user/signup/LoginController.java b/src/main/java/com/rebuild/web/user/signup/LoginController.java index 27e6c13d3..d544cbbab 100644 --- a/src/main/java/com/rebuild/web/user/signup/LoginController.java +++ b/src/main/java/com/rebuild/web/user/signup/LoginController.java @@ -8,7 +8,6 @@ See LICENSE and COMMERCIAL in the project root for license information. package com.rebuild.web.user.signup; import cn.devezhao.commons.CodecUtils; -import cn.devezhao.commons.ObjectUtils; import cn.devezhao.commons.RegexUtils; import cn.devezhao.commons.web.ServletUtils; import cn.devezhao.persist4j.Record; @@ -28,9 +27,7 @@ import com.rebuild.core.service.DataSpecificationException; import com.rebuild.core.support.*; import com.rebuild.core.support.i18n.Language; import com.rebuild.core.support.integration.SMSender; -import com.rebuild.utils.AES; import com.rebuild.utils.AppUtils; -import com.rebuild.web.user.UserAvatar; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.springframework.web.bind.annotation.GetMapping; @@ -85,28 +82,9 @@ public class LoginController extends LoginAction { // 记住登录 final String useAlt = ServletUtils.readCookie(request, CK_AUTOLOGIN); if (StringUtils.isNotBlank(useAlt)) { - ID altUser = null; - try { - String[] alts = AES.decrypt(useAlt).split(","); - altUser = alts.length == 3 && ID.isId(alts[0]) ? ID.valueOf(alts[0]) : null; + final ID altUser = (ID) Application.getCommonsCache().getx(PREFIX_ALT + useAlt); - // 最大30天有效期 - if (altUser != null) { - long t = ObjectUtils.toLong(alts[1]); - if ((System.currentTimeMillis() - t) / 1000 > 30 * 24 * 60 * 60) { - altUser = null; - } - if (altUser != null && !UserHelper.isActive(altUser)) { - altUser = null; - } - } - - } catch (Exception ex) { - ServletUtils.removeCookie(request, response, CK_AUTOLOGIN); - log.error("Cannot decode User from alt : {}", useAlt, ex); - } - - if (altUser != null && Application.getUserStore().existsUser(altUser)) { + if (altUser != null && UserHelper.isActive(altUser)) { Integer ed = loginSuccessed(request, response, altUser, true); String nexturl = getParameter(request, "nexturl", homeUrl); @@ -183,8 +161,6 @@ public class LoginController extends LoginAction { // 清理验证码 getLoginRetryTimes(user, -1); ServletUtils.setSessionAttribute(request, SK_NEED_VCODE, null); - // 头像缓存 - ServletUtils.setSessionAttribute(request, UserAvatar.SK_DAVATAR, System.currentTimeMillis()); final User loginUser = Application.getUserStore().getUser(user); final boolean isRbMobile = AppUtils.isRbMobile(request); @@ -197,8 +173,8 @@ public class LoginController extends LoginAction { if (faMode > 0 && !faModeSkip) { resMap.put("login2FaMode", faMode); - String userToken = CodecUtils.randomCode(40); - Application.getCommonsCache().putx(PREFIX_2FA + userToken, loginUser.getId(), 15 * 60); // 15m + final String userToken = CodecUtils.randomCode(40); + Application.getCommonsCache().putx(PREFIX_2FA + userToken, loginUser.getId(), CommonsCache.TS_MINTE * 15); resMap.put("login2FaUserToken", userToken); if (isRbMobile) { diff --git a/src/main/resources/i18n/lang.zh_CN.json b/src/main/resources/i18n/lang.zh_CN.json index c8748de7c..821c3438d 100644 --- a/src/main/resources/i18n/lang.zh_CN.json +++ b/src/main/resources/i18n/lang.zh_CN.json @@ -2369,5 +2369,15 @@ "批量添加字段":"批量添加字段", "支持 H5":"支持 H5", "手机登录":"手机登录", - "批量添加":"批量添加" + "批量添加":"批量添加", + "触发类 (TriggerAction)":"触发类 (TriggerAction)", + "无 (不限制)":"无 (不限制)", + "重置 APP SECRET":"重置 APP SECRET", + "自定义触发器":"自定义触发器", + "白名单内的 IP 才可以通过此 API 秘钥调用接口,如有多个 IP 请使用逗号或空格分开,留空则不限制":"白名单内的 IP 才可以通过此 API 秘钥调用接口,如有多个 IP 请使用逗号或空格分开,留空则不限制", + "配色":"配色", + "APP SECRET 已重置":"APP SECRET 已重置", + "修改 API 秘钥":"修改 API 秘钥", + "自动合并单元格":"自动合并单元格", + "重置后第三方应用需更换新的 APP SECRET 使用":"重置后第三方应用需更换新的 APP SECRET 使用" } diff --git a/src/main/resources/web/admin/integration/apis-manager.html b/src/main/resources/web/admin/integration/apis-manager.html index cb54849bf..e76505665 100644 --- a/src/main/resources/web/admin/integration/apis-manager.html +++ b/src/main/resources/web/admin/integration/apis-manager.html @@ -27,12 +27,13 @@ - - - - + + + + + - + @@ -57,6 +58,7 @@ + diff --git a/src/main/resources/web/admin/metadata/picklist-editor.html b/src/main/resources/web/admin/metadata/picklist-editor.html index 33418710e..59a5181ff 100644 --- a/src/main/resources/web/admin/metadata/picklist-editor.html +++ b/src/main/resources/web/admin/metadata/picklist-editor.html @@ -17,35 +17,8 @@ .unset-list .dd-item:hover a.action { color: #fff; } - - .colors { - line-height: 1; - font-size: 0; - } - .colors > a { - width: 24px; - height: 24px; - display: inline-block; - background-color: #ccc; - border-radius: 50%; - color: #fff; - overflow: hidden; - font-size: 1.3rem; - padding-top: 4px; - text-align: center; - } - .colors > a:hover { - opacity: 0.8; - color: rgb(117, 0, 234); - } - .colors > a + a { - margin-left: 9px; - } - .colors > a > i { - color: #fff !important; - } - .colors > a:first-child > i { - color: #aaa !important; + .rbcolors > a:first-child > i { + color: #777 !important; } @@ -64,7 +37,7 @@ -
+
diff --git a/src/main/resources/web/assets/css/chart-design.css b/src/main/resources/web/assets/css/chart-design.css index 31e32709a..745e8616f 100644 --- a/src/main/resources/web/assets/css/chart-design.css +++ b/src/main/resources/web/assets/css/chart-design.css @@ -429,3 +429,11 @@ a.ui-draggable.ui-draggable-dragging { .chart-type > a.active > i.C243 { background-position: -1290px -1288px; } + +.rbcolors > a:first-child > i { + color: #777 !important; +} + +.chart-option label { + margin-bottom: 10px; +} \ No newline at end of file diff --git a/src/main/resources/web/assets/css/charts.css b/src/main/resources/web/assets/css/charts.css index b3c7e0256..1fadebc49 100644 --- a/src/main/resources/web/assets/css/charts.css +++ b/src/main/resources/web/assets/css/charts.css @@ -122,6 +122,7 @@ See LICENSE and COMMERCIAL in the project root for license information. font-size: 1.1rem; margin-bottom: 1px; opacity: 0.8; + line-height: 1; } .chart.index > .data-item strong { @@ -129,6 +130,15 @@ See LICENSE and COMMERCIAL in the project root for license information. font-weight: 400; } +.grid-stack-item.fullscreen .chart.index > .data-item p { + font-size: 3rem; +} + +.grid-stack-item.fullscreen .chart.index > .data-item strong { + font-size: 8.8rem; + zoom: 1 !important; +} + .chart.index > .data-item a { color: #404040; } @@ -453,17 +463,30 @@ See LICENSE and COMMERCIAL in the project root for license information. display: none !important; } -/* useColor */ +/* Colors */ -.grid-stack-item.color .grid-stack-item-content, -.grid-stack-item.color .chart.index > .data-item strong { +.grid-stack-item.bgcolor .grid-stack-item-content, +.grid-stack-item.bgcolor .chart.index > .data-item strong { color: #fff; } -.grid-stack-item.color .rb-loading:after { +.grid-stack-item.bgcolor .rb-loading:after { background-color: transparent; } -.grid-stack-item.color .rb-spinner svg { +.grid-stack-item.bgcolor .rb-spinner svg { stroke: #fff; } + +body.fullscreen { + background: #0a1b3b url(../img/datav-bg.png) no-repeat 0 0; + background-size: 100% 100%; +} + +body.fullscreen .grid-stack .grid-stack-item .grid-stack-item-content { + background-color: rgba(6, 30, 93, 0.5); +} + +body.fullscreen .grid-stack .grid-stack-item.fullscreen .grid-stack-item-content { + background-color: #0a1b3b; +} \ No newline at end of file diff --git a/src/main/resources/web/assets/css/rb-page.css b/src/main/resources/web/assets/css/rb-page.css index 163aaf92c..d036842de 100644 --- a/src/main/resources/web/assets/css/rb-page.css +++ b/src/main/resources/web/assets/css/rb-page.css @@ -4979,3 +4979,34 @@ pre.unstyle { .modal-title > .support-plat2 { margin-top: 7px; } + +.rbcolors { + line-height: 1; + font-size: 0; +} + +.rbcolors > a { + width: 24px; + height: 24px; + display: inline-block; + background-color: #ccc; + border-radius: 50%; + color: #fff; + overflow: hidden; + font-size: 1.3rem; + padding-top: 4px; + text-align: center; +} + +.rbcolors > a:hover { + opacity: 0.8; + color: rgb(117, 0, 234); +} + +.rbcolors > a + a { + margin-left: 7px; +} + +.rbcolors > a > i { + color: #fff !important; +} diff --git a/src/main/resources/web/assets/css/task-view.css b/src/main/resources/web/assets/css/task-view.css index 662d14291..318eba3be 100644 --- a/src/main/resources/web/assets/css/task-view.css +++ b/src/main/resources/web/assets/css/task-view.css @@ -194,6 +194,7 @@ See LICENSE and COMMERCIAL in the project root for license information. padding: 4px 9px 0; margin-right: 4px; margin-top: 1px; + cursor: default; } .task-tags > span.tag-value > a { @@ -219,12 +220,13 @@ See LICENSE and COMMERCIAL in the project root for license information. .task-tags a.tag-add { color: #999; display: inline-block; - padding: 2px 8px; + padding: 2px; font-size: 1.231rem; background-color: #eee; border-radius: 50%; width: 26px; height: 26px; + text-align: center; } .task-tags a.tag-add:hover { @@ -249,28 +251,10 @@ See LICENSE and COMMERCIAL in the project root for license information. opacity: 0.8; } -.tags-editor .colors > a { +.tags-editor .rbcolors > a { width: 22px; height: 22px; - display: inline-block; - background-color: #ccc; - border-radius: 50%; - color: #fff; - overflow: hidden; - font-size: 1.3rem; - padding-top: 4px; -} - -.tags-editor .colors > a:hover { - opacity: 0.8; -} - -.tags-editor .colors > a + a { - margin-left: 7px; -} - -.tags-editor .colors > a > i { - color: #fff !important; + font-size: 1.2rem; } .dropdown-menu.tags { @@ -326,6 +310,7 @@ See LICENSE and COMMERCIAL in the project root for license information. padding-left: 4px; font-size: 1.25rem; display: none; + cursor: pointer; } .tags-list .dropdown-item:hover > a { diff --git a/src/main/resources/web/assets/img/datav-bg.png b/src/main/resources/web/assets/img/datav-bg.png new file mode 100644 index 000000000..54aa0457f Binary files /dev/null and b/src/main/resources/web/assets/img/datav-bg.png differ 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 c69cea4de..61b56d11a 100644 --- a/src/main/resources/web/assets/js/admin/apis-manager.js +++ b/src/main/resources/web/assets/js/admin/apis-manager.js @@ -4,41 +4,50 @@ Copyright (c) REBUILD and/or its owners. All rights re rebuild is dual-licensed under commercial and open source licenses (GPLv3). See LICENSE and COMMERCIAL in the project root for license information. */ +/* global dlgActionAfter */ $(document).ready(function () { - $('.J_add').on('click', () => renderRbcomp()) + $('.J_add').on('click', () => renderRbcomp()) renderRbcomp(, 'appList') }) -class AppList extends React.Component { +class AppList extends ConfigList { constructor(props) { super(props) - this.state = { ...props, secretShows: [] } + this.requestUrl = '/admin/apis-manager/app-list' + this.state.secretShows = [] } render() { return ( - {(this.state.list || []).map((item) => { - let secret = item[2].substr(0, 8) + '...' + item[2].substr(32) + {(this.state.data || []).map((item) => { + let secret = `${item[2].substr(0, 8)}...${item[2].substr(32)}` secret = ( - this.showSecret(item[2])}> + this.showSecret(e, item[2])}> {secret} ) if (this.state.secretShows.includes(item[2])) secret = item[2] return ( -
+ + @@ -49,84 +58,85 @@ class AppList extends React.Component { ) } - componentDidMount = () => this._componentDidMount() - - _componentDidMount() { - $.get('/admin/apis-manager/app-list', (res) => { - const _data = res.data || [] - this.setState({ list: _data }, () => { - $('.rb-loading-active').removeClass('rb-loading-active') - $('.dataTables_info').text($L('共 %d 项', _data.length)) - if (_data.length === 0) $('.list-nodata').removeClass('hide') - }) - }) + handleEdit(app) { + renderRbcomp() } - showSecret(s) { - event.preventDefault() - const shows = this.state.secretShows - shows.push(s) - this.setState({ secretShows: shows }) - } - - delete(app) { - const that = this + handleDelete(app) { + const handle = super.handleDelete RbAlert.create($L('删除后,使用此 API 秘钥的第三方应用功能将会失败'), { type: 'danger', confirmText: $L('删除'), - confirm: function () { + onConfirm: function () { this.disabled(true) - $.post(`/admin/apis-manager/app-delete?id=${app[0]}`, (res) => { - if (res.error_code === 0) { - RbHighbar.success($L('删除成功')) - that._componentDidMount() - this.hide() - } else { - RbHighbar.error(res.error_msg) - } + handle(app[0], () => dlgActionAfter(this)) + }, + }) + } + + resetSecret(id) { + RbAlert.create($L('重置后第三方应用需更换新的 APP SECRET 使用'), { + type: 'danger', + confirmText: $L('重置'), + onConfirm: function () { + this.disabled(true) + $.post(`/admin/apis-manager/reset-secret?id=${id}`, () => { + RbHighbar.success($L('APP SECRET 已重置')) + dlgActionAfter(this) }) }, }) } + + showSecret(e, s) { + $stopEvent(e, true) + const shows = this.state.secretShows + shows.push(s) + this.setState({ secretShows: shows }) + } } -class DlgEdit extends RbFormHandler { +class AppEdit extends ConfigFormDlg { constructor(props) { super(props) - this.state = { ...props } + this.title = props.id ? $L('修改 API 秘钥') : $L('添加 API 秘钥') } - render() { + renderFrom() { return ( - (this._dlg = c)}> -
-
- -
- (this._UserSelector = c)} /> -

{$L('强烈建议为 API 秘钥绑定一个用户,此秘钥将拥有和其一样的权限。如不绑定则拥有全部权限')}

-
-
-
-
(this._btns = c)}> - - - {$L('取消')} - -
+ +
+ +
+ (this._UserSelector = c)} defaultValue={this.props.bindUser} /> +

{$L('强烈建议为 API 秘钥绑定一个用户,此秘钥将拥有和其一样的权限。如不绑定则拥有全部权限')}

- +
+ +
+
APP IDAPP SECRET[[${bundle.L('绑定用户 (权限)')}]][[${bundle.L('调用量 (30 天)')}]]APP IDAPP SECRET[[${bundle.L('绑定用户 (权限)')}]][[${bundle.L('IP 白名单')}]][[${bundle.L('调用量 (30 天)')}]] [[${bundle.L('创建时间')}]]
{item[1]} {secret} {item[4] || $L('无 (拥有全部权限)')}{item[7] || $L('无 (不限制)')} {item[6] || 0} - this.delete(item)}> + this.resetSecret(item[0])}> + + + this.handleEdit(item)}> + + + this.handleDelete(item)}>