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 e087483

Browse files
committedDec 3, 2024
v0.5.8 update
updated README bumped jsch and postgresql dependency versions build script override to generate two addons, one with a preset configuration and one without do not verify PostgreSQL host when connecting to localhost or 127.0.0.1 dynamically set version in Setup.sql improved error handling during archive resource extraction decorative improvements to front-end HTML and CSS more verbose logging when in debug mode sync only the latest cumulative update
1 parent 45b0199 commit e087483

30 files changed

+661
-220
lines changed
 

‎README.md

Lines changed: 329 additions & 2 deletions
Large diffs are not rendered by default.

‎config/BUILD_DETAILS

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ update-api-9.0.002
2828
webserver-api-9.0.002
2929

3030
Packaged Dependencies:
31-
jsch-0.2.17-sources
32-
jsch-0.2.17
31+
jsch-0.2.21-sources
32+
jsch-0.2.21
3333
json-20240303-sources
3434
json-20240303
35-
postgresql-42.7.3-sources
36-
postgresql-42.7.3
35+
postgresql-42.7.4-sources
36+
postgresql-42.7.4

‎config/EXTERNAL_DEPS

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
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
1+
url:postgresql-42.7.4.jar:https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.4/postgresql-42.7.4.jar
2+
url:postgresql-42.7.4-sources.jar:https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.4/postgresql-42.7.4-sources.jar
3+
url:jsch-0.2.21.jar:https://repo1.maven.org/maven2/com/github/mwiede/jsch/0.2.21/jsch-0.2.21.jar
4+
url:jsch-0.2.21-sources.jar:https://repo1.maven.org/maven2/com/github/mwiede/jsch/0.2.21/jsch-0.2.21-sources.jar
55
url:json-20240303.jar:https://repo1.maven.org/maven2/org/json/json/20240303/json-20240303.jar
66
url:json-20240303-sources.jar:https://repo1.maven.org/maven2/org/json/json/20240303/json-20240303-sources.jar

‎ext/pack.bat

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
if /i "%*" EQU "--help" (
2+
echo PACK Packages all relevant files into newly created .addon and .jar archives.
3+
exit /b 0
4+
)
5+
if "%*" NEQ "" (
6+
echo Unexpected parameter.
7+
exit /b 1
8+
)
9+
echo Packing...
10+
rmdir /Q /S "%classes%" >nul 2>nul
11+
for /D %%i in ("%trackingClasses%\*") do robocopy /E "%%~fi" "%classes%" >nul 2>nul
12+
robocopy /E "%src%" "%classes%" /XF "*.java" >nul 2>nul
13+
copy /Y "%workspace%\LICENSE" "%root%\LICENSE" >nul 2>nul
14+
robocopy /MIR /MOVE "%lib%" "%workspace%\lib-sources" *-sources.jar >nul 2>nul
15+
"%JDKBin%\jar.exe" -c -M -f "%addonFile%" -C "%root%" .
16+
if %ERRORLEVEL% NEQ 0 (
17+
robocopy /E /MOVE "%workspace%\lib-sources" "%lib%" >nul 2>nul
18+
rmdir /Q /S "%workspace%\lib-sources" >nul 2>nul
19+
echo Packing unsuccessful.
20+
exit /b 1
21+
)
22+
del /F "%classes%\aces\webctrl\postgresql\resources\config.dat" >nul 2>nul
23+
del /F "%classes%\aces\webctrl\postgresql\resources\pgsslkey.pfx" >nul 2>nul
24+
del /F "%classes%\aces\webctrl\postgresql\resources\pgsslroot.cer" >nul 2>nul
25+
"%JDKBin%\jar.exe" -c -M -f "%workspace%\!name!-blank.addon" -C "%root%" .
26+
if %ERRORLEVEL% EQU 0 (
27+
robocopy /E /MOVE "%workspace%\lib-sources" "%lib%" >nul 2>nul
28+
rmdir /Q /S "%workspace%\lib-sources" >nul 2>nul
29+
echo Packing successful.
30+
exit /b 0
31+
) else (
32+
robocopy /E /MOVE "%workspace%\lib-sources" "%lib%" >nul 2>nul
33+
rmdir /Q /S "%workspace%\lib-sources" >nul 2>nul
34+
echo Packing unsuccessful.
35+
exit /b 1
36+
)

‎ext/sign.bat

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
if /i "%*" EQU "--help" (
2+
echo SIGN Signs the .addon archive.
3+
exit /b 0
4+
)
5+
if "%*" NEQ "" (
6+
echo Unexpected parameter.
7+
exit /b 1
8+
)
9+
if exist "%addonFile%" (
10+
echo Signing...
11+
"%JDKBin%\jarsigner.exe" -keystore "%keystore%" -storepass "!pass!" "%addonFile%" %alias% >nul
12+
if !ERRORLEVEL! EQU 0 (
13+
"%JDKBin%\jarsigner.exe" -keystore "%keystore%" -storepass "!pass!" "%workspace%\!name!-blank.addon" %alias% >nul
14+
if !ERRORLEVEL! EQU 0 (
15+
echo Signing successful.
16+
exit /b 0
17+
) else (
18+
echo Signing unsuccessful.
19+
exit /b 1
20+
)
21+
) else (
22+
echo Signing unsuccessful.
23+
exit /b 1
24+
)
25+
) else (
26+
echo Cannot sign because !name!.addon does not exist.
27+
exit /b 1
28+
)

‎resources/download_sql.png

5.83 KB
Loading

‎resources/postgresql_config.png

21.1 KB
Loading

‎resources/renew.sh

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/bin/bash
2+
3+
# Crontab example:
4+
# 47 23 1 * * /bin/bash /data/ssl/renew.sh
5+
6+
# Decsriptive name for this server
7+
name='PostgreSQL Database Server'
8+
# Keystore password
9+
password='PASSWORD'
10+
# Recipient email addresses for notifications (comma-delimited)
11+
recipients='cvogt@automaticcontrols.net,cvogt729@gmail.com'
12+
# DNS name for your SSL certificate
13+
dns='postgresql.domain.com'
14+
# Distinguished name for your SSL certificate
15+
dname="CN=$dns, OU=IT, O=Automatic Controls Equipment Systems\, Inc., L=Fenton, ST=MO, C=US"
16+
# Working directory
17+
folder='/data/ssl/certbot'
18+
# Final server certificate
19+
pem_cert='/data/ssl/ssl_cert'
20+
# Final server private key
21+
pem_key='/data/ssl/ssl_key'
22+
23+
# Function to send an email
24+
function send_email(){
25+
msmtp -t <<EOF
26+
To: $recipients
27+
Subject: $1
28+
29+
$2
30+
EOF
31+
}
32+
33+
# Create working directory
34+
sudo rm -Rf "$folder"
35+
sudo mkdir "$folder"
36+
if ! cd "$folder"; then
37+
send_email "$name SSL Renewal Failure" 'Monthly certificate renewal script failed to locate SSL directory.'
38+
exit 1
39+
fi
40+
41+
# Generate a new key
42+
if ! sudo keytool -keystore store -storepass "$password" -genkeypair -alias server -keyalg RSA -sigalg SHA256withRSA -keysize 2048 -keypass "$password" -validity 365 -ext "san=dns:$dns" -dname "$dname"; then
43+
send_email "$name SSL Renewal Failure" 'Monthly certificate renewal script failed to create a new 2048 bit RSA key-pair.'
44+
exit 1
45+
fi
46+
47+
# Generate a certificate request
48+
if ! sudo keytool -keystore store -storepass "$password" -alias server -certreq -file 'request.csr'; then
49+
send_email "$name SSL Renewal Failure" 'Monthly certificate renewal script failed to generate CSR.'
50+
exit 1
51+
fi
52+
53+
# Open HTTP and HTTPS ports
54+
sudo ufw allow 80/tcp
55+
sudo ufw allow 443/tcp
56+
57+
# Use certbot to sign the certificate request
58+
sudo certbot certonly --standalone --csr "$folder/request.csr" --logs-dir "$folder/logs"
59+
err="$?"
60+
61+
# Close HTTP and HTTPS ports
62+
sudo ufw delete allow 80/tcp
63+
sudo ufw delete allow 443/tcp
64+
65+
# Handle certbot failure
66+
if [[ "$err" != '0' ]]; then
67+
sudo rm -f 'request.csr'
68+
sudo rm -f ./*.pem
69+
send_email "$name SSL Renewal Failure" "Monthly certificate renewal script failed: certbot encountered error. Please see '$folder/logs' for more details."
70+
exit 1
71+
fi
72+
73+
# Apply changes
74+
sudo mv -f "$(find "/data/ssl/certbot" -maxdepth 1 -name '*_chain.pem' | sort -n | tail -n 1)" "$pem_cert"
75+
sudo openssl pkcs12 -in store -passin "pass:$password" -nocerts -noenc | sudo openssl rsa -out "$pem_key"
76+
sudo chown postgres:postgres "$pem_key"
77+
sudo chown postgres:postgres "$pem_cert"
78+
sudo chmod 600 "$pem_key"
79+
sudo chmod 666 "$pem_cert"
80+
sudo systemctl reload postgresql
81+
82+
# Clean files
83+
cd ..
84+
sudo rm -Rf "$folder"

‎resources/sftp_config.png

25.3 KB
Loading

‎resources/test_sftp.png

5.51 KB
Loading

‎resources/trend_browser.png

43.4 KB
Loading

‎resources/upload_client_key.png

5.7 KB
Loading

‎resources/upload_root_cert.png

5 KB
Loading

‎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.6</version>
4+
<version>0.5.8</version>
55
<vendor>Automatic Controls Equipment Systems, Inc.</vendor>
66
<system-menu-provider>aces.webctrl.postgresql.web.SystemMenuEditor</system-menu-provider>
77
</extension>

‎root/webapp/main.css

Lines changed: 9 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ body, input, textarea, select {
1111
.c {
1212
text-align:center;
1313
}
14-
.checker {
15-
margin-right:0.5em;
16-
}
1714
.column {
1815
float:left;
1916
width:50%;
@@ -48,20 +45,6 @@ button:disabled {
4845
color:forestgreen;
4946
cursor:default;
5047
}
51-
.buttonCopy {
52-
border:1px solid white;
53-
border-radius: 8px;
54-
padding-left:6px;
55-
padding-right:6px;
56-
padding-top:1px;
57-
padding-bottom:1px;
58-
color:lightgreen;
59-
cursor:pointer;
60-
user-select: none;
61-
}
62-
.buttonCopy:hover {
63-
color:darkgoldenrod;
64-
}
6548
a {
6649
border:1px solid white;
6750
border-radius: 8px;
@@ -87,7 +70,7 @@ a:active,a.nav:active {
8770
}
8871
td, th {
8972
padding:4px;
90-
border:solid 1px white;
73+
border:solid 1px gray;
9174
}
9275
tr:nth-child(odd) {
9376
background-color:#222222;
@@ -102,58 +85,8 @@ table {
10285
border-collapse:collapse;
10386
margin:0 auto;
10487
}
105-
thead {
106-
border:solid 3px white;
107-
}
108-
tbody {
109-
border:solid 3px darkgoldenrod;
110-
}
111-
tfoot {
112-
border:solid 3px darkmagenta;
113-
}
114-
.tagYes {
115-
border-style:hidden;
116-
border-radius: 8px;
117-
display:inline-block;
118-
padding-left:6px;
119-
padding-right:6px;
120-
font-style:italic;
121-
margin:2px;
122-
background-color:green;
123-
}
124-
.tagNo {
125-
border-style:hidden;
126-
border-radius: 8px;
127-
display:inline-block;
128-
padding-left:6px;
129-
padding-right:6px;
130-
font-style:italic;
131-
margin:2px;
132-
background-color:darkred;
133-
}
134-
.tag {
135-
border-style:hidden;
136-
border-radius: 8px;
137-
display:inline-block;
138-
padding-left:6px;
139-
padding-right:6px;
140-
font-style:italic;
141-
margin:2px;
142-
user-select: none;
143-
}
144-
.popupSection {
145-
border:2px solid hotpink;
146-
border-radius: 2em;
147-
}
148-
.tagBox {
149-
border:2px solid dodgerblue;
150-
display:inline-block;
151-
padding-left:6px;
152-
padding-right:6px;
153-
margin:2px;
154-
margin-left:0.5em;
155-
background-color:midnightblue;
156-
font-style:normal;
88+
thead,tbody,tfoot {
89+
border:solid 3px gray;
15790
}
15891
.divGrouping {
15992
display:inline-block;
@@ -162,20 +95,12 @@ tfoot {
16295
margin-top:5px;
16396
margin-bottom:5px;
16497
}
165-
.triangle {
166-
width:0;
167-
height:0;
168-
margin-right:-0.5em;
169-
border-width:0.5em;
170-
border-style:solid;
171-
border-color:transparent transparent transparent gold;
172-
}
173-
.bar {
174-
position:absolute;
98+
.stickyBar {
99+
position:sticky;
175100
top:0;
176-
left:0;
177101
width:100%;
178-
height:1em;
179-
border:1px solid white;
180-
background-color:darkgray;
102+
background-color:black;
103+
padding-top:0.75em;
104+
border-bottom:1px solid gray;
105+
border-top:1px solid gray;
181106
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public static void reset(){
3232
Sync.versionCompatible = false;
3333
Sync.started = false;
3434
}
35+
Initializer.log("Server ID has been reset.");
3536
}
3637
public static void init(Path file){
3738
Config.file = file;
@@ -108,6 +109,9 @@ public static boolean save(){
108109
}
109110
}
110111
}
112+
if (Initializer.debug()){
113+
Initializer.log("Data file saved.");
114+
}
111115
return true;
112116
}catch(Throwable t){
113117
Initializer.log(t);

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ public boolean overwriteFile(InputStream src, String dst){
7272
}
7373
@Override public void end(){}
7474
}, ChannelSftp.OVERWRITE);
75+
if (!Initializer.stop && Initializer.debug()){
76+
Initializer.log("Uploaded file: "+dst);
77+
}
7578
return !Initializer.stop;
7679
}catch(Throwable t){
7780
Initializer.log(t);
@@ -108,6 +111,9 @@ public boolean retrieveFile(String path, OutputStream out){
108111
}
109112
@Override public void end(){}
110113
});
114+
if (!Initializer.stop && Initializer.debug()){
115+
Initializer.log("Downloaded file: "+path);
116+
}
111117
return !Initializer.stop;
112118
}catch(Throwable t){
113119
Initializer.log(t);

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,7 @@ public static boolean selfUpdate(){
345345
Thread.sleep(timeout);
346346
Files.move(Initializer.tmpAddonFile, Initializer.addonsDir.resolve(Initializer.getName()+".update"), StandardCopyOption.REPLACE_EXISTING);
347347
final Path addon = Initializer.addonsDir.resolve(Initializer.AUTO_UPDATE_ADDON+".addon");
348-
Utility.extractResource("aces/webctrl/postgresql/resources/"+Initializer.AUTO_UPDATE_ADDON+".addon", addon);
349-
if (!Files.exists(addon)){
348+
if (!Utility.extractResource("aces/webctrl/postgresql/resources/"+Initializer.AUTO_UPDATE_ADDON+".addon", addon) || !Files.exists(addon)){
350349
return false;
351350
}
352351
Thread.sleep(timeout);

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

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
import com.controlj.green.update.*;
1313
import com.controlj.green.update.entries.*;
1414
public class Initializer implements ServletContextListener {
15-
public final static boolean EMBEDDED_CONNECTION = true;
15+
/** Leave this on when you want to have a preset configuration built-in to the add-on. */
16+
private final static boolean EMBEDDED_CONNECTION = true;
1617
/** Name of the addon used for auto udpates */
1718
public final static String AUTO_UPDATE_ADDON = "AutoUpdater";
1819
/** The version of this addon */
@@ -43,7 +44,7 @@ public class Initializer implements ServletContextListener {
4344
public volatile static String simpleVersion = null;
4445
/** Contains the product.name of this WebCTRL server */
4546
public volatile static String productName = null;
46-
/** Contains a list of applied cumulative updates */
47+
/** Contains an identifier for the latest applied cumulative update */
4748
public volatile static String cumUpdates = null;
4849
/** Logger for this addon */
4950
private volatile static FileLogger logger;
@@ -99,29 +100,32 @@ public class Initializer implements ServletContextListener {
99100
}
100101
}
101102
{
102-
final StringBuilder sb = new StringBuilder(64);
103+
int x = -1;
103104
try{
104-
boolean first = true;
105105
String s;
106+
int y;
106107
final UpdateManager mgr = UpdateManagerFactory.getSingletonInstance();
107108
if (mgr.haveAnyUpdatesBeenApplied()){
108109
final Pattern p = Pattern.compile("(?:-\\d++_)?+WS\\d++(\\.\\d++)++$", Pattern.CASE_INSENSITIVE);
110+
final Pattern p2 = Pattern.compile("\\D");
109111
for (UpdateInfo info: mgr.getUpdateInfo().getSortedUpdateInfoOfType(UpdateType.Patch)){
110112
s = info.getFileName();
111-
if (s.endsWith("umulative.update")){
112-
if (first){
113-
first = false;
114-
}else{
115-
sb.append(", ");
116-
}
117-
sb.append(p.matcher(s.replace("_Cumulative.update", "")).replaceAll(""));
113+
if (s.endsWith("_Cumulative.update")){
114+
s = p.matcher(s.replace("_Cumulative.update", "")).replaceAll("");
115+
s = p2.matcher(s).replaceAll("");
116+
try{
117+
y = Integer.parseInt(s);
118+
if (y>x){
119+
x = y;
120+
}
121+
}catch(NumberFormatException e){}
118122
}
119123
}
120124
}
121125
}catch(Throwable t){
122126
log(t);
123127
}
124-
cumUpdates = sb.toString();
128+
cumUpdates = x==-1?"":String.valueOf(x);
125129
}
126130
Config.init(root.resolve("config.dat"));
127131
pgsslroot = root.resolve("pgsslroot.cer");
@@ -244,6 +248,12 @@ public void run(){
244248
}
245249
}
246250
}
251+
/**
252+
* @return whether debug mode is enabled.
253+
*/
254+
public static boolean debug(){
255+
return "true".equalsIgnoreCase(Sync.settings.get("debug"));
256+
}
247257
/**
248258
* Tells the processing thread to invoke a synchronization event ASAP.
249259
*/

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

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package aces.webctrl.postgresql.core;
2+
import aces.webctrl.postgresql.web.*;
23
import com.controlj.green.core.data.*;
3-
4-
import aces.webctrl.postgresql.web.DownloadLicensePage;
5-
64
import com.controlj.green.addonsupport.access.*;
75
import com.controlj.green.addonsupport.access.trend.*;
86
import com.controlj.green.addonsupport.access.aspect.*;
@@ -40,8 +38,9 @@ public Sync(Event event, String... args){
4038
synchronized (Sync.class){
4139
if (Initializer.stop && event!=Event.SHUTDOWN){ return; }
4240
try{
43-
boolean debug = "true".equalsIgnoreCase(settings.get("debug"));
44-
final String url = "jdbc:postgresql://"+Config.connectionURL;
41+
boolean debug = Initializer.debug();
42+
final String connUrl = Config.connectionURL;
43+
final String url = "jdbc:postgresql://"+connUrl;
4544
final String username = Config.username;
4645
final String password = Config.password;
4746
if (url.length()<=18){
@@ -50,7 +49,7 @@ public Sync(Event event, String... args){
5049
final Properties connectionParams = new Properties();
5150
connectionParams.setProperty("user", username);
5251
connectionParams.setProperty("password", password);
53-
connectionParams.setProperty("sslmode", "verify-full");
52+
connectionParams.setProperty("sslmode", connUrl.startsWith("localhost") || connUrl.startsWith("127.0.0.1")?"require":"verify-full");
5453
connectionParams.setProperty("sslkey", Initializer.pgsslkey.toString());
5554
connectionParams.setProperty("sslpassword", Config.keystorePassword);
5655
connectionParams.setProperty("sslrootcert", Initializer.pgsslroot.toString());
@@ -265,7 +264,7 @@ public void execute(SystemAccess sys){
265264
}
266265
con.commit();
267266
settings = map;
268-
final boolean d = "true".equalsIgnoreCase(map.get("debug"));
267+
final boolean d = Initializer.debug();
269268
if (d^debug){
270269
debug = d;
271270
Initializer.log("Debug mode "+(d?"en":"dis")+"abled.");

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public static void init(){
3131
"\"cum_updates\", \"notes\" FROM webctrl.servers ORDER BY STRING_TO_ARRAY(REGEXP_REPLACE(REPLACE(\"version\",'-','.'),'[^\\d\\.]','','g'), '.')::int[] DESC, \"name\" ASC;";
3232
x.conversion = basic;
3333
x.header = Utility.format(
34-
"[\"ID\",\"Name\",\"WebCTRL Version\",\"Add-On Version\",\"IP Address\",\"Last Sync\",\"License\",\"Cumulative Updates\",\"Notes\"],[\"Internal ID which uniquely identifies the server.\",\"User-friendly display name for the server.\",\"Full version string for the WebCTRL server.\",\"Installed version of the PostgreSQL_Connect add-on.\",\"External IP address of the server as viewed by the PostgreSQL database.\",\"Timestamp of the last successful synchronization. If synced within the last 24 hours, the background color is green.\",\"Click to download the WebCTRL license.\",\"List of applied cumulative updates.\",\"Notes pertaining to this server.\"],[\"$0\",\"$1\",\"$2\",\"$3\",\"$4\",\"$5\",\"$6\",\"$7\",\"\"]",
34+
"[\"ID\",\"Name\",\"WebCTRL Version\",\"Add-On Version\",\"IP Address\",\"Last Sync\",\"License\",\"Cumulative Update\",\"Notes\"],[\"Internal ID which uniquely identifies the server.\",\"User-friendly display name for the server.\",\"Full version string for the WebCTRL server.\",\"Installed version of the PostgreSQL_Connect add-on.\",\"External IP address of the server as viewed by the PostgreSQL database.\",\"Timestamp of the last successful synchronization. If synced within the last 24 hours, the background color is green.\",\"Click to download the WebCTRL license.\",\"Latest applied cumulative update.\",\"Notes pertaining to this server.\"],[\"$0\",\"$1\",\"$2\",\"$3\",\"$4\",\"$5\",\"$6\",\"$7\",\"\"]",
3535
"<READONLY>",
3636
"^.+$",
3737
"<READONLY>",

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

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,26 @@ public static String replaceAll(String s, Pattern p, java.util.function.Function
4747
}
4848
/**
4949
* Writes all bytes from the specified resource to the output file.
50+
* @return {@code true} on success, {@code false} when the resource cannot be found.
5051
*/
51-
public static void extractResource(String name, Path out) throws Throwable {
52+
public static boolean extractResource(String name, Path out) throws Throwable {
5253
try(
5354
InputStream s = Utility.class.getClassLoader().getResourceAsStream(name);
54-
OutputStream t = Files.newOutputStream(out);
5555
){
56-
int read;
57-
byte[] buffer = new byte[8192];
58-
while ((read = s.read(buffer, 0, 8192)) >= 0) {
59-
t.write(buffer, 0, read);
56+
if (s==null){
57+
return false;
58+
}
59+
try(
60+
OutputStream t = Files.newOutputStream(out);
61+
){
62+
int read;
63+
byte[] buffer = new byte[8192];
64+
while ((read = s.read(buffer, 0, 8192)) >= 0) {
65+
t.write(buffer, 0, read);
66+
}
6067
}
6168
}
69+
return true;
6270
}
6371
/**
6472
* This method is provided for compatibility with older JRE versions.

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

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -155,28 +155,31 @@
155155
<body>
156156
<div style="text-align:center">
157157
<h1>Trend Browser</h1>
158-
<div class="divGrouping">
159-
<label>Status:</label>
160-
<span id="statusBox"></span>
158+
<div class="stickyBar">
159+
<a class="e nav" href="__PREFIX__/TableEditor?table=servers">Server List</a>
160+
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_whitelist">Operator Whitelist</a>
161+
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_blacklist">Operator Blacklist</a>
162+
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_blacklist_exceptions">Operator Blacklist Exceptions</a>
163+
<a class="e nav" href="__PREFIX__/TableEditor?table=addon_whitelist">Add-On Whitelist</a>
164+
<a class="e nav" href="__PREFIX__/TableEditor?table=addon_blacklist">Add-On Blacklist</a>
165+
<br><br>
166+
<a class="e nav" href="__PREFIX__/index">Connection Parameters</a>
167+
<a class="e nav" href="__PREFIX__/TableEditor?table=settings">Settings</a>
168+
<a class="e nav" href="__PREFIX__/TableEditor?table=trend_mappings">Trend Mappings</a>
169+
<a class="e nav" href="__PREFIX__/LocalOperators">View Local Operators</a>
170+
<a class="e nav" href="__PREFIX__/LogViewer">View Log</a>
171+
<a class="e nav" href="__DOCUMENTATION__" target="_blank">Documentation</a>
172+
<br><br>
173+
<button class="e" onclick="refresh()">Refresh</button>
174+
<br>
175+
<div class="divGrouping">
176+
<label>Status:</label>
177+
<span id="statusBox"></span>
178+
</div>
179+
<br>
161180
</div>
162181
<br>
163-
<button class="e" onclick="refresh()">Refresh</button>
164-
<br><br>
165182
<div id="mainDiv" style="display:inline-block;text-align:left;color:lightsteelblue"></div>
166-
<br><br><br>
167-
<a class="e nav" href="__PREFIX__/TableEditor?table=servers">Server List</a>
168-
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_whitelist">Operator Whitelist</a>
169-
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_blacklist">Operator Blacklist</a>
170-
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_blacklist_exceptions">Operator Blacklist Exceptions</a>
171-
<a class="e nav" href="__PREFIX__/TableEditor?table=addon_whitelist">Add-On Whitelist</a>
172-
<a class="e nav" href="__PREFIX__/TableEditor?table=addon_blacklist">Add-On Blacklist</a>
173-
<br><br>
174-
<a class="e nav" href="__PREFIX__/index">Connection Parameters</a>
175-
<a class="e nav" href="__PREFIX__/TableEditor?table=settings">Settings</a>
176-
<a class="e nav" href="__PREFIX__/TableEditor?table=trend_mappings">Trend Mappings</a>
177-
<a class="e nav" href="__PREFIX__/LocalOperators">View Local Operators</a>
178-
<a class="e nav" href="__PREFIX__/LogViewer">View Log</a>
179-
<a class="e nav" href="__DOCUMENTATION__" target="_blank">Documentation</a>
180183
</div>
181184
<script>
182185
var imgExpand = "/_common/lvl5/skin/graphics/tree/clean_expanded.png";

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

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -59,35 +59,37 @@
5959
<body>
6060
<div style="text-align:center">
6161
<h1 id="mainTitle">Local Operators</h1>
62+
<div class="stickyBar">
63+
<a class="e nav" href="__PREFIX__/TableEditor?table=servers">Server List</a>
64+
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_whitelist">Operator Whitelist</a>
65+
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_blacklist">Operator Blacklist</a>
66+
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_blacklist_exceptions">Operator Blacklist Exceptions</a>
67+
<a class="e nav" href="__PREFIX__/TableEditor?table=addon_whitelist">Add-On Whitelist</a>
68+
<a class="e nav" href="__PREFIX__/TableEditor?table=addon_blacklist">Add-On Blacklist</a>
69+
<br><br>
70+
<a class="e nav" href="__PREFIX__/index">Connection Parameters</a>
71+
<a class="e nav" href="__PREFIX__/TableEditor?table=settings">Settings</a>
72+
<a class="e nav" href="__PREFIX__/TableEditor?table=trend_mappings">Trend Mappings</a>
73+
<a class="e nav" href="__PREFIX__/FindTrends">Find Trends</a>
74+
<a class="e nav" href="__PREFIX__/LogViewer">View Log</a>
75+
<a class="e nav" href="__DOCUMENTATION__" target="_blank">Documentation</a>
76+
<br><br>
77+
<a class="e" id="exportButton" href="#" download="operators.json" onclick="prepareExport()">Export</a>
78+
<button id="importButton" class="e" onclick="fileField.click()">Import</button>
79+
<br><br>
80+
</div>
6281
<br>
6382
<table>
6483
<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>
84+
<th id="th1" title="Username to uniquely identify this user.">Username</th>
85+
<th id="th2" title="User-friendly display name.">Display Name</th>
86+
<th id="th3" title="A password hash for the user.">Password Hash</th>
87+
<th id="th4" title="Specifies how many seconds to wait before automatically logging this user out. 0 disables automatic logoff. -1 uses the system default.">Session Timeout</th>
88+
<th id="th5" title="This pertains to the geographic and network trees. If 'true', previously expanded nodes will collapse when you try to expand an unrelated node. If 'false', you can have as many nodes expanded at the same time as you like.">Auto-Collapse Trees</th>
7089
</tr></thead>
7190
<tbody id="tableBody"></tbody>
7291
</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>
7692
<input type="file" id="fileField" accept=".json" style="display:none" oninput="uploadOperators();">
77-
<br><br>
78-
<a class="e nav" href="__PREFIX__/TableEditor?table=servers">Server List</a>
79-
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_whitelist">Operator Whitelist</a>
80-
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_blacklist">Operator Blacklist</a>
81-
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_blacklist_exceptions">Operator Blacklist Exceptions</a>
82-
<a class="e nav" href="__PREFIX__/TableEditor?table=addon_whitelist">Add-On Whitelist</a>
83-
<a class="e nav" href="__PREFIX__/TableEditor?table=addon_blacklist">Add-On Blacklist</a>
84-
<br><br>
85-
<a class="e nav" href="__PREFIX__/index">Connection Parameters</a>
86-
<a class="e nav" href="__PREFIX__/TableEditor?table=settings">Settings</a>
87-
<a class="e nav" href="__PREFIX__/TableEditor?table=trend_mappings">Trend Mappings</a>
88-
<a class="e nav" href="__PREFIX__/FindTrends">Find Trends</a>
89-
<a class="e nav" href="__PREFIX__/LogViewer">View Log</a>
90-
<a class="e nav" href="__DOCUMENTATION__" target="_blank">Documentation</a>
9193
</div>
9294
<script>
9395
var submittingFile = false;
@@ -98,22 +100,27 @@ <h1 id="mainTitle">Local Operators</h1>
98100
const usernameTD = document.createElement("TD");
99101
usernameTD.className = "e c";
100102
usernameTD.innerText = r[0];
103+
usernameTD.title = th1.title;
101104
body.appendChild(usernameTD);
102105
const displayNameTD = document.createElement("TD");
103106
displayNameTD.className = "e c";
104107
displayNameTD.innerText = r[1];
108+
displayNameTD.title = th2.title;
105109
body.appendChild(displayNameTD);
106110
const passwordTD = document.createElement("TD");
107111
passwordTD.className = "e c";
108112
passwordTD.innerText = r[2];
113+
passwordTD.title = th3.title;
109114
body.appendChild(passwordTD);
110115
const sessionTD = document.createElement("TD");
111116
sessionTD.className = "e c";
112117
sessionTD.innerText = r[3];
118+
sessionTD.title = th4.title;
113119
body.appendChild(sessionTD);
114120
const collapseTD = document.createElement("TD");
115121
collapseTD.className = "e c";
116122
collapseTD.innerText = r[4];
123+
collapseTD.title = th5.title;
117124
body.appendChild(collapseTD);
118125
body.appendChild(tr);
119126
}

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

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,30 @@
1414
<body>
1515
<div style="text-align:center">
1616
<h1 id="mainTitle">Log Viewer</h1>
17+
<div class="stickyBar">
18+
<a class="e nav" href="__PREFIX__/TableEditor?table=servers">Server List</a>
19+
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_whitelist">Operator Whitelist</a>
20+
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_blacklist">Operator Blacklist</a>
21+
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_blacklist_exceptions">Operator Blacklist Exceptions</a>
22+
<a class="e nav" href="__PREFIX__/TableEditor?table=addon_whitelist">Add-On Whitelist</a>
23+
<a class="e nav" href="__PREFIX__/TableEditor?table=addon_blacklist">Add-On Blacklist</a>
24+
<br><br>
25+
<a class="e nav" href="__PREFIX__/index">Connection Parameters</a>
26+
<a class="e nav" href="__PREFIX__/TableEditor?table=settings">Settings</a>
27+
<a class="e nav" href="__PREFIX__/TableEditor?table=trend_mappings">Trend Mappings</a>
28+
<a class="e nav" href="__PREFIX__/FindTrends">Find Trends</a>
29+
<a class="e nav" href="__PREFIX__/LocalOperators">View Local Operators</a>
30+
<a class="e nav" href="__DOCUMENTATION__" target="_blank">Documentation</a>
31+
<br><br>
32+
</div>
1733
<br>
18-
<table>
19-
<thead><tr>
20-
<th>Timestamp</th>
21-
<th>Message</th>
22-
</tr></thead>
23-
<tbody id="tableBody"></tbody>
24-
</table>
25-
<br><br>
26-
<a class="e nav" href="__PREFIX__/TableEditor?table=servers">Server List</a>
27-
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_whitelist">Operator Whitelist</a>
28-
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_blacklist">Operator Blacklist</a>
29-
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_blacklist_exceptions">Operator Blacklist Exceptions</a>
30-
<a class="e nav" href="__PREFIX__/TableEditor?table=addon_whitelist">Add-On Whitelist</a>
31-
<a class="e nav" href="__PREFIX__/TableEditor?table=addon_blacklist">Add-On Blacklist</a>
32-
<br><br>
33-
<a class="e nav" href="__PREFIX__/index">Connection Parameters</a>
34-
<a class="e nav" href="__PREFIX__/TableEditor?table=settings">Settings</a>
35-
<a class="e nav" href="__PREFIX__/TableEditor?table=trend_mappings">Trend Mappings</a>
36-
<a class="e nav" href="__PREFIX__/FindTrends">Find Trends</a>
37-
<a class="e nav" href="__PREFIX__/LocalOperators">View Local Operators</a>
38-
<a class="e nav" href="__DOCUMENTATION__" target="_blank">Documentation</a>
34+
<table>
35+
<thead><tr>
36+
<th>Timestamp</th>
37+
<th>Message</th>
38+
</tr></thead>
39+
<tbody id="tableBody"></tbody>
40+
</table>
3941
</div>
4042
<script>
4143
const data = __LOGS__;

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
-- This script was tested on PostgreSQL 16.3
2+
-- This script was tested on PostgreSQL 17
33
-- The core function of this script is to create and setup the required WebCTRL tables in your database.
44

55
-- Schema to contain all relevant tables
@@ -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.6'),
320+
('version','__VERSION__'),
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

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

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -398,9 +398,9 @@
398398
tr.appendChild(td);
399399
}
400400
if (createRows){
401-
body.insertBefore(tr,createTR);
401+
body.insertBefore(tr,createTR.nextElementSibling);
402402
}else{
403-
body.appendChild(tr);
403+
body.prepend(tr);
404404
}
405405
for (const x of tr.getElementsByTagName("TEXTAREA")){
406406
resize(x);
@@ -419,7 +419,7 @@
419419
createTR.appendChild(createTD);
420420
body.appendChild(createTR);
421421
}
422-
for (var i=3;i<data.length;++i){
422+
for (var i=data.length-1;i>=3;--i){
423423
addRow(data[i]);
424424
}
425425
checkDuplicateKeys();
@@ -469,34 +469,37 @@
469469
<body>
470470
<div style="text-align:center">
471471
<h1 id="mainTitle"></h1>
472-
<div class="divGrouping">
473-
<label>Status:</label>
474-
<span id="statusBox"></span>
472+
<div class="stickyBar">
473+
<a class="e nav" href="__PREFIX__/TableEditor?table=servers">Server List</a>
474+
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_whitelist">Operator Whitelist</a>
475+
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_blacklist">Operator Blacklist</a>
476+
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_blacklist_exceptions">Operator Blacklist Exceptions</a>
477+
<a class="e nav" href="__PREFIX__/TableEditor?table=addon_whitelist">Add-On Whitelist</a>
478+
<a class="e nav" href="__PREFIX__/TableEditor?table=addon_blacklist">Add-On Blacklist</a>
479+
<br><br>
480+
<a class="e nav" href="__PREFIX__/index">Connection Parameters</a>
481+
<a class="e nav" href="__PREFIX__/TableEditor?table=settings">Settings</a>
482+
<a class="e nav" href="__PREFIX__/TableEditor?table=trend_mappings">Trend Mappings</a>
483+
<a class="e nav" href="__PREFIX__/FindTrends">Find Trends</a>
484+
<a class="e nav" href="__PREFIX__/LocalOperators">View Local Operators</a>
485+
<a class="e nav" href="__PREFIX__/LogViewer">View Log</a>
486+
<a class="e nav" href="__DOCUMENTATION__" target="_blank">Documentation</a>
487+
<br><br>
488+
<button class="e" id="saveButton" onclick="save()">Save Changes</button>
489+
<button class="e" id="discardButton" onclick="discard()">Discard Changes</button>
490+
<button class="e" id="refreshButton" onclick="refresh()">Refresh</button>
491+
<br>
492+
<div class="divGrouping">
493+
<label>Status:</label>
494+
<span id="statusBox"></span>
495+
</div>
496+
<br>
475497
</div>
476-
<br><br>
477-
<table>
478-
<thead><tr id="tableHeaderRow"></tr></thead>
479-
<tbody id="tableBody"></tbody>
480-
</table>
481498
<br>
482-
<button class="e" id="saveButton" onclick="save()">Save Changes</button>
483-
<button class="e" id="discardButton" onclick="discard()">Discard Changes</button>
484-
<button class="e" id="refreshButton" onclick="refresh()">Refresh</button>
485-
<br><br>
486-
<a class="e nav" href="__PREFIX__/TableEditor?table=servers">Server List</a>
487-
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_whitelist">Operator Whitelist</a>
488-
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_blacklist">Operator Blacklist</a>
489-
<a class="e nav" href="__PREFIX__/TableEditor?table=operator_blacklist_exceptions">Operator Blacklist Exceptions</a>
490-
<a class="e nav" href="__PREFIX__/TableEditor?table=addon_whitelist">Add-On Whitelist</a>
491-
<a class="e nav" href="__PREFIX__/TableEditor?table=addon_blacklist">Add-On Blacklist</a>
492-
<br><br>
493-
<a class="e nav" href="__PREFIX__/index">Connection Parameters</a>
494-
<a class="e nav" href="__PREFIX__/TableEditor?table=settings">Settings</a>
495-
<a class="e nav" href="__PREFIX__/TableEditor?table=trend_mappings">Trend Mappings</a>
496-
<a class="e nav" href="__PREFIX__/FindTrends">Find Trends</a>
497-
<a class="e nav" href="__PREFIX__/LocalOperators">View Local Operators</a>
498-
<a class="e nav" href="__PREFIX__/LogViewer">View Log</a>
499-
<a class="e nav" href="__DOCUMENTATION__" target="_blank">Documentation</a>
499+
<table>
500+
<thead><tr id="tableHeaderRow"></tr></thead>
501+
<tbody id="tableBody"></tbody>
502+
</table>
500503
<span id="hiddenSpan" style="min-width:3em;color:black;display:inline-block;position:absolute;left:-100000px;white-space:pre"></span>
501504
</div>
502505
<script>

‎src/aces/webctrl/postgresql/web/DownloadLicensePage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public class DownloadLicensePage extends ServletBase {
4848
}
4949
}
5050
}catch(Throwable t){
51-
if ("true".equalsIgnoreCase(Sync.settings.get("debug"))){
51+
if (Initializer.debug()){
5252
Initializer.log(t);
5353
}
5454
res.sendError(404, "An error has occurred. This could mean the license file does not exist, or the SFTP server is misconfigured.");

‎src/aces/webctrl/postgresql/web/FindTrendsPage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public void execute(SystemAccess sys){
6666
}
6767
}catch(Throwable t){
6868
arr.clear();
69-
if ("true".equalsIgnoreCase(Sync.settings.get("debug"))){
69+
if (Initializer.debug()){
7070
Initializer.log(t);
7171
}
7272
}

‎src/aces/webctrl/postgresql/web/MainPage.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public class MainPage extends ServletBase {
7777
break;
7878
}
7979
case "uploadCertificate": case "uploadKeystore":{
80-
final boolean debug = "true".equalsIgnoreCase(Sync.settings.get("debug"));
80+
final boolean debug = Initializer.debug();
8181
final Part filePart = req.getPart("file");
8282
if (filePart==null || filePart.getSize()>8388608){
8383
if (debug){
@@ -137,7 +137,7 @@ public class MainPage extends ServletBase {
137137
}
138138
final PrintWriter w = res.getWriter();
139139
if (err==null){
140-
w.println(s);
140+
w.println(s.replace("__VERSION__",Initializer.addonVersion));
141141
final StringBuilder sb = new StringBuilder(2048);
142142
try(
143143
OperatorLink link = new OperatorLink(true);

0 commit comments

Comments
 (0)
Please sign in to comment.