mirror of
https://github.com/getrebuild/rebuild.git
synced 2025-03-13 15:44:26 +08:00
Merge branch 'master' into develop
This commit is contained in:
commit
1528a5b26c
12 changed files with 104 additions and 53 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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("你有一条新通知");
|
||||
|
|
|
@ -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}
|
||||
*
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in a new issue