Merge pull request #415 from getrebuild/copy-entity

Copy entity
This commit is contained in:
RB 2021-12-20 11:27:13 +08:00 committed by GitHub
commit 51f59ab36f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 478 additions and 233 deletions

2
@rbv

@ -1 +1 @@
Subproject commit f6f4a5f87e30c9865e580d117d30e1b8a4c9a41b Subproject commit 29deac78d1ba561dc503aefb2ab6530a9438b460

View file

@ -8,19 +8,31 @@ See LICENSE and COMMERCIAL in the project root for license information.
package com.rebuild.core; package com.rebuild.core;
import cn.devezhao.commons.ObjectUtils; import cn.devezhao.commons.ObjectUtils;
import cn.devezhao.commons.xml.XMLHelper;
import com.rebuild.core.support.ConfigurationItem;
import com.rebuild.core.support.RebuildConfiguration;
import com.rebuild.core.support.distributed.KnownJedisPool; import com.rebuild.core.support.distributed.KnownJedisPool;
import com.rebuild.core.support.setup.InstallState; import com.rebuild.core.support.setup.InstallState;
import com.rebuild.utils.CommonsUtils; import com.rebuild.utils.CommonsUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.springframework.cache.CacheManager; import org.springframework.cache.CacheManager;
import org.springframework.cache.ehcache.EhCacheCacheManager; import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPool;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
/** /**
* NOTE JRebel reloading error
*
* @author devezhao * @author devezhao
* @since 2020/9/23 * @since 2020/9/23
*/ */
@ -41,9 +53,24 @@ public class BootConfiguration implements InstallState {
@Bean @Bean
CacheManager createCacheManager() throws IOException { CacheManager createCacheManager() throws IOException {
net.sf.ehcache.CacheManager cacheManager;
String datadir = BootEnvironmentPostProcessor.getProperty(ConfigurationItem.DataDirectory.name());
if (StringUtils.isBlank(datadir)) {
cacheManager = new net.sf.ehcache.CacheManager(CommonsUtils.getStreamOfRes("ehcache.xml"));
} else {
// 使用数据目录存储缓存文件
Document config = XMLHelper.createDocument(CommonsUtils.getStreamOfRes("ehcache.xml"));
Element diskStore = (Element) config.getRootElement().selectSingleNode("//diskStore");
File tempdir = RebuildConfiguration.getFileOfTemp(".ehcache");
diskStore.addAttribute("path", tempdir.getAbsolutePath());
InputStream is = new ByteArrayInputStream(config.asXML().getBytes(StandardCharsets.UTF_8));
cacheManager = new net.sf.ehcache.CacheManager(is);
}
EhCacheCacheManager manager = new EhCacheCacheManager(); EhCacheCacheManager manager = new EhCacheCacheManager();
manager.setCacheManager( manager.setCacheManager(cacheManager);
new net.sf.ehcache.CacheManager(CommonsUtils.getStreamOfRes("ehcache.xml")));
return manager; return manager;
} }
@ -56,12 +83,16 @@ public class BootConfiguration implements InstallState {
* @return * @return
*/ */
public static JedisPool createJedisPoolInternal() { public static JedisPool createJedisPoolInternal() {
String use = BootEnvironmentPostProcessor.getProperty("db.CacheHost"); String useHost = BootEnvironmentPostProcessor.getProperty("db.CacheHost");
if ("0".equals(use)) return USE_EHCACHE; if ("0".equals(useHost)) return USE_EHCACHE;
String spec = BootEnvironmentPostProcessor.getProperty(ConfigurationItem.RedisDatabase.name());
int database = NumberUtils.toInt(spec, (Integer) ConfigurationItem.RedisDatabase.getDefaultValue());
return new KnownJedisPool( return new KnownJedisPool(
StringUtils.defaultIfBlank(use, "127.0.0.1"), StringUtils.defaultIfBlank(useHost, "127.0.0.1"),
ObjectUtils.toInt(BootEnvironmentPostProcessor.getProperty("db.CachePort"), 6379), ObjectUtils.toInt(BootEnvironmentPostProcessor.getProperty("db.CachePort"), 6379),
BootEnvironmentPostProcessor.getProperty("db.CachePassword", null)); BootEnvironmentPostProcessor.getProperty("db.CachePassword", null),
database);
} }
} }

View file

@ -13,7 +13,6 @@ import com.rebuild.core.support.RebuildConfiguration;
import com.rebuild.core.support.setup.InstallState; import com.rebuild.core.support.setup.InstallState;
import com.rebuild.core.support.setup.Installer; import com.rebuild.core.support.setup.Installer;
import com.rebuild.utils.AES; import com.rebuild.utils.AES;
import com.rebuild.utils.RebuildBanner;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.impl.StaticLoggerBinder; import org.slf4j.impl.StaticLoggerBinder;
@ -170,6 +169,7 @@ public class BootEnvironmentPostProcessor implements EnvironmentPostProcessor, I
String value = null; String value = null;
// in CLI // in CLI
if (ConfigurationItem.DataDirectory.name().equalsIgnoreCase(name) if (ConfigurationItem.DataDirectory.name().equalsIgnoreCase(name)
|| ConfigurationItem.RedisDatabase.name().equalsIgnoreCase(name)
|| ConfigurationItem.MobileUrl.name().equalsIgnoreCase(name) || ConfigurationItem.MobileUrl.name().equalsIgnoreCase(name)
|| ConfigurationItem.RbStoreUrl.name().equalsIgnoreCase(name)) { || ConfigurationItem.RbStoreUrl.name().equalsIgnoreCase(name)) {
value = StringUtils.defaultIfBlank(System.getProperty(name), System.getProperty(V2_PREFIX + name)); value = StringUtils.defaultIfBlank(System.getProperty(name), System.getProperty(V2_PREFIX + name));

View file

@ -46,8 +46,7 @@ public abstract class BaseCacheTemplate<V extends Serializable> implements Cache
this.delegate = new EhcacheDriver<>(backup); this.delegate = new EhcacheDriver<>(backup);
} }
String fix = StringUtils.defaultIfBlank(System.getProperty("cache.keyprefix"), "RB."); this.keyPrefix = "RB." + StringUtils.defaultIfBlank(keyPrefix, StringUtils.EMPTY);
this.keyPrefix = fix + StringUtils.defaultIfBlank(keyPrefix, StringUtils.EMPTY);
} }
@Override @Override

View file

@ -8,7 +8,6 @@ See LICENSE and COMMERCIAL in the project root for license information.
package com.rebuild.core.cache; package com.rebuild.core.cache;
import com.rebuild.core.Application; import com.rebuild.core.Application;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache; import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager; import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;

View file

@ -133,8 +133,8 @@ public class NavBuilder extends NavManager {
return true; return true;
} }
return !Application.getPrivilegesManager().allowRead(user, return !Application.getPrivilegesManager().allowRead(
MetadataHelper.getEntity(value).getEntityCode()); user, MetadataHelper.getEntity(value).getEntityCode());
} else if ("URL".equals(type)) { } else if ("URL".equals(type)) {
String[] split = value.split(URL_BIND_EP); String[] split = value.split(URL_BIND_EP);

View file

@ -30,9 +30,9 @@ public class RebuildApiManager implements ConfigManager {
*/ */
public ConfigBean getApp(String appid) { public ConfigBean getApp(String appid) {
final String ckey = CKEY_PREFIX + appid; final String ckey = CKEY_PREFIX + appid;
ConfigBean config = (ConfigBean) Application.getCommonsCache().getx(ckey); ConfigBean cb = (ConfigBean) Application.getCommonsCache().getx(ckey);
if (config != null) { if (cb != null) {
return config; return cb;
} }
Object[] o = Application.createQueryNoFilter( Object[] o = Application.createQueryNoFilter(
@ -41,13 +41,13 @@ public class RebuildApiManager implements ConfigManager {
.unique(); .unique();
if (o == null) return null; if (o == null) return null;
config = new ConfigBean() cb = new ConfigBean()
.set("appId", appid) .set("appId", appid)
.set("appSecret", o[0]) .set("appSecret", o[0])
.set("bindUser", o[1]) .set("bindUser", o[1])
.set("bindIps", o[2]); .set("bindIps", o[2]);
Application.getCommonsCache().putx(ckey, config); Application.getCommonsCache().putx(ckey, cb);
return config; return cb;
} }
@Override @Override

View file

@ -61,9 +61,9 @@ public class PickListManager implements ConfigManager {
*/ */
public ConfigBean[] getPickListRaw(String entity, String field, boolean includeHide) { public ConfigBean[] getPickListRaw(String entity, String field, boolean includeHide) {
final String ckey = String.format("PickList-%s.%s", entity, field); final String ckey = String.format("PickList-%s.%s", entity, field);
ConfigBean[] entries = (ConfigBean[]) Application.getCommonsCache().getx(ckey); ConfigBean[] cached = (ConfigBean[]) Application.getCommonsCache().getx(ckey);
if (entries == null) { if (cached == null) {
Object[][] array = Application.createQueryNoFilter( Object[][] array = Application.createQueryNoFilter(
"select itemId,text,isDefault,isHide,maskValue from PickList where belongEntity = ? and belongField = ? order by seq asc") "select itemId,text,isDefault,isHide,maskValue from PickList where belongEntity = ? and belongField = ? order by seq asc")
.setParameter(1, entity) .setParameter(1, entity)
@ -80,12 +80,12 @@ public class PickListManager implements ConfigManager {
list.add(entry); list.add(entry);
} }
entries = list.toArray(new ConfigBean[0]); cached = list.toArray(new ConfigBean[0]);
Application.getCommonsCache().putx(ckey, entries); Application.getCommonsCache().putx(ckey, cached);
} }
List<ConfigBean> ret = new ArrayList<>(); List<ConfigBean> ret = new ArrayList<>();
for (ConfigBean entry : entries) { for (ConfigBean entry : cached) {
if (includeHide || !entry.getBoolean("hide")) { if (includeHide || !entry.getBoolean("hide")) {
ret.add(entry.clone()); ret.add(entry.clone());
} }

View file

@ -0,0 +1,92 @@
/*
Copyright (c) Ruifang Tech <http://ruifang-tech.com/> and/or its owners. All rights reserved.
*/
package com.rebuild.core.metadata.impl;
import cn.devezhao.persist4j.Entity;
import cn.devezhao.persist4j.engine.ID;
import com.alibaba.fastjson.JSONObject;
import com.rebuild.core.metadata.MetadataHelper;
import com.rebuild.core.privileges.UserHelper;
import com.rebuild.core.rbstore.MetaSchemaGenerator;
import com.rebuild.core.rbstore.MetaschemaImporter;
import com.rebuild.core.support.i18n.Language;
import com.rebuild.core.support.task.TaskExecutors;
import com.rebuild.utils.RbAssert;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.RandomUtils;
/**
* 复制实体
*
* @author devezhao
* @see MetaSchemaGenerator
* @see MetaschemaImporter
* @since 2021/12/17
*/
public class CopyEntity extends Entity2Schema {
final private Entity sourceEntity;
public CopyEntity(Entity sourceEntity) {
this.sourceEntity = sourceEntity;
}
/**
* @param entityName
* @param detailName
* @return
*/
public String copy(String entityName, String detailName) {
final ID user = getUser();
RbAssert.isAllow(UserHelper.isSuperAdmin(user), Language.L("仅超级管理员可操作"));
// 导出
JSONObject schemadata = (JSONObject) new MetaSchemaGenerator(sourceEntity).generate();
String uniqueEntityName = clearConfig(schemadata, entityName);
JSONObject detailSchema = schemadata.getJSONObject("detail");
if (StringUtils.isBlank(detailName)) {
schemadata.remove("detail");
} else if (detailSchema != null) {
clearConfig(detailSchema, detailName);
}
// 导入
MetaschemaImporter importer = new MetaschemaImporter(schemadata);
importer.setUser(user);
TaskExecutors.run(importer);
// TODO 保留审批字段
return uniqueEntityName;
}
private String clearConfig(JSONObject schema, String entityName) {
schema.remove(MetaSchemaGenerator.CFG_TRANSFORMS);
schema.remove(MetaSchemaGenerator.CFG_APPROVALS);
schema.remove(MetaSchemaGenerator.CFG_TRIGGERS);
schema.remove(MetaSchemaGenerator.CFG_FILTERS);
// 以下保留
// schema.remove(MetaSchemaGenerator.CFG_FILLINS);
// schema.remove(MetaSchemaGenerator.CFG_LAYOUTS);
String uniqueEntityName = toPinyinName(entityName);
for (int i = 0; i < 5; i++) {
if (MetadataHelper.containsEntity(uniqueEntityName)) {
uniqueEntityName += RandomUtils.nextInt(99);
} else {
break;
}
}
schema.put("entity", uniqueEntityName);
schema.put("entityLabel", entityName);
return uniqueEntityName;
}
}

View file

@ -23,7 +23,6 @@ import com.rebuild.core.metadata.MetadataHelper;
import com.rebuild.core.metadata.easymeta.DisplayType; import com.rebuild.core.metadata.easymeta.DisplayType;
import com.rebuild.core.metadata.easymeta.EasyEntity; import com.rebuild.core.metadata.easymeta.EasyEntity;
import com.rebuild.core.metadata.easymeta.EasyMetaFactory; import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
import com.rebuild.core.privileges.UserService;
import com.rebuild.core.support.License; import com.rebuild.core.support.License;
import com.rebuild.core.support.i18n.Language; import com.rebuild.core.support.i18n.Language;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -39,11 +38,12 @@ import org.apache.commons.lang.math.RandomUtils;
@Slf4j @Slf4j
public class Entity2Schema extends Field2Schema { public class Entity2Schema extends Field2Schema {
/** public Entity2Schema() {
* @param user super();
*/ }
public Entity2Schema(ID user) { public Entity2Schema(ID user) {
super(user); super.setUser(user);
} }
/** /**
@ -70,7 +70,6 @@ public class Entity2Schema extends Field2Schema {
if (MetadataHelper.containsEntity(entityName)) { if (MetadataHelper.containsEntity(entityName)) {
throw new MetadataModificationException(Language.L("实体已存在 : %s", entityName)); throw new MetadataModificationException(Language.L("实体已存在 : %s", entityName));
} }
} else { } else {
entityName = toPinyinName(entityLabel); entityName = toPinyinName(entityLabel);
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
@ -103,7 +102,7 @@ public class Entity2Schema extends Field2Schema {
nameFiled = entityName + "Name"; nameFiled = entityName + "Name";
} }
Record record = EntityHelper.forNew(EntityHelper.MetaEntity, user); Record record = EntityHelper.forNew(EntityHelper.MetaEntity, getUser());
record.setString("entityLabel", entityLabel); record.setString("entityLabel", entityLabel);
record.setString("entityName", entityName); record.setString("entityName", entityName);
record.setString("physicalName", physicalName); record.setString("physicalName", physicalName);
@ -179,9 +178,7 @@ public class Entity2Schema extends Field2Schema {
* @return * @return
*/ */
public boolean dropEntity(Entity entity, boolean force) { public boolean dropEntity(Entity entity, boolean force) {
if (!user.equals(UserService.ADMIN_USER)) { getUser(); // Check admin
throw new MetadataModificationException(Language.L("仅超级管理员可删除实体"));
}
EasyEntity easy = EasyMetaFactory.valueOf(entity); EasyEntity easy = EasyMetaFactory.valueOf(entity);
ID metaRecordId = easy.getMetaId(); ID metaRecordId = easy.getMetaId();
@ -224,7 +221,7 @@ public class Entity2Schema extends Field2Schema {
// 先删配置 // 先删配置
final ID sessionUser = UserContextHolder.getUser(true); final ID sessionUser = UserContextHolder.getUser(true);
if (sessionUser == null) UserContextHolder.setUser(user); if (sessionUser == null) UserContextHolder.setUser(getUser());
try { try {
Application.getBean(MetaEntityService.class).delete(metaRecordId); Application.getBean(MetaEntityService.class).delete(metaRecordId);

View file

@ -27,6 +27,7 @@ import com.rebuild.core.metadata.easymeta.DisplayType;
import com.rebuild.core.metadata.easymeta.EasyField; import com.rebuild.core.metadata.easymeta.EasyField;
import com.rebuild.core.metadata.easymeta.EasyMetaFactory; import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
import com.rebuild.core.privileges.UserHelper; import com.rebuild.core.privileges.UserHelper;
import com.rebuild.core.support.SetUser;
import com.rebuild.core.support.i18n.Language; import com.rebuild.core.support.i18n.Language;
import com.rebuild.core.support.setup.Installer; import com.rebuild.core.support.setup.Installer;
import com.rebuild.utils.BlockList; import com.rebuild.utils.BlockList;
@ -46,20 +47,26 @@ import java.util.Set;
* @since 08/13/2018 * @since 08/13/2018
*/ */
@Slf4j @Slf4j
public class Field2Schema { public class Field2Schema extends SetUser {
// 小数位真实长度 // 小数位真实长度
private static final int DECIMAL_SCALE = 8; private static final int DECIMAL_SCALE = 8;
final protected ID user;
final protected Set<ID> recordedMetaId = new HashSet<>(); final protected Set<ID> recordedMetaId = new HashSet<>();
/** public Field2Schema() {
* @param user super();
*/ }
public Field2Schema(ID user) { public Field2Schema(ID user) {
super.setUser(user);
}
@Override
public ID getUser() {
ID user = super.getUser();
RbAssert.isAllow(UserHelper.isSuperAdmin(user), Language.L("仅超级管理员可操作")); RbAssert.isAllow(UserHelper.isSuperAdmin(user), Language.L("仅超级管理员可操作"));
this.user = user; return user;
} }
/** /**
@ -234,7 +241,7 @@ public class Field2Schema {
String physicalName = StringHelper.hyphenate(fieldName).toUpperCase(); String physicalName = StringHelper.hyphenate(fieldName).toUpperCase();
Record recordOfField = EntityHelper.forNew(EntityHelper.MetaField, user); Record recordOfField = EntityHelper.forNew(EntityHelper.MetaField, getUser());
recordOfField.setString("belongEntity", entity.getName()); recordOfField.setString("belongEntity", entity.getName());
recordOfField.setString("fieldName", fieldName); recordOfField.setString("fieldName", fieldName);
recordOfField.setString("physicalName", physicalName); recordOfField.setString("physicalName", physicalName);

View file

@ -17,10 +17,10 @@ import com.rebuild.core.Application;
import com.rebuild.core.configuration.ConfigBean; import com.rebuild.core.configuration.ConfigBean;
import com.rebuild.core.configuration.general.PickListManager; import com.rebuild.core.configuration.general.PickListManager;
import com.rebuild.core.metadata.MetadataHelper; import com.rebuild.core.metadata.MetadataHelper;
import com.rebuild.core.metadata.easymeta.DisplayType;
import com.rebuild.core.metadata.easymeta.EasyEntity; import com.rebuild.core.metadata.easymeta.EasyEntity;
import com.rebuild.core.metadata.easymeta.EasyField; import com.rebuild.core.metadata.easymeta.EasyField;
import com.rebuild.core.metadata.easymeta.EasyMetaFactory; import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
import com.rebuild.core.metadata.easymeta.DisplayType;
import com.rebuild.core.privileges.UserService; import com.rebuild.core.privileges.UserService;
import com.rebuild.utils.JSONUtils; import com.rebuild.utils.JSONUtils;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
@ -38,6 +38,13 @@ import java.io.IOException;
*/ */
public class MetaSchemaGenerator { public class MetaSchemaGenerator {
public static final String CFG_FILLINS = "fillins";
public static final String CFG_LAYOUTS = "layouts";
public static final String CFG_FILTERS = "filters";
public static final String CFG_TRIGGERS = "triggers";
public static final String CFG_APPROVALS = "approvals";
public static final String CFG_TRANSFORMS = "transforms";
final private Entity mainEntity; final private Entity mainEntity;
/** /**
@ -68,12 +75,7 @@ public class MetaSchemaGenerator {
return schema; return schema;
} }
/** private JSON performEntity(Entity entity, boolean detail) {
* @param entity
* @param isDetail
* @return
*/
private JSON performEntity(Entity entity, boolean isDetail) {
JSONObject schemaEntity = new JSONObject(true); JSONObject schemaEntity = new JSONObject(true);
// 实体 // 实体
@ -92,29 +94,31 @@ public class MetaSchemaGenerator {
for (Field field : entity.getFields()) { for (Field field : entity.getFields()) {
if (field.getType() == FieldType.PRIMARY if (field.getType() == FieldType.PRIMARY
|| MetadataHelper.isCommonsField(field) || MetadataHelper.isCommonsField(field)
|| (isDetail && MetadataHelper.getDetailToMainField(entity).equals(field))) { || (detail && MetadataHelper.getDetailToMainField(entity).equals(field))) {
continue; continue;
} }
metaFields.add(performField(field)); metaFields.add(performField(field));
} }
schemaEntity.put("fields", metaFields); schemaEntity.put("fields", metaFields);
// 布局
schemaEntity.put("layouts", performLayouts(entity));
// 表单回填 // 表单回填
schemaEntity.put("fillins", performFillins(entity)); schemaEntity.put(CFG_FILLINS, performFillins(entity));
// 高级过滤 // 布局
schemaEntity.put("filters", performFilters(entity)); schemaEntity.put(CFG_LAYOUTS, performLayouts(entity));
// 高级查询
schemaEntity.put(CFG_FILTERS, performFilters(entity));
// 触发器 // 触发器
schemaEntity.put("triggers", performTriggers(entity)); schemaEntity.put(CFG_TRIGGERS, performTriggers(entity));
if (!isDetail) { if (!detail) {
// 审批流程 // 审批流程
schemaEntity.put("approvals", performApprovals(entity)); schemaEntity.put(CFG_APPROVALS, performApprovals(entity));
// 字段转换 // 字段转换
schemaEntity.put("transforms", performTransforms(entity)); schemaEntity.put(CFG_TRANSFORMS, performTransforms(entity));
} }
// TODO 报表模板?
return schemaEntity; return schemaEntity;
} }

View file

@ -10,10 +10,12 @@ package com.rebuild.core.rbstore;
import cn.devezhao.persist4j.Entity; import cn.devezhao.persist4j.Entity;
import cn.devezhao.persist4j.Field; import cn.devezhao.persist4j.Field;
import cn.devezhao.persist4j.Record; import cn.devezhao.persist4j.Record;
import cn.devezhao.persist4j.engine.ID;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.rebuild.core.Application; import com.rebuild.core.Application;
import com.rebuild.core.UserContextHolder;
import com.rebuild.core.configuration.general.*; import com.rebuild.core.configuration.general.*;
import com.rebuild.core.metadata.EntityHelper; import com.rebuild.core.metadata.EntityHelper;
import com.rebuild.core.metadata.EntityRecordCreator; import com.rebuild.core.metadata.EntityRecordCreator;
@ -36,6 +38,7 @@ import com.rebuild.utils.JSONUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -51,7 +54,7 @@ public class MetaschemaImporter extends HeavyTask<String> {
private JSONObject data; private JSONObject data;
private List<Object[]> picklistHolders = new ArrayList<>(); private Map<Field, JSONObject> picklistHolders = new HashMap<>();
private boolean needClearContextHolder = false; private boolean needClearContextHolder = false;
@ -69,9 +72,7 @@ public class MetaschemaImporter extends HeavyTask<String> {
*/ */
public String verfiy() { public String verfiy() {
String hasError = verfiyEntity(data); String hasError = verfiyEntity(data);
if (hasError != null) { if (hasError != null) return hasError;
return hasError;
}
JSONObject detailData = data.getJSONObject("detail"); JSONObject detailData = data.getJSONObject("detail");
if (detailData == null) detailData = data.getJSONObject("slave"); if (detailData == null) detailData = data.getJSONObject("slave");
@ -93,13 +94,16 @@ public class MetaschemaImporter extends HeavyTask<String> {
for (Object o : entity.getJSONArray("fields")) { for (Object o : entity.getJSONArray("fields")) {
JSONObject field = (JSONObject) o; JSONObject field = (JSONObject) o;
String dt = field.getString("displayType"); String dt = field.getString("displayType");
if (DisplayType.REFERENCE.name().equals(dt) || DisplayType.N2NREFERENCE.name().equals(dt)) {
if (DisplayType.REFERENCE.name().equals(dt)
|| DisplayType.N2NREFERENCE.name().equals(dt)) {
String refEntity = field.getString("refEntity"); String refEntity = field.getString("refEntity");
if (!entityName.equals(refEntity) && !MetadataHelper.containsEntity(refEntity)) { if (!entityName.equals(refEntity) && !MetadataHelper.containsEntity(refEntity)) {
return Language.L("缺少必要的引用实体 : %s (%s)", field.getString("fieldLabel"), refEntity); return Language.L("缺少必要的引用实体 : %s (%s)", field.getString("fieldLabel"), refEntity);
} }
} }
} }
return null; return null;
} }
@ -136,10 +140,18 @@ public class MetaschemaImporter extends HeavyTask<String> {
} }
} }
for (Object[] picklist : picklistHolders) { final ID sessionUser = UserContextHolder.getUser(true);
Field refreshField = (Field) picklist[0]; if (sessionUser == null) UserContextHolder.setUser(getUser());
refreshField = MetadataHelper.getField(refreshField.getOwnEntity().getName(), refreshField.getName());
Application.getBean(PickListService.class).updateBatch(refreshField, (JSONObject) picklist[1]); // 字段选项
try {
for (Map.Entry<Field, JSONObject> e : picklistHolders.entrySet()) {
Field field = e.getKey();
Application.getBean(PickListService.class).updateBatch(
MetadataHelper.getField(field.getOwnEntity().getName(), field.getName()), e.getValue());
}
} finally {
if (sessionUser == null) UserContextHolder.clear();
} }
setCompleted(100); setCompleted(100);
@ -156,34 +168,35 @@ public class MetaschemaImporter extends HeavyTask<String> {
} }
/** /**
* @param schemaEntity * @param schema
* @param mainEntityName * @param mainEntity
* @return * @return
* @throws MetadataModificationException * @throws MetadataModificationException
*/ */
private String performEntity(JSONObject schemaEntity, String mainEntityName) throws MetadataModificationException { private String performEntity(JSONObject schema, String mainEntity) throws MetadataModificationException {
final String entityName = schemaEntity.getString("entity"); final String entityName = schema.getString("entity");
final String entityLabel = schemaEntity.getString("entityLabel"); final String entityLabel = schema.getString("entityLabel");
Entity2Schema entity2Schema = new Entity2Schema(this.getUser()); Entity2Schema entity2Schema = new Entity2Schema(this.getUser());
entity2Schema.createEntity( entity2Schema.createEntity(
entityName, entityLabel, schemaEntity.getString("comments"), mainEntityName, false); entityName, entityLabel, schema.getString("comments"), mainEntity, false);
Entity entity = MetadataHelper.getEntity(entityName);
Entity newEntity = MetadataHelper.getEntity(entityName);
this.setCompleted((int) (this.getCompleted() * 1.5)); this.setCompleted((int) (this.getCompleted() * 1.5));
JSONArray fields = schemaEntity.getJSONArray("fields"); JSONArray fields = schema.getJSONArray("fields");
try { try {
List<Field> fieldsList = new ArrayList<>(); List<Field> fieldsList = new ArrayList<>();
for (Object field : fields) { for (Object field : fields) {
Field unsafe = performField((JSONObject) field, entity); Field unsafe = performField((JSONObject) field, newEntity);
if (unsafe != null) fieldsList.add(unsafe); if (unsafe != null) fieldsList.add(unsafe);
} }
// 同步字段到数据库 // 同步字段到数据库
new Field2Schema(UserService.ADMIN_USER).schema2Database(entity, fieldsList.toArray(new Field[0])); new Field2Schema(UserService.ADMIN_USER).schema2Database(newEntity, fieldsList.toArray(new Field[0]));
} catch (Exception ex) { } catch (Exception ex) {
entity2Schema.dropEntity(entity, true); entity2Schema.dropEntity(newEntity, true);
if (ex instanceof MetadataModificationException) { if (ex instanceof MetadataModificationException) {
throw ex; throw ex;
@ -192,17 +205,18 @@ public class MetaschemaImporter extends HeavyTask<String> {
} }
} }
Record needUpdate = EntityHelper.forUpdate(EasyMetaFactory.valueOf(entity).getMetaId(), this.getUser(), false); Record needUpdate = EntityHelper.forUpdate(
EasyMetaFactory.valueOf(newEntity).getMetaId(), this.getUser(), false);
String nameField = schemaEntity.getString("nameField"); String nameField = schema.getString("nameField");
if (nameField != null) { if (nameField != null) {
needUpdate.setString("nameField", nameField); needUpdate.setString("nameField", nameField);
} }
String entityIcon = schemaEntity.getString("entityIcon"); String entityIcon = schema.getString("entityIcon");
if (entityIcon != null) { if (entityIcon != null) {
needUpdate.setString("icon", entityIcon); needUpdate.setString("icon", entityIcon);
} }
String quickFields = schemaEntity.getString("quickFields"); String quickFields = schema.getString("quickFields");
if (quickFields != null) { if (quickFields != null) {
needUpdate.setString("extConfig", JSONUtils.toJSONObject("quickFields", quickFields).toJSONString()); needUpdate.setString("extConfig", JSONUtils.toJSONObject("quickFields", quickFields).toJSONString());
} }
@ -214,24 +228,24 @@ public class MetaschemaImporter extends HeavyTask<String> {
// 刷新元数据 // 刷新元数据
MetadataHelper.getMetadataFactory().refresh(false); MetadataHelper.getMetadataFactory().refresh(false);
// 布局
JSONObject layouts = schemaEntity.getJSONObject("layouts");
if (layouts != null) {
for (Map.Entry<String, Object> e : layouts.entrySet()) {
performLayout(entityName, e.getKey(), (JSON) e.getValue());
}
}
// 表单回填 // 表单回填
JSONArray fillins = schemaEntity.getJSONArray("fillins"); JSONArray fillins = schema.getJSONArray(MetaSchemaGenerator.CFG_FILLINS);
if (fillins != null) { if (fillins != null) {
for (Object o : fillins) { for (Object o : fillins) {
performFillin(entityName, (JSONObject) o); performFillin(entityName, (JSONObject) o);
} }
} }
// 布局
JSONObject layouts = schema.getJSONObject(MetaSchemaGenerator.CFG_LAYOUTS);
if (layouts != null) {
for (Map.Entry<String, Object> e : layouts.entrySet()) {
performLayout(entityName, e.getKey(), (JSON) e.getValue());
}
}
// 高级查询 // 高级查询
JSONArray filters = schemaEntity.getJSONArray("filters"); JSONArray filters = schema.getJSONArray(MetaSchemaGenerator.CFG_FILTERS);
if (filters != null) { if (filters != null) {
for (Object o : filters) { for (Object o : filters) {
performFilter(entityName, (JSONObject) o); performFilter(entityName, (JSONObject) o);
@ -239,7 +253,7 @@ public class MetaschemaImporter extends HeavyTask<String> {
} }
// 触发器 // 触发器
JSONArray triggers = schemaEntity.getJSONArray("triggers"); JSONArray triggers = schema.getJSONArray(MetaSchemaGenerator.CFG_TRIGGERS);
if (triggers != null) { if (triggers != null) {
for (Object o : triggers) { for (Object o : triggers) {
performTrigger(entityName, (JSONObject) o); performTrigger(entityName, (JSONObject) o);
@ -247,7 +261,7 @@ public class MetaschemaImporter extends HeavyTask<String> {
} }
// 审批流程 // 审批流程
JSONArray approvals = schemaEntity.getJSONArray("approvals"); JSONArray approvals = schema.getJSONArray(MetaSchemaGenerator.CFG_APPROVALS);
if (approvals != null) { if (approvals != null) {
for (Object o : approvals) { for (Object o : approvals) {
performApproval(entityName, (JSONObject) o); performApproval(entityName, (JSONObject) o);
@ -255,7 +269,7 @@ public class MetaschemaImporter extends HeavyTask<String> {
} }
// 记录转换 // 记录转换
JSONArray transforms = schemaEntity.getJSONArray("transforms"); JSONArray transforms = schema.getJSONArray(MetaSchemaGenerator.CFG_TRANSFORMS);
if (transforms != null) { if (transforms != null) {
for (Object o : transforms) { for (Object o : transforms) {
performTransform(entityName, (JSONObject) o); performTransform(entityName, (JSONObject) o);
@ -277,7 +291,10 @@ public class MetaschemaImporter extends HeavyTask<String> {
} }
Field unsafeField = new Field2Schema(this.getUser()).createUnsafeField( Field unsafeField = new Field2Schema(this.getUser()).createUnsafeField(
belong, fieldName, fieldLabel, dt, belong,
fieldName,
fieldLabel,
dt,
schemaField.getBooleanValue("nullable"), schemaField.getBooleanValue("nullable"),
true, true,
schemaField.getBooleanValue("updatable"), schemaField.getBooleanValue("updatable"),
@ -290,8 +307,7 @@ public class MetaschemaImporter extends HeavyTask<String> {
schemaField.getString("defaultValue")); schemaField.getString("defaultValue"));
if (DisplayType.PICKLIST == dt || DisplayType.MULTISELECT == dt) { if (DisplayType.PICKLIST == dt || DisplayType.MULTISELECT == dt) {
picklistHolders.add(new Object[] { picklistHolders.put(unsafeField, performPickList(schemaField.getJSONArray("items")));
unsafeField, performPickList(schemaField.getJSONArray("items")) });
} }
return unsafeField; return unsafeField;
@ -300,7 +316,7 @@ public class MetaschemaImporter extends HeavyTask<String> {
private JSONObject performPickList(JSONArray items) { private JSONObject performPickList(JSONArray items) {
JSONArray shown = new JSONArray(); JSONArray shown = new JSONArray();
for (Object o : items) { for (Object o : items) {
JSONArray item = (JSONArray) o; JSONArray item = o instanceof Object[] ? (JSONArray) JSON.toJSON(o) : (JSONArray) o;
JSONObject option = JSONUtils.toJSONObject( JSONObject option = JSONUtils.toJSONObject(
new String[] { "text", "default" }, new String[] { "text", "default" },

View file

@ -43,9 +43,9 @@ public class ChartManager implements ConfigManager {
*/ */
public ConfigBean getChart(ID chartid) { public ConfigBean getChart(ID chartid) {
final String ckey = "Chart-" + chartid; final String ckey = "Chart-" + chartid;
ConfigBean entry = (ConfigBean) Application.getCommonsCache().getx(ckey); ConfigBean cb = (ConfigBean) Application.getCommonsCache().getx(ckey);
if (entry != null) { if (cb != null) {
return entry.clone(); return cb.clone();
} }
Object[] o = Application.createQueryNoFilter( Object[] o = Application.createQueryNoFilter(
@ -64,13 +64,13 @@ public class ChartManager implements ConfigManager {
} }
} }
entry = new ConfigBean() cb = new ConfigBean()
.set("title", o[0]) .set("title", o[0])
.set("type", o[1]) .set("type", o[1])
.set("config", o[2] instanceof JSON ? o[2] : JSON.parse((String) o[2])) .set("config", o[2] instanceof JSON ? o[2] : JSON.parse((String) o[2]))
.set("createdBy", o[3]); .set("createdBy", o[3]);
Application.getCommonsCache().putx(ckey, entry); Application.getCommonsCache().putx(ckey, cb);
return entry.clone(); return cb.clone();
} }
/** /**

View file

@ -82,9 +82,9 @@ public class ProjectManager implements ConfigManager {
* @return * @return
*/ */
private ConfigBean[] getProjects() { private ConfigBean[] getProjects() {
ConfigBean[] projects = (ConfigBean[]) Application.getCommonsCache().getx(CKEY_PROJECTS); ConfigBean[] cached = (ConfigBean[]) Application.getCommonsCache().getx(CKEY_PROJECTS);
if (projects == null) { if (cached == null) {
Object[][] array = Application.createQueryNoFilter( Object[][] array = Application.createQueryNoFilter(
"select configId,projectCode,projectName,iconName,scope,members,principal,extraDefinition,status from ProjectConfig") "select configId,projectCode,projectName,iconName,scope,members,principal,extraDefinition,status from ProjectConfig")
.array(); .array();
@ -117,11 +117,11 @@ public class ProjectManager implements ConfigManager {
alist.add(e); alist.add(e);
} }
projects = alist.toArray(new ConfigBean[0]); cached = alist.toArray(new ConfigBean[0]);
Application.getCommonsCache().putx(CKEY_PROJECTS, projects); Application.getCommonsCache().putx(CKEY_PROJECTS, cached);
} }
for (ConfigBean p : projects) { for (ConfigBean p : cached) {
Set<ID> members = Collections.emptySet(); Set<ID> members = Collections.emptySet();
String userDefs = p.getString("_members"); String userDefs = p.getString("_members");
if (StringUtils.isNotBlank(userDefs) && userDefs.length() >= 20) { if (StringUtils.isNotBlank(userDefs) && userDefs.length() >= 20) {
@ -129,7 +129,7 @@ public class ProjectManager implements ConfigManager {
} }
p.set("members", members); p.set("members", members);
} }
return projects; return cached;
} }
/** /**
@ -160,9 +160,9 @@ public class ProjectManager implements ConfigManager {
Assert.notNull(projectId, "[projectId] cannot be null"); Assert.notNull(projectId, "[projectId] cannot be null");
final String ckey = CKEY_PLANS + projectId; final String ckey = CKEY_PLANS + projectId;
ConfigBean[] cache = (ConfigBean[]) Application.getCommonsCache().getx(ckey); ConfigBean[] cached = (ConfigBean[]) Application.getCommonsCache().getx(ckey);
if (cache == null) { if (cached == null) {
Object[][] array = Application.createQueryNoFilter( Object[][] array = Application.createQueryNoFilter(
"select configId,planName,flowStatus,flowNexts from ProjectPlanConfig where projectId = ? order by seq") "select configId,planName,flowStatus,flowNexts from ProjectPlanConfig where projectId = ? order by seq")
.setParameter(1, projectId) .setParameter(1, projectId)
@ -185,10 +185,10 @@ public class ProjectManager implements ConfigManager {
alist.add(e); alist.add(e);
} }
cache = alist.toArray(new ConfigBean[0]); cached = alist.toArray(new ConfigBean[0]);
Application.getCommonsCache().putx(ckey, cache); Application.getCommonsCache().putx(ckey, cached);
} }
return cache.clone(); return cached.clone();
} }
/** /**

View file

@ -93,9 +93,10 @@ public enum ConfigurationItem {
SamlIdPEntityid, SamlIdPEndpoint, SamlIdPSloEndpoint, SamlIdPCert, SamlIdPEntityid, SamlIdPEndpoint, SamlIdPSloEndpoint, SamlIdPCert,
// !!! 仅命令行适用 // !!! 仅命令行适用
DataDirectory, // 数据目录 DataDirectory, // 数据目录
MobileUrl, // 移动端地址 RedisDatabase(0), // Redis DB
RbStoreUrl // 在线仓库地址 MobileUrl, // 移动端地址
RbStoreUrl // 在线仓库地址
; ;

View file

@ -82,9 +82,10 @@ public class RebuildConfiguration extends KVStorage {
File temp = getFileOfData("temp"); File temp = getFileOfData("temp");
if (!temp.exists()) { if (!temp.exists()) {
if (!temp.mkdirs()) { if (!temp.mkdirs()) {
throw new RebuildException("Cannot mkdirs for temp : " + temp); throw new RebuildException("Cannot mkdir for temp directory : " + temp);
} }
} }
return filepath == null ? temp : new File(temp, filepath); return filepath == null ? temp : new File(temp, filepath);
} }

View file

@ -16,16 +16,12 @@ import redis.clients.jedis.JedisPoolConfig;
*/ */
public class KnownJedisPool extends JedisPool { public class KnownJedisPool extends JedisPool {
public static final int TIMEOUT = 5000;
public static final int DATABASE = 0;
private String host; private String host;
private int port; private int port;
private String password; private String password;
public KnownJedisPool(String host, int port, String password) { public KnownJedisPool(String host, int port, String password, int database) {
super(new JedisPoolConfig(), host, port, TIMEOUT, password, DATABASE); super(new JedisPoolConfig(), host, port, 5000, password, database);
this.host = host; this.host = host;
this.port = port; this.port = port;
this.password = password; this.password = password;

View file

@ -20,6 +20,7 @@ import com.rebuild.core.metadata.MetadataHelper;
import com.rebuild.core.metadata.MetadataSorter; import com.rebuild.core.metadata.MetadataSorter;
import com.rebuild.core.metadata.easymeta.EasyEntity; import com.rebuild.core.metadata.easymeta.EasyEntity;
import com.rebuild.core.metadata.easymeta.EasyMetaFactory; import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
import com.rebuild.core.metadata.impl.CopyEntity;
import com.rebuild.core.metadata.impl.Entity2Schema; import com.rebuild.core.metadata.impl.Entity2Schema;
import com.rebuild.core.metadata.impl.MetaEntityService; import com.rebuild.core.metadata.impl.MetaEntityService;
import com.rebuild.core.privileges.UserHelper; import com.rebuild.core.privileges.UserHelper;
@ -64,6 +65,8 @@ public class MetaEntityController extends BaseController {
@GetMapping("entity/{entity}/base") @GetMapping("entity/{entity}/base")
public ModelAndView pageBase(@PathVariable String entity, HttpServletResponse response) throws IOException { public ModelAndView pageBase(@PathVariable String entity, HttpServletResponse response) throws IOException {
Entity metaEntity = MetadataHelper.getEntity(entity); Entity metaEntity = MetadataHelper.getEntity(entity);
// 不允许访问
if (!(MetadataHelper.isBusinessEntity(metaEntity) || MetadataHelper.isBizzEntity(metaEntity))) { if (!(MetadataHelper.isBusinessEntity(metaEntity) || MetadataHelper.isBizzEntity(metaEntity))) {
response.sendError(403); response.sendError(403);
return null; return null;
@ -129,7 +132,6 @@ public class MetaEntityController extends BaseController {
@PostMapping("entity/entity-new") @PostMapping("entity/entity-new")
public RespBody entityNew(HttpServletRequest request) { public RespBody entityNew(HttpServletRequest request) {
final ID user = getRequestUser(request);
final JSONObject reqJson = (JSONObject) ServletUtils.getRequestJson(request); final JSONObject reqJson = (JSONObject) ServletUtils.getRequestJson(request);
String label = reqJson.getString("label"); String label = reqJson.getString("label");
@ -149,7 +151,7 @@ public class MetaEntityController extends BaseController {
} }
try { try {
String entityName = new Entity2Schema(user) String entityName = new Entity2Schema()
.createEntity(label, comments, mainEntity, getBoolParameter(request, "nameField")); .createEntity(label, comments, mainEntity, getBoolParameter(request, "nameField"));
return RespBody.ok(entityName); return RespBody.ok(entityName);
} catch (Exception ex) { } catch (Exception ex) {
@ -158,6 +160,23 @@ public class MetaEntityController extends BaseController {
} }
} }
@PostMapping("entity/entity-copy")
public RespBody entityCopy(HttpServletRequest request) {
final JSONObject reqJson = (JSONObject) ServletUtils.getRequestJson(request);
Entity sourceEntity = MetadataHelper.getEntity(reqJson.getString("sourceEntity"));
String entityName = reqJson.getString("entityName");
String detailEntityName = reqJson.getString("detailEntityName");
try {
entityName = new CopyEntity(sourceEntity).copy(entityName, detailEntityName);
return RespBody.ok(entityName);
} catch (Exception ex) {
log.error("entity-copy", ex);
return RespBody.error(ex.getLocalizedMessage());
}
}
@PostMapping("entity/entity-update") @PostMapping("entity/entity-update")
public RespBody entityUpdate(HttpServletRequest request) { public RespBody entityUpdate(HttpServletRequest request) {
final ID user = getRequestUser(request); final ID user = getRequestUser(request);
@ -193,12 +212,11 @@ public class MetaEntityController extends BaseController {
@RequestMapping("entity/entity-drop") @RequestMapping("entity/entity-drop")
public RespBody entityDrop(HttpServletRequest request) { public RespBody entityDrop(HttpServletRequest request) {
final ID user = getRequestUser(request);
final Entity entity = getEntityById(getIdParameterNotNull(request, "id")); final Entity entity = getEntityById(getIdParameterNotNull(request, "id"));
final boolean force = getBoolParameter(request, "force", false); final boolean force = getBoolParameter(request, "force", false);
try { try {
boolean drop = new Entity2Schema(user).dropEntity(entity, force); boolean drop = new Entity2Schema().dropEntity(entity, force);
return drop ? RespBody.ok() : RespBody.error(); return drop ? RespBody.ok() : RespBody.error();
} catch (Exception ex) { } catch (Exception ex) {

View file

@ -39,7 +39,10 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.*; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** /**
* @author zhaofang123@gmail.com * @author zhaofang123@gmail.com
@ -134,7 +137,6 @@ public class MetaFieldController extends BaseController {
@PostMapping("field-new") @PostMapping("field-new")
public RespBody fieldNew(HttpServletRequest request) { public RespBody fieldNew(HttpServletRequest request) {
final ID user = getRequestUser(request);
JSONObject reqJson = (JSONObject) ServletUtils.getRequestJson(request); JSONObject reqJson = (JSONObject) ServletUtils.getRequestJson(request);
String entityName = reqJson.getString("entity"); String entityName = reqJson.getString("entity");
@ -162,7 +164,7 @@ public class MetaFieldController extends BaseController {
} }
try { try {
String fieldName = new Field2Schema(user).createField(entity, label, dt, comments, refEntity, extConfig); String fieldName = new Field2Schema().createField(entity, label, dt, comments, refEntity, extConfig);
return RespBody.ok(fieldName); return RespBody.ok(fieldName);
} catch (Exception ex) { } catch (Exception ex) {
@ -181,16 +183,14 @@ public class MetaFieldController extends BaseController {
} }
@RequestMapping("field-drop") @RequestMapping("field-drop")
public RespBody fieldDrop(@IdParam ID fieldId, HttpServletRequest request) { public RespBody fieldDrop(@IdParam ID fieldId) {
final ID user = getRequestUser(request);
Object[] fieldRecord = Application.createQueryNoFilter( Object[] fieldRecord = Application.createQueryNoFilter(
"select belongEntity,fieldName from MetaField where fieldId = ?") "select belongEntity,fieldName from MetaField where fieldId = ?")
.setParameter(1, fieldId) .setParameter(1, fieldId)
.unique(); .unique();
Field field = MetadataHelper.getEntity((String) fieldRecord[0]).getField((String) fieldRecord[1]); Field field = MetadataHelper.getEntity((String) fieldRecord[0]).getField((String) fieldRecord[1]);
boolean drop = new Field2Schema(user).dropField(field, false); boolean drop = new Field2Schema().dropField(field, false);
return drop ? RespBody.ok() : RespBody.error(); return drop ? RespBody.ok() : RespBody.error();
} }

View file

@ -2,10 +2,10 @@
<ehcache> <ehcache>
<diskStore path="java.io.tmpdir"/> <diskStore path="java.io.tmpdir"/>
<cache name="rebuild" <cache name="rebuild"
maxElementsInMemory="100" maxElementsInMemory="10000"
eternal="false" eternal="false"
overflowToDisk="true" overflowToDisk="true"
maxElementsOnDisk="100000000" maxElementsOnDisk="1000000"
diskPersistent="true" diskPersistent="true"
timeToIdleSeconds="0" timeToIdleSeconds="0"
timeToLiveSeconds="0" timeToLiveSeconds="0"

View file

@ -2044,5 +2044,16 @@
"排列方式":"排列方式", "排列方式":"排列方式",
"更早":"更早", "更早":"更早",
"任务排序,或切换任务排列方式":"任务排序,或切换任务排列方式", "任务排序,或切换任务排列方式":"任务排序,或切换任务排列方式",
"显示方式":"显示方式" "显示方式":"显示方式",
"请至少添加 1 个字段映射":"请至少添加 1 个字段映射",
"不填写则不复制明细实体":"不填写则不复制明细实体",
"请选择从哪个实体复制":"请选择从哪个实体复制",
"数据库自动备份":"数据库自动备份",
"明细实体名称":"明细实体名称",
"无法读取文件":"无法读取文件",
"部分必填字段未映射,可能导致转换失败。是否继续保存?":"部分必填字段未映射,可能导致转换失败。是否继续保存?",
"无法读取图片":"无法读取图片",
"复制哪个实体":"复制哪个实体",
"免费版不支持此功能 [(查看详情)](https://getrebuild.com/docs/rbv-features)":"免费版不支持此功能 [(查看详情)](https://getrebuild.com/docs/rbv-features)",
"升级":"升级"
} }

View file

@ -20,7 +20,7 @@
<script th:src="@{/assets/js/rb-page.js}"></script> <script th:src="@{/assets/js/rb-page.js}"></script>
<script th:src="@{/assets/js/rb-components.js}" type="text/babel"></script> <script th:src="@{/assets/js/rb-components.js}" type="text/babel"></script>
<script th:src="@{/assets/js/file-preview.js}" type="text/babel"></script> <script th:src="@{/assets/js/file-preview.js}" type="text/babel"></script>
<th:block th:if="${user != null && commercial > 0}"> <th:block th:if="${user != null && commercial > 1}">
<script th:src="@{/assets/js/frontjs/frontjs-sdk.js}" type="text/babel"></script> <script th:src="@{/assets/js/frontjs/frontjs-sdk.js}" type="text/babel"></script>
<script th:src="@{/commons/frontjs/use-frontjs}" type="text/babel"></script> <script th:src="@{/commons/frontjs/use-frontjs}" type="text/babel"></script>
</th:block> </th:block>

View file

@ -15,7 +15,7 @@
<link rel="stylesheet" type="text/css" th:href="@{/assets/lib/widget/simplemde.min.css}" /> <link rel="stylesheet" type="text/css" th:href="@{/assets/lib/widget/simplemde.min.css}" />
<link rel="stylesheet" type="text/css" th:href="@{/assets/css/rb-base.css}" /> <link rel="stylesheet" type="text/css" th:href="@{/assets/css/rb-base.css}" />
<link rel="stylesheet" type="text/css" th:href="@{/assets/css/rb-page.css}" /> <link rel="stylesheet" type="text/css" th:href="@{/assets/css/rb-page.css}" />
<link rel="stylesheet" type="text/css" th:href="@{/commons/theme/use-theme}" th:if="${user != null && commercial > 0}" /> <link rel="stylesheet" type="text/css" th:href="@{/commons/theme/use-theme}" th:if="${user != null && commercial > 1}" />
<meta name="rb.env" th:content="${env}" /> <meta name="rb.env" th:content="${env}" />
<meta name="rb.commercial" th:content="${commercial}" /> <meta name="rb.commercial" th:content="${commercial}" />
<meta name="rb.locale" th:content="${locale}" /> <meta name="rb.locale" th:content="${locale}" />
@ -33,7 +33,7 @@
<!--[if lt IE 10]><script>location.href = '[[${baseUrl}]]/error/unsupported-browser'</script><![endif]--> <!--[if lt IE 10]><script>location.href = '[[${baseUrl}]]/error/unsupported-browser'</script><![endif]-->
<script th:if="${T(com.rebuild.utils.AppUtils).isIE11(#request)}" th:src="@{/assets/lib/react/polyfill.min.js?v=7.6.0}"></script> <script th:if="${T(com.rebuild.utils.AppUtils).isIE11(#request)}" th:src="@{/assets/lib/react/polyfill.min.js?v=7.6.0}"></script>
<script th:if="${markWatermark == 'true'}" th:src="@{/assets/lib/watermark.js?v=2.3.2.2}"></script> <script th:if="${markWatermark == 'true'}" th:src="@{/assets/lib/watermark.js?v=2.3.2.2}"></script>
<style th:if="${commercial > 0}" type="text/css"> <style th:if="${commercial > 1}" type="text/css">
.logo-img, .logo-img,
.rb-top-header .rb-navbar-header .navbar-brand { .rb-top-header .rb-navbar-header .navbar-brand {
background-image: url('[[${baseUrl}]]/commons/theme/use-logo'); background-image: url('[[${baseUrl}]]/commons/theme/use-logo');

View file

@ -11,9 +11,8 @@
margin: 0 -10px; margin: 0 -10px;
} }
.dialog-footer { .dialog-footer {
margin: 15px -15px 0; margin: 15px -40px 0;
padding-top: 20px; padding-top: 20px;
text-align: center;
} }
</style> </style>
</head> </head>
@ -23,9 +22,10 @@
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="nav-item"><a class="nav-link active" href="#MANUAL" data-toggle="tab">[[${bundle.L('手动')}]]</a></li> <li class="nav-item"><a class="nav-link active" href="#MANUAL" data-toggle="tab">[[${bundle.L('手动')}]]</a></li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link J_imports" href="#IMPORTS" data-toggle="tab"> <a class="nav-link" href="#COPY" data-toggle="tab">[[${bundle.L('复制')}]] <sup class="rbv" th:title="${bundle.L('增值功能')}"></sup></a>
<i class="icon zmdi zmdi-cloud-outline-alt"></i> [[${bundle.L('从 RB 仓库导入')}]] </li>
</a> <li class="nav-item">
<a class="nav-link J_imports" href="#IMPORTS" data-toggle="tab"> <i class="icon zmdi zmdi-cloud-outline-alt"></i> [[${bundle.L('从 RB 仓库导入')}]] </a>
</li> </li>
</ul> </ul>
<div class="tab-content m-0 pb-0"> <div class="tab-content m-0 pb-0">
@ -59,11 +59,7 @@
<input class="custom-control-input" type="checkbox" id="isDetail" /> <input class="custom-control-input" type="checkbox" id="isDetail" />
<span class="custom-control-label"> <span class="custom-control-label">
[[${bundle.L('这是一个明细实体')}]] [[${bundle.L('这是一个明细实体')}]]
<i <i class="zmdi zmdi-help zicon" data-toggle="tooltip" th:title="${bundle.L('通过明细实体可以更好的组织业务关系。例如订单明细通常依附于订单,而非独立存在')}"></i>
class="zmdi zmdi-help zicon"
data-toggle="tooltip"
th:title="${bundle.L('通过明细实体可以更好的组织业务关系。例如订单明细通常依附于订单,而非独立存在')}"
></i>
</span> </span>
</label> </label>
</div> </div>
@ -76,7 +72,36 @@
</div> </div>
<div class="form-group row footer"> <div class="form-group row footer">
<div class="col-sm-7 offset-sm-3"> <div class="col-sm-7 offset-sm-3">
<button class="btn btn-primary" type="button">[[${bundle.L('确定')}]]</button> <button class="btn btn-primary new" type="button">[[${bundle.L('确定')}]]</button>
<button class="btn btn-link" type="button" onclick="parent.RbModal.hide()">[[${bundle.L('取消')}]]</button>
</div>
</div>
</div>
</div>
<div class="tab-pane" id="COPY">
<div class="form">
<div class="form-group row">
<label class="col-sm-3 col-form-label text-sm-right">[[${bundle.L('复制哪个实体')}]]</label>
<div class="col-sm-7">
<select class="form-control form-control-sm" id="copySourceEntity"></select>
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label text-sm-right">[[${bundle.L('实体名称')}]]</label>
<div class="col-sm-7">
<input class="form-control form-control-sm" type="text" id="newEntityLabel" maxlength="40" />
</div>
</div>
<div class="form-group row hide J_newDetailLabel">
<label class="col-sm-3 col-form-label text-sm-right">[[${bundle.L('明细实体名称')}]]</label>
<div class="col-sm-7">
<input class="form-control form-control-sm" type="text" id="newDetailLabel" maxlength="40" />
<p class="form-text">[[${bundle.L('不填写则不复制明细实体')}]]</p>
</div>
</div>
<div class="form-group row footer">
<div class="col-sm-7 offset-sm-3">
<button class="btn btn-primary copy" type="button">[[${bundle.L('确定')}]]</button>
<button class="btn btn-link" type="button" onclick="parent.RbModal.hide()">[[${bundle.L('取消')}]]</button> <button class="btn btn-link" type="button" onclick="parent.RbModal.hide()">[[${bundle.L('取消')}]]</button>
</div> </div>
</div> </div>

View file

@ -76,7 +76,7 @@
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
<div class="tab-pane" id="adv-control"> <div class="tab-pane" id="adv-control">
<table th:if="${commercial > 0}" class="table table-hover table-p"> <table th:if="${commercial > 1}" class="table table-hover table-p">
<thead> <thead>
<tr> <tr>
<th>[[${bundle.L('字段')}]]</th> <th>[[${bundle.L('字段')}]]</th>

View file

@ -55,6 +55,8 @@ $(document).ready(() => {
const fm = fieldsMapping.buildMapping() const fm = fieldsMapping.buildMapping()
const fmd = fieldsMappingDetail ? fieldsMappingDetail.buildMapping() : null const fmd = fieldsMappingDetail ? fieldsMappingDetail.buildMapping() : null
if (Object.keys(fm).length === 0) return RbHighbar.create($L('请至少添加 1 个字段映射'))
function _save() { function _save() {
const config = { const config = {
fieldsMapping: fm, fieldsMapping: fm,

View file

@ -8,7 +8,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
// ~~ 图片/文档预览 // ~~ 图片/文档预览
const TYPE_DOCS = ['.doc', '.docx', '.rtf', '.xls', '.xlsx', '.ppt', '.pptx', '.pdf'] const TYPE_DOCS = ['.doc', '.docx', '.rtf', '.xls', '.xlsx', '.ppt', '.pptx', '.pdf']
const TYPE_TEXTS = ['.txt', '.xml', '.json', '.md', '.yml', '.css', '.js', '.htm', '.html', '.log', '.sql'] const TYPE_TEXTS = ['.txt', '.xml', '.json', '.md', '.yml', '.css', '.js', '.htm', '.html', '.log', '.sql', '.conf']
const TYPE_IMGS = ['.jpg', '.jpeg', '.gif', '.png', '.bmp'] const TYPE_IMGS = ['.jpg', '.jpeg', '.gif', '.png', '.bmp']
const TYPE_AUDIOS = ['.mp3', '.wav', '.ogg', '.acc'] const TYPE_AUDIOS = ['.mp3', '.wav', '.ogg', '.acc']
const TYPE_VIDEOS = ['.mp4', '.webm'] const TYPE_VIDEOS = ['.mp4', '.webm']
@ -94,7 +94,7 @@ class RbPreview extends React.Component {
alt="Loading" alt="Loading"
onLoad={() => this.setState({ imgRendered: true })} onLoad={() => this.setState({ imgRendered: true })}
onError={() => { onError={() => {
RbHighbar.error($L('无法加载图片')) RbHighbar.error($L('无法读取图片'))
this.hide() this.hide()
}} }}
/> />
@ -203,7 +203,8 @@ class RbPreview extends React.Component {
success: function (res) { success: function (res) {
that.setState({ previewText: res }) that.setState({ previewText: res })
}, },
error: function () { error: function (res) {
if (res.status > 0) RbHighbar.error(`${$L('无法读取文件')} (${res.status})`)
that.hide() that.hide()
}, },
}) })

View file

@ -7,56 +7,109 @@ See LICENSE and COMMERCIAL in the project root for license information.
/* global InitModels */ /* global InitModels */
$(document).ready(function () { $(document).ready(function () {
const $btn = $('.btn-primary').click(function () { const $new = $('.btn-primary.new').on('click', function () {
const entityLabel = $val('#entityLabel'), const entityLabel = $val('#entityLabel'),
comments = $val('#comments') comments = $val('#comments')
if (!entityLabel) { if (!entityLabel) return RbHighbar.create($L('请输入实体名称'))
RbHighbar.create($L('请输入实体名称'))
return
}
const data = { const data = {
label: entityLabel, label: entityLabel,
comments: comments, comments: comments,
} }
if ($val('#isDetail')) { if ($val('#isDetail')) {
data.mainEntity = $val('#mainEntity') data.mainEntity = $val('#mainEntity')
if (!data.mainEntity) { if (!data.mainEntity) return RbHighbar.create($L('请选择主实体'))
RbHighbar.create($L('请选择主实体'))
return
}
} }
$btn.button('loading') $new.button('loading')
$.post(`/admin/entity/entity-new?nameField=${$val('#nameField')}`, JSON.stringify(data), function (res) { $.post(`/admin/entity/entity-new?nameField=${$val('#nameField')}`, JSON.stringify(data), (res) => {
if (res.error_code === 0) parent.location.href = `${rb.baseUrl}/admin/entity/${res.data}/base` if (res.error_code === 0) parent.location.href = `${rb.baseUrl}/admin/entity/${res.data}/base`
else RbHighbar.error(res.error_msg) else RbHighbar.error(res.error_msg)
}) })
}) })
let entityLoaded = false const $copy = $('.btn-primary.copy').on('click', () => {
$('#isDetail').click(function () { if (rb.commercial < 1) return
const sourceEntity = $val('#copySourceEntity')
if (!sourceEntity) RbHighbar.create($L('请选择从哪个实体复制'))
const entityLabel = $val('#newEntityLabel')
if (!entityLabel) return RbHighbar.create($L('请输入实体名称'))
const data = {
sourceEntity: sourceEntity,
entityName: entityLabel,
detailEntityName: $val('#newDetailLabel'),
keepConfig: [],
}
$copy.button('loading')
$.post('/admin/entity/entity-copy', JSON.stringify(data), (res) => {
if (res.error_code === 0) parent.location.href = `${rb.baseUrl}/admin/entity/${res.data}/base`
else RbHighbar.error(res.error_msg)
})
})
let entities
function _loadEntities(call) {
if (entities) {
typeof call === 'function' && call(entities)
} else {
$.get('/admin/entity/entity-list', (res) => {
entities = res.data
typeof call === 'function' && call(entities)
})
}
}
_loadEntities((e) => {
e.forEach(function (item) {
$(`<option value="${item.entityName}" data-detail="${item.detailEntity || ''}">${item.entityLabel}</option>`).appendTo('#copySourceEntity')
})
$('#copySourceEntity')
.on('change', function () {
const $s = $('#copySourceEntity option:selected')
if ($s.data('detail')) $('.J_newDetailLabel').removeClass('hide')
else $('.J_newDetailLabel').addClass('hide')
parent.RbModal.resize()
})
.trigger('change')
})
$('#isDetail').on('click', function () {
$('.J_mainEntity').toggleClass('hide') $('.J_mainEntity').toggleClass('hide')
parent.RbModal.resize() parent.RbModal.resize()
if (entityLoaded === false) {
entityLoaded = true if ($('#mainEntity option').length === 0) {
$.get('/admin/entity/entity-list', function (res) { _loadEntities((e) => {
$(res.data).each(function () { e.forEach(function (item) {
if (!this.detailEntity) $(`<option value="${this.entityName}">${this.entityLabel}</option>`).appendTo('#mainEntity') if (!item.detailEntity) $(`<option value="${item.entityName}">${item.entityLabel}</option>`).appendTo('#mainEntity')
}) })
}) })
} }
}) })
$('.nav-tabs a').click(() => parent.RbModal.resize())
let _MetaschemaList let _MetaschemaList
$('.J_imports').click(() => { $('.J_imports').on('click', () => {
if (_MetaschemaList) return if (_MetaschemaList) return
renderRbcomp(<MetaschemaList />, 'metaschemas', function () { renderRbcomp(<MetaschemaList />, 'metaschemas', function () {
_MetaschemaList = this _MetaschemaList = this
}) })
}) })
$('.nav-tabs a').on('click', function (e) {
if (rb.commercial < 1 && $(this).find('.rbv').length > 0) {
RbHighbar.error(WrapHtml($L('免费版不支持此功能 [(查看详情)](https://getrebuild.com/docs/rbv-features)')))
$stopEvent(e, true)
return false
}
parent.RbModal.resize()
})
}) })
class MetaschemaList extends React.Component { class MetaschemaList extends React.Component {
@ -65,10 +118,15 @@ class MetaschemaList extends React.Component {
<div> <div>
<InitModels ref={(c) => (this._InitModels = c)} onLoad={() => parent.RbModal.resize()} /> <InitModels ref={(c) => (this._InitModels = c)} onLoad={() => parent.RbModal.resize()} />
<div className="dialog-footer"> <div className="dialog-footer">
<button className="btn btn-primary" onClick={() => this.imports()} ref={(c) => (this._$btn = c)}> <div className="float-right">
{$L('开始导入')} <button className="btn btn-primary" onClick={() => this.imports()} ref={(c) => (this._$btn = c)}>
</button> {$L('开始导入')}
<p className="protips mt-2">{$L('可在导入后根据自身需求做适当调整/修改')}</p> </button>
</div>
<div className="float-right">
<p className="protips mt-2 pr-2">{$L('可在导入后根据自身需求做适当调整/修改')}</p>
</div>
<div className="clearfix" />
</div> </div>
</div> </div>
) )

View file

@ -1,20 +0,0 @@
/*
Copyright (c) REBUILD <https://getrebuild.com/> 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.metadata.easymeta;
import com.rebuild.TestSupport;
/**
* @author devezhao
* @since 2020/11/18
*/
class EasyEntityTest extends TestSupport {
}

View file

@ -1,19 +0,0 @@
/*
Copyright (c) REBUILD <https://getrebuild.com/> 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.metadata.easymeta;
import com.rebuild.TestSupport;
/**
* @author devezhao
* @since 2020/11/18
*/
class EasyFieldTest extends TestSupport {
}

View file

@ -5,13 +5,11 @@ rebuild is dual-licensed under commercial and open source licenses (GPLv3).
See LICENSE and COMMERCIAL in the project root for license information. See LICENSE and COMMERCIAL in the project root for license information.
*/ */
package com.rebuild.core.metadata.entity; package com.rebuild.core.metadata.easymeta;
import cn.devezhao.persist4j.Entity; import cn.devezhao.persist4j.Entity;
import com.rebuild.TestSupport; import com.rebuild.TestSupport;
import com.rebuild.core.metadata.MetadataHelper; import com.rebuild.core.metadata.MetadataHelper;
import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
import com.rebuild.core.metadata.easymeta.EasyPhone;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -19,7 +17,7 @@ import org.junit.jupiter.api.Test;
* @author devezhao-mbp zhaofang123@gmail.com * @author devezhao-mbp zhaofang123@gmail.com
* @since 2019/05/30 * @since 2019/05/30
*/ */
public class EasyMetaTest extends TestSupport { class EasyMetaTest extends TestSupport {
@Test @Test
void getLabel() { void getLabel() {

View file

@ -0,0 +1,30 @@
/*
Copyright (c) REBUILD <https://getrebuild.com/> 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.metadata.impl;
import com.rebuild.TestSupport;
import com.rebuild.core.metadata.MetadataHelper;
import com.rebuild.core.privileges.UserService;
import org.junit.jupiter.api.Test;
/**
* @author zhaofang123@gmail.com
* @since 12/17/2021
*/
class CopyEntityTest extends TestSupport {
@Test
void copy() {
String sourceName = TestAllFields;
String newName =
((CopyEntity) new CopyEntity(MetadataHelper.getEntity(sourceName)).setUser(UserService.ADMIN_USER))
.copy(sourceName + "Copy", null);
System.out.println("New entity : " + newName);
}
}

View file

@ -5,15 +5,13 @@ rebuild is dual-licensed under commercial and open source licenses (GPLv3).
See LICENSE and COMMERCIAL in the project root for license information. See LICENSE and COMMERCIAL in the project root for license information.
*/ */
package com.rebuild.core.metadata.entity; package com.rebuild.core.metadata.impl;
import cn.devezhao.persist4j.Entity; import cn.devezhao.persist4j.Entity;
import com.rebuild.TestSupport; import com.rebuild.TestSupport;
import com.rebuild.core.UserContextHolder; import com.rebuild.core.UserContextHolder;
import com.rebuild.core.metadata.MetadataHelper; import com.rebuild.core.metadata.MetadataHelper;
import com.rebuild.core.metadata.easymeta.DisplayType; import com.rebuild.core.metadata.easymeta.DisplayType;
import com.rebuild.core.metadata.impl.Entity2Schema;
import com.rebuild.core.metadata.impl.Field2Schema;
import com.rebuild.core.privileges.UserService; import com.rebuild.core.privileges.UserService;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -22,7 +20,7 @@ import org.junit.jupiter.api.Test;
* @author zhaofang123@gmail.com * @author zhaofang123@gmail.com
* @since 08/03/2018 * @since 08/03/2018
*/ */
public class Meta2SchemaTest extends TestSupport { class Meta2SchemaTest extends TestSupport {
@BeforeEach @BeforeEach
public void setUpPerMethod() { public void setUpPerMethod() {
@ -30,7 +28,7 @@ public class Meta2SchemaTest extends TestSupport {
} }
@Test @Test
public void testCreateEntity() { void testCreateEntity() {
String newEntityName = new Entity2Schema(UserService.ADMIN_USER) String newEntityName = new Entity2Schema(UserService.ADMIN_USER)
.createEntity("测试实体", null, null, false); .createEntity("测试实体", null, null, false);
System.out.println("New Entity is created : " + newEntityName); System.out.println("New Entity is created : " + newEntityName);
@ -41,7 +39,7 @@ public class Meta2SchemaTest extends TestSupport {
} }
@Test @Test
public void testCreateField() { void testCreateField() {
String newEntityName = new Entity2Schema(UserService.ADMIN_USER) String newEntityName = new Entity2Schema(UserService.ADMIN_USER)
.createEntity("测试字段", null, null, false); .createEntity("测试字段", null, null, false);
Entity newEntity = MetadataHelper.getEntity(newEntityName); Entity newEntity = MetadataHelper.getEntity(newEntityName);