Commit 76483cc8 authored by Elias Villiger's avatar Elias Villiger
Browse files

Merge branch 'master' into 4922-excel-import

parents d5a03b6a a8a05937
Pipeline #818 passed with stage
in 1 minute and 47 seconds
This diff is collapsed.
......@@ -43,12 +43,12 @@ Neue Versionsnummer
* Update the version number in this document (topic 6)
* Commit & Push new version changes to master branch:
New version x.y.z.
New version 18.8.2
6) **New Tag**:
git tag v18.6.1
git push -u origin v18.6.1
git tag v18.8.2
git push -u origin v18.8.2
7) PhpStorm: **Sync** all files to VM qfq.
......
This diff is collapsed.
......@@ -22,8 +22,8 @@
Release
=======
Version 0.future
----------------
Version 18.x.x
--------------
Date: <date>
......@@ -36,6 +36,82 @@ Features
Bug Fixes
^^^^^^^^^
Version 18.8.2
--------------
Date: 28.8.18
Features
^^^^^^^^
* F6563 / Accept 0 as required.
Bug Fixes
^^^^^^^^^
* DatabaseUpdateData.php: add missed 'on the fly' update for Form.title, changed in FormEditor.sql in 18.8.1
* 6562 / sendmail: redirect all mail - the sender is replaced too.
* Manual.rst: several typos fixed
Version 18.8.1
---------------
Date: 26.08.2018
Features
^^^^^^^^
* #4432 / Every 'form submit' will be logged with raw data.
* #4763 / Render vertical text more stable: '... AS _vertical'
* #4996 / Log QFQ Version update
* #5403 / Tooltip on pills are now supported
* #5876 / Subrecord title of column 'Edit' & 'Delete' are now customizable.
* #6249 / Subrecords can now be reordered via drag and drop.
* #6333 / Add to qfq.log: IP Address, User Agent, QFQ Cookie, FE User
Bug Fixes
^^^^^^^^^
* #6401 / Handle Backticks in sendmail
* #6452 / Empty form title: no title row will be rendered anymore.
Version 18.8.0
--------------
Date: 25.08.2018
Notes
^^^^^
* Excel export
* Copy to clipboard
Features
^^^^^^^^
* #4922 / Excel Export - create Excel sheets from scratch or based on a template.
* #3294 / Improve Typo3 QFQ backend layout. Add sparql syntax highlighting.
* #5878 / Formelement.type=note with #!report - whitespace is trimmed.
* #6314 / HTML Mails enabled by specifying flag 'mode=html'.
* Import/Merge form: A new form 'copyFormFromExt' (see file `copyFormFromExt.sql`) offers a one click import of external
QFQ forms (incl. renumbering of id's).
* formEditor.sql: resized Form.title from 255 to 511 (requested by IK Tool)
* Drag and Drop now offers the possibility to show the renumbered values.
* Manual.rst: security hints, T3 Setup best practice, text input retype, charactercountwrap.
* Config.qfq: central defaults for DATA_MATCH, DATA_ERROR
* Bootstrap QFQ development: switched from bower to npm only.
Bug Fixes
^^^^^^^^^
* #5843 / File upload: limitation to file extensions are no case insensitive.
* #6247 / Replace deprecated each function
* #6281 / FormElement / column 'note': token '#!report' - STORE_RECORD does not work.
* #6331 / File Upload: Wrong error message if filesize is much too big.
* #6229 / Add QFQ icon to content element and content element wizard
* AbstractException.php: fixed problem with htmlEntities() on link to 'Edit Form' and 'Edit FormElement'.
Version 18.6.1
--------------
......
......@@ -2,8 +2,8 @@
[general]
project = QFQ - Quick Form Query
version = 18.6
release = 18.6.1
version = 18.8
release = 18.8.2
t3author = Carsten Rose
copyright = since 2017 by the author
......
......@@ -57,9 +57,9 @@ copyright = u'2017, Carsten Rose'
# built documents.lease
#
# The short X.Y version.
version = '18.6'
version = '18.8'
# The full version, including alpha/beta/rc tags.
release = '18.6.1'
release = '18.8.2'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
......
This diff is collapsed.
......@@ -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
......
......@@ -11,7 +11,7 @@ $EM_CONF[$_EXTKEY] = array(
'dependencies' => 'fluid,extbase',
'clearcacheonload' => true,
'state' => 'stable',
'version' => '18.6.1',
'version' => '18.8.2',
'constraints' => [
'depends' => [
'typo3' => '6.0.0-9.2.99',
......
......@@ -43,12 +43,12 @@ require_once(__DIR__ . '/../qfq/exceptions/CodeException.php');
*
* Description:
*
* Delete successfull.
* Delete successful.
* status = 'success'
* message = <message>
* redirect = 'client'
*
* Delete successfull.
* Delete successful.
* status = 'success'
* message = <message>
* redirect = 'url'
......
......@@ -59,12 +59,14 @@ try {
$qfq = new QuickFormQuery(['bodytext' => '']);
$data = $qfq->dragAndDrop();
$answer = array_merge($data, $answer);
$answer[API_STATUS] = API_ANSWER_STATUS_SUCCESS;
$answer[API_MESSAGE] = 'reorder: success';
// $answer[API_FORM_UPDATE] = $data[API_FORM_UPDATE];
// $answer[API_ELEMENT_UPDATE] = $data[API_ELEMENT_UPDATE];
// unset($answer[API_FORM_UPDATE][API_ELEMENT_UPDATE]);
// $answer[API_ELEMENT_UPDATE] = [ 'dynamic-125' => [ 'content' => 'latest news', 'attr' => [ 'title' => 'latest title'] ] ];
} catch (qfq\UserFormException $e) {
$answer[API_MESSAGE] = $e->formatMessage();
......
......@@ -13,6 +13,8 @@ use qfq;
require_once(__DIR__ . '/../qfq/store/Store.php');
require_once(__DIR__ . '/../qfq/Constants.php');
require_once(__DIR__ . '/../qfq/File.php');
require_once(__DIR__ . '/../qfq/exceptions/UserFormException.php');
require_once(__DIR__ . '/../qfq/exceptions/CodeException.php');
/**
* Process File Upload - immediately when the the user selects a file.
......@@ -23,7 +25,7 @@ require_once(__DIR__ . '/../qfq/File.php');
*
* Description:
*
* Upload successfull & File accepted by server.
* Upload successful & File accepted by server.
* status = 'success'
* message = <message>
*
......
......@@ -2337,14 +2337,14 @@ abstract class AbstractBuildForm {
/**
* @param string $linkNew Complete Button, incl. SIP href
* @param bool $flagDelete Flag to show if there is columns 'delete' rendered.
* @param string $deleteColumnTitle - if null, no delete column is rendered
* @param array $firstRow First row of all subrecords to extract columntitles
* @param array $control Array with <th> column names / format.
*
* @return string
* @throws UserFormException
*/
private function subrecordHead($linkNew, $flagDelete, array $firstRow, array &$control) {
private function subrecordHead($linkNew, $flagDelete, $deleteTitle, array $firstRow, array &$control) {
$columns = $linkNew;
......@@ -2357,7 +2357,7 @@ abstract class AbstractBuildForm {
}
if ($flagDelete) {
$columns .= '<th></th>';
$columns .= "<th>$deleteTitle</th>";
}
return Support::wrapTag('<thead><tr>', $columns);
......@@ -2407,11 +2407,38 @@ abstract class AbstractBuildForm {
$flagEdit = Support::findInSet(SUBRECORD_EDIT, $formElement[FE_SUBRECORD_OPTION]);
$flagDelete = Support::findInSet(SUBRECORD_DELETE, $formElement[FE_SUBRECORD_OPTION]) && ($formElement[FE_MODE] != FE_MODE_READONLY);
$linkNew = $flagNew ? Support::wrapTag('<th>', $this->createFormLink($formElement, 0, $primaryRecord, $this->symbol[SYMBOL_NEW], 'New')) : '<th></th>';
$editColumnTitle = $flagNew ? $this->createFormLink($formElement, 0, $primaryRecord, $this->symbol[SYMBOL_NEW], 'New') : '';
$editColumnTitle .= ' ' . $formElement[SUBRECORD_COLUMN_TITLE_EDIT];
$linkNew = Support::wrapTag('<th>', $editColumnTitle);
}
// Determine if DragAndDrop is active
$hasDragAndDrop = false;
$orderColumn = $formElement[FE_ORDER_COLUMN] ?? DND_COLUMN_ORD;
$dndTable = '';
if (isset($formElement[FE_DND_TABLE])) {
// Table is specified in parameter field
$dndTable = $formElement[FE_DND_TABLE];
} else {
// Read table from form specified in subrecord
$formName = $formElement[SUBRECORD_PARAMETER_FORM];
$form = $this->dbArray[$this->dbIndexQfq]->sql("SELECT * FROM Form AS f WHERE f." . F_NAME . " LIKE ? AND f.deleted='no'",
ROW_REGULAR, [$formName]);
if (count($form) > 0) { $dndTable = $form[0][F_TABLE_NAME]; }
}
if ($dndTable) {
$columns = $this->dbArray[$this->dbIndexQfq]->sql("SHOW COLUMNS FROM $dndTable");
foreach ($columns as $column) {
if ($column['Field'] === $orderColumn) {
// DragAndDrop is active if the dndTable has the orderColumn
$hasDragAndDrop = true;
break;
}
}
}
$firstRow = isset($formElement[FE_SQL1][0]) ? $formElement[FE_SQL1][0] : array();
$htmlHead = $this->subrecordHead($linkNew, $flagDelete, $firstRow, $control);
$htmlHead = $this->subrecordHead($linkNew, $flagDelete, $formElement[SUBRECORD_COLUMN_TITLE_DELETE], $firstRow, $control);
$htmlBody = '';
foreach ($formElement[FE_SQL1] as $row) {
$rowHtml = '';
......@@ -2456,12 +2483,37 @@ abstract class AbstractBuildForm {
}
$rowAttribute = Support::doAttribute('class', $rowClass);
$rowAttribute .= Support::doAttribute('title', $rowTooltip);
if ($hasDragAndDrop) {
$rowAttribute .= Support::doAttribute('id', $formElement[FE_HTML_ID] . '-' . $row[$nameColumnId]);
$rowAttribute .= Support::doAttribute('data-dnd-id', $row[$nameColumnId]);
}
$htmlBody .= Support::wrapTag("<tr $rowAttribute>", $rowHtml, true);
}
// Handle DragAndDrop
$dndAttributes = '';
if ($hasDragAndDrop) {
$orderInterval = 10;
$numColumns = 0;
if (count($formElement[FE_SQL1]) > 0) {
$numColumns = count($formElement[FE_SQL1][0]) + (int)$flagDelete + (int)($flagNew || $flagEdit);
}
$dataDndApi = DND_SUBRECORD_ID . '=' . $formElement[FE_ID];
$dataDndApi .= '&' . DND_SUBRECORD_FORM_ID . '=' . $this->store->getVar('id', STORE_RECORD);
$dataDndApi .= '&' . FE_ORDER_INTERVAL . '=' . $orderInterval;
$dataDndApi .= '&' . FE_ORDER_COLUMN . '=' . $orderColumn;
$dataDndApi .= '&' . FE_DND_TABLE . '=' . $dndTable;
$dndAttributes = Support::doAttribute('class', 'qfq-dnd-sort');
$dndAttributes .= $this->evaluate->parse( "{{ '$dataDndApi' AS _data-dnd-api }}").' ';
$dndAttributes .= Support::doAttribute('data-columns', $numColumns);
}
$attribute = Support::doAttribute('class', $formElement[FE_SUBRECORD_TABLE_CLASS]);
return Support::wrapTag("<table $attribute>", $htmlHead . Support::wrapTag('<tbody>', $htmlBody), true);
return Support::wrapTag("<table $attribute>",
$htmlHead . Support::wrapTag("<tbody $dndAttributes>", $htmlBody), true);
}
/**
......
......@@ -126,7 +126,7 @@ class BuildFormBootstrap extends AbstractBuildForm {
$button = Support::wrapTag('<div class="row"><div class="col-md-12">', $this->buildButtons());
// Show title / frame only if there is a title given.
if ($this->formSpec[F_TITLE] != '') {
if (trim($this->formSpec[F_TITLE]) != '') {
$classTitle = isset($this->formSpec[F_CLASS_TITLE]) ? $this->formSpec[F_CLASS_TITLE] : "qfq-form-title";
$title = Support::wrapTag('<div class="row"><div class="col-md-12">', Support::wrapTag('<div class="' . $classTitle . '">', $this->formSpec[F_TITLE]));
}
......@@ -501,6 +501,7 @@ class BuildFormBootstrap extends AbstractBuildForm {
}
$attributeLi .= Support::doAttribute(HTML_ATTR_ID, $htmlIdLi);
$attributeLi .= Support::doAttribute( 'title', $formElement[FE_TOOLTIP]);
$attributeLiA .= Support::doAttribute(HTML_ATTR_ID, $htmlIdLiA);
$a = Support::wrapTag("<a $attributeLiA" . Support::doAttribute('href', $hrefTarget) . ">", $formElement[FE_LABEL]);
$json[$htmlFormElementName][API_ELEMENT_UPDATE][$htmlIdLiA][API_ELEMENT_CONTENT] = $formElement[FE_LABEL];
......
......@@ -55,6 +55,7 @@ const RETURN_URL = 'return_url';
const RETURN_SIP = 'return_sip';
const RETURN_ARRAY = 'return_array';
const SQL_FORM_ELEMENT_BY_ID = "SELECT * FROM FormElement AS fe WHERE fe.id = ?";
const SQL_FORM_ELEMENT_RAW = "SELECT * FROM FormElement AS fe WHERE fe.formId = ? AND fe.deleted = 'no' AND fe.enabled='yes' ORDER BY fe.ord, fe.id";
const SQL_FORM_ELEMENT_SPECIFIC_CONTAINER = "SELECT *, ? AS 'nestedInFieldSet' FROM FormElement AS fe WHERE fe.formId = ? AND fe.deleted = 'no' AND FIND_IN_SET(fe.class, ? ) AND fe.feIdContainer = ? AND fe.enabled='yes' ORDER BY fe.ord, fe.id";
const SQL_FORM_ELEMENT_ALL_CONTAINER = "SELECT *, ? AS 'nestedInFieldSet' FROM FormElement AS fe WHERE fe.formId = ? AND fe.deleted = 'no' AND FIND_IN_SET(fe.class, ? ) AND fe.enabled='yes' ORDER BY fe.ord, fe.id";
......@@ -257,6 +258,7 @@ const ERROR_DOWNLOAD_NOTHING_TO_DO = 1702;
const ERROR_DOWNLOAD_UNEXPECTED_MIME_TYPE = 1703;
const ERROR_DOWNLOAD_UNEXPECTED_NUMBER_OF_SOURCES = 1704;
const ERROR_DOWNLOAD_FILE_NOT_READABLE = 1705;
const ERROR_DOWNLOAD_FOPEN_BLOCKED = 1706;
// Excel
const ERROR_EXCEL_POSITION_ARGUMENT_EMPTY = 1800;
......@@ -303,12 +305,17 @@ const ERROR_LANGUAGE_NOT_CONFIGURED_IN_QFQ = 2300;
const ERROR_MISSING_SESSIONNAME = 2400;
const ERROR_QFQ_SESSION_MISSING = 2401;
const ERROR_SESSION_BROKEN_SCRIPT_PATH = 2402;
const ERROR_MISSING_COOKIE = 2403;
const ERROR_HTML2PDF_MISSING_CONFIG = 2500;
const ERROR_HTML2PDF_WKHTML_NOT_EXECUTABLE = 2501;
const ERROR_HTML2PDF_WKHTML_FAILED = 2502;
// Thumbnail
const ERROR_THUMBNAIL_RENDER = 2600;
// Drag and Drop
const ERROR_DND_EMPTY_REORDER_SQL = 2700;
//
// Store Names: Identifier
//
......@@ -354,6 +361,7 @@ const CLIENT_TYPO3VARS = '_sipForTypo3Vars';
// The following exist and might be the most used ones.
const CLIENT_SCRIPT_URL = 'SCRIPT_URL';
const CLIENT_SCRIPT_URI = 'SCRIPT_URI';
const CLIENT_HTTP_COOKIE = 'HTTP_COOKIE';
const CLIENT_HTTP_HOST = 'HTTP_HOST';
const CLIENT_HTTP_USER_AGENT = 'HTTP_USER_AGENT';
const CLIENT_SERVER_NAME = 'SERVER_NAME';
......@@ -423,6 +431,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';
......@@ -752,6 +764,8 @@ const ALIGN_VERTICAL = 'vertical';
// Subrecord
const SUBRECORD_COLUMN_DEFAULT_MAX_LENGTH = 20;
const SUBRECORD_COLUMN_TITLE_EDIT = 'subrecordColumnTitleEdit';
const SUBRECORD_COLUMN_TITLE_DELETE = 'subrecordColumnTitleDelete';
const FORM_ELEMENTS_NATIVE = 'native';
const FORM_ELEMENTS_SUBRECORD = 'subrecord';
const FORM_ELEMENTS_NATIVE_SUBRECORD = 'native_subrecord';
......@@ -843,6 +857,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';
......@@ -1040,6 +1055,7 @@ const FE_FILE_BUTTON_TEXT = 'fileButtonText';
const FE_FILE_BUTTON_TEXT_DEFAULT = 'Choose File';
const FE_INPUT_TYPE = 'inputType';
const FE_STEP = 'step';
const FE_ACCEPT_ZERO_AS_REQUIRED = 'acceptZeroAsRequired';
const FE_IMAGE_CUT_RESIZE_WIDTH = 'resizeWidth';
const FE_IMAGE_CUT_KEEP_ORIGINAL = 'keepOriginal';
......@@ -1096,6 +1112,10 @@ const FE_TYPE_PILL = 'pill';
const FE_HTML_ID = 'htmlId'; // Will be dynamically computed during runtime.
const FE_ORDER_INTERVAL = 'orderInterval';
const FE_ORDER_COLUMN = 'orderColumn';
const FE_DND_TABLE = 'dndTable';
const MODE_ENCODE = 'encode';
const MODE_DECODE = 'decode';
const MODE_NONE = 'none';
......@@ -1297,6 +1317,8 @@ const COLUMN_PAGEI = 'pagei';
const COLUMN_PAGEN = 'pagen';
const COLUMN_PAGES = 'pages';
const COLUMN_YANK = 'yank';
const COLUMN_PDF = 'pdf';
const COLUMN_FILE = 'file';
const COLUMN_ZIP = 'zip';
......@@ -1308,9 +1330,10 @@ const COLUMN_STRIPTAGS = 'striptags';
const COLUMN_MIME_TYPE = 'mimeType'; // Will also be used to identify equal named columns in upload record.
const COLUMN_FILE_SIZE = 'fileSize'; // Will also be used to identify equal named columns in upload record.
const COLUMN_IMPORT = "import";
const COLUMN_EXCEL_STRING = 'XLSs';
const COLUMN_EXCEL_NUMERIC = 'XLSn';
const COLUMN_EXCEL_PLAIN = 'XLS';
const COLUMN_EXCEL_NUMERIC = 'XLSn';
const COLUMN_EXCEL_STRING = 'XLSs';
const COLUMN_EXCEL_BASE64 = 'XLSb';
const COLUMN_WRAP_TOKEN = '+';
......@@ -1356,7 +1379,7 @@ const EXCEL_STRING2 = 'str';
const EXCEL_STRING = 's';
const EXCEL_FORMULA = 'f';
const EXCEL_NUMERIC = 'n';
const EXCEL_BOOL = 'b';
const EXCEL_BASE64 = 'b';
const EXCEL_NULL = 'null';
const EXCEL_INLINE = 'inlineStr';
const EXCEL_ERROR = 'e';
......@@ -1520,6 +1543,7 @@ const EXCEPTION_REPORT_FULL_LEVEL = 'Report level key';
const EXCEPTION_SIP = 'current sip';
const EXCEPTION_PAGE_ID = 'Page Id';
const EXCEPTION_TT_CONTENT_UID = 'Content Id';
const EXCEPTION_FE_USER = 'FE User';
const EXCEPTION_EDIT_FORM = 'Edit';
const EXCEPTION_TIMESTAMP = 'Timestamp';
......@@ -1531,6 +1555,10 @@ const EXCEPTION_MESSAGE_DEBUG = SYSTEM_MESSAGE_DEBUG; // Will only be shown as
const EXCEPTION_FILE = 'File';
const EXCEPTION_LINE = 'Line';
const EXCEPTION_STACKTRACE = 'Stacktrace';
const EXCEPTION_IP_ADDRESS = 'IP Address';
const EXCEPTION_QFQ_COOKIE = 'QFQ Cookie';
const EXCEPTION_HTTP_USER_AGENT = 'HTTP User Agent';
const EXCEPTION_PHP_SESSION = 'PHP Session';
const EXCEPTION_TABLE_CLASS = 'table table-hover qfq-table-80';
......@@ -1546,4 +1574,7 @@ const DND_COLUMN_ID = 'id';
const DND_COLUMN_ORD = 'ord';
const DND_COLUMN_ORD_NEW = 'ordNew';
const DND_DATA_DND_API = 'data-dnd-api';
const DND_SUBRECORD_ID = 'dnd-subrecord-id'; // Internal qualifier used to communicate with dnd api for subrecord dnd
const DND_SUBRECORD_FORM_ID = 'dnd-subrecord-form-id';
const DND_ORD_HTML_ID_PREFIX = 'qfq-dnd-ord-id-';
......@@ -319,9 +319,10 @@ class QuickFormQuery {
private function doForm($formMode) {
$data = '';
$foundInStore = '';
$flagApiStructureReGroup=true;
// Fill STORE_FORM
if ($formMode === FORM_UPDATE || $formMode === FORM_SAVE || $formMode === FORM_DRAG_AND_DROP) {
if ($formMode === FORM_UPDATE || $formMode === FORM_SAVE) {
$fillStoreForm = new FillStoreForm();
$fillStoreForm->process($formMode);
}
......@@ -457,6 +458,8 @@ class QuickFormQuery {
break;
case FORM_SAVE:
$this->logFormSubmitRequest();
$recordId = $this->store->getVar(SIP_RECORD_ID, STORE_SIP);
// Action: Before
......@@ -527,7 +530,8 @@ class QuickFormQuery {
$formAction->elements($recordId, $this->feSpecAction, FE_TYPE_BEFORE_LOAD);
$dragAndDrop = new DragAndDrop($this->formSpec);
$dragAndDrop->process();
$data = $dragAndDrop->process();
$flagApiStructureReGroup=false;
$formAction->elements($recordId, $this->feSpecAction, FE_TYPE_AFTER_LOAD);
break;
......@@ -536,7 +540,7 @@ class QuickFormQuery {
throw new CodeException("This statement should never be reached", ERROR_CODE_SHOULD_NOT_HAPPEN);
}
if (is_array($data)) {
if ($flagApiStructureReGroup && is_array($data)) {
// $data['element-update']=...
$data = $this->groupElementUpdateEntries($data);
}
......@@ -544,6 +548,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...'.
......@@ -717,7 +751,7 @@ class QuickFormQuery {
unlink($file);
} else {
$form[FORM_LOG_FILE . '_' . $mode] = $file;
$form[FORM_LOG_ACTIVE]=1;
$form[FORM_LOG_ACTIVE] = 1;
}
}
}
......@@ -1379,8 +1413,38 @@ class QuickFormQuery {
* @throws UserReportException
*/
public function dragAndDrop() {
$fillStoreForm = new FillStoreForm();
$fillStoreForm->process(FORM_DRAG_AND_DROP);
$json = "";
$dndSubrecordId = $this->store->getVar(DND_SUBRECORD_ID, STORE_SIP . STORE_CLIENT . STORE_ZERO);
if ($dndSubrecordId > 0) {
// Subrecord DragAndDrop
$subrecord = $this->dbArray[$this->dbIndexQfq]->sql(SQL_FORM_ELEMENT_BY_ID, ROW_REGULAR, [$dndSubrecordId]);
$recordId = $this->store->getVar(DND_SUBRECORD_FORM_ID, STORE_SIP . STORE_ZERO);
$this->fillStoreWithRecord('Form', $recordId);
$dndOrderSql = $this->eval->parse($subrecord[0][FE_SQL1]);
foreach ($dndOrderSql as $i => $row) {
foreach ($row as $key => $value) {
if (substr($key, 0, 1) === '_') {
$dndOrderSql[$i][substr($key, 1)] = $value;
}
}
}
$dummyFormSpec= [
F_ORDER_INTERVAL => $this->store->getVar(FE_ORDER_INTERVAL, STORE_SIP . STORE_ZERO),
F_ORDER_COLUMN => $this->store->getVar(FE_ORDER_COLUMN, STORE_SIP . STORE_ZERO),
F_DRAG_AND_DROP_ORDER_SQL => $dndOrderSql,
F_TABLE_NAME => $this->store->getVar(FE_DND_TABLE, STORE_SIP . STORE_ZERO)
];
$json = $this->doForm(FORM_DRAG_AND_DROP);
$dragAndDrop = new DragAndDrop($dummyFormSpec);
$json = $dragAndDrop->process();
} else {
// User-defined DragAndDrop
$json = $this->doForm(FORM_DRAG_AND_DROP);
}
return $json;
}
......
......@@ -439,6 +439,11 @@ class Save {
$this->feSpecNative[$key][FE_MODE_SQL] = $mode;
}
if(isset($formElement[FE_ACCEPT_ZERO_AS_REQUIRED]) && $formElement[FE_ACCEPT_ZERO_AS_REQUIRED] != '0' &&
isset($clientValues[$formElement[FE_NAME]]) && $clientValues[$formElement[FE_NAME]]=='0'){
$mode='fake'; // The next if() should never be true.
}
if (!$requiredOff && $mode == FE_MODE_REQUIRED && empty($clientValues[$formElement[FE_NAME]])) {
throw new UserFormException("Missing required value: " . $formElement[FE_LABEL], ERROR_REQUIRED_VALUE_EMPTY);