mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-09-20 15:35:55 +08:00
Fix 2.9.3 (#476)
* some fix * detail AutoTransform * fix: h5 captcha * fix: auto-share * fix avatar cache * open: ref-detail, field label * fix bool style in protable * better : field-formula * fix: imports owningUser * post passwd
This commit is contained in:
parent
ac9129c036
commit
8bb2a4505b
2
@rbv
2
@rbv
|
@ -1 +1 @@
|
|||
Subproject commit 277f6eb150627c53654dd02238870b7e138c2f53
|
||||
Subproject commit 20c457c31c7c569bc5590d495447e62f8a1b6cb8
|
2
pom.xml
2
pom.xml
|
@ -10,7 +10,7 @@
|
|||
</parent>
|
||||
<groupId>com.rebuild</groupId>
|
||||
<artifactId>rebuild</artifactId>
|
||||
<version>2.9.2</version>
|
||||
<version>2.9.3</version>
|
||||
<name>rebuild</name>
|
||||
<description>Building your business-systems freely!</description>
|
||||
<!-- UNCOMMENT USE TOMCAT -->
|
||||
|
|
|
@ -65,11 +65,11 @@ public class Application implements ApplicationListener<ApplicationStartedEvent>
|
|||
/**
|
||||
* Rebuild Version
|
||||
*/
|
||||
public static final String VER = "2.9.2";
|
||||
public static final String VER = "2.9.3";
|
||||
/**
|
||||
* Rebuild Build [MAJOR]{1}[MINOR]{2}[PATCH]{2}[BUILD]{2}
|
||||
*/
|
||||
public static final int BUILD = 2090209;
|
||||
public static final int BUILD = 2090210;
|
||||
|
||||
static {
|
||||
// Driver for DB
|
||||
|
|
|
@ -8,6 +8,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
package com.rebuild.core.configuration.general;
|
||||
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
|
||||
/**
|
||||
* 主/明细实体权限处理。创建明细实体必须指定主实体,以便验证权限
|
||||
|
@ -17,17 +18,22 @@ import cn.devezhao.persist4j.engine.ID;
|
|||
*/
|
||||
public class FormBuilderContextHolder {
|
||||
|
||||
private static final ThreadLocal<ID> MAINID_OF_DETAIL = new ThreadLocal<>();
|
||||
private static final ThreadLocal<ID> MAINID_OF_DETAIL = new NamedThreadLocal<>("MainId from details");
|
||||
|
||||
public static void setMainIdOfDetail(ID mainId) {
|
||||
MAINID_OF_DETAIL.set(mainId);
|
||||
/**
|
||||
* @param mainid
|
||||
*/
|
||||
public static void setMainIdOfDetail(ID mainid) {
|
||||
MAINID_OF_DETAIL.set(mainid);
|
||||
}
|
||||
|
||||
public static ID getMainIdOfDetail() {
|
||||
return MAINID_OF_DETAIL.get();
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
MAINID_OF_DETAIL.remove();
|
||||
/**
|
||||
* @param once
|
||||
* @return
|
||||
*/
|
||||
public static ID getMainIdOfDetail(boolean once) {
|
||||
ID mainid = MAINID_OF_DETAIL.get();
|
||||
if (mainid != null && once) MAINID_OF_DETAIL.remove();
|
||||
return mainid;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ public class FormsBuilder extends FormsManager {
|
|||
// 新建
|
||||
if (record == null) {
|
||||
if (hasMainEntity != null) {
|
||||
ID mainid = FormBuilderContextHolder.getMainIdOfDetail();
|
||||
ID mainid = FormBuilderContextHolder.getMainIdOfDetail(false);
|
||||
Assert.notNull(mainid, "Call `FormBuilderContextHolder#setMainIdOfDetail` first!");
|
||||
|
||||
approvalState = EntityHelper.isUnsavedId(mainid) ? null : getHadApproval(hasMainEntity, mainid);
|
||||
|
@ -237,7 +237,7 @@ public class FormsBuilder extends FormsManager {
|
|||
|
||||
// 明细实体
|
||||
|
||||
ID mainid = FormBuilderContextHolder.getMainIdOfDetail();
|
||||
ID mainid = FormBuilderContextHolder.getMainIdOfDetail(false);
|
||||
if (mainid == null) {
|
||||
Field dtmField = MetadataHelper.getDetailToMainField(entity);
|
||||
Object[] o = Application.getQueryFactory().uniqueNoFilter(recordId, dtmField.getName());
|
||||
|
@ -475,7 +475,7 @@ public class FormsBuilder extends FormsManager {
|
|||
* @param user4Desensitized 不传则不脱敏
|
||||
* @return
|
||||
* @see FieldValueHelper#wrapFieldValue(Object, EasyField)
|
||||
* @see com.rebuild.core.support.general.DataListWrapper#wrapFieldValue(Object, Field)
|
||||
* @see com.rebuild.core.support.general.DataListWrapper#wrapFieldValue(Object, Field, String)
|
||||
*/
|
||||
public Object wrapFieldValue(Record data, EasyField field, ID user4Desensitized) {
|
||||
Object value = data.getObjectValue(field.getName());
|
||||
|
|
|
@ -37,7 +37,6 @@ import java.util.*;
|
|||
public class DataImporter extends HeavyTask<Integer> {
|
||||
|
||||
final private ImportRule rule;
|
||||
private ID owningUser;
|
||||
|
||||
final private List<Object[]> traceLogs = new ArrayList<>();
|
||||
private String cellTraces = null;
|
||||
|
@ -54,7 +53,7 @@ public class DataImporter extends HeavyTask<Integer> {
|
|||
final List<Cell[]> rows = new DataFileParser(rule.getSourceFile()).parse();
|
||||
this.setTotal(rows.size() - 1);
|
||||
|
||||
owningUser = rule.getDefaultOwningUser() != null ? rule.getDefaultOwningUser() : getUser();
|
||||
final ID defaultOwning = rule.getDefaultOwningUser() != null ? rule.getDefaultOwningUser() : getUser();
|
||||
GeneralEntityServiceContextHolder.setSkipSeriesValue();
|
||||
|
||||
for (final Cell[] row : rows) {
|
||||
|
@ -69,7 +68,7 @@ public class DataImporter extends HeavyTask<Integer> {
|
|||
}
|
||||
|
||||
try {
|
||||
Record record = checkoutRecord(row);
|
||||
Record record = checkoutRecord(row, defaultOwning);
|
||||
if (record == null) {
|
||||
traceLogs.add(new Object[] { fc.getRowNo(), "SKIP" });
|
||||
} else {
|
||||
|
@ -98,11 +97,13 @@ public class DataImporter extends HeavyTask<Integer> {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param row
|
||||
* @param defaultOwning
|
||||
* @return
|
||||
*/
|
||||
protected Record checkoutRecord(Cell[] row) {
|
||||
Record recordHub = EntityHelper.forNew(rule.getToEntity().getEntityCode(), this.owningUser);
|
||||
protected Record checkoutRecord(Cell[] row, ID defaultOwning) {
|
||||
Record recordHub = EntityHelper.forNew(rule.getToEntity().getEntityCode(), defaultOwning);
|
||||
|
||||
// 解析数据
|
||||
RecordCheckout recordCheckout = new RecordCheckout(rule.getFiledsMapping());
|
||||
|
@ -124,7 +125,7 @@ public class DataImporter extends HeavyTask<Integer> {
|
|||
|
||||
if (repeat != null && rule.getRepeatOpt() == ImportRule.REPEAT_OPT_UPDATE) {
|
||||
// 更新
|
||||
checkout = EntityHelper.forUpdate(repeat, this.owningUser);
|
||||
checkout = EntityHelper.forUpdate(repeat, defaultOwning);
|
||||
for (Iterator<String> iter = recordHub.getAvailableFieldIterator(); iter.hasNext(); ) {
|
||||
String field = iter.next();
|
||||
if (MetadataHelper.isCommonsField(field)) continue;
|
||||
|
|
|
@ -27,6 +27,7 @@ import com.rebuild.core.metadata.EntityHelper;
|
|||
import com.rebuild.core.metadata.MetadataSorter;
|
||||
import com.rebuild.core.metadata.easymeta.*;
|
||||
import com.rebuild.core.metadata.impl.MetadataModificationException;
|
||||
import com.rebuild.core.privileges.bizz.User;
|
||||
import com.rebuild.core.support.i18n.Language;
|
||||
import com.rebuild.core.support.state.StateManager;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@ -72,7 +73,20 @@ public class RecordCheckout {
|
|||
Object value = checkoutFieldValue(field, cellValue, true);
|
||||
|
||||
if (value != null) {
|
||||
record.setObjectValue(field.getName(), value);
|
||||
if (field.getName().equalsIgnoreCase(EntityHelper.OwningUser)) {
|
||||
User owning = Application.getUserStore().getUser((ID) value);
|
||||
if (owning.getOwningDept() == null) {
|
||||
putTraceLog(cellValue, Language.L(EasyMetaFactory.getDisplayType(field)));
|
||||
} else {
|
||||
// 用户部门联动
|
||||
record.setObjectValue(field.getName(), value);
|
||||
record.setID(EntityHelper.OwningDept, (ID) owning.getOwningDept().getIdentity());
|
||||
}
|
||||
|
||||
} else {
|
||||
record.setObjectValue(field.getName(), value);
|
||||
}
|
||||
|
||||
} else {
|
||||
putTraceLog(cellValue, Language.L(EasyMetaFactory.getDisplayType(field)));
|
||||
}
|
||||
|
@ -182,7 +196,7 @@ public class RecordCheckout {
|
|||
final String val = cell.asString();
|
||||
final Entity refEntity = field.getReferenceEntity();
|
||||
|
||||
// 支持ID
|
||||
// 支持 ID
|
||||
if (ID.isId(val) && ID.valueOf(val).getEntityCode().intValue() == refEntity.getEntityCode()) {
|
||||
ID checkId = ID.valueOf(val);
|
||||
Object exists = Application.getQueryFactory().uniqueNoFilter(checkId, refEntity.getPrimaryField().getName());
|
||||
|
|
|
@ -274,12 +274,15 @@ public class GeneralEntityService extends ObservableService implements EntitySer
|
|||
final ID currentUser = UserContextHolder.getUser();
|
||||
final String entityName = MetadataHelper.getEntityName(record);
|
||||
|
||||
// 如用户无更新权限,则降级为只读共享
|
||||
if ((rights & BizzPermission.UPDATE.getMask()) != 0) {
|
||||
if (!Application.getPrivilegesManager().allowUpdate(to, record.getEntityCode()) /* 目标用户无基础更新权限 */
|
||||
|| !Application.getPrivilegesManager().allow(currentUser, record, BizzPermission.UPDATE, true) /* 操作用户无记录更新权限 */) {
|
||||
rights = BizzPermission.READ.getMask();
|
||||
log.warn("Downgrade share rights to READ(8) : {}", record);
|
||||
boolean fromTriggerNoDowngrade = GeneralEntityServiceContextHolder.isFromTrigger(false);
|
||||
if (!fromTriggerNoDowngrade) {
|
||||
// 如用户无更新权限,则降级为只读共享
|
||||
if ((rights & BizzPermission.UPDATE.getMask()) != 0) {
|
||||
if (!Application.getPrivilegesManager().allowUpdate(to, record.getEntityCode()) /* 目标用户无基础更新权限 */
|
||||
|| !Application.getPrivilegesManager().allow(currentUser, record, BizzPermission.UPDATE, true) /* 操作用户无记录更新权限 */) {
|
||||
rights = BizzPermission.READ.getMask();
|
||||
log.warn("Downgrade share rights to READ(8) : {}", record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -311,10 +314,12 @@ public class GeneralEntityService extends ObservableService implements EntitySer
|
|||
log.debug("The record has been shared and has the same rights, ignore : {}", record);
|
||||
}
|
||||
|
||||
// 可以共享给自己
|
||||
// } else if (to.equals(Application.getRecordOwningCache().getOwningUser(record))) {
|
||||
// log.debug("Share to the same user as the record, ignore : {}", record);
|
||||
} else {
|
||||
// // 可以共享给自己
|
||||
// if (to.equals(Application.getRecordOwningCache().getOwningUser(record))) {
|
||||
// log.debug("Share to the same user as the record, ignore : {}", record);
|
||||
// }
|
||||
|
||||
delegateService.create(sharedAfter);
|
||||
affected = 1;
|
||||
shareChange = true;
|
||||
|
@ -391,7 +396,7 @@ public class GeneralEntityService extends ObservableService implements EntitySer
|
|||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
final boolean fromTriggerNoFilter = GeneralEntityServiceContextHolder.isFromTriggersOnce();
|
||||
final boolean fromTriggerNoFilter = GeneralEntityServiceContextHolder.isFromTrigger(false);
|
||||
|
||||
Map<String, Set<ID>> entityRecordsMap = new HashMap<>();
|
||||
Entity mainEntity = MetadataHelper.getEntity(recordMain.getEntityCode());
|
||||
|
|
|
@ -66,17 +66,17 @@ public class GeneralEntityServiceContextHolder {
|
|||
*
|
||||
* @param recordId
|
||||
*/
|
||||
public static void setFromTriggers(ID recordId) {
|
||||
public static void setFromTrigger(ID recordId) {
|
||||
FROM_TRIGGERS.set(recordId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see #setFromTriggers(ID)
|
||||
* @see #setFromTrigger(ID)
|
||||
*/
|
||||
public static boolean isFromTriggersOnce() {
|
||||
public static boolean isFromTrigger(boolean once) {
|
||||
ID recordId = FROM_TRIGGERS.get();
|
||||
if (recordId != null) FROM_TRIGGERS.remove();
|
||||
if (recordId != null && once) FROM_TRIGGERS.remove();
|
||||
return recordId != null;
|
||||
}
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ public class RecordTransfomer extends SetUser {
|
|||
int fillbackMode = transConfig.getIntValue("fillbackMode");
|
||||
|
||||
// 仅更新,无业务规则
|
||||
if (fillbackMode == 3) {
|
||||
if (fillbackMode == 3 || fillbackMode == 0) {
|
||||
Application.getCommonsService().update(updateSource, false);
|
||||
}
|
||||
// 忽略审批状态(进行中)强制更新
|
||||
|
|
|
@ -8,6 +8,8 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
package com.rebuild.core.service.trigger.impl;
|
||||
|
||||
import cn.devezhao.persist4j.Entity;
|
||||
import cn.devezhao.persist4j.Field;
|
||||
import cn.devezhao.persist4j.dialect.FieldType;
|
||||
import cn.devezhao.persist4j.metadata.MissingMetaExcetion;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.rebuild.core.Application;
|
||||
|
@ -80,12 +82,20 @@ public class AggregationEvaluator {
|
|||
Set<String> matchsVars = ContentWithFieldVars.matchsVars(formula);
|
||||
|
||||
List<String[]> fields = new ArrayList<>();
|
||||
Set<String> nonNumericFields = new HashSet<>();
|
||||
for (String m : matchsVars) {
|
||||
String[] fieldAndFunc = m.split(MetadataHelper.SPLITER_RE);
|
||||
if (MetadataHelper.getLastJoinField(sourceEntity, fieldAndFunc[0]) == null) {
|
||||
Field field;
|
||||
if ((field = MetadataHelper.getLastJoinField(sourceEntity, fieldAndFunc[0])) == null) {
|
||||
throw new MissingMetaExcetion(fieldAndFunc[0], sourceEntity.getName());
|
||||
}
|
||||
fields.add(fieldAndFunc);
|
||||
|
||||
// 数字型
|
||||
if (fieldAndFunc.length > 1 || field.getType() == FieldType.LONG || field.getType() == FieldType.DECIMAL);
|
||||
else {
|
||||
nonNumericFields.add("nn:" + fieldAndFunc[0]);
|
||||
}
|
||||
}
|
||||
if (fields.isEmpty()) {
|
||||
log.warn("No fields found in formula : {}", formula);
|
||||
|
@ -134,8 +144,9 @@ public class AggregationEvaluator {
|
|||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object value = useSourceData[i] == null ? 0 : useSourceData[i];
|
||||
|
||||
Object value = useSourceData[i];
|
||||
if (value == null) value = nonNumericFields.contains("nn:" + field[0]) ? "" : 0;
|
||||
envMap.put(fieldKey, value);
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ public class AutoAssign extends TriggerAction {
|
|||
}
|
||||
|
||||
PrivilegesGuardContextHolder.setSkipGuard(recordId);
|
||||
GeneralEntityServiceContextHolder.setFromTriggers(recordId);
|
||||
GeneralEntityServiceContextHolder.setFromTrigger(recordId);
|
||||
|
||||
try {
|
||||
Application.getEntityService(actionContext.getSourceEntity().getEntityCode())
|
||||
|
@ -111,7 +111,7 @@ public class AutoAssign extends TriggerAction {
|
|||
|
||||
} finally {
|
||||
PrivilegesGuardContextHolder.getSkipGuardOnce();
|
||||
GeneralEntityServiceContextHolder.isFromTriggersOnce();
|
||||
GeneralEntityServiceContextHolder.isFromTrigger(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ public class AutoShare extends AutoAssign {
|
|||
final EntityService es = Application.getEntityService(actionContext.getSourceEntity().getEntityCode());
|
||||
for (ID toUser : toUsers) {
|
||||
PrivilegesGuardContextHolder.setSkipGuard(recordId);
|
||||
GeneralEntityServiceContextHolder.setFromTriggers(recordId);
|
||||
GeneralEntityServiceContextHolder.setFromTrigger(recordId);
|
||||
|
||||
try {
|
||||
es.share(recordId, toUser, cascades, shareRights);
|
||||
|
|
|
@ -32,7 +32,7 @@ public class SystemDiagnosis {
|
|||
public static final String DatabaseBackupFail = "DatabaseBackupFail";
|
||||
public static final String DataFileBackupFail = "DataFileBackupFail";
|
||||
|
||||
public static String _DENIEDMSG = null;
|
||||
volatile public static String _DENIEDMSG = null;
|
||||
|
||||
public void diagnose() {
|
||||
ServerStatus.getLastStatus(true);
|
||||
|
@ -58,12 +58,12 @@ public class SystemDiagnosis {
|
|||
if (usersMsg == null) dangers.remove(UsersMsg);
|
||||
else dangers.put(UsersMsg, usersMsg);
|
||||
|
||||
// MULTIPLE RUNNING INSTANCES DETECTED!
|
||||
_DENIEDMSG = echoValidity.getString("deniedMsg");
|
||||
|
||||
} else {
|
||||
dangers.remove(AdminMsg);
|
||||
dangers.remove(UsersMsg);
|
||||
_DENIEDMSG = null;
|
||||
}
|
||||
|
||||
Application.getCommonsCache().putx(CKEY_DANGERS, dangers, CommonsCache.TS_DAY);
|
||||
|
|
|
@ -9,8 +9,8 @@ package com.rebuild.web.admin.metadata;
|
|||
|
||||
import cn.devezhao.commons.web.ServletUtils;
|
||||
import cn.devezhao.persist4j.Entity;
|
||||
import cn.devezhao.persist4j.Field;
|
||||
import cn.devezhao.persist4j.Record;
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
@ -23,7 +23,6 @@ import com.rebuild.core.metadata.MetadataHelper;
|
|||
import com.rebuild.core.metadata.easymeta.EasyField;
|
||||
import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
|
||||
import com.rebuild.core.privileges.UserHelper;
|
||||
import com.rebuild.core.privileges.UserService;
|
||||
import com.rebuild.web.BaseController;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
@ -63,6 +62,7 @@ public class FormDesignController extends BaseController {
|
|||
@RequestMapping({"form-update"})
|
||||
public void sets(@PathVariable String entity,
|
||||
HttpServletRequest request, HttpServletResponse response) {
|
||||
final ID user = getRequestUser(request);
|
||||
JSON formJson = ServletUtils.getRequestJson(request);
|
||||
|
||||
// 修改字段名称
|
||||
|
@ -88,13 +88,10 @@ public class FormDesignController extends BaseController {
|
|||
List<Record> willUpdate = new ArrayList<>();
|
||||
Entity entityMeta = MetadataHelper.getEntity(entity);
|
||||
for (Map.Entry<String, String> e : newLabels.entrySet()) {
|
||||
Field fieldMeta = entityMeta.getField(e.getKey());
|
||||
EasyField fieldEasy = EasyMetaFactory.valueOf(fieldMeta);
|
||||
if (fieldEasy.isBuiltin() || fieldEasy.getMetaId() == null) {
|
||||
continue;
|
||||
}
|
||||
EasyField fieldEasy = EasyMetaFactory.valueOf(entityMeta.getField(e.getKey()));
|
||||
if (fieldEasy.getMetaId() == null) continue;
|
||||
|
||||
Record fieldRecord = EntityHelper.forUpdate(fieldEasy.getMetaId(), UserService.SYSTEM_USER, false);
|
||||
Record fieldRecord = EntityHelper.forUpdate(fieldEasy.getMetaId(), user, false);
|
||||
fieldRecord.setString("fieldLabel", e.getValue());
|
||||
willUpdate.add(fieldRecord);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
package com.rebuild.web.commons;
|
||||
|
||||
import cn.devezhao.commons.CodecUtils;
|
||||
import cn.devezhao.commons.ObjectUtils;
|
||||
import cn.devezhao.commons.web.ServletUtils;
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
import com.rebuild.api.user.AuthTokenManager;
|
||||
|
@ -35,8 +36,12 @@ import javax.imageio.ImageIO;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
|
||||
/**
|
||||
* 文件下载/查看
|
||||
|
@ -100,8 +105,8 @@ public class FileDownloader extends BaseController {
|
|||
|
||||
BufferedImage bi = ImageIO.read(img);
|
||||
if (bi == null) {
|
||||
log.debug("None image type : {}", filePath);
|
||||
writeStream(new FileInputStream(img), response);
|
||||
log.debug("Unsupport image type : {}", filePath);
|
||||
writeStream(Files.newInputStream(img.toPath()), response);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -146,10 +151,10 @@ public class FileDownloader extends BaseController {
|
|||
private int parseWidth(String imageView2) {
|
||||
if (!imageView2.contains("/w/")) {
|
||||
return 1000;
|
||||
} else {
|
||||
String w = imageView2.split("/w/")[1].split("/")[0];
|
||||
return ObjectUtils.toInt(w, 1000);
|
||||
}
|
||||
|
||||
String w = imageView2.split("/w/")[1].split("/")[0];
|
||||
return Integer.parseInt(w);
|
||||
}
|
||||
|
||||
@GetMapping(value = {"download/**", "access/**"})
|
||||
|
@ -240,7 +245,7 @@ public class FileDownloader extends BaseController {
|
|||
long size = FileUtils.sizeOf(file);
|
||||
response.setHeader("Content-Length", String.valueOf(size));
|
||||
|
||||
try (InputStream fis = new FileInputStream(file)) {
|
||||
try (InputStream fis = Files.newInputStream(file.toPath())) {
|
||||
return writeStream(fis, response);
|
||||
}
|
||||
}
|
||||
|
@ -319,4 +324,5 @@ public class FileDownloader extends BaseController {
|
|||
if (attname != null) url += "&attname=" + CodecUtils.urlEncode(attname);
|
||||
resp.sendRedirect(AppUtils.getContextPath(url));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -131,7 +131,7 @@ public class GeneralModelController extends EntityController {
|
|||
return model;
|
||||
|
||||
} finally {
|
||||
FormBuilderContextHolder.clear();
|
||||
FormBuilderContextHolder.getMainIdOfDetail(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,8 @@ import java.io.IOException;
|
|||
@RequestMapping("/account")
|
||||
public class UserAvatar extends BaseController {
|
||||
|
||||
public static final String SK_DAVATAR = "davatarTime";
|
||||
|
||||
@GetMapping("/user-avatar")
|
||||
public void renderAvatat(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
renderUserAvatar(getRequestUser(request), request, response);
|
||||
|
@ -137,7 +139,7 @@ public class UserAvatar extends BaseController {
|
|||
record.setString("avatarUrl", uploadName);
|
||||
Application.getBean(UserService.class).update(record);
|
||||
|
||||
ServletUtils.setSessionAttribute(request, "davatarTime", System.currentTimeMillis());
|
||||
ServletUtils.setSessionAttribute(request, SK_DAVATAR, System.currentTimeMillis());
|
||||
return RespBody.ok(uploadName);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
package com.rebuild.web.user;
|
||||
|
||||
import cn.devezhao.commons.EncryptUtils;
|
||||
import cn.devezhao.commons.web.ServletUtils;
|
||||
import cn.devezhao.persist4j.Record;
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
@ -113,15 +114,15 @@ public class UserSettingsController extends EntityController {
|
|||
return RespBody.ok();
|
||||
}
|
||||
|
||||
@RequestMapping("/user/save-passwd")
|
||||
@PostMapping("/user/save-passwd")
|
||||
public RespBody savePasswd(HttpServletRequest request) {
|
||||
final ID user = getRequestUser(request);
|
||||
String oldp = getParameterNotNull(request, "oldp");
|
||||
String newp = getParameterNotNull(request, "newp");
|
||||
|
||||
Object[] o = Application.createQuery("select password from User where userId = ?")
|
||||
.setParameter(1, user)
|
||||
.unique();
|
||||
JSONObject p = (JSONObject) ServletUtils.getRequestJson(request);
|
||||
String oldp = p.getString("oldp");
|
||||
String newp = p.getString("newp");
|
||||
|
||||
Object[] o = Application.getQueryFactory().uniqueNoFilter(user, "password");
|
||||
if (o == null || !StringUtils.equals((String) o[0], EncryptUtils.toSHA256Hex(oldp))) {
|
||||
return RespBody.errorl("原密码输入有误");
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ 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 com.wf.captcha.utils.CaptchaUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
@ -157,9 +158,13 @@ public class LoginController extends LoginAction {
|
|||
public RespBody userLogin(HttpServletRequest request, HttpServletResponse response) {
|
||||
String vcode = getParameter(request, "vcode");
|
||||
Boolean needVcode = (Boolean) ServletUtils.getSessionAttribute(request, SK_NEED_VCODE);
|
||||
if (needVcode != null && needVcode
|
||||
&& (StringUtils.isBlank(vcode) || !CaptchaUtil.ver(vcode, request))) {
|
||||
return RespBody.errorl("验证码错误");
|
||||
if ((needVcode != null && needVcode) || StringUtils.isNotBlank(vcode)) {
|
||||
if (StringUtils.isBlank(vcode)) {
|
||||
ServletUtils.setSessionAttribute(request, SK_NEED_VCODE, true);
|
||||
return RespBody.error("VCODE");
|
||||
} else if (!CaptchaUtil.ver(vcode, request)) {
|
||||
return RespBody.errorl("验证码错误");
|
||||
}
|
||||
}
|
||||
|
||||
final String user = getParameterNotNull(request, "user");
|
||||
|
@ -176,11 +181,14 @@ public class LoginController extends LoginAction {
|
|||
return RespBody.error(hasError);
|
||||
}
|
||||
|
||||
// 清理
|
||||
// 清理验证码
|
||||
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 isMobile = AppUtils.isRbMobile(request);
|
||||
|
||||
Map<String, Object> resMap = new HashMap<>();
|
||||
|
||||
|
@ -193,14 +201,14 @@ public class LoginController extends LoginAction {
|
|||
Application.getCommonsCache().putx("2FA" + userToken, loginUser.getId(), CommonsCache.TS_HOUR / 4); // 15m
|
||||
resMap.put("login2FaUserToken", userToken);
|
||||
|
||||
if (AppUtils.isRbMobile(request)) {
|
||||
if (isMobile) {
|
||||
request.getSession().invalidate();
|
||||
}
|
||||
|
||||
return RespBody.ok(resMap);
|
||||
}
|
||||
|
||||
if (AppUtils.isRbMobile(request)) {
|
||||
if (isMobile) {
|
||||
resMap = loginSuccessedH5(request, response, loginUser.getId());
|
||||
} else {
|
||||
Integer ed = loginSuccessed(
|
||||
|
|
|
@ -24,12 +24,13 @@
|
|||
font-size: 32px;
|
||||
color: #4285f4;
|
||||
}
|
||||
.card.entity .badge {
|
||||
.card.entity i.badge {
|
||||
position: absolute;
|
||||
top: 11px;
|
||||
right: 11px;
|
||||
font-size: 11px;
|
||||
text-transform: uppercase;
|
||||
font-style: normal;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.card.entity span {
|
||||
margin-top: 2px;
|
||||
|
@ -156,8 +157,8 @@
|
|||
$t.find('.icon').addClass(`zmdi-${item.icon}`)
|
||||
$t.find('span').text(item.entityLabel)
|
||||
$t.find('p').text(item.comments || '-')
|
||||
if (item.builtin) $(`<i class="badge badge-pill badge-secondary thin text-muted">${$L('内置')}</i>`).appendTo($t.find('a.card'))
|
||||
if (!!item.detailEntity) $(`<i class="badge badge-pill badge-secondary thin text-muted">${$L('明细')}</i>`).appendTo($t.find('a.card'))
|
||||
if (item.builtin) $(`<i class="badge badge-pill badge-secondary font-weight-light">${$L('内置')}</i>`).appendTo($t.find('a.card'))
|
||||
if (!!item.detailEntity) $(`<i class="badge badge-pill badge-secondary font-weight-light">${$L('明细')}</i>`).appendTo($t.find('a.card'))
|
||||
return $t
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -349,7 +349,7 @@
|
|||
<div class="dropdown-menu common-patt">
|
||||
<h5>[[${bundle.L('常用')}]]</h5>
|
||||
<a class="badge" data-patt="^([0-9A-Z]{15}|[0-9A-Z]{17}|[0-9A-Z]{18}|[0-9A-Z]{20})$">[[${bundle.L('税号')}]]</a>
|
||||
<a class="badge" data-patt="^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9X]$">[[${bundle.L('身份证')}]]</a>
|
||||
<a class="badge" data-patt="^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$">[[${bundle.L('身份证')}]]</a>
|
||||
<a class="badge" data-patt="^[1-9][0-9]{4,10}$">[[${bundle.L('QQ号')}]]</a>
|
||||
<a class="badge" data-patt="^[1-9][0-9]{5}$">[[${bundle.L('邮编')}]]</a>
|
||||
<a class="badge" data-patt="^[\u4e00-\u9fa5]{0,}$">[[${bundle.L('仅中文')}]]</a>
|
||||
|
|
|
@ -125,7 +125,7 @@
|
|||
const $name = $(`<td><a href="field/${item.fieldName}" class="column-main">${item.fieldLabel}</a></td>`).appendTo($tr)
|
||||
if (item.fieldName === wpc.nameField) {
|
||||
$tr.addClass('primary')
|
||||
$(`<span class="badge badge-pill badge-secondary thin ml-1">${$L('名称')}</span>`).appendTo($name)
|
||||
$(`<span class="badge badge-pill badge-secondary font-weight-light ml-1 pb-0">${$L('名称')}</span>`).appendTo($name)
|
||||
} else if (!item.creatable) {
|
||||
$tr.addClass('muted')
|
||||
} else if (!item.nullable) {
|
||||
|
|
|
@ -514,12 +514,6 @@ a.btn {
|
|||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.badge.thin {
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.badge + .badge {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
@ -4606,6 +4600,14 @@ pre.unstyle {
|
|||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.protable .table tr td .custom-control {
|
||||
padding-left: 2.1377rem;
|
||||
}
|
||||
|
||||
.protable .table tr td .custom-control + .custom-control {
|
||||
margin-left: 1.385rem;
|
||||
}
|
||||
|
||||
.protable .table {
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
margin: 0;
|
||||
|
|
|
@ -207,7 +207,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
}
|
||||
|
||||
.formula-calc .numbers li > a:active {
|
||||
box-shadow: inset 0 2px 0 rgba(0, 0, 0, 0.06);
|
||||
box-shadow: inset 3px 3px 3px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.formula-calc ul li.empty-1 > a {
|
||||
|
|
|
@ -31,7 +31,7 @@ $(document).ready(function () {
|
|||
|
||||
const $copy = $('.btn-primary.copy').on('click', () => {
|
||||
const sourceEntity = $val('#copySourceEntity')
|
||||
if (!sourceEntity) RbHighbar.create($L('请选择从哪个实体复制'))
|
||||
if (!sourceEntity) return RbHighbar.create($L('请选择从哪个实体复制'))
|
||||
|
||||
const entityLabel = $val('#newEntityLabel')
|
||||
if (!entityLabel) return RbHighbar.create($L('请输入实体名称'))
|
||||
|
@ -76,6 +76,8 @@ $(document).ready(function () {
|
|||
parent.RbModal.resize()
|
||||
})
|
||||
.trigger('change')
|
||||
|
||||
if (e.length === 0) $(`<option value="">${$L('无可用实体')}</option>`).appendTo('#copySourceEntity')
|
||||
})
|
||||
|
||||
$('#isDetail').on('click', function () {
|
||||
|
|
|
@ -11,16 +11,22 @@ function verifyFormula(formula, entity, onConfirm) {
|
|||
if (res.error_code === 0) {
|
||||
onConfirm()
|
||||
} else {
|
||||
RbAlert.create($L('计算公式可能存在错误,这会导致触发器执行失败。是否继续?'), {
|
||||
type: 'warning',
|
||||
onConfirm: function () {
|
||||
this.hide()
|
||||
onConfirm()
|
||||
},
|
||||
onCancel: function () {
|
||||
this.hide()
|
||||
},
|
||||
})
|
||||
RbAlert.create(
|
||||
<RF>
|
||||
<p>{$L('计算公式可能存在错误,这会导致触发器执行失败。是否继续?')}</p>
|
||||
{res.error_msg && <pre className="text-danger">{res.error_msg}</pre>}
|
||||
</RF>,
|
||||
{
|
||||
type: 'warning',
|
||||
onConfirm: function () {
|
||||
this.hide()
|
||||
onConfirm()
|
||||
},
|
||||
onCancel: function () {
|
||||
this.hide()
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -80,8 +80,7 @@ $(document).ready(function () {
|
|||
// _data.push({ entityName: 'Role', entityLabel: $L('角色') })
|
||||
|
||||
$(d).each(function () {
|
||||
// 明细实体默认隐藏
|
||||
$(`<option value="${this.entityName}" class="${this.mainEntity ? 'bosskey-show' : ''}">${this.entityLabel}${this.mainEntity ? ` (${$L('明细实体')})` : ''}</option>`).appendTo('#refEntity')
|
||||
$(`<option value="${this.entityName}">${this.entityLabel}</option>`).appendTo('#refEntity')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1074,7 +1074,7 @@ class RbFormTime extends RbFormDateTime {
|
|||
class RbFormImage extends RbFormElement {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this._inputid = `${props.field}-input${$random()}`
|
||||
this._htmlid = `${props.field}-${$random()}-input`
|
||||
|
||||
if (props.value) this.state.value = [...props.value] // clone
|
||||
if (this.props.uploadNumber) {
|
||||
|
@ -1111,8 +1111,8 @@ class RbFormImage extends RbFormElement {
|
|||
)
|
||||
})}
|
||||
<span title={$L('上传图片。需要 %s 个', `${this.__minUpload}~${this.__maxUpload}`)} className={showUpload ? '' : 'hide'}>
|
||||
<input ref={(c) => (this._fieldValue__input = c)} type="file" className="inputfile" id={this._inputid} accept="image/*" />
|
||||
<label htmlFor={this._inputid} className="img-thumbnail img-upload">
|
||||
<input ref={(c) => (this._fieldValue__input = c)} type="file" className="inputfile" id={this._htmlid} accept="image/*" />
|
||||
<label htmlFor={this._htmlid} className="img-thumbnail img-upload">
|
||||
<span className="zmdi zmdi-image-alt" />
|
||||
</label>
|
||||
</span>
|
||||
|
@ -1221,8 +1221,8 @@ class RbFormFile extends RbFormImage {
|
|||
)
|
||||
})}
|
||||
<div className={`file-select ${showUpload ? '' : 'hide'}`}>
|
||||
<input type="file" className="inputfile" ref={(c) => (this._fieldValue__input = c)} id={this._inputid} />
|
||||
<label htmlFor={this._inputid} title={$L('上传文件。需要 %d 个', `${this.__minUpload}~${this.__maxUpload}`)} className="btn-secondary">
|
||||
<input type="file" className="inputfile" ref={(c) => (this._fieldValue__input = c)} id={this._htmlid} />
|
||||
<label htmlFor={this._htmlid} title={$L('上传文件。需要 %d 个', `${this.__minUpload}~${this.__maxUpload}`)} className="btn-secondary">
|
||||
<i className="zmdi zmdi-upload" />
|
||||
<span>{$L('上传文件')}</span>
|
||||
</label>
|
||||
|
@ -1749,6 +1749,7 @@ class RbFormBool extends RbFormElement {
|
|||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this._htmlid = `${props.field}-${$random()}_`
|
||||
}
|
||||
|
||||
renderElement() {
|
||||
|
@ -1757,7 +1758,7 @@ class RbFormBool extends RbFormElement {
|
|||
<label className="custom-control custom-radio custom-control-inline">
|
||||
<input
|
||||
className="custom-control-input"
|
||||
name={`radio-${this.props.field}`}
|
||||
name={`${this._htmlid}T`}
|
||||
type="radio"
|
||||
checked={$isTrue(this.state.value)}
|
||||
data-value="T"
|
||||
|
@ -1769,7 +1770,7 @@ class RbFormBool extends RbFormElement {
|
|||
<label className="custom-control custom-radio custom-control-inline">
|
||||
<input
|
||||
className="custom-control-input"
|
||||
name={`radio-${this.props.field}`}
|
||||
name={`${this._htmlid}F`}
|
||||
type="radio"
|
||||
checked={!$isTrue(this.state.value)}
|
||||
data-value="F"
|
||||
|
@ -1831,15 +1832,15 @@ class RbFormBarcode extends RbFormElement {
|
|||
class RbFormAvatar extends RbFormElement {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this._inputid = `${props.field}-input${$random()}`
|
||||
this._htmlid = `${props.field}-${$random()}-input`
|
||||
}
|
||||
|
||||
renderElement() {
|
||||
return (
|
||||
<div className="img-field avatar">
|
||||
<span title={this.props.readonly ? null : $L('选择头像')}>
|
||||
{!this.props.readonly && <input ref={(c) => (this._fieldValue__input = c)} type="file" className="inputfile" id={this._inputid} accept="image/*" />}
|
||||
<label htmlFor={this._inputid} className="img-thumbnail img-upload" disabled={this.props.readonly}>
|
||||
{!this.props.readonly && <input ref={(c) => (this._fieldValue__input = c)} type="file" className="inputfile" id={this._htmlid} accept="image/*" />}
|
||||
<label htmlFor={this._htmlid} className="img-thumbnail img-upload" disabled={this.props.readonly}>
|
||||
<img src={this._formatUrl(this.state.value)} alt="Avatar" />
|
||||
</label>
|
||||
</span>
|
||||
|
|
|
@ -106,19 +106,19 @@ class DlgChangePasswd extends RbFormHandler {
|
|||
<div className="form-group row">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">{$L('原密码')}</label>
|
||||
<div className="col-sm-7">
|
||||
<input type="password" className="form-control form-control-sm" data-id="oldPasswd" onChange={this.handleChange} />
|
||||
<input type="password" className="form-control form-control-sm" data-id="oldPasswd" onChange={this.handleChange} autoComplete="new-password" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-group row">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">{$L('新密码')}</label>
|
||||
<div className="col-sm-7">
|
||||
<input type="password" className="form-control form-control-sm" data-id="newPasswd" onChange={this.handleChange} />
|
||||
<input type="password" className="form-control form-control-sm" data-id="newPasswd" onChange={this.handleChange} autoComplete="new-password" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-group row">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">{$L('重复新密码')}</label>
|
||||
<div className="col-sm-7">
|
||||
<input type="password" className="form-control form-control-sm" data-id="newPasswdAgain" onChange={this.handleChange} />
|
||||
<input type="password" className="form-control form-control-sm" data-id="newPasswdAgain" onChange={this.handleChange} autoComplete="new-password" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-group row footer">
|
||||
|
@ -142,9 +142,9 @@ class DlgChangePasswd extends RbFormHandler {
|
|||
if (!s.newPasswd) return RbHighbar.create($L('请输入新密码'))
|
||||
if (s.newPasswd !== s.newPasswdAgain) return RbHighbar.create($L('两次输入的新密码不一致'))
|
||||
|
||||
const $btns = $(this.refs['btns']).find('.btn').button('loading')
|
||||
$.post(`/settings/user/save-passwd?oldp=${$encode(s.oldPasswd)}&newp=${$encode(s.newPasswd)}`, (res) => {
|
||||
$btns.button('reset')
|
||||
const $btn = $(this.refs['btns']).find('.btn').button('loading')
|
||||
$.post('/settings/user/save-passwd', JSON.stringify({ oldp: s.oldPasswd, newp: s.newPasswd }), (res) => {
|
||||
$btn.button('reset')
|
||||
if (res.error_code === 0) {
|
||||
this.hide()
|
||||
RbHighbar.success($L('修改成功'))
|
||||
|
|
Loading…
Reference in a new issue