Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 45b0199

Browse files
committedNov 11, 2024
v0.5.6 update
fixed bug where optional addons would be forcibly enabled if already installed - only required addons should be forcibly enabled added buttons to export and import local operators
1 parent fa8dcaa commit 45b0199

File tree

11 files changed

+198
-68
lines changed

11 files changed

+198
-68
lines changed
 

‎config/BUILD_DETAILS

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
JDK Version:
2-
openjdk 21.0.2 2024-01-16
3-
OpenJDK Runtime Environment (build 21.0.2+13-58)
4-
OpenJDK 64-Bit Server VM (build 21.0.2+13-58, mixed mode, sharing)
2+
openjdk 22.0.1 2024-04-16
3+
OpenJDK Runtime Environment (build 22.0.1+8-16)
4+
OpenJDK 64-Bit Server VM (build 22.0.1+8-16, mixed mode, sharing)
55

66
Compilation Flags:
77
--release 11
@@ -23,12 +23,14 @@ datatable-9.0.002
2323
directaccess-9.0.002
2424
directaccess-api-9.0.002
2525
extensionsupport-api-9.0.002
26-
jsch-0.2.17-sources
27-
postgresql-42.7.3-sources
2826
spring-context-5.3.33
2927
update-api-9.0.002
3028
webserver-api-9.0.002
3129

3230
Packaged Dependencies:
31+
jsch-0.2.17-sources
3332
jsch-0.2.17
33+
json-20240303-sources
34+
json-20240303
35+
postgresql-42.7.3-sources
3436
postgresql-42.7.3

‎config/EXTERNAL_DEPS

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
1-
url:postgresql:https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.3/postgresql-42.7.3.jar
2-
url:jsch:https://repo1.maven.org/maven2/com/github/mwiede/jsch/0.2.17/jsch-0.2.17.jar
1+
url:postgresql-42.7.3.jar:https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.3/postgresql-42.7.3.jar
2+
url:postgresql-42.7.3-sources.jar:https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.3/postgresql-42.7.3-sources.jar
3+
url:jsch-0.2.17.jar:https://repo1.maven.org/maven2/com/github/mwiede/jsch/0.2.17/jsch-0.2.17.jar
4+
url:jsch-0.2.17-sources.jar:https://repo1.maven.org/maven2/com/github/mwiede/jsch/0.2.17/jsch-0.2.17-sources.jar
5+
url:json-20240303.jar:https://repo1.maven.org/maven2/org/json/json/20240303/json-20240303.jar
6+
url:json-20240303-sources.jar:https://repo1.maven.org/maven2/org/json/json/20240303/json-20240303-sources.jar

‎config/RUNTIME_DEPS

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,4 @@ file:commonbaseutils:bin\lib
99
file:directaccess:modules\directaccess
1010
file:directaccess-api:modules\directaccess
1111
file:cjupdate:bin\lib
12-
file:update-api:modules\update
13-
url:postgresql:https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.3/postgresql-42.7.3-sources.jar
14-
url:jsch:https://repo1.maven.org/maven2/com/github/mwiede/jsch/0.2.17/jsch-0.2.17-sources.jar
12+
file:update-api:modules\update

‎root/info.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<extension version="1">
22
<name>PostgreSQL_Connect</name>
33
<description>Periodically synchronizes operators, add-ons, and specified trends with an external PostgreSQL database.</description>
4-
<version>0.5.5</version>
4+
<version>0.5.6</version>
55
<vendor>Automatic Controls Equipment Systems, Inc.</vendor>
66
<system-menu-provider>aces.webctrl.postgresql.web.SystemMenuEditor</system-menu-provider>
77
</extension>

‎src/aces/webctrl/postgresql/core/CronExpression.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import java.util.*;
33
import java.time.*;
44
import org.springframework.scheduling.support.*;
5+
@SuppressWarnings("deprecation") // CronSequenceGenerator is deprecated
56
public class CronExpression {
67
private volatile String expr = null;
78
private volatile CronSequenceGenerator gen = null;

‎src/aces/webctrl/postgresql/core/HelperAPI.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -245,15 +245,17 @@ public static boolean downloadAddons(ArrayList<AddonDownload> whitelist){
245245
j = y.version==null?0:Utility.compareVersions(x.getVersion(),y.version);
246246
if (j==0 || y.keepNewer && j>0){
247247
whitelist.set(i,null);
248-
final WebApp.State s = x.getState();
249-
if (s!=WebApp.State.RUNNING && s!=WebApp.State.STARTING && s!=WebApp.State.STARTUP_ERROR){
250-
try{
251-
server.enableAddOn(x);
252-
}catch(Throwable t){
253-
Thread.sleep(timeout);
254-
server.deployAddOn(Initializer.addonsDir.resolve(x.getName()+".addon").toFile());
248+
if (!y.optional){
249+
final WebApp.State s = x.getState();
250+
if (s!=WebApp.State.RUNNING && s!=WebApp.State.STARTING && s!=WebApp.State.STARTUP_ERROR){
251+
try{
252+
server.enableAddOn(x);
253+
}catch(Throwable t){
254+
Thread.sleep(timeout);
255+
server.deployAddOn(Initializer.addonsDir.resolve(x.getName()+".addon").toFile());
256+
}
257+
Initializer.log("Enabled "+y.displayName+" v"+x.getVersion());
255258
}
256-
Initializer.log("Enabled "+y.displayName+" v"+x.getVersion());
257259
}
258260
}else{
259261
y.addon = x;

‎src/aces/webctrl/postgresql/core/OperatorData.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package aces.webctrl.postgresql.core;
22
import com.controlj.green.common.CJDataValueException;
33
import com.controlj.green.core.data.*;
4-
public class OperatorData {
4+
public class OperatorData implements Comparable<OperatorData> {
55
public volatile String username;
66
public volatile String display_name;
77
public volatile String password;
@@ -15,6 +15,9 @@ public OperatorData(CoreNode operator, String username) throws CoreNotFoundExcep
1515
this.username = username;
1616
read(operator,false);
1717
}
18+
@Override public int compareTo(OperatorData d){
19+
return username.compareTo(d.username);
20+
}
1821
public void read(CoreNode op) throws CoreNotFoundException {
1922
read(op,true);
2023
}
@@ -28,14 +31,16 @@ public void read(CoreNode op, boolean readUsername) throws CoreNotFoundException
2831
lvl5_auto_collapse = pref.getChild("lvl5_auto_collapse").getBooleanAttribute(CoreNode.VALUE);
2932
lvl5_auto_logout = pref.getChild("lvl5_auto_logout").getIntAttribute(CoreNode.VALUE);
3033
}
31-
public void write(OperatorLink link, CoreNode op) throws CoreNotFoundException, CoreDatabaseException, CJDataValueException {
34+
public void write(OperatorLink link, CoreNode op, boolean admin) throws CoreNotFoundException, CoreDatabaseException, CJDataValueException {
3235
op.setAttribute(CoreNode.KEY, username);
3336
op.setAttribute(NodeAttribute.lookup(CoreNode.DISPLAY_NAME, "en", true), display_name);
3437
link.setRawPassword(op, password, false);
3538
final CoreNode pref = op.getChild("preferences");
3639
pref.getChild("lvl5_auto_collapse").setBooleanAttribute(CoreNode.VALUE, lvl5_auto_collapse);
3740
pref.getChild("lvl5_auto_logout").setIntAttribute(CoreNode.VALUE, lvl5_auto_logout);
38-
link.assignAdminRole(op);
41+
if (admin){
42+
link.assignAdminRole(op);
43+
}
3944
}
4045
@Override public boolean equals(Object obj){
4146
if (this==obj){

‎src/aces/webctrl/postgresql/core/Sync.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ public void execute(SystemAccess sys){
407407
deletedOps.add(opname);
408408
Initializer.log("Deleted blacklisted operator: "+opname);
409409
}else if ((data = whitelist.get(opname))!=null){
410-
data.write(link, op);
410+
data.write(link, op, true);
411411
whitelist.remove(opname);
412412
}
413413
}

‎src/aces/webctrl/postgresql/resources/LocalOperatorsPage.html

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,70 @@
1010
Local Operators
1111
</title>
1212
<link rel="stylesheet" type="text/css" href="../../../../../root/webapp/main.css"/>
13+
<script>
14+
function prepareExport() {
15+
if (exportButton.getAttribute("href").length===1) {
16+
const ops = [];
17+
for (const r of data){
18+
ops.push({
19+
"username":r[0],
20+
"display_name":r[1],
21+
"password":r[2],
22+
"session_timeout":Number(r[3]),
23+
"auto_collapse":Boolean(r[4])
24+
});
25+
}
26+
exportButton.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(JSON.stringify(ops, undefined, 2)));
27+
}
28+
}
29+
function uploadOperators(){
30+
if (!submittingFile && fileField.value.length>0){
31+
if (fileField.files[0].size>1048576){
32+
fileField.value = null;
33+
alert("Selected file size has exceeded the 1MB limit.");
34+
return;
35+
}
36+
submittingFile = true;
37+
const formData = new FormData();
38+
formData.append("file",fileField.files[0]);
39+
fileField.value = null;
40+
const req = new XMLHttpRequest();
41+
req.open("POST","__PREFIX__/LocalOperators?cmd=import");
42+
req.onreadystatechange = function(){
43+
if (this.readyState===4){
44+
if (this.status===200){
45+
location.reload();
46+
}else if (this.status==0){
47+
alert("Request timed out.");
48+
}else{
49+
alert("An error has occurred: "+this.status);
50+
}
51+
submittingFile = false;
52+
}
53+
};
54+
req.send(formData);
55+
}
56+
}
57+
</script>
1358
</head>
1459
<body>
1560
<div style="text-align:center">
1661
<h1 id="mainTitle">Local Operators</h1>
1762
<br>
18-
<table>
19-
<thead><tr>
20-
<th>Username</th>
21-
<th>Display Name</th>
22-
<th>Password</th>
23-
<th>Session Timeout (seconds)</th>
24-
<th>Auto-Collapse Trees</th>
25-
</tr></thead>
26-
<tbody id="tableBody"></tbody>
27-
</table>
63+
<table>
64+
<thead><tr>
65+
<th>Username</th>
66+
<th>Display Name</th>
67+
<th>Password</th>
68+
<th>Session Timeout (seconds)</th>
69+
<th>Auto-Collapse Trees</th>
70+
</tr></thead>
71+
<tbody id="tableBody"></tbody>
72+
</table>
73+
<br>
74+
<a class="e" id="exportButton" href="#" download="operators.json" onclick="prepareExport()">Export</a>
75+
<button id="importButton" class="e" onclick="fileField.click()">Import</button>
76+
<input type="file" id="fileField" accept=".json" style="display:none" oninput="uploadOperators();">
2877
<br><br>
2978
<a class="e nav" href="__PREFIX__/TableEditor?table=servers">Server List</a>
3079
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_whitelist">Operator Whitelist</a>
@@ -41,6 +90,7 @@ <h1 id="mainTitle">Local Operators</h1>
4190
<a class="e nav" href="__DOCUMENTATION__" target="_blank">Documentation</a>
4291
</div>
4392
<script>
93+
var submittingFile = false;
4494
const data = __OPERATORS__;
4595
const body = document.getElementById("tableBody");
4696
for (const r of data){

‎src/aces/webctrl/postgresql/resources/Setup.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ CREATE TABLE webctrl.settings (
317317
-- Populate default values for webctrl.settings
318318
INSERT INTO webctrl.settings VALUES
319319
-- Version of PostgreSQL connector addon
320-
('version','0.5.5'),
320+
('version','0.5.6'),
321321
-- Whether debug mode is enabled (e.g, verbose log messages when true)
322322
('debug','false'),
323323
-- Whether to auto-update the PostgreSQL connector addon
Lines changed: 102 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,117 @@
11
package aces.webctrl.postgresql.web;
22
import aces.webctrl.postgresql.core.*;
3-
import javax.servlet.http.*;
43
import com.controlj.green.core.data.*;
4+
import javax.servlet.http.*;
5+
import org.json.*;
56
import java.util.*;
7+
import java.nio.charset.StandardCharsets;
8+
import javax.servlet.annotation.MultipartConfig;
9+
@MultipartConfig
610
public class LocalOperatorsPage extends ServletBase {
711
@Override public void exec(final HttpServletRequest req, final HttpServletResponse res) throws Throwable {
8-
if (!checkWhitelist(req)){
12+
final String reqUser = getUsername(req);
13+
if (!checkWhitelist(reqUser)){
914
res.sendError(403, "Insufficient permissions.");
1015
return;
1116
}
12-
final ArrayList<OperatorData> ops = new ArrayList<OperatorData>(64);
13-
try(
14-
OperatorLink link = new OperatorLink(true);
15-
){
16-
for (CoreNode op:link.getOperators()){
17-
if (!Sync.operatorWhitelist.containsKey(op.getAttribute(CoreNode.KEY).toLowerCase())){
18-
ops.add(new OperatorData(op));
17+
final String cmd = req.getParameter("cmd");
18+
if (cmd==null){
19+
final ArrayList<OperatorData> ops = new ArrayList<OperatorData>(64);
20+
try(
21+
OperatorLink link = new OperatorLink(true);
22+
){
23+
for (CoreNode op:link.getOperators()){
24+
if (!Sync.operatorWhitelist.containsKey(op.getAttribute(CoreNode.KEY).toLowerCase())){
25+
ops.add(new OperatorData(op));
26+
}
1927
}
28+
}catch(Throwable t){
29+
Initializer.log(t);
30+
res.sendError(500, "An error occurred while retrieving local operators.");
31+
return;
2032
}
21-
}catch(Throwable t){
22-
Initializer.log(t);
23-
res.sendError(500, "An error occurred while retrieving local operators.");
24-
return;
25-
}
26-
final StringBuilder sb = new StringBuilder(2048);
27-
sb.append("[\n");
28-
boolean first = true;
29-
for (OperatorData op:ops){
30-
if (first){
31-
first = false;
32-
}else{
33-
sb.append(",\n");
33+
ops.sort(null);
34+
final StringBuilder sb = new StringBuilder(2048);
35+
sb.append("[\n");
36+
boolean first = true;
37+
for (OperatorData op:ops){
38+
if (first){
39+
first = false;
40+
}else{
41+
sb.append(",\n");
42+
}
43+
sb.append('[');
44+
sb.append('"').append(Utility.escapeJSON(op.username)).append("\",");
45+
sb.append('"').append(Utility.escapeJSON(op.display_name)).append("\",");
46+
sb.append('"').append(Utility.escapeJSON(op.password)).append("\",");
47+
sb.append('"').append(op.lvl5_auto_logout).append("\",");
48+
sb.append('"').append(op.lvl5_auto_collapse).append('"');
49+
sb.append(']');
50+
}
51+
sb.append("\n]");
52+
res.setContentType("text/html");
53+
res.getWriter().print(getHTML(req)
54+
.replace("__OPERATORS__", sb.toString())
55+
);
56+
}else if (cmd.equals("import")){
57+
String json;
58+
{
59+
final Part filePart = req.getPart("file");
60+
if (filePart==null || filePart.getSize()>1048576){
61+
res.setStatus(400);
62+
return;
63+
}
64+
json = new String(Utility.readAllBytes(filePart.getInputStream()), StandardCharsets.UTF_8);
65+
}
66+
final HashMap<String,OperatorData> ops = new HashMap<>(64);
67+
try{
68+
OperatorData op;
69+
final JSONArray arr = new JSONArray(json);
70+
JSONObject jo;
71+
for (Object o: arr){
72+
if (o instanceof JSONObject){
73+
jo = (JSONObject)o;
74+
op = new OperatorData();
75+
op.username = jo.getString("username").toLowerCase();
76+
if (!Sync.operatorWhitelist.containsKey(op.username)){
77+
op.display_name = jo.getString("display_name");
78+
op.password = jo.getString("password");
79+
op.lvl5_auto_logout = jo.getInt("session_timeout");
80+
op.lvl5_auto_collapse = jo.getBoolean("auto_collapse");
81+
ops.put(op.username,op);
82+
}
83+
}
84+
}
85+
}catch(JSONException|NumberFormatException e){
86+
res.setStatus(400);
87+
return;
88+
}
89+
if (!ops.isEmpty()){
90+
try(
91+
OperatorLink link = new OperatorLink(false);
92+
){
93+
OperatorData data;
94+
String opname;
95+
for (CoreNode op:link.getOperators()){
96+
opname = op.getAttribute(CoreNode.KEY).toLowerCase();
97+
if ((data = ops.remove(opname))!=null){
98+
data.write(link, op, false);
99+
Initializer.log(reqUser+" imported operator: "+opname);
100+
}
101+
}
102+
CoreNode op, pref;
103+
for (OperatorData d:ops.values()){
104+
op = link.createOperator(d.username, d.display_name, d.password, true);
105+
pref = op.getChild("preferences");
106+
pref.getChild("lvl5_auto_collapse").setBooleanAttribute(CoreNode.VALUE, d.lvl5_auto_collapse);
107+
pref.getChild("lvl5_auto_logout").setIntAttribute(CoreNode.VALUE, d.lvl5_auto_logout);
108+
Initializer.log(reqUser+" imported new operator: "+d.username);
109+
}
110+
link.commit();
111+
}
34112
}
35-
sb.append('[');
36-
sb.append('"').append(Utility.escapeJSON(op.username)).append("\",");
37-
sb.append('"').append(Utility.escapeJSON(op.display_name)).append("\",");
38-
sb.append('"').append(Utility.escapeJSON(op.password)).append("\",");
39-
sb.append('"').append(op.lvl5_auto_logout).append("\",");
40-
sb.append('"').append(op.lvl5_auto_collapse).append('"');
41-
sb.append(']');
113+
}else{
114+
res.setStatus(400);
42115
}
43-
sb.append("\n]");
44-
res.setContentType("text/html");
45-
res.getWriter().print(getHTML(req)
46-
.replace("__OPERATORS__", sb.toString())
47-
);
48116
}
49117
}

0 commit comments

Comments
 (0)
Please sign in to comment.