mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-09-21 07:55:56 +08:00
Merge pull request #110 from getrebuild/systems-config-527
RB-527 Systems config
This commit is contained in:
commit
5e9d45ab23
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
* @getrebuild @devezhao
|
|
@ -1 +0,0 @@
|
|||
-- The file has been moved to `src/main/resources/scripts/db-init.sql`
|
4
pom.xml
4
pom.xml
|
@ -116,7 +116,7 @@
|
|||
<dependency>
|
||||
<groupId>com.github.devezhao</groupId>
|
||||
<artifactId>commons</artifactId>
|
||||
<version>1.1.5</version>
|
||||
<version>af6088998f</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>httpclient</artifactId>
|
||||
|
@ -127,7 +127,7 @@
|
|||
<dependency>
|
||||
<groupId>com.github.devezhao</groupId>
|
||||
<artifactId>persist4j</artifactId>
|
||||
<version>1.3.3</version>
|
||||
<version>1c66159c86</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
|
|
|
@ -127,7 +127,7 @@ public final class ServerStatus {
|
|||
if (!test.exists()) {
|
||||
return Status.error(name, "Couldn't create file in temp Directory");
|
||||
} else {
|
||||
test.delete();
|
||||
FileUtils.deleteQuietly(test);
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
|
|
|
@ -80,6 +80,10 @@ public class AesPreferencesConfigurer extends PreferencesPlaceholderConfigurer i
|
|||
props.put("db.url", dbUrl);
|
||||
}
|
||||
|
||||
// MUST NOT BE NULL
|
||||
setIfEmpty(props, ConfigurableItem.CacheHost, "127.0.0.1");
|
||||
setIfEmpty(props, ConfigurableItem.CachePort, "16379");
|
||||
|
||||
propsHold = (Properties) props.clone();
|
||||
|
||||
if (propsHold.getProperty("db.url").contains("jdbc:h2:")) {
|
||||
|
@ -108,6 +112,17 @@ public class AesPreferencesConfigurer extends PreferencesPlaceholderConfigurer i
|
|||
return new Properties();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param props
|
||||
* @param item
|
||||
* @param defaultValue
|
||||
*/
|
||||
private void setIfEmpty(Properties props, ConfigurableItem item, String defaultValue) {
|
||||
if (StringUtils.isBlank(props.getProperty(item.name()))) {
|
||||
props.put(item.name(), defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置项
|
||||
*
|
||||
|
|
|
@ -57,14 +57,33 @@ public final class Lisence {
|
|||
* @return
|
||||
*/
|
||||
public static JSON queryAuthority() {
|
||||
String queryUrl = "https://getrebuild.com/authority/query?k=IjkMHgq94T7s7WkP&sn=" + SN();
|
||||
JSON result = rbApi("authority/query");
|
||||
if (result == null) {
|
||||
result = JSONUtils.toJSONObject(
|
||||
new String[]{ "sn", "authType" },
|
||||
new String[]{ SN(), "开源社区版" });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 RB 官方服务 API
|
||||
*
|
||||
* @param apiPath
|
||||
* @return
|
||||
*/
|
||||
public static JSON rbApi(String apiPath) {
|
||||
String apiUrl = "https://getrebuild.com/" + apiPath;
|
||||
apiUrl += apiPath.contains("\\?") ? "&" : "?";
|
||||
apiUrl += "k=IjkMHgq94T7s7WkP&sn=" + SN();
|
||||
|
||||
try {
|
||||
String result = CommonsUtils.get(queryUrl);
|
||||
String result = CommonsUtils.get(apiUrl);
|
||||
if (StringUtils.isNotBlank(result) && JSONUtils.wellFormat(result)) {
|
||||
return JSON.parseObject(result);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return JSONUtils.toJSONObject(new String[]{"sn", "authType"}, new String[]{SN(), "开源社区版"});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import com.qiniu.util.Auth;
|
|||
import com.qiniu.util.StringMap;
|
||||
import com.rebuild.server.RebuildException;
|
||||
import com.rebuild.utils.CommonsUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
@ -49,8 +50,12 @@ import java.util.UUID;
|
|||
public class QiniuCloud {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(QiniuCloud.class);
|
||||
|
||||
private final Configuration CONFIGURATION = new Configuration(Region.autoRegion());
|
||||
|
||||
/**
|
||||
* 默认配置
|
||||
*/
|
||||
public static final Configuration CONFIGURATION = new Configuration(Region.autoRegion());
|
||||
|
||||
private final UploadManager UPLOAD_MANAGER = new UploadManager(CONFIGURATION);
|
||||
|
||||
private Auth auth;
|
||||
|
@ -70,7 +75,6 @@ public class QiniuCloud {
|
|||
* @return
|
||||
*/
|
||||
public boolean available() {
|
||||
// return false; // TEST
|
||||
return this.auth != null;
|
||||
}
|
||||
|
||||
|
@ -111,7 +115,7 @@ public class QiniuCloud {
|
|||
try {
|
||||
return upload(tmp);
|
||||
} finally {
|
||||
tmp.delete();
|
||||
FileUtils.deleteQuietly(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -122,17 +122,7 @@ public final class SysConfiguration extends KVStorage {
|
|||
return getsNoUnset(false,
|
||||
ConfigurableItem.StorageApiKey, ConfigurableItem.StorageApiSecret, ConfigurableItem.StorageBucket, ConfigurableItem.StorageURL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存账号
|
||||
*
|
||||
* @return returns [CacheHost, CachePort, CachePassword]
|
||||
*/
|
||||
public static String[] getCacheAccount() {
|
||||
return getsNoUnset(false,
|
||||
ConfigurableItem.CacheHost, ConfigurableItem.CachePort, ConfigurableItem.CachePassword);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 邮件账号
|
||||
*
|
||||
|
@ -153,23 +143,30 @@ public final class SysConfiguration extends KVStorage {
|
|||
ConfigurableItem.SmsUser, ConfigurableItem.SmsPassword, ConfigurableItem.SmsSign);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public static String getHomeUrl() {
|
||||
return getHomeUrl(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取绝对 URL
|
||||
*
|
||||
* @param path 可带有路径,会自动拼接
|
||||
* @return
|
||||
*/
|
||||
public static String getHomeUrl(String...path) {
|
||||
public static String getHomeUrl(String path) {
|
||||
String homeUrl = get(ConfigurableItem.HomeURL);
|
||||
if (!homeUrl.endsWith("/")) {
|
||||
homeUrl += "/";
|
||||
}
|
||||
|
||||
if (path.length > 0) {
|
||||
if (path[0].startsWith("/")) {
|
||||
path[0] = path[0].substring(1);
|
||||
if (path != null) {
|
||||
if (path.startsWith("/")) {
|
||||
path = path.substring(1);
|
||||
}
|
||||
return homeUrl + path[0];
|
||||
return homeUrl + path;
|
||||
}
|
||||
return homeUrl;
|
||||
}
|
||||
|
|
|
@ -258,7 +258,8 @@ public class Entity2Schema extends Field2Schema {
|
|||
private boolean schema2Database(Entity entity) {
|
||||
Dialect dialect = Application.getPersistManagerFactory().getDialect();
|
||||
Table table = new Table(entity, dialect);
|
||||
String[] ddls = table.generateDDL(false, false);
|
||||
String[] ddls = table.generateDDL(false, false, false);
|
||||
|
||||
try {
|
||||
Application.getSQLExecutor().executeBatch(ddls);
|
||||
} catch (Throwable ex) {
|
||||
|
|
|
@ -18,19 +18,30 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
||||
package com.rebuild.web.admin;
|
||||
|
||||
import com.rebuild.server.Application;
|
||||
import cn.devezhao.commons.RegexUtils;
|
||||
import cn.devezhao.commons.ThrowableUtils;
|
||||
import cn.devezhao.commons.web.ServletUtils;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.qiniu.common.QiniuException;
|
||||
import com.qiniu.storage.BucketManager;
|
||||
import com.qiniu.util.Auth;
|
||||
import com.rebuild.server.helper.ConfigurableItem;
|
||||
import com.rebuild.server.helper.Lisence;
|
||||
import com.rebuild.server.helper.QiniuCloud;
|
||||
import com.rebuild.server.helper.SysConfiguration;
|
||||
import com.rebuild.utils.CommonsUtils;
|
||||
import com.rebuild.web.BasePageControll;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.math.NumberUtils;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 系统配置
|
||||
|
@ -51,6 +62,29 @@ public class SysConfigurationControll extends BasePageControll {
|
|||
}
|
||||
return mv;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "systems", method = RequestMethod.POST)
|
||||
public void postSystems(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
JSONObject data = (JSONObject) ServletUtils.getRequestJson(request);
|
||||
|
||||
String dHomeURL = defaultIfBlank(data, ConfigurableItem.HomeURL);
|
||||
if (!RegexUtils.isUrl(dHomeURL)) {
|
||||
writeFailure(response, "无效主页地址/域名");
|
||||
return;
|
||||
}
|
||||
String dRecycleBinKeepingDays = defaultIfBlank(data, ConfigurableItem.RecycleBinKeepingDays);
|
||||
if (!NumberUtils.isNumber(dRecycleBinKeepingDays)) {
|
||||
data.put(ConfigurableItem.RecycleBinKeepingDays.name(), ConfigurableItem.RecycleBinKeepingDays.getDefaultValue());
|
||||
}
|
||||
|
||||
setValues(data);
|
||||
|
||||
// @see ServerListener
|
||||
request.getServletContext().setAttribute("appName", SysConfiguration.get(ConfigurableItem.AppName));
|
||||
request.getServletContext().setAttribute("homeUrl", SysConfiguration.get(ConfigurableItem.HomeURL));
|
||||
|
||||
writeSuccess(response);
|
||||
}
|
||||
|
||||
@RequestMapping("integration/storage")
|
||||
public ModelAndView pageIntegrationStorage() {
|
||||
|
@ -60,26 +94,64 @@ public class SysConfigurationControll extends BasePageControll {
|
|||
mv.getModel().put("storageStatus", QiniuCloud.instance().available());
|
||||
return mv;
|
||||
}
|
||||
|
||||
@RequestMapping("integration/cache")
|
||||
public ModelAndView pageIntegrationCache() {
|
||||
ModelAndView mv = createModelAndView("/admin/integration/cache-redis.jsp");
|
||||
mv.getModel().put("cacheAccount",
|
||||
starsAccount(SysConfiguration.getCacheAccount(), 2));
|
||||
mv.getModel().put("cacheStatus", Application.getCommonCache().isUseRedis());
|
||||
return mv;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "integration/storage", method = RequestMethod.POST)
|
||||
public void postIntegrationStorage(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
JSONObject data = (JSONObject) ServletUtils.getRequestJson(request);
|
||||
|
||||
String dStorageURL = defaultIfBlank(data, ConfigurableItem.StorageURL);
|
||||
String dStorageBucket = defaultIfBlank(data, ConfigurableItem.StorageBucket);
|
||||
String dStorageApiKey = defaultIfBlank(data, ConfigurableItem.StorageApiKey);
|
||||
String dStorageApiSecret = defaultIfBlank(data, ConfigurableItem.StorageApiSecret);
|
||||
|
||||
if (dStorageURL.startsWith("//")) {
|
||||
dStorageURL = "https:" + dStorageURL;
|
||||
}
|
||||
if (!RegexUtils.isUrl(dStorageURL)) {
|
||||
writeFailure(response, "无效访问域名");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Test
|
||||
Auth auth = Auth.create(dStorageApiKey, dStorageApiSecret);
|
||||
BucketManager bucketManager = new BucketManager(auth, QiniuCloud.CONFIGURATION);
|
||||
bucketManager.getBucketInfo(dStorageBucket);
|
||||
|
||||
setValues(data);
|
||||
writeSuccess(response);
|
||||
|
||||
} catch (QiniuException ex) {
|
||||
writeFailure(response, "无效配置参数 : " + ex.response.error);
|
||||
} catch (Exception ex) {
|
||||
writeFailure(response, ThrowableUtils.getRootCause(ex).getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("integration/submail")
|
||||
public ModelAndView pageIntegrationSubmail() {
|
||||
ModelAndView mv = createModelAndView("/admin/integration/submail.jsp");
|
||||
mv.getModel().put("smsAccount",
|
||||
mv.getModel().put("smsAccount",
|
||||
starsAccount(SysConfiguration.getSmsAccount(), 1));
|
||||
mv.getModel().put("mailAccount",
|
||||
starsAccount(SysConfiguration.getMailAccount(), 1));
|
||||
return mv;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "integration/submail", method = RequestMethod.POST)
|
||||
public void postIntegrationSubmail(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
JSONObject data = (JSONObject) ServletUtils.getRequestJson(request);
|
||||
|
||||
String dMailAddr = defaultIfBlank(data, ConfigurableItem.MailAddr);
|
||||
if (!RegexUtils.isEMail(dMailAddr)) {
|
||||
writeFailure(response, "无效发件人地址");
|
||||
return;
|
||||
}
|
||||
|
||||
setValues(data);
|
||||
writeSuccess(response);
|
||||
}
|
||||
|
||||
@RequestMapping("systems/query-authority")
|
||||
public void queryAuthority(HttpServletResponse response) throws IOException {
|
||||
writeSuccess(response, Lisence.queryAuthority());
|
||||
|
@ -94,4 +166,19 @@ public class SysConfigurationControll extends BasePageControll {
|
|||
}
|
||||
return account;
|
||||
}
|
||||
|
||||
private String defaultIfBlank(JSONObject data, ConfigurableItem item) {
|
||||
return StringUtils.defaultIfBlank(data.getString(item.name()), SysConfiguration.get(item));
|
||||
}
|
||||
|
||||
private void setValues(JSONObject data) {
|
||||
for (Map.Entry<String, Object> e : data.entrySet()) {
|
||||
try {
|
||||
ConfigurableItem item = ConfigurableItem.valueOf(e.getKey());
|
||||
SysConfiguration.set(item, e.getValue());
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Invalid item : " + e.getKey() + " = " + e.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,10 +26,14 @@ import cn.devezhao.commons.web.ServletUtils;
|
|||
import cn.devezhao.commons.web.WebUtils;
|
||||
import cn.devezhao.persist4j.Record;
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.rebuild.api.LoginToken;
|
||||
import com.rebuild.server.Application;
|
||||
import com.rebuild.server.helper.ConfigurableItem;
|
||||
import com.rebuild.server.helper.Lisence;
|
||||
import com.rebuild.server.helper.SMSender;
|
||||
import com.rebuild.server.helper.SysConfiguration;
|
||||
import com.rebuild.server.helper.VCode;
|
||||
import com.rebuild.server.helper.cache.CommonCache;
|
||||
import com.rebuild.server.metadata.EntityHelper;
|
||||
|
@ -304,4 +308,19 @@ public class LoginControll extends BasePageControll {
|
|||
Application.getSessionStore().clean();
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("live-wallpaper")
|
||||
public void getLiveWallpaper(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
if (!SysConfiguration.getBool(ConfigurableItem.LiveWallpaper)) {
|
||||
writeFailure(response);
|
||||
return;
|
||||
}
|
||||
|
||||
JSON ret = Lisence.rbApi("api/misc/bgimg");
|
||||
if (ret == null) {
|
||||
writeFailure(response);
|
||||
} else {
|
||||
writeSuccess(response, ((JSONObject) ret).getString("url"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,16 +5,45 @@
|
|||
<%@ include file="/_include/Head.jsp"%>
|
||||
<title>实体管理</title>
|
||||
<style type="text/css">
|
||||
.card.entity{position:relative;margin-bottom:20px}
|
||||
.card.entity:hover{background-color:rgba(255,255,255,.7)}
|
||||
.card.entity .card-body{padding:12px 20px;color:#333;}
|
||||
.card.entity .card-body .float-left{width:30px;text-align:center;}
|
||||
.card.entity .icon{font-size:32px;color:#4285f4;}
|
||||
.card.entity .badge{position:absolute;top:11px;right:11px}
|
||||
.card.entity span{margin-top:2px;display:block;}
|
||||
#entityList{margin:0 -10px}
|
||||
#entityList>div{padding-left:10px;padding-right:10px}
|
||||
.card.ph{margin-left:10px;margin-top:0}
|
||||
.card.entity {
|
||||
position: relative;
|
||||
margin-bottom: 20px
|
||||
}
|
||||
.card.entity:hover {
|
||||
background-color: rgba(255, 255, 255, .7)
|
||||
}
|
||||
.card.entity .card-body {
|
||||
padding: 12px 20px;
|
||||
color: #333;
|
||||
}
|
||||
.card.entity .card-body .float-left {
|
||||
width: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
.card.entity .icon {
|
||||
font-size: 32px;
|
||||
color: #4285f4;
|
||||
}
|
||||
.card.entity .badge {
|
||||
position: absolute;
|
||||
top: 11px;
|
||||
right: 11px
|
||||
}
|
||||
.card.entity span {
|
||||
margin-top: 2px;
|
||||
display: block;
|
||||
}
|
||||
#entityList {
|
||||
margin: 0 -10px
|
||||
}
|
||||
#entityList > div {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px
|
||||
}
|
||||
.card.ph {
|
||||
margin-left: 10px;
|
||||
margin-top: 0
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -26,7 +55,7 @@
|
|||
<jsp:param value="entities" name="activeNav"/>
|
||||
</jsp:include>
|
||||
<div class="rb-content">
|
||||
<div class="main-content container-fluid">
|
||||
<div class="main-content container-fluid" style="padding-bottom:5px">
|
||||
<div class="row" id="entityList">
|
||||
<div class="card ph">
|
||||
<div class="card-body">
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<%@ include file="/_include/Head.jsp"%>
|
||||
<title>缓存系统配置</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="rb-wrapper rb-fixed-sidebar rb-collapsible-sidebar rb-collapsible-sidebar-hide-logo rb-color-header">
|
||||
<jsp:include page="/_include/NavTop.jsp">
|
||||
<jsp:param value="缓存系统配置" name="pageTitle"/>
|
||||
</jsp:include>
|
||||
<jsp:include page="/_include/NavLeftAdmin.jsp">
|
||||
<jsp:param value="integration-cache" name="activeNav"/>
|
||||
</jsp:include>
|
||||
<div class="rb-content">
|
||||
<div class="main-content container-fluid syscfg">
|
||||
<div class="row">
|
||||
<div class="col-md-9 col-12">
|
||||
<div class="card">
|
||||
<div class="card-header card-header-divider">缓存系统</div>
|
||||
<div class="card-body">
|
||||
<h5><a class="cl-base" href="https://redis.io/?utm_source=getrebuild.com" target="_blank" rel="noopener noreferrer">Redis</a></h5>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="40%">缓存服务器</td>
|
||||
<td>
|
||||
<c:if test="${cacheAccount == null}">未配置</c:if>
|
||||
<c:if test="${cacheAccount != null}">${cacheAccount[0]}:${cacheAccount[1]}</c:if>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>访问秘钥</td>
|
||||
<td>${cacheAccount == null ? "未配置" : cacheAccount[2]}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<c:if test="${!cacheStatus}">
|
||||
<div class="alert alert-warning alert-icon mt-6">
|
||||
<div class="icon"><span class="zmdi zmdi-alert-triangle"></span></div>
|
||||
<div class="message">REDIS 未配置或配置有误,当前已启用 EHCACHE 内建缓存</div>
|
||||
</div>
|
||||
</c:if>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 col-12">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%@ include file="/_include/Foot.jsp"%>
|
||||
</body>
|
||||
</html>
|
|
@ -19,26 +19,29 @@
|
|||
<div class="row">
|
||||
<div class="col-md-9 col-12">
|
||||
<div class="card">
|
||||
<div class="card-header card-header-divider">云存储</div>
|
||||
<div class="card-header card-header-divider">
|
||||
云存储
|
||||
<a href="#modfiy" class="float-right"><i class="icon zmdi zmdi-edit"></i> 修改</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h5><a class="cl-base" href="https://portal.qiniu.com/signup?utm_source=getrebuild.com&code=3letk048wdsnm" target="_blank" rel="noopener noreferrer">七牛云</a></h5>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="40%">访问域名</td>
|
||||
<td>${storageAccount == null ? "未配置" : storageAccount[3]}</td>
|
||||
<td data-id="StorageURL">${storageAccount == null ? "未配置" : storageAccount[3]}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>存储空间</td>
|
||||
<td>${storageAccount == null ? "未配置" : storageAccount[2]}</td>
|
||||
<td data-id="StorageBucket">${storageAccount == null ? "未配置" : storageAccount[2]}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>秘钥 AK</td>
|
||||
<td>${storageAccount == null ? "未配置" : storageAccount[0]}</td>
|
||||
<td data-id="StorageApiKey">${storageAccount == null ? "未配置" : storageAccount[0]}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>秘钥 SK</td>
|
||||
<td>${storageAccount == null ? "未配置" : storageAccount[1]}</td>
|
||||
<td data-id="StorageApiSecret">${storageAccount == null ? "未配置" : storageAccount[1]}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -48,6 +51,10 @@
|
|||
<div class="message">七牛云存储账户未配置或配置有误,当前已启用本地文件存储</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<div class="edit-footer">
|
||||
<button class="btn btn-link">取消</button>
|
||||
<button class="btn btn-primary">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -58,5 +65,6 @@
|
|||
</div>
|
||||
</div>
|
||||
<%@ include file="/_include/Foot.jsp"%>
|
||||
<script src="${baseUrl}/assets/js/admin/syscfg.jsx" type="text/babel"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -19,66 +19,65 @@
|
|||
<div class="row">
|
||||
<div class="col-md-9 col-12">
|
||||
<div class="card">
|
||||
<div class="card-header card-header-divider"><a class="cl-base" href="https://www.mysubmail.com/?utm_source=getrebuild.com" target="_blank" rel="noopener noreferrer">赛邮 SUBMAIL</a></div>
|
||||
<div class="card-header card-header-divider">
|
||||
赛邮 SUBMAIL
|
||||
<a href="#modfiy" class="float-right"><i class="icon zmdi zmdi-edit"></i> 修改</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h5>邮件服务</h5>
|
||||
<c:choose>
|
||||
<c:when test="${mailAccount != null}">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="40%">APPID</td>
|
||||
<td>${mailAccount[0]}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>APPKEY</td>
|
||||
<td>${mailAccount[1]}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>发件人地址</td>
|
||||
<td>${mailAccount[2]}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>发件人名称</td>
|
||||
<td>${mailAccount[3]}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div class="alert alert-danger alert-icon mt-6 mb-6">
|
||||
<div class="icon"><span class="zmdi zmdi-close-circle-o"></span></div>
|
||||
<div class="message">邮件账号未配置,邮件相关功能不可用</div>
|
||||
</div>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="40%">APPID</td>
|
||||
<td data-id="MailUser">${mailAccount == null ? "未配置" : mailAccount[0]}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>APPKEY</td>
|
||||
<td data-id="MailPassword">${mailAccount == null ? "未配置" : mailAccount[1]}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>发件人地址</td>
|
||||
<td data-id="MailAddr">${mailAccount == null ? "未配置" : mailAccount[2]}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>发件人名称</td>
|
||||
<td data-id="MailName">${mailAccount == null ? "未配置" : mailAccount[3]}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<c:if test="${mailAccount == null}">
|
||||
<div class="alert alert-danger alert-icon mt-6 mb-6">
|
||||
<div class="icon"><span class="zmdi zmdi-close-circle-o"></span></div>
|
||||
<div class="message">邮件账号未配置,邮件相关功能不可用</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<h5>短信服务</h5>
|
||||
<c:choose>
|
||||
<c:when test="${smsAccount != null}">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="40%">APPID</td>
|
||||
<td>${smsAccount[0]}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>APPKEY</td>
|
||||
<td>${smsAccount[1]}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>短信签名</td>
|
||||
<td>${smsAccount[2]}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div class="alert alert-danger alert-icon mt-6">
|
||||
<div class="icon"><span class="zmdi zmdi-close-circle-o"></span></div>
|
||||
<div class="message">短信账号未配置,短信相关功能不可用</div>
|
||||
</div>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="40%">APPID</td>
|
||||
<td data-id="SmsUser">${smsAccount == null ? "未配置" : smsAccount[0]}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>APPKEY</td>
|
||||
<td data-id="SmsPassword">${smsAccount == null ? "未配置" : smsAccount[1]}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>短信签名</td>
|
||||
<td data-id="SmsSign">${smsAccount == null ? "未配置" : smsAccount[2]}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<c:if test="${smsAccount == null}">
|
||||
<div class="alert alert-danger alert-icon mt-6">
|
||||
<div class="icon"><span class="zmdi zmdi-close-circle-o"></span></div>
|
||||
<div class="message">短信账号未配置,短信相关功能不可用</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<div class="edit-footer">
|
||||
<button class="btn btn-link">取消</button>
|
||||
<button class="btn btn-primary">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -89,5 +88,6 @@
|
|||
</div>
|
||||
</div>
|
||||
<%@ include file="/_include/Foot.jsp"%>
|
||||
<script src="${baseUrl}/assets/js/admin/syscfg.jsx" type="text/babel"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -7,11 +7,17 @@
|
|||
<%@ include file="/_include/Head.jsp"%>
|
||||
<title>通用配置</title>
|
||||
<style type="text/css">
|
||||
.syscfg a.img-thumbnail{display:inline-block;padding:0.3rem 0;background-color:#fff;line-height:1;font-size:0;cursor:default;}
|
||||
.syscfg a.img-thumbnail .logo-img{transform: scale(0.8);}
|
||||
.syscfg h5{background-color:#eee;margin:0;padding:10px;}
|
||||
.syscfg .table td{padding:10px;}
|
||||
.syscfg .table td p{margin:0;color:#999;font-weight:normal;font-size:12px;}
|
||||
.syscfg a.img-thumbnail {
|
||||
display: inline-block;
|
||||
padding: 0.3rem 0;
|
||||
background-color: #fff;
|
||||
line-height: 1;
|
||||
font-size: 0;
|
||||
cursor: default;
|
||||
}
|
||||
.syscfg a.img-thumbnail .logo-img {
|
||||
transform: scale(0.8);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -27,14 +33,17 @@
|
|||
<div class="row">
|
||||
<div class="col-lg-9 col-12">
|
||||
<div class="card">
|
||||
<div class="card-header card-header-divider">通用配置</div>
|
||||
<div class="card-header card-header-divider">
|
||||
通用配置
|
||||
<a href="#modfiy" class="float-right"><i class="icon zmdi zmdi-edit"></i> 修改</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h5>通用</h5>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="40%">名称</td>
|
||||
<td>${appName}</td>
|
||||
<td data-id="AppName">${appName}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>LOGO</td>
|
||||
|
@ -45,15 +54,15 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td>主页地址/域名<p>基础 URL 所有链接将以此作为前缀</p></td>
|
||||
<td><a href="${HomeURL}" class="link" target="_blank">${HomeURL}</a></td>
|
||||
<td data-id="HomeURL">${HomeURL}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>公开注册</td>
|
||||
<td>${OpenSignUp ? "是" : "否"}</td>
|
||||
<td data-id="OpenSignUp" data-options="true:是;false:否">${OpenSignUp ? "是" : "否"}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>登录页每日一图</td>
|
||||
<td>${LiveWallpaper ? "是" : "否"}</td>
|
||||
<td data-id="LiveWallpaper" data-options="true:是;false:否">${LiveWallpaper ? "是" : "否"}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -62,7 +71,7 @@
|
|||
<tbody>
|
||||
<tr>
|
||||
<td width="40%">登录密码安全策略</td>
|
||||
<td>
|
||||
<td data-id="PasswordPolicy" data-options="1:低;2:中;3:高">
|
||||
<c:choose>
|
||||
<c:when test="${PasswordPolicy >= 3}">高 (最低8位,必须同时包含数字、字母、特殊字符)</c:when>
|
||||
<c:when test="${PasswordPolicy == 2}">中 (最低6位,必须同时包含数字、字母)</c:when>
|
||||
|
@ -71,11 +80,15 @@
|
|||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>回收站数据保留时间</td>
|
||||
<td>${RecycleBinKeepingDays}天</td>
|
||||
<td>回收站数据保留天数</td>
|
||||
<td data-id="RecycleBinKeepingDays">${RecycleBinKeepingDays}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="edit-footer">
|
||||
<button class="btn btn-link">取消</button>
|
||||
<button class="btn btn-primary">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -101,6 +114,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<%@ include file="/_include/Foot.jsp"%>
|
||||
<script src="${baseUrl}/assets/js/admin/syscfg.jsx" type="text/babel"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$.get('systems/query-authority', function (res) { $('#authType').text(res.data.authType) })
|
||||
|
|
|
@ -3092,6 +3092,31 @@ a.icon-link>.zmdi {
|
|||
font-size: 12px;
|
||||
}
|
||||
|
||||
.syscfg .card {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.syscfg .card .card-header-divider>a {
|
||||
font-size: 1rem;
|
||||
margin-top: 4px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.syscfg .card:hover .card-header-divider>a {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.syscfg .edit-footer {
|
||||
background-color: #eee;
|
||||
padding: 10px;
|
||||
text-align: right;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.syscfg.edit .edit-footer {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.announcement-wrapper>div {
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
|
|
58
src/main/webapp/assets/js/admin/syscfg.jsx
Normal file
58
src/main/webapp/assets/js/admin/syscfg.jsx
Normal file
|
@ -0,0 +1,58 @@
|
|||
// 系统参数设置 - 公共部分
|
||||
|
||||
$(document).ready(() => {
|
||||
$('.card-header-divider>a').click((e) => {
|
||||
e.preventDefault()
|
||||
editMode()
|
||||
})
|
||||
$('.edit-footer>.btn-link').click(() => location.reload())
|
||||
$('.edit-footer>.btn-primary').click(() => post(__data))
|
||||
})
|
||||
|
||||
let __data = {}
|
||||
const changeValue = function (e) {
|
||||
let name = e.target.name
|
||||
__data[name] = e.target.value
|
||||
}
|
||||
// 激活编辑模式
|
||||
const editMode = function () {
|
||||
$('.syscfg table td[data-id]').each(function () {
|
||||
let $item = $(this)
|
||||
let val = $item.text()
|
||||
if (val === '未配置') val = ''
|
||||
let name = $item.data('id')
|
||||
|
||||
let options = $item.data('options')
|
||||
if (options) {
|
||||
options = options.split(';')
|
||||
let comp = <select name={name} className="form-control form-control-sm" onChange={changeValue}>
|
||||
{options.map((item) => {
|
||||
let kv = item.split(':')
|
||||
return <option value={kv[0]} key={kv[0]}>{kv[1]}</option>
|
||||
})}
|
||||
</select>
|
||||
renderRbcomp(comp, $item)
|
||||
} else {
|
||||
renderRbcomp(<input defaultValue={val} name={name} className="form-control form-control-sm" onChange={changeValue} />, $item)
|
||||
}
|
||||
})
|
||||
$('.syscfg').addClass('edit')
|
||||
}
|
||||
|
||||
// 提交
|
||||
const post = function (data) {
|
||||
for (let k in data) {
|
||||
if (!data[k]) {
|
||||
let field = $('td[data-id=' + k + ']').prev().text()
|
||||
RbHighbar.create(field + '不能为空')
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const btn = $('.edit-footer>.btn-primary').button('loading')
|
||||
$.post(location.href, JSON.stringify(data), (res) => {
|
||||
btn.button('reset')
|
||||
if (res.error_code === 0) location.reload()
|
||||
else RbHighbar.error(res.error_msg)
|
||||
})
|
||||
}
|
|
@ -19,15 +19,15 @@
|
|||
<style type="text/css">
|
||||
.block{max-width:1000px;padding:0 14px;margin:30px auto 0;}
|
||||
.error{background-color:#ea4335;color:#fff;padding:18px 0;}
|
||||
.error a{color:#fff;text-decoration:underline;}
|
||||
.error a{color:#fff}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<% if (!ServerStatus.isStatusOK()) { %>
|
||||
<% if (!ServerStatus.isStatusOK() || !Application.serversReady()) { %>
|
||||
<div class="error">
|
||||
<div class="block mt-0">
|
||||
<h2 class="mt-0">系统故障</h2>
|
||||
<div>部分服务未能正常启动,请通过快速检查列表排除故障,故障排除后重启服务。你也可以获取 <a href="https://getrebuild.com/">技术支持</a></div>
|
||||
<div>服务未能正常启动,请通过快速检查列表排除故障,故障排除后请重启服务。你也可以 <a href="https://getrebuild.com/report-issue?title=boot-error" target="_blank">报告此问题</a></div>
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
|
@ -35,9 +35,13 @@
|
|||
<h5 class="text-bold">快速检查</h5>
|
||||
<table class="table table-bordered table-sm table-hover">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th width="30%">Master Service</th>
|
||||
<td class="text-danger"><%=Application.serversReady() ? "<span class='text-success'>OK<span>" : "启动失败"%></td>
|
||||
</tr>
|
||||
<% for (Status s : ServerStatus.getLastStatus()) { %>
|
||||
<tr>
|
||||
<th width="30%"><%=s.name%></th>
|
||||
<th><%=s.name%></th>
|
||||
<td class="text-danger"><%=s.success ? "<span class='text-success'>OK<span>" : ("ERROR : " + s.error)%></td>
|
||||
</tr>
|
||||
<% } %>
|
||||
|
@ -92,7 +96,7 @@
|
|||
<% } %>
|
||||
<div class="block">
|
||||
<div class="text-muted">
|
||||
© 2019 <a href="https://getrebuild.com/?utm_source=rebuild">REBUILD</a>
|
||||
© 2020 <a href="https://getrebuild.com/?utm_source=rebuild">REBUILD</a>
|
||||
<% if (AppUtils.getRequestUser(request) != null) { %>
|
||||
·
|
||||
<a href="server-status.json">Status Api</a>
|
||||
|
|
|
@ -119,9 +119,6 @@
|
|||
</div>
|
||||
<%@ include file="/_include/Foot.jsp"%>
|
||||
<script src="${baseUrl}/assets/js/feeds/announcement.jsx" type="text/babel"></script>
|
||||
<script>
|
||||
useLiveWallpaper = <%=SysConfiguration.getBool(ConfigurableItem.LiveWallpaper)%>
|
||||
</script>
|
||||
<script type="text/babel">
|
||||
$(document).ready(function() {
|
||||
if (top != self) { parent.location.reload(); return }
|
||||
|
@ -161,20 +158,15 @@ $(document).ready(function() {
|
|||
})
|
||||
})
|
||||
|
||||
if (useLiveWallpaper) {
|
||||
$.get('https://getrebuild.com/api/misc/bgimg?k=IjkMHgq94T7s7WkP', (res) => {
|
||||
if (!res.url) return
|
||||
let bgimg = new Image()
|
||||
bgimg.src = res.url
|
||||
bgimg.onload = function() {
|
||||
$('.rb-bgimg').animate({ opacity: 0 })
|
||||
setTimeout(() => {
|
||||
$('.rb-bgimg').css('background-image', 'url(' + res.url + ')').animate({ opacity: 1 })
|
||||
}, 400)
|
||||
if (res.copyright) $('.rb-bgimg').attr('alt', res.copyright + ' (' + res.source + ')')
|
||||
}
|
||||
}).fail(function () { /* NOOP */ })
|
||||
}
|
||||
$.get('live-wallpaper', (res) => {
|
||||
if (res.error_code != 0 || !res.data) return
|
||||
let bgimg = new Image()
|
||||
bgimg.src = res.data
|
||||
bgimg.onload = function() {
|
||||
$('.rb-bgimg').animate({ opacity: 0 })
|
||||
setTimeout(() => $('.rb-bgimg').css('background-image', 'url(' + res.data + ')').animate({ opacity: 1 }), 400)
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -35,12 +35,11 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
|
|||
* @since 0.2, 2014-4-10
|
||||
*/
|
||||
public class SchemaGen {
|
||||
|
||||
|
||||
private static ApplicationContext CTX;
|
||||
private static PersistManagerFactory PMF;
|
||||
|
||||
private static boolean DROP_EXISTS = false;
|
||||
private static boolean TEMPSTAMP_ZERO = false;
|
||||
|
||||
public static void main(String[] args) {
|
||||
CTX = new ClassPathXmlApplicationContext(new String[] { "application-ctx.xml", });
|
||||
|
@ -51,13 +50,21 @@ public class SchemaGen {
|
|||
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
static void genAll() {
|
||||
|
||||
/**
|
||||
* 生成全部实体
|
||||
*/
|
||||
static void genAll() {
|
||||
for (Entity entity : PMF.getMetadataFactory().getEntities()) {
|
||||
gen(entity.getEntityCode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成指定实体
|
||||
*
|
||||
* @param e
|
||||
*/
|
||||
static void gen(int e) {
|
||||
Entity entity = PMF.getMetadataFactory().getEntity(e);
|
||||
Element root = ((ConfigurationMetadataFactory) PMF.getMetadataFactory()).getConfigDocument().getRootElement();
|
||||
|
@ -65,15 +72,12 @@ public class SchemaGen {
|
|||
entity,
|
||||
PMF.getDialect(),
|
||||
root.selectSingleNode("//entity[@name='" + entity.getName() + "']").selectNodes("index"));
|
||||
|
||||
String[] ddl = table.generateDDL(DROP_EXISTS, false);
|
||||
|
||||
String[] ddl = table.generateDDL(DROP_EXISTS, false, false);
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("-- ************ Entity [" + entity.getName() + "] DDL ************\n");
|
||||
for (String d : ddl) {
|
||||
if (!TEMPSTAMP_ZERO) {
|
||||
d = d.replace(" default '0000-00-00 00:00:00'", " default current_timestamp");
|
||||
}
|
||||
sb.append(d).append("\n");
|
||||
}
|
||||
System.out.println(sb);
|
||||
|
|
Loading…
Reference in a new issue