Fix 3.6 beta5 (#734)

* style

* Delete codeql-analysis.yml

* fix some

* enh: VN

* v3.6.0

---------

Co-authored-by: devezhao <zhaofang123@gmail.com>
This commit is contained in:
REBUILD 企业管理系统 2024-03-18 13:00:38 +08:00 committed by GitHub
parent 142c8fc203
commit fb71f6db1d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 83 additions and 109 deletions

View file

@ -1,70 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: 'CodeQL'
on:
push:
branches: [master, develop]
pull_request:
# The branches below must be a subset of the branches above
branches: [master, develop]
schedule:
- cron: '41 0 * * 0'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: ['java', 'javascript']
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

2
@rbv

@ -1 +1 @@
Subproject commit c24b2e835e839341f850de2161cff51525ee6cfc
Subproject commit b620fe7925c82990b116927ba6434dcccbddfdfb

View file

@ -10,7 +10,7 @@
</parent>
<groupId>com.rebuild</groupId>
<artifactId>rebuild</artifactId>
<version>3.6.0-beta4</version>
<version>3.6.0</version>
<name>rebuild</name>
<description>Building your business-systems freely!</description>
<url>https://getrebuild.com/</url>

View file

@ -74,11 +74,11 @@ public class Application implements ApplicationListener<ApplicationStartedEvent>
/**
* Rebuild Version
*/
public static final String VER = "3.6.0-beta4";
public static final String VER = "3.6.0";
/**
* Rebuild Build [MAJOR]{1}[MINOR]{2}[PATCH]{2}[BUILD]{2}
*/
public static final int BUILD = 3060004;
public static final int BUILD = 3060005;
static {
// Driver for DB

View file

@ -12,6 +12,7 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.rebuild.utils.JSONUtils;
import com.rebuild.utils.JSONable;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.util.Assert;
import java.io.Serializable;
@ -66,11 +67,11 @@ public class ConfigBean implements Serializable, Cloneable, JSONable {
}
public Integer getInteger(String name) {
return (Integer) data.get(name);
return ObjectUtils.defaultIfNull((Integer) data.get(name), 0);
}
public Long getLong(String name) {
return (Long) data.get(name);
return ObjectUtils.defaultIfNull((Long) data.get(name), 0L);
}
public JSON getJSON(String name) {

View file

@ -364,7 +364,7 @@ public abstract class ChartData extends SetUser implements ChartSpec {
if (useRefLink && axisType == DisplayType.REFERENCE
&& ID.valueOf(value.toString()).getEntityCode() > 100) {
label = String.format("<a href='/app/redirect?id=%s'>%s</a>", value, label);
label = String.format("<a href='/app/redirect?id=%s&type=newtab'>%s</a>", value, label);
}
} else {

View file

@ -31,6 +31,7 @@ public class CommonsLog {
public static final String TYPE_TRIGGER = "TRIGGER";
public static final String TYPE_EXPORT = "EXPORT";
public static final String TYPE_ACCESS = "ACCESS";
/**
* @param type

View file

@ -255,6 +255,8 @@ public class QueryParser {
String[] sorts = sort.split("[,;]");
for (String s : sorts) {
String[] split = s.split(":");
if (StringUtils.isBlank(split[0])) return null;
sb.append(split[0]);
if (split.length > 1) sb.append("desc".equalsIgnoreCase(split[1]) ? " desc" : " asc");
sb.append(", ");

View file

@ -43,7 +43,8 @@ public class TaskExecutors extends DistributedJobLock {
MAX_TASKS_NUMBER, MAX_TASKS_NUMBER, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(MAX_TASKS_NUMBER * 6));
private static final Map<String, HeavyTask<?>> TASKS = new ConcurrentHashMap<>();
// 异步任务
private static final Map<String, HeavyTask<?>> ASYNC_TASKS = new ConcurrentHashMap<>();
// 队列执行
private static final ExecutorService SINGLE_QUEUE = new ThreadPoolExecutor(
@ -61,7 +62,7 @@ public class TaskExecutors extends DistributedJobLock {
String taskid = task.getClass().getSimpleName() + "-" + CodecUtils.randomCode(20);
task.setUser(execUser);
EXEC.execute(task);
TASKS.put(taskid, task);
ASYNC_TASKS.put(taskid, task);
return taskid;
}
@ -71,7 +72,7 @@ public class TaskExecutors extends DistributedJobLock {
* @param taskid
*/
public static boolean cancel(String taskid) {
HeavyTask<?> task = TASKS.get(taskid);
HeavyTask<?> task = ASYNC_TASKS.get(taskid);
if (task == null) {
log.warn("No task found : {}", taskid);
return false;
@ -98,7 +99,7 @@ public class TaskExecutors extends DistributedJobLock {
* @return
*/
public static HeavyTask<?> get(String taskid) {
return TASKS.get(taskid);
return ASYNC_TASKS.get(taskid);
}
/**
@ -140,9 +141,9 @@ public class TaskExecutors extends DistributedJobLock {
public void executeJob() {
if (!tryLock()) return;
if (!TASKS.isEmpty()) {
if (!ASYNC_TASKS.isEmpty()) {
int completed = 0;
for (Map.Entry<String, HeavyTask<?>> e : TASKS.entrySet()) {
for (Map.Entry<String, HeavyTask<?>> e : ASYNC_TASKS.entrySet()) {
HeavyTask<?> task = e.getValue();
if (task.getCompletedTime() == null || !task.isCompleted()) {
continue;
@ -150,12 +151,12 @@ public class TaskExecutors extends DistributedJobLock {
long leftTime = (System.currentTimeMillis() - task.getCompletedTime().getTime()) / 1000;
if (leftTime > 60 * 120) {
TASKS.remove(e.getKey());
ASYNC_TASKS.remove(e.getKey());
log.info("HeavyTask clean-up : {}", e.getKey());
}
completed++;
}
log.info("{} task(s) in the queue. {} are completed (will clean-up later)", TASKS.size(), completed);
log.info("{} task(s) in the queue. {} are completed (will clean-up later)", ASYNC_TASKS.size(), completed);
}
Queue<Runnable> queue = ((ThreadPoolExecutor) SINGLE_QUEUE).getQueue();

View file

@ -18,6 +18,7 @@ import com.rebuild.core.UserContextHolder;
import com.rebuild.core.cache.CommonsCache;
import com.rebuild.core.privileges.UserHelper;
import com.rebuild.core.privileges.bizz.ZeroEntry;
import com.rebuild.core.support.CommonsLog;
import com.rebuild.core.support.ConfigurationItem;
import com.rebuild.core.support.License;
import com.rebuild.core.support.RebuildConfiguration;
@ -129,6 +130,8 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
// User
request.setAttribute(WebConstants.$USER, Application.getUserStore().getUser(requestUser));
boolean isSecurityEnhanced = RebuildConfiguration.getBool(ConfigurationItem.SecurityEnhanced);
if (isHtmlRequest(requestUri, request)) {
// Last active
Application.getSessionStore().storeLastActive(request);
@ -146,10 +149,15 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
request.setAttribute(ZeroEntry.AllowCustomNav.name(),
Application.getPrivilegesManager().allow(requestUser, ZeroEntry.AllowCustomNav));
// v3.6-b5
if (isSecurityEnhanced) {
CommonsLog.createLog(CommonsLog.TYPE_ACCESS, requestUser, null, requestUri);
}
}
// 非增强安全超管可访问
if (RebuildConfiguration.getBool(ConfigurationItem.SecurityEnhanced)) skipCheckSafeUse = false;
if (isSecurityEnhanced) skipCheckSafeUse = false;
else skipCheckSafeUse = UserHelper.isSuperAdmin(requestUser);
} else if (!isIgnoreAuth(requestUri)) {

View file

@ -76,11 +76,12 @@ public class ConfigurationController extends BaseController {
// Available langs
mv.getModel().put("availableLangs", JSON.toJSON(Application.getLanguage().availableLocales()));
JSONObject auth = License.queryAuthority();
final JSONObject auth = License.queryAuthority();
mv.getModel().put("LicenseType",
auth.getString("authType") + " (" + auth.getString("authObject") + ")");
mv.getModel().put("Version", Application.VER);
mv.getModel().put("SN", "***" + License.SN().substring(12));
mv.getModel().put("SN", "***" + auth.getString("sn").substring(12));
mv.getModel().put("VN", auth.getString("vn"));
return mv;
}

View file

@ -319,7 +319,8 @@
<div class="card-header card-header-divider">[[${bundle.L('关于')}]] REBUILD</div>
<div class="card-body">
<p class="mb-1">[[${bundle.L('系统版本')}]] <a class="link" target="_blank" th:href="|https://getrebuild.com/download?v=${Version}|">[[${Version}]]</a></p>
<p class="mb-2">[[${bundle.L('授权类型')}]] <a class="link" target="_blank" th:href="|https://getrebuild.com/authority?sn=${SN}|">[[${LicenseType}]]</a></p>
<p class="mb-1">[[${bundle.L('授权类型')}]] <a class="link" target="_blank" th:href="|https://getrebuild.com/authority?sn=${SN}|">[[${LicenseType}]]</a></p>
<p th:if="${VN != null}" class="mb-1">[[${bundle.L('服务支持码')}]] <a>[[${VN}]]</a></p>
<ul style="line-height: 2">
<li><a class="link" target="_blank" th:href="@{/error/server-status}">[[${bundle.L('系统状态')}]]</a></li>
<li><a class="link" target="_blank" href="https://getrebuild.com/docs/">[[${bundle.L('帮助文档')}]]</a></li>

View file

@ -532,6 +532,22 @@ See LICENSE and COMMERCIAL in the project root for license information.
max-width: 400px;
}
.chart-box.DataList .table td.open-newtab {
padding-bottom: 0;
text-align: center;
padding: 8px;
}
.chart-box.DataList .table td.open-newtab .icon {
font-size: 15px;
width: 100%;
color: #404040;
}
.chart-box.DataList .table td.open-newtab a:hover .icon {
color: #4285f4;
}
.DataList-showfields .select2-container--default .select2-selection--single .select2-selection__arrow b::after {
font-family: 'Material Design Icons', serif;
content: '\f0415';

View file

@ -5558,3 +5558,7 @@ span.icon-append .icon {
background-color: red;
animation: blink 1s infinite;
}
.dropdown-menu.nott .dropdown-item {
text-transform: none;
}

View file

@ -24,8 +24,16 @@ body {
display: none;
}
.view-body.loading .view-header > .header-icon::before {
animation: flash 2s infinite;
@keyframes spinAnimation {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.view-body.loading .view-header .zmdi-refresh {
animation: spinAnimation 1s infinite linear;
}
.tab-container {

View file

@ -1272,6 +1272,7 @@ class DataList extends BaseChart {
</th>
)
})}
<th width="40" />
</tr>
</thead>
<tbody>
@ -1279,17 +1280,17 @@ class DataList extends BaseChart {
const lastCell = row[lastIndex]
const rkey = `tr-${lastCell.id}`
return (
<tr
key={rkey}
data-id={lastCell.id}
onDoubleClick={(e) => {
$stopEvent(e, true)
window.open(`${rb.baseUrl}/app/redirect?id=${lastCell.id}&type=newtab`)
}}>
<tr key={rkey} data-id={lastCell.id}>
{row.map((c, idx) => {
if (idx === lastIndex) return null // Last is ID
return this.renderCell(c, listFields[idx])
})}
<td className="open-newtab">
<a href={`${rb.baseUrl}/app/redirect?id=${lastCell.id}&type=newtab`} target="_blank" title={$L('打开')}>
<i className="zmdi zmdi-open-in-new icon" />
</a>
</td>
</tr>
)
})}
@ -1307,21 +1308,20 @@ class DataList extends BaseChart {
.perfectScrollbar()
let trActive
const $els = this._$tb.find('tbody tr').on('mousedown', function () {
const $trs = this._$tb.find('tbody tr').on('mousedown', function () {
if (trActive === this) {
$(this).toggleClass('highlight')
return
} else {
trActive = this
$trs.removeClass('highlight')
$(this).addClass('highlight')
}
trActive = this
$els.removeClass('highlight')
$(this).addClass('highlight')
})
})
}
renderCell(cellVal, field) {
const c = CellRenders.render(cellVal, field.type, 'auto', `cell-${field.field}`)
return c
return CellRenders.render(cellVal, field.type, 'auto', `cell-${field.field}`)
}
resize() {

View file

@ -70,8 +70,8 @@ const AdvFilters = {
const $menu = $('.adv-search .dropdown-menu')
$(res.data).each(function () {
const item = this
const $item = $(`<div class="dropdown-item J_custom" data-id="${item.id}"><a class="text-truncate">${item.name}</a></div>`).appendTo($menu)
$item.on('click', () => that._effectFilter($item, 'aside'))
const $item = $(`<div class="dropdown-item J_custom" data-id="${item.id}"><a class="text-truncate"></a></div>`).appendTo($menu)
$item.text(item.name).on('click', () => that._effectFilter($item, 'aside'))
if (lastFilter === item.id) $defaultFilter = $item

View file

@ -439,7 +439,8 @@ var _showNotification = function (state) {
if (_Notification) {
if (_Notification.permission === 'granted') {
var n = new _Notification($L('你有 %d 条未读消息', state), {
icon: rb.baseUrl + '/assets/img/favicon.png',
body: window.rb.appName,
icon: rb.baseUrl + '/assets/img/icon-192x192.png',
tag: 'rbNotification',
renotify: true,
silent: false,

View file

@ -70,7 +70,7 @@
<button th:title="${bundle.L('常用查询')}" class="btn btn-secondary dropdown-toggle J_filterlist" type="button" data-toggle="dropdown">
<span class="text-truncate J_name">[[${bundle.L('全部数据')}]]</span><i class="icon zmdi zmdi-caret-down"></i>
</button>
<div class="dropdown-menu rb-scroller">
<div class="dropdown-menu rb-scroller nott">
<div class="dropdown-item" data-id="$ALL$"><a>[[${bundle.L('全部数据')}]]</a></div>
</div>
<div class="input-group-append">