Commit 6ea87256 authored by Elias Villiger's avatar Elias Villiger
Browse files

Feature #4432 - Form Submit Log, as a new FormSubmitLog QFQ-Form, with code in...

Feature #4432 - Form Submit Log, as a new FormSubmitLog QFQ-Form, with code in the manual for a FE page to browse the table.
Also added code in the manual for a MailLog FE page.
parent fef1a122
Pipeline #716 passed with stage
in 1 minute and 51 seconds
......@@ -326,6 +326,10 @@ Extension Manager: QFQ Configuration
| sqlLog | fileadmin/protected/log/sql.log | Filename to log SQL commands: relative to <site path> or absolute. If the |
| | | directory does not exist, create it. |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| formSubmitLogMode | all | *all*: every form submission will be logged. |
| | | *none*: no logging. |
| | | See `Form Submit Log page`_ for example qfq code to display the log. |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| mailLog | fileadmin/protected/log/mail.log | Filename to log `sendEmail` commands: relative to <site path> or absolute. |
| | | If the directory does not exist, create it. |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
......@@ -733,25 +737,29 @@ version, the system tables will be automatically installed or updated.
System tables
^^^^^^^^^^^^^
+-------------+------------+------------+
| Name | Use | Database |
+=============+============+============+
| Clipboard | Temporary | QFQ |
+-------------+------------+------------+
| Cron | Persistent | QFQ |
+-------------+------------+------------+
| Dirty | Temporary | QFQ | Data |
+-------------+------------+------------+
| Form | Persistent | QFQ |
+-------------+------------+------------+
| FormElement | Persistent | QFQ |
+-------------+------------+------------+
| MailLog | Persistent | QFQ | Data |
+-------------+------------+------------+
| Period | Persistent | Data |
+-------------+------------+------------+
| Split | Persistent | Data |
+-------------+------------+------------+
+---------------+------------+------------+
| Name | Use | Database |
+===============+============+============+
| Clipboard | Temporary | QFQ |
+---------------+------------+------------+
| Cron | Persistent | QFQ |
+---------------+------------+------------+
| Dirty | Temporary | QFQ | Data |
+---------------+------------+------------+
| Form | Persistent | QFQ |
+---------------+------------+------------+
| FormElement | Persistent | QFQ |
+---------------+------------+------------+
| FormSubmitLog | Persistent | QFQ | Data |
+---------------+------------+------------+
| MailLog | Persistent | QFQ | Data |
+---------------+------------+------------+
| Period | Persistent | Data |
+---------------+------------+------------+
| Split | Persistent | Data |
+---------------+------------+------------+
See `Mail Log page`_ and `Form Submit Log page`_ for some Frontend views for these tables.
* Check Bug #5459 - support of system tables in different DBs not supported.
......@@ -918,6 +926,109 @@ configuration_
* Clear 'CC' and 'Bcc'
* Write a note and the original configured receiver at the top of the email body.
_`Mail Log page`
Mail Log page
-------------
For debugging purposes you may like to add a Mail Log page in the frontend.
The following QFQ code could be used for that purpose (put it in a QFQ PageContent element): ::
# Page parameters
1.sql = SELECT @grId := '{{grId:C0:digit}}' AS _grId
2.sql = SELECT @summary := IF('{{summary:CE:alnumx}}' = 'true', 'true', 'false') AS _s
# Filters
10 {
sql = SELECT gr.id, IF(gr.id = @grId, "' selected>", "'>"), gr.value, ' (Id: ', gr.id, ')'
FROM gGroup AS gr
INNER JOIN MailLog AS ml ON ml.grId = gr.id
GROUP BY gr.id
head = <form onchange='this.submit();' class='form-inline'><input type='hidden' name='id' value='{{pageId:T0}}'>Filter By Group: <select name='grId' class='form-control'><option value=''></option>
rbeg = <option value='
rend = </option>
tail = </select>
}
20 {
sql = SELECT IF(@summary = 'true', ' checked', '')
head = <div class='checkbox'><label><input type='checkbox' name='summary' value='true'
tail = >Summary</label></div></form>
}
# Mail Log
50 {
sql = SELECT id, '</td><td>', grId, '</td><td>', xId, '</td><td>',
REPLACE(receiver, ',', '<br>'), '</td><td>', REPLACE(sender, ',', '<br>'), '</td><td>',
DATE_FORMAT(modified, '%d.%m.%Y<br>%H:%i:%s'), '</td><td style="word-break:break-word;">',
CONCAT('<b>', subject, '</b><br>', IF(@summary = 'true', CONCAT(SUBSTR(body, 1, LEAST(IF(INSTR(body, '\n') = 0, 50, INSTR(body, '\n')), IF(INSTR(body, '<br>') = 0, 50, INSTR(body, '<br>')))-1), ' ...'), CONCAT('<br>', REPLACE(body, '\n', '<br>'))) )
FROM MailLog WHERE (grId = @grId OR @grId = 0)
ORDER BY modified DESC
LIMIT 100
head = <table class="table table-condensed table-hover"><tr><th>Id</th><th>grId</th><th>xId</th><th>To</th><th>From</th><th>Date</th><th>E-Mail</th></tr>
tail = </table>
rbeg = <tr><td>
rend = </td></tr>
}
_`Form Submit Log page`
Form Submit Log page
--------------------
For debugging purposes you may like to add a Form Submit Log page in the frontend.
The following QFQ code could be used for that purpose (put it in a QFQ PageContent element): ::
# Filters
20.shead = <form onchange='this.submit()' class='form-inline'><input type='hidden' name='id' value='{{pageId:T0}}'>
20 {
sql = SELECT id, IF(id = '{{formId:SC0}}', "' selected>", "'>"), name
FROM Form ORDER BY name
head = <label for='formId'>Form:</label> <select name='formId' id='formId' class='form-control'><option value=0></option>
tail = </select>
rbeg = <option value='
rend = </option>
}
30 {
sql = SELECT feUser, IF(feUser = '{{feUser:SCE:alnumx}}', "' selected>", "'>"), feUser
FROM FormSubmitLog GROUP BY feUser ORDER BY feUser
head = <label for='feUser'>FE User:</label> <select name='feUser' id='feUser' class='form-control'><option value=''></option>
tail = </select>
rbeg = <option value='
rend = </option>
}
30.stail = </form>
# Show Log
50 {
sql = SELECT l.id,
CONCAT('<b>Form</b>: ', f.name,
'<br><b>Record Id</b>: ', l.recordId,
'<br><b>Fe User</b>: ', l.feUser,
'<br><b>Date</b>: ', l.created,
'<br><b>Page Id</b>: ', l.pageId,
'<br><b>Session Id</b>: ', l.sessionId,
'<br><b>IP Address</b>: ', l.clientIp,
'<br><b>User Agent</b>: ', l.userAgent,
'<br><b>SIP Data</b>: <div style="margin-left:20px;">', "<script>var data = JSON.parse('", l.sipData,
"'); for (var key in data) {
document.write('<b>' + key + '</b>: ' + data[key] + '<br>'); }</script>", '</div>'),
CONCAT("<script>var data = JSON.parse('", l.formData,
"'); for (var key in data) {
document.write('<b>' + key + '</b>: ' + data[key] + '<br>'); }</script>")
FROM FormSubmitLog AS l
LEFT JOIN Form AS f ON f.id = l.formId
WHERE (l.formId = '{{formId:SC0}}' OR '{{formId:SC0}}' = 0)
AND (l.feUser = '{{feUser:SCE:alnumx}}' OR '{{feUser:SCE:alnumx}}' = '')
ORDER BY l.created DESC LIMIT 100
head = <table class="table table-hover">
<tr><th>Id</th><th style="min-width:250px;">Environment</th><th>Submitted Data</th>
tail = </table>
rbeg = <tr>
renr = </tr>
fbeg = <td>
fend = </td>
}
.. _variables:
Variable
......@@ -2200,6 +2311,8 @@ Parameter
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| showIdInFormTitle | string | Overwrite default from configuration_ |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| formSubmitLogMode | string | Overwrite default from configuration_ |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
* Example:
......
......@@ -60,6 +60,9 @@ sqlLogMode = modify
# cat=debug/sql; type=string; label=SQL log file:Default is 'fileadmin/protected/log/sql.log'. A logfile of fired SQL statements. PathFile is absolute or relative to '<site path>'.
sqlLog = fileadmin/protected/log/sql.log
# cat=debug/form; type=string; label=Form submit log mode:Default is 'all'. Form submit requests will be logged in the table FormSubmitLog. Possible modes are 'all' - every form save will be logged. 'none' - no logging. This setting can also be changed per form.
formSubmitLogMode = all
# cat=debug/mail; type=string; label=Mail log file:Default is 'fileadmin/protected/log/mail.log'. A logfile of sent mail. PathFile is absolute or relative to '<site path>'.
mailLog = fileadmin/protected/log/mail.log
......
......@@ -422,6 +422,10 @@ const SYSTEM_SQL_LOG = 'sqlLog'; // Logging to file
const SYSTEM_SQL_LOG_FILE = 'fileadmin/protected/log/sql.log';
const SYSTEM_SQL_LOG_MODE = 'sqlLogMode'; // Mode, which statements to log.
const SYSTEM_FORM_SUBMIT_LOG_MODE = 'formSubmitLogMode';
const FORM_SUBMIT_LOG_MODE_ALL = 'all';
const FORM_SUBMIT_LOG_MODE_NONE = 'none';
const SYSTEM_DATE_FORMAT = 'dateFormat';
const SYSTEM_REDIRECT_ALL_MAIL_TO = 'redirectAllMailTo';
const SYSTEM_MAIL_LOG = 'mailLog';
......@@ -842,6 +846,7 @@ const F_PARAMETER = 'parameter'; // valid for F_ and FE_
const F_DB_INDEX = 'dbIndex';
const DB_INDEX_DEFAULT = "1";
const PARAM_DB_INDEX_DATA = '__dbIndexData'; // Submitted via SIP to make record locking DB aware.
const F_FORM_SUBMIT_LOG_MODE = 'formSubmitLogMode';
const F_LDAP_SERVER = 'ldapServer';
const F_LDAP_BASE_DN = 'ldapBaseDn';
......
......@@ -457,6 +457,8 @@ class QuickFormQuery {
break;
case FORM_SAVE:
$this->logFormSubmitRequest();
$recordId = $this->store->getVar(SIP_RECORD_ID, STORE_SIP);
// Action: Before
......@@ -544,6 +546,36 @@ class QuickFormQuery {
return $data;
}
/**
* @throws CodeException
* @throws DbException
* @throws UserFormException
*/
private function logFormSubmitRequest() {
$formSubmitLogMode = $this->formSpec[F_FORM_SUBMIT_LOG_MODE] ??
$this->store->getVar(SYSTEM_FORM_SUBMIT_LOG_MODE, STORE_SYSTEM, SANITIZE_ALLOW_ALNUMX);
if ($formSubmitLogMode === FORM_SUBMIT_LOG_MODE_NONE) {
return;
}
$formData = $_POST;
unset($formData[CLIENT_SIP]);
$formData = json_encode($formData, JSON_UNESCAPED_UNICODE);
$clientIp = $_SERVER[CLIENT_REMOTE_ADDRESS];
$userAgent = $_SERVER[CLIENT_HTTP_USER_AGENT];
$sipData = json_encode($this->store->getStore(STORE_SIP), JSON_UNESCAPED_UNICODE);
$formId = $this->formSpec[F_ID];
$recordId = $this->store->getVar(SIP_RECORD_ID, STORE_SIP);
$feUser = $this->store->getVar(TYPO3_FE_USER, STORE_TYPO3, SANITIZE_ALLOW_ALNUMX);
$pageId = $this->store->getVar(TYPO3_PAGE_ID, STORE_TYPO3, SANITIZE_ALLOW_ALNUMX);
$sessionId = session_id();
$sql = "INSERT INTO FormSubmitLog (formData, sipData, clientIp, feUser, userAgent, formId, recordId, pageId, sessionId, created)" .
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())";
$params = [$formData, $sipData, $clientIp, $feUser, $userAgent, $formId, $recordId, $pageId, $sessionId];
$this->dbArray[$this->dbIndexQfq]->sql($sql, ROW_REGULAR, $params);
}
/**
* Check if forwardMode='url...'.
......
......@@ -120,7 +120,6 @@ $UPDATE_ARRAY = array(
"ALTER TABLE `Form` CHANGE `forwardMode` `forwardMode` ENUM('auto', 'close', 'no','url','url-skip-history','url-sip') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'auto';",
],
);
......
......@@ -353,6 +353,27 @@ CREATE TABLE IF NOT EXISTS `MailLog` (
DEFAULT CHARSET = utf8
AUTO_INCREMENT = 0;
CREATE TABLE IF NOT EXISTS `FormSubmitLog` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`formData` TEXT NOT NULL,
`sipData` TEXT NOT NULL,
`clientIp` VARCHAR(64) NOT NULL,
`feUser` VARCHAR(64) NOT NULL,
`userAgent` TEXT NOT NULL,
`formId` INT(11) NOT NULL,
`recordId` INT(11) NOT NULL,
`pageId` INT NOT NULL,
`sessionId` VARCHAR(32) NOT NULL,
`created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX (`feUser`),
INDEX (`formId`)
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8
AUTO_INCREMENT = 0;
CREATE TABLE IF NOT EXISTS `Clipboard` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment