Merge branch 'master' into develop

This commit is contained in:
RB 2022-04-01 11:05:57 +08:00
commit 1528a5b26c
12 changed files with 104 additions and 53 deletions

View file

@ -48,13 +48,9 @@ public class EasyDateTime extends EasyField {
}
String dateValue = (String) wrapValue(value);
if (dateValue.length() == 4) { // YYYY
dateValue += "01-01 00:00:00";
} else if (dateValue.length() == 7) { // YYYY-MM
dateValue += "-01 00:00:00";
} else { // YYYY-MM-DD
dateValue += " 00:00:00";
}
// padding
dateValue += "1970-01-01 00:00:00".substring(dateValue.length());
return CalendarUtils.parse(dateValue);
}

View file

@ -96,7 +96,8 @@ public class GeneralEntityService extends ObservableService implements EntitySer
record = super.createOrUpdate(record);
if (details == null || details.isEmpty()) return record;
// 明细
// 主记录+明细记录处理
String dtf = MetadataHelper.getDetailToMainField(record.getEntity().getDetailEntity()).getName();
ID mainid = record.getPrimary();

View file

@ -94,21 +94,23 @@ public abstract class ObservableService extends Observable implements ServiceSpe
@Override
public int delete(ID recordId) {
final ID currentUser = UserContextHolder.getUser();
Record deleted = null;
if (countObservers() > 0) {
deleted = EntityHelper.forUpdate(recordId, UserContextHolder.getUser());
deleted = EntityHelper.forUpdate(recordId, currentUser);
deleted = record(deleted);
// 删除前触发做一些状态保持
setChanged();
notifyObservers(OperatingContext.create(UserContextHolder.getUser(), DELETE_BEFORE, deleted, null));
notifyObservers(OperatingContext.create(currentUser, DELETE_BEFORE, deleted, null));
}
int affected = delegateService.delete(recordId);
if (countObservers() > 0) {
setChanged();
notifyObservers(OperatingContext.create(UserContextHolder.getUser(), BizzPermission.DELETE, deleted, null));
notifyObservers(OperatingContext.create(currentUser, BizzPermission.DELETE, deleted, null));
}
return affected;
}

View file

@ -79,12 +79,10 @@ public class FieldWriteback extends FieldAggregation {
if (tschain == null) return;
this.prepare(operatingContext);
if (targetRecordIds.isEmpty()) return;
if (targetRecordIds.isEmpty()) {
return;
}
if (targetRecordData.getAvailableFields().isEmpty()) {
log.warn("No data of target record available");
log.info("No data of target record available");
return;
}
@ -94,6 +92,12 @@ public class FieldWriteback extends FieldAggregation {
boolean tschainAdded = false;
for (ID targetRecordId : targetRecordIds) {
if (operatingContext.getAction() == BizzPermission.DELETE
&& targetRecordId.equals(operatingContext.getAnyRecord().getPrimary())) {
// 删除时无需更新自己
continue;
}
if (allowNoPermissionUpdate) {
PrivilegesGuardContextHolder.setSkipGuard(targetRecordId);
}
@ -115,7 +119,7 @@ public class FieldWriteback extends FieldAggregation {
GeneralEntityServiceContextHolder.setRepeatedCheckMode(GeneralEntityServiceContextHolder.RCM_CHECK_MAIN);
try {
targetService.createOrUpdate(targetRecord); // Only create
targetService.createOrUpdate(targetRecord);
} finally {
PrivilegesGuardContextHolder.getSkipGuardOnce();
GeneralEntityServiceContextHolder.getRepeatedCheckModeOnce();
@ -137,7 +141,7 @@ public class FieldWriteback extends FieldAggregation {
targetRecordIds = new HashSet<>();
if (SOURCE_SELF.equalsIgnoreCase(targetFieldEntity[0])) {
// 自己
// 自己更新自己
targetRecordIds.add(context.getSourceRecord());
} else if (isOne2One) {

View file

@ -7,6 +7,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
package com.rebuild.core.service.trigger.impl;
import cn.devezhao.bizz.privileges.impl.BizzPermission;
import cn.devezhao.commons.RegexUtils;
import cn.devezhao.commons.ThreadPool;
import cn.devezhao.persist4j.engine.ID;
@ -35,7 +36,7 @@ import java.util.Set;
public class SendNotification implements TriggerAction {
// 通知
private static final int TYPE_NOTIFICATION = 1;
// private static final int TYPE_NOTIFICATION = 1;
// 邮件
private static final int TYPE_MAIL = 2;
// 短信
@ -59,14 +60,14 @@ public class SendNotification implements TriggerAction {
// FIXME 等待事物完成
ThreadPool.waitFor(3000);
executeAsync();
executeAsync(operatingContext);
} catch (Exception ex) {
log.error(null, ex);
}
});
}
private void executeAsync() {
private void executeAsync(OperatingContext operatingContext) {
final JSONObject content = (JSONObject) context.getActionContent();
Set<ID> toUsers = UserHelper.parseUsers(content.getJSONArray("sendTo"), context.getSourceRecord());
@ -84,7 +85,12 @@ public class SendNotification implements TriggerAction {
}
String message = content.getString("content");
message = ContentWithFieldVars.replaceWithRecord(message, context.getSourceRecord());
if (operatingContext.getAction() == BizzPermission.DELETE) {
message = ContentWithFieldVars.replaceWithRecord(message, operatingContext.getBeforeRecord());
} else {
message = ContentWithFieldVars.replaceWithRecord(message, context.getSourceRecord());
}
String emailSubject = content.getString("title");
if (StringUtils.isBlank(emailSubject)) emailSubject = Language.L("你有一条新通知");

View file

@ -35,16 +35,17 @@ public class ContentWithFieldVars {
* 替换文本中的字段变量
*
* @param content
* @param record
* @param recordId
* @return
* @see #replaceWithRecord(String, Record)
*/
public static String replaceWithRecord(String content, ID record) {
if (StringUtils.isBlank(content) || record == null) {
public static String replaceWithRecord(String content, ID recordId) {
if (StringUtils.isBlank(content) || recordId == null) {
return content;
}
Entity entity = MetadataHelper.getEntity(record.getEntityCode());
// 主键
Entity entity = MetadataHelper.getEntity(recordId.getEntityCode());
// 主键占位符
content = content.replace("{ID}", String.format("{%s}", entity.getPrimaryField().getName()));
Map<String, String> fieldVars = new HashMap<>();
@ -53,29 +54,56 @@ public class ContentWithFieldVars {
fieldVars.put(field, null);
}
}
if (fieldVars.isEmpty()) return content;
String sql = String.format("select %s from %s where %s = ?",
StringUtils.join(fieldVars.keySet(), ","), entity.getName(), entity.getPrimaryField().getName());
Record o = Application.createQueryNoFilter(sql).setParameter(1, record).record();
if (o != null) {
for (String field : fieldVars.keySet()) {
Object value = o.getObjectValue(field);
value = FieldValueHelper.wrapFieldValue(value, MetadataHelper.getLastJoinField(entity, field), true);
if (value != null) {
fieldVars.put(field, value.toString());
}
StringUtils.join(fieldVars.keySet(), ","),
entity.getName(), entity.getPrimaryField().getName());
Record o = Application.createQueryNoFilter(sql).setParameter(1, recordId).record();
return replaceWithRecord(content, o);
}
/**
* 替换文本中的字段变量
*
* @param content
* @param record
* @return
*/
public static String replaceWithRecord(String content, Record record) {
if (StringUtils.isBlank(content) || record == null) {
return content;
}
// 主键占位符
content = content.replace("{ID}",
String.format("{%s}", record.getEntity().getPrimaryField().getName()));
Map<String, String> fieldVars = new HashMap<>();
for (String field : matchsVars(content)) {
if (MetadataHelper.getLastJoinField(record.getEntity(), field) != null) {
fieldVars.put(field, null);
}
}
if (fieldVars.isEmpty()) return content;
for (String field : fieldVars.keySet()) {
Object value = record.getObjectValue(field);
value = FieldValueHelper.wrapFieldValue(value,
MetadataHelper.getLastJoinField(record.getEntity(), field), true);
if (value != null) {
fieldVars.put(field, value.toString());
}
}
for (Map.Entry<String, String> e : fieldVars.entrySet()) {
content = content.replace("{" + e.getKey() + "}", StringUtils.defaultIfBlank(e.getValue(), StringUtils.EMPTY));
content = content.replace("{" + e.getKey() + "}",
StringUtils.defaultIfBlank(e.getValue(), StringUtils.EMPTY));
}
return content;
}
/**
* 提取内容中的变量 {xxx}
*

View file

@ -64,13 +64,7 @@ public class QiniuCloud {
private String bucketName;
private QiniuCloud() {
String[] account = RebuildConfiguration.getStorageAccount();
if (account != null) {
this.auth = Auth.create(account[0], account[1]);
this.bucketName = account[2];
} else {
log.warn("No QiniuCloud configuration! Using local storage.");
}
initAuth();
}
/**
@ -82,6 +76,18 @@ public class QiniuCloud {
return this.auth != null;
}
/**
*/
public void initAuth() {
String[] account = RebuildConfiguration.getStorageAccount();
if (account != null) {
this.auth = Auth.create(account[0], account[1]);
this.bucketName = account[2];
} else {
log.warn("No QiniuCloud configuration! Using local storage.");
}
}
/**
* @return
*/

View file

@ -151,6 +151,10 @@ public class ConfigurationController extends BaseController {
bucketManager.getBucketInfo(dStorageBucket);
setValues(data);
QiniuCloud.instance().initAuth();
Application.getBean(RebuildWebConfigurer.class).init();
return RespBody.ok();
} catch (QiniuException ex) {

View file

@ -10,6 +10,7 @@ package com.rebuild.web.user;
import cn.devezhao.commons.web.ServletUtils;
import cn.devezhao.persist4j.Record;
import cn.devezhao.persist4j.engine.ID;
import com.rebuild.api.RespBody;
import com.rebuild.core.Application;
import com.rebuild.core.metadata.EntityHelper;
import com.rebuild.core.privileges.UserHelper;
@ -117,7 +118,7 @@ public class UserAvatar extends BaseController {
@RequestMapping("/user-avatar-update")
@ResponseBody
public String avatarUpdate(HttpServletRequest request) throws IOException {
public RespBody avatarUpdate(HttpServletRequest request) throws IOException {
final ID user = getRequestUser(request);
String avatarRaw = getParameterNotNull(request, "avatar");
String xywh = getParameterNotNull(request, "xywh");
@ -130,7 +131,7 @@ public class UserAvatar extends BaseController {
Application.getBean(UserService.class).update(record);
ServletUtils.setSessionAttribute(request, "davatarTime", System.currentTimeMillis());
return uploadName;
return RespBody.ok(uploadName);
}
/**

View file

@ -24,7 +24,7 @@ class RbList extends React.Component {
this.__sortFieldKey = `SortField-${props.config.entity}`
this.__columnWidthKey = `ColumnWidth-${props.config.entity}.`
const sort = ($storage.get(this.__sortFieldKey) || ':').split(':')
const sort = ($storage.get(this.__sortFieldKey) || props.config.sort || ':').split(':')
const fields = props.config.fields || []
for (let i = 0; i < fields.length; i++) {
const cw = $storage.get(this.__columnWidthKey + fields[i].field)

View file

@ -301,10 +301,12 @@ var _initNavs = function () {
var navUrl = '/' + urls.slice(3).join('/')
var $navHit = $('.sidebar-elements a[href="' + navUrl + '"]')
if ($navHit.length > 0 && !$navHit.parent().hasClass('active')) {
$('.sidebar-elements li.active:not(.parent)').removeClass('active')
$navHit.parent().addClass('active')
if ($navHit.parents('li.parent').length > 0) {
$navHit.parents('li.parent').addClass('active').first().trigger('click')
$(document.body).trigger('click')
// parent
var $parent = $navHit.parents('li.parent:not(.active)')
if ($parent.length > 0) {
$parent.addClass('active').first().trigger('click')
}
}
}

View file

@ -14,7 +14,8 @@ class RbViewForm extends React.Component {
super(props)
this.state = { ...props }
this.onViewEditable = wpc.onViewEditable !== false
this.onViewEditable = this.props.onViewEditable
if (this.onViewEditable) this.onViewEditable = wpc.onViewEditable !== false
this.__FormData = {}
}
@ -510,7 +511,7 @@ const RbViewPage = {
this.__entity = entity
this.__ep = ep
renderRbcomp(<RbViewForm entity={entity[0]} id={id} />, 'tab-rbview', function () {
renderRbcomp(<RbViewForm entity={entity[0]} id={id} onViewEditable={ep && ep.U} />, 'tab-rbview', function () {
RbViewPage._RbViewForm = this
})