Skip to content

Commit d7960ad

Browse files
author
Till Brehm
committed
Merge branch '6840-improve-feedback-from-server-sh-process' into 'develop'
Resolve "Improve feedback from server.sh process" Closes #6840 See merge request ispconfig/ispconfig3!1997
2 parents aa7f775 + b40dd0d commit d7960ad

File tree

15 files changed

+672
-58
lines changed

15 files changed

+672
-58
lines changed

install/sql/incremental/upd_dev_collection.sql

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,18 @@ ALTER TABLE `client_template` ADD `limit_database_postgresql` INT NOT NULL DEFAU
55
ALTER TABLE `server_php` ADD `php_cli_binary` varchar(255) DEFAULT NULL AFTER `php_fpm_socket_dir`;
66
ALTER TABLE `server_php` ADD `php_jk_section` varchar(255) DEFAULT NULL AFTER `php_cli_binary`;
77
ALTER TABLE `mail_domain` ADD `local_delivery` enum('n','y') NOT NULL DEFAULT 'y' AFTER `active`;
8+
9+
CREATE TABLE IF NOT EXISTS `sys_message` (
10+
`message_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
11+
`sys_userid` int(11) unsigned NOT NULL DEFAULT 0,
12+
`sys_groupid` int(11) unsigned NOT NULL DEFAULT 0,
13+
`sys_perm_user` VARCHAR(5) DEFAULT 'r',
14+
`sys_perm_group` VARCHAR(5) DEFAULT 'r',
15+
`sys_perm_other` VARCHAR(5) DEFAULT '',
16+
`message_state` enum('info','warning','error') NOT NULL DEFAULT 'info',
17+
`message_date` datetime NULL DEFAULT NULL,
18+
`message_ack` enum('y','n') NOT NULL DEFAULT 'n',
19+
`relation` varchar(255) NULL DEFAULT NULL,
20+
`message` TEXT DEFAULT NULL,
21+
PRIMARY KEY (`message_id`)
22+
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

install/sql/ispconfig3.sql

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,6 +1771,27 @@ CREATE TABLE `sys_log` (
17711771

17721772
-- --------------------------------------------------------
17731773

1774+
--
1775+
-- Table structure for table `sys_message`
1776+
--
1777+
1778+
CREATE TABLE IF NOT EXISTS `sys_message` (
1779+
`message_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
1780+
`sys_userid` int(11) unsigned NOT NULL DEFAULT 0,
1781+
`sys_groupid` int(11) unsigned NOT NULL DEFAULT 0,
1782+
`sys_perm_user` VARCHAR(5) DEFAULT 'r',
1783+
`sys_perm_group` VARCHAR(5) DEFAULT 'r',
1784+
`sys_perm_other` VARCHAR(5) DEFAULT '',
1785+
`message_state` enum('info','warning','error') NOT NULL DEFAULT 'info',
1786+
`message_date` datetime NULL DEFAULT NULL,
1787+
`message_ack` enum('y','n') NOT NULL DEFAULT 'n',
1788+
`relation` varchar(255) NULL DEFAULT NULL,
1789+
`message` TEXT DEFAULT NULL,
1790+
PRIMARY KEY (`message_id`)
1791+
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
1792+
1793+
-- --------------------------------------------------------
1794+
17741795
--
17751796
-- Table structure for table `sys_remoteaction`
17761797
--
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
<?php
2+
3+
/*
4+
Copyright (c) 2025, Falko Timme, Timme Hosting GmbH & Co. KG
5+
All rights reserved.
6+
7+
Redistribution and use in source and binary forms, with or without modification,
8+
are permitted provided that the following conditions are met:
9+
10+
* Redistributions of source code must retain the above copyright notice,
11+
this list of conditions and the following disclaimer.
12+
* Redistributions in binary form must reproduce the above copyright notice,
13+
this list of conditions and the following disclaimer in the documentation
14+
and/or other materials provided with the distribution.
15+
* Neither the name of ISPConfig nor the names of its contributors
16+
may be used to endorse or promote products derived from this software without
17+
specific prior written permission.
18+
19+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22+
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24+
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26+
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
*/
30+
31+
/*
32+
* This library allows it to display messages on the ISPConfig dashboard which the user
33+
* has to actively acknowledge to hide them. The messages are stored in the sys_message table.
34+
*/
35+
36+
class message {
37+
38+
/*
39+
* This function is used to add a new message
40+
*/
41+
42+
public function add($message, $message_state = 'info', $sys_userid = 0, $sys_groupid = 0, $relation = '') {
43+
global $app, $conf;
44+
45+
if(!in_array($message_state,['info','warning','error'])) $app->debug_log('Unknown message_state in message add function.');
46+
$message_date = date('Y-m-d H:i:s');
47+
$sql = "INSERT INTO `sys_message` (`sys_userid`,`sys_groupid`,`message_state`,`message_date`,`message`,`relation`) VALUES (?,?,?,?,?,?)";
48+
if(is_object($app->dbmaster)) {
49+
// server
50+
if(!$app->dbmaster->query($sql,(int)$sys_userid,(int)$sys_groupid,$message_state,$message_date,$message,$relation)) {
51+
$app->debug_log('Adding '.$message_state.' message to sys_message failed.');
52+
}
53+
} else {
54+
// interface
55+
if(!$app->db->query($sql,(int)$sys_userid,(int)$sys_groupid,$message_state,$message_date,$message,$relation)) {
56+
$app->debug_log('Adding '.$message_state.' message to sys_message failed.');
57+
}
58+
}
59+
}
60+
61+
/*
62+
* This function is used to hide a message by message_id
63+
*/
64+
65+
public function hide_by_id($message_id) {
66+
global $app, $conf;
67+
$sql = "UPDATE `sys_message` SET `message_ack` = 'y' WHERE `message_id` = ?";
68+
if(is_object($app->dbmaster)) {
69+
// server
70+
if(!$app->dbmaster->query($sql,(int)$message_id)) {
71+
$app->debug_log('Hiding message '.$message_id.' in sys_message failed.');
72+
}
73+
} else {
74+
// interface
75+
if(!$app->db->query($sql,(int)$message_id)) {
76+
$app->debug_log('Hiding message '.$message_id.' in sys_message failed.');
77+
}
78+
}
79+
}
80+
81+
/*
82+
* This function is used to hide a message by message_state
83+
*/
84+
85+
public function hide_by_message_state($message_state, $relation = '') {
86+
global $app, $conf;
87+
88+
if(!in_array($message_state,['info','warning','error'])) $app->debug_log('Unknown message_state in message add function.');
89+
90+
if(is_object($app->dbmaster)) {
91+
// server
92+
$sql = "UPDATE `sys_message` SET `message_ack` = 'y' WHERE `message_state` = ?";
93+
if(!empty($relation)) $sql .= " AND relation = ?";
94+
95+
if(!$app->dbmaster->query($sql, $message_state, $relation)) {
96+
$app->debug_log('Hiding message by '.$message_state.' in sys_message failed.');
97+
}
98+
} else {
99+
// interface
100+
$app->uses('tform_base');
101+
$sql = "UPDATE `sys_message` SET `message_ack` = 'y' WHERE `message_state` = ? AND ".$app->tform_base->getAuthSQL('r');
102+
if(!empty($relation)) $sql .= " AND relation = ?";
103+
104+
if(!$app->db->query($sql, $message_state, $relation)) {
105+
$app->debug_log('Hiding message by '.$message_state.' in sys_message failed.');
106+
}
107+
108+
// Do some cleanup
109+
$this->cleanup();
110+
}
111+
}
112+
113+
/*
114+
* This function is used to hide a message by relation
115+
*/
116+
117+
public function hide_by_message_relation($relation) {
118+
global $app, $conf;
119+
120+
if(is_object($app->dbmaster)) {
121+
// server
122+
$sql = "UPDATE `sys_message` SET `message_ack` = 'y' WHERE `relation` = ?";
123+
124+
if(!$app->dbmaster->query($sql, $relation)) {
125+
$app->debug_log('Hiding message by '.$relation.' in sys_message failed.');
126+
}
127+
} else {
128+
// interface
129+
$app->uses('tform_base');
130+
$sql = "UPDATE `sys_message` SET `message_ack` = 'y' WHERE `relation` = ? AND ".$app->tform_base->getAuthSQL('r');
131+
132+
if(!$app->db->query($sql, $relation)) {
133+
$app->debug_log('Hiding message by '.$relation.' in sys_message failed.');
134+
}
135+
136+
// Do some cleanup
137+
$this->cleanup();
138+
}
139+
}
140+
141+
/*
142+
* This function is used to delete a message by message_id
143+
*/
144+
145+
public function delete($message_id) {
146+
global $app, $conf;
147+
$sql = "DELETE FROM `sys_message` WHERE `message_id` = ?";
148+
149+
if(is_object($app->dbmaster)) {
150+
// server
151+
if(!$app->dbmaster->query($sql,(int)$message_id)) {
152+
$app->debug_log('Deleting message '.$message_id.' from sys_message failed.');
153+
}
154+
} else {
155+
// interface
156+
if(!$app->db->query($sql,(int)$message_id)) {
157+
$app->debug_log('Deleting message '.$message_id.' from sys_message failed.');
158+
}
159+
}
160+
}
161+
162+
/*
163+
* This function is used to clean up old messages
164+
*/
165+
166+
private function cleanup() {
167+
global $app, $conf;
168+
$message_cleanup_date = date('Y-m-d H:i:s',strtotime('- 1 month'));
169+
$sql = "DELETE FROM `sys_message` WHERE `message_ack` = 'y' and `message_date` < ?";
170+
if(!$app->db->query($sql,$message_cleanup_date)) {
171+
$app->debug_log('Cleaning up messages from sys_message failed.');
172+
}
173+
}
174+
175+
/*
176+
* This function returns an array with all not acknowledged messages
177+
* for the currently logged-in user (use in interface only)
178+
*/
179+
180+
public function get_current_messages($relation = '') {
181+
global $app, $conf;
182+
183+
$app->uses('tform_base');
184+
if(!is_object($app->tform_base)) {
185+
$app->debug_log('No tform_base object. Do not use this function in server part.');
186+
return false;
187+
}
188+
189+
if($relation != '') {
190+
$sql = "SELECT * FROM `sys_message` WHERE `message_ack` = 'n' AND `relation` = ? AND ".$app->tform_base->getAuthSQL('r');
191+
} else {
192+
$sql = "SELECT * FROM `sys_message` WHERE `message_ack` = 'n' AND ".$app->tform_base->getAuthSQL('r');
193+
}
194+
$messages = $app->db->queryAllRecords($sql,$relation);
195+
196+
// Translate messages
197+
$app->load_language_file('web/dashboard/lib/lang/'.$_SESSION['s']['language'].'_message.lng');
198+
foreach($messages as $key => $msg) {
199+
$messages[$key]['message'] = $app->lng($msg['message']);
200+
}
201+
202+
return $messages;
203+
}
204+
}

interface/web/dashboard/dashboard.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,20 @@
153153
}
154154
}
155155

156-
$app->tpl->setloop('info', $info);
156+
// Load messages from sys_message
157+
$app->uses('message');
158+
$messages = $app->message->get_current_messages();
159+
if(!empty($messages)) {
160+
foreach($messages as $message) {
161+
if($message['message_state'] == 'info') $info[] = array('info_msg' => '<p>'.$message['message'].'</p>');
162+
if($message['message_state'] == 'warning') $warning[] = array('warning_msg' => '<p>'.$message['message'].'</p>');
163+
if($message['message_state'] == 'error') $error[] = array('error_msg' => '<p>'.$message['message'].'</p>');
164+
}
165+
}
166+
167+
if(!empty($info)) $app->tpl->setloop('info', $info);
168+
if(!empty($warning)) $app->tpl->setloop('warning', $warning);
169+
if(!empty($error)) $app->tpl->setloop('error', $error);
157170

158171
/* Load the dashlets*/
159172
$dashlet_list = array();
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
/*
3+
Copyright (c) 2025, Falko Timme, Timme Hosting GmbH & Co. KG
4+
All rights reserved.
5+
6+
Redistribution and use in source and binary forms, with or without modification,
7+
are permitted provided that the following conditions are met:
8+
9+
* Redistributions of source code must retain the above copyright notice,
10+
this list of conditions and the following disclaimer.
11+
* Redistributions in binary form must reproduce the above copyright notice,
12+
this list of conditions and the following disclaimer in the documentation
13+
and/or other materials provided with the distribution.
14+
* Neither the name of ISPConfig nor the names of its contributors
15+
may be used to endorse or promote products derived from this software without
16+
specific prior written permission.
17+
18+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21+
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23+
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25+
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28+
*/
29+
30+
require_once '../../lib/config.inc.php';
31+
require_once '../../lib/app.inc.php';
32+
33+
//* Check permissions for module
34+
$app->auth->check_module_permissions('dashboard');
35+
36+
$app->uses('message');
37+
38+
if(!empty($_GET['message_state'])) {
39+
$app->message->hide_by_message_state($_GET['message_state']);
40+
}
41+
if(!empty($_GET['relation'])) {
42+
$app->message->hide_by_message_relation($_GET['relation']);
43+
}
44+
45+
?>

interface/web/dashboard/templates/dashboard.htm

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,24 @@ <h1>{tmpl_var name='welcome_user'}</h1>
33
</div>
44

55
<tmpl_if name='error'>
6-
<div class="alert alert-danger">
6+
<div id="errormsg" class="alert alert-danger alert-dismissible" role="alert">
7+
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
78
<tmpl_loop name="error">
89
{tmpl_var name='error_msg'}
910
</tmpl_loop>
1011
</div>
1112
</tmpl_if>
1213
<tmpl_if name='warning'>
13-
<div class="alert alert-danger">
14+
<div id="warningmsg" class="alert alert-warning alert-dismissible" role="alert">
15+
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
1416
<tmpl_loop name="warning">
1517
{tmpl_var name='warning_msg'}
1618
</tmpl_loop>
1719
</div>
1820
</tmpl_if>
1921
<tmpl_if name='info'>
20-
<div class="alert alert-notification">
22+
<div id="infomsg" class="alert alert-notification alert-dismissible" role="alert">
23+
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
2124
<tmpl_loop name="info">
2225
{tmpl_var name='info_msg'}
2326
</tmpl_loop>
@@ -30,3 +33,15 @@ <h1>{tmpl_var name='welcome_user'}</h1>
3033
<tmpl_loop name='rightcol'>
3134
{tmpl_var name='content'}
3235
</tmpl_loop>
36+
37+
<script type = "text/javascript">
38+
$('#infomsg').on('closed.bs.alert', function () {
39+
$.get("dashboard/message_ack.php?message_state=info");
40+
});
41+
$('#warningmsg').on('closed.bs.alert', function () {
42+
$.get("dashboard/message_ack.php?message_state=warning");
43+
});
44+
$('#errormsg').on('closed.bs.alert', function () {
45+
$.get("dashboard/message_ack.php?message_state=error");
46+
});
47+
</script>

0 commit comments

Comments
 (0)