Commit feaeeffc authored by Carsten  Rose's avatar Carsten Rose
Browse files

recordLocking

DatabaseUpdateData.php: Table Form: recordLockTimeoutSeconds - default changed from 0 to 900 secs. Existing forms get the default timeout timout interval.
Dirty.php, QuickFormQuery.php: recordLockTimeoutSeconds will be retrieved from the Form.recordLockTimeoutSeconds definition (instead of parsing config.qfq.ini). Therefore a definition per form ist possible.
parent 4475fab6
......@@ -268,10 +268,9 @@ class QuickFormQuery {
// Check and release dirtyRecord.
if ($formMode === FORM_DELETE || $formMode === FORM_SAVE) {
$lockTimeout = $this->store->getVar(STORE_SYSTEM, SYSTEM_RECORD_LOCK_TIMEOUT_SECONDS);
$dirty = new Dirty($lockTimeout);
$dirty->checkDirtyAndRelease($formMode, $this->formSpec[F_DIRTY_MODE], $this->formSpec[F_TABLE_NAME],
$recordId);
$dirty = new Dirty();
$dirty->checkDirtyAndRelease($formMode, $this->formSpec[F_RECORD_LOCK_TIMEOUT_SECONDS],
$this->formSpec[F_DIRTY_MODE], $this->formSpec[F_TABLE_NAME], $recordId);
}
if ($formMode === FORM_DELETE) {
......
......@@ -55,7 +55,7 @@ $UPDATE_ARRAY = array(
'0.19.0' => [
"ALTER TABLE `Form` ADD `dirtyMode` ENUM( 'exclusive', 'advisory', 'none' ) NOT NULL DEFAULT 'exclusive' AFTER `requiredParameter`",
"ALTER TABLE `Form` ADD `recordLockTimeoutSeconds` INT NOT NULL DEFAULT '0' AFTER `parameter`"
"ALTER TABLE `Form` ADD `recordLockTimeoutSeconds` INT NOT NULL DEFAULT '900' AFTER `parameter`"
],
);
......
......@@ -40,26 +40,14 @@ class Dirty {
*/
private $session = null;
/**
* @var array()
*/
private $lockTimeout = false;
/**
* Init class
*/
public function __construct($lockTimeout = false, $phpUnit = false) {
public function __construct($phpUnit = false) {
$this->session = Session::getInstance($phpUnit);
$this->client = Client::getParam();
$this->db = new Database();
if($lockTimeout === false) {
$cfg = new Config();
$config = $cfg->readConfig('');
$this->lockTimeout = $config[SYSTEM_RECORD_LOCK_TIMEOUT_SECONDS];
} else {
$this->lockTimeout = $lockTimeout;
}
}
/**
......@@ -83,7 +71,7 @@ class Dirty {
$recordId = empty($sipVars[SIP_RECORD_ID]) ? 0 : $sipVars[SIP_RECORD_ID];
if($recordId>0) {
$tableVars = $this->db->sql("SELECT tableName, dirtyMode FROM Form AS f WHERE f.name=?", ROW_EXPECT_1, [$sipVars[SIP_FORM]], "Form not found: '" . $sipVars[SIP_FORM] . "'");
$tableVars = $this->db->sql("SELECT tableName, dirtyMode, recordLockTimeoutSeconds FROM Form AS f WHERE f.name=?", ROW_EXPECT_1, [$sipVars[SIP_FORM]], "Form not found: '" . $sipVars[SIP_FORM] . "'");
}
switch($this->client[API_LOCK_ACTION]) {
......@@ -91,7 +79,7 @@ class Dirty {
$answer = $this->acquireDirty($recordId, $tableVars);
break;
case API_LOCK_ACTION_RELEASE:
$answer = $this->checkDirtyAndRelease(FORM_SAVE, $tableVars[F_DIRTY_MODE], $tableVars[F_TABLE_NAME], $recordId);
$answer = $this->checkDirtyAndRelease(FORM_SAVE, $tableVars[F_RECORD_LOCK_TIMEOUT_SECONDS], $tableVars[F_DIRTY_MODE], $tableVars[F_TABLE_NAME], $recordId);
break;
default;
throw new CodeException("Unknown action: " . $this->client[API_LOCK_ACTION], ERROR_DIRTY_UNKNOWN_ACTION);
......@@ -127,8 +115,9 @@ class Dirty {
$recordDirty = $this->getRecordDirty($tableName, $recordId);
// Check if the record is timed out
if (count($recordDirty) != 0 && $this->lockTimeout > 0) {
$datetimeExpire = date_add(date_create($recordDirty[COLUMN_MODIFIED]), date_interval_create_from_date_string($this->lockTimeout . " second"));
if (count($recordDirty) != 0 && $tableVars[F_RECORD_LOCK_TIMEOUT_SECONDS] > 0) {
$datetimeExpire = date_add(date_create($recordDirty[COLUMN_MODIFIED]),
date_interval_create_from_date_string($tableVars[F_RECORD_LOCK_TIMEOUT_SECONDS] . " second"));
if ($datetimeExpire <= date_create("now")) {
$this->deleteDirtyRecord($recordDirty[COLUMN_ID]);
$recordDirty=array();
......@@ -137,7 +126,7 @@ class Dirty {
if (count($recordDirty) == 0) {
// No dirty record found.
$answer = $this->writeDirty($this->client[SIP_SIP], $recordId, $tableName, $formDirtyMode, $feUser);
$answer = $this->writeDirty($this->client[SIP_SIP], $recordId, $tableVars, $feUser);
} else {
$answer = $this->conflict($recordDirty, $formDirtyMode);
}
......@@ -204,14 +193,16 @@ class Dirty {
*
* @param string $s SIP given by URL GET
* @param int $recordId extracted from SIP
* @param string $tableName extracted from SIP
* @param string $formDirtyMode
* @param array $tableVars
* @param string $feUser
* @return array
* @throws CodeException
* @throws DbException
*/
private function writeDirty($s, $recordId, $tableName, $formDirtyMode, $feUser) {
private function writeDirty($s, $recordId,array $tableVars, $feUser) {
$tableName = $tableVars[F_TABLE_NAME];
$formDirtyMode = $tableVars[F_DIRTY_MODE];
$record = $this->db->sql("SELECT * FROM $tableName WHERE id=?", ROW_EXPECT_1, [$recordId], "Record to tag 'dirty' not found.");
......@@ -220,9 +211,12 @@ class Dirty {
// Write 'dirty' record
$this->db->sql("INSERT INTO Dirty (`sip`, `tableName`, `recordId`, `recordModified`, `feUser`, `qfqUserSessionCookie`, `dirtyMode`, `remoteAddress`, `created`) " .
"VALUES ( ?,?,?,?,?,?,?,?,? )", ROW_REGULAR, [$s, $tableName, $recordId, $recordModified, $feUser, $this->client[CLIENT_COOKIE_QFQ], $formDirtyMode, $this->client[CLIENT_REMOTE_ADDRESS], date('YmdHis')]);
"VALUES ( ?,?,?,?,?,?,?,?,? )", ROW_REGULAR,
[$s, $tableName, $recordId, $recordModified, $feUser, $this->client[CLIENT_COOKIE_QFQ], $formDirtyMode,
$this->client[CLIENT_REMOTE_ADDRESS], date('YmdHis')]);
return [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '', API_LOCK_TIMEOUT => $this->lockTimeout ];
return [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '',
API_LOCK_TIMEOUT => $tableVars[F_RECORD_LOCK_TIMEOUT_SECONDS] ];
}
......@@ -230,15 +224,16 @@ class Dirty {
* Release a dirtyRecord. This is only possible if the current user owns the dirtyRecord.
* In case of not owner, throws an exception and the save should break.
*
* @param string $formMode FORM_DELETE, FORM_SAVE
* @param string $dirtyMode DIRTY_MODE_EXCLUSIVE, DIRTY_MODE_ADVISORY, DIRTY_MODE_NONE
* @param string $formMode FORM_DELETE, FORM_SAVE
* @param int $lockTimeout
* @param string $dirtyMode DIRTY_MODE_EXCLUSIVE, DIRTY_MODE_ADVISORY, DIRTY_MODE_NONE
* @param string $tableName
* @param int $recordId
* @return array
* @throws CodeException
* @throws UserFormException
*/
public function checkDirtyAndRelease($formMode, $dirtyMode, $tableName, $recordId) {
public function checkDirtyAndRelease($formMode, $lockTimeout, $dirtyMode, $tableName, $recordId) {
$answer = [ API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => ''];
......@@ -286,8 +281,8 @@ class Dirty {
}
// Check if the record is timed out
if ($this->lockTimeout > 0) {
$datetimeExpire = date_add(date_create($recordDirty[COLUMN_MODIFIED]), date_interval_create_from_date_string($this->lockTimeout . " second"));
if ($lockTimeout > 0) {
$datetimeExpire = date_add(date_create($recordDirty[COLUMN_MODIFIED]), date_interval_create_from_date_string($lockTimeout . " second"));
if ($datetimeExpire <= date_create("now")) {
$this->deleteDirtyRecord($recordDirty[COLUMN_ID]);
return $answer;
......
......@@ -12,7 +12,7 @@ CREATE TABLE IF NOT EXISTS `Form` (
`escapeTypeDefault` VARCHAR(32) NOT NULL DEFAULT 'c',
`render` ENUM('bootstrap', 'table', 'plain') NOT NULL DEFAULT 'bootstrap',
`requiredParameter` VARCHAR(255) NOT NULL DEFAULT '',
`dirtyMode` ENUM('exclusive', 'advisory', 'none') NOT NULL DEFAULT 'exclusive',
`dirtyMode` ENUM('exclusive', 'advisory', 'none') NOT NULL DEFAULT 'exclusive',
`showButton` SET('new', 'delete', 'close', 'save') NOT NULL DEFAULT 'new,delete,close,save',
`multiMode` ENUM('none', 'horizontal', 'vertical') NOT NULL DEFAULT 'none',
`multiSql` TEXT NOT NULL,
......@@ -27,7 +27,7 @@ CREATE TABLE IF NOT EXISTS `Form` (
`bsNoteColumns` VARCHAR(255) NOT NULL DEFAULT '',
`parameter` TEXT NOT NULL,
`recordLockTimeoutSeconds` INT(11) NOT NULL DEFAULT 0,
`recordLockTimeoutSeconds` INT(11) NOT NULL DEFAULT 900,
`deleted` ENUM('yes', 'no') NOT NULL DEFAULT 'no',
`modified` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
......@@ -58,54 +58,54 @@ CREATE TABLE IF NOT EXISTS `Form` (
#DROP TABLE IF EXISTS `FormElement`;
CREATE TABLE IF NOT EXISTS `FormElement` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`formId` INT(11) NOT NULL,
`feIdContainer` INT(11) NOT NULL DEFAULT '0',
`dynamicUpdate` ENUM('yes', 'no') NOT NULL DEFAULT 'no',
`id` INT(11) NOT NULL AUTO_INCREMENT,
`formId` INT(11) NOT NULL,
`feIdContainer` INT(11) NOT NULL DEFAULT '0',
`dynamicUpdate` ENUM('yes', 'no') NOT NULL DEFAULT 'no',
`enabled` ENUM('yes', 'no') NOT NULL DEFAULT 'yes',
`enabled` ENUM('yes', 'no') NOT NULL DEFAULT 'yes',
`name` VARCHAR(255) NOT NULL DEFAULT '',
`label` VARCHAR(255) NOT NULL DEFAULT '',
`name` VARCHAR(255) NOT NULL DEFAULT '',
`label` VARCHAR(255) NOT NULL DEFAULT '',
`mode` ENUM('show', 'required', 'readonly', 'hidden') NOT NULL DEFAULT 'show',
`modeSql` TEXT NOT NULL,
`class` ENUM('native', 'action', 'container') NOT NULL DEFAULT 'native',
`mode` ENUM('show', 'required', 'readonly', 'hidden') NOT NULL DEFAULT 'show',
`modeSql` TEXT NOT NULL,
`class` ENUM('native', 'action', 'container') NOT NULL DEFAULT 'native',
`type` ENUM('checkbox', 'date', 'datetime', 'dateJQW', 'datetimeJQW', 'extra', 'gridJQW', 'text',
'editor', 'time', 'note', 'password', 'radio', 'select', 'subrecord', 'upload',
'fieldset', 'pill', 'templateGroup',
'beforeLoad', 'beforeSave', 'beforeInsert', 'beforeUpdate', 'beforeDelete', 'afterLoad',
'afterSave', 'afterInsert', 'afterUpdate', 'afterDelete', 'sendMail', 'paste') NOT NULL DEFAULT 'text',
`subrecordOption` SET('edit', 'delete', 'new') NOT NULL DEFAULT '',
`encode` ENUM('none', 'specialchar') NOT NULL DEFAULT 'specialchar',
'afterSave', 'afterInsert', 'afterUpdate', 'afterDelete', 'sendMail', 'paste') NOT NULL DEFAULT 'text',
`subrecordOption` SET('edit', 'delete', 'new') NOT NULL DEFAULT '',
`encode` ENUM('none', 'specialchar') NOT NULL DEFAULT 'specialchar',
`checkType` ENUM('alnumx', 'digit', 'numerical', 'email', 'min|max', 'min|max date', 'pattern', 'allbut', 'all') NOT NULL DEFAULT 'alnumx',
`checkPattern` VARCHAR(255) NOT NULL DEFAULT '',
`onChange` VARCHAR(255) NOT NULL DEFAULT '',
`ord` INT(11) NOT NULL DEFAULT '0',
`tabindex` INT(11) NOT NULL DEFAULT '0',
`size` VARCHAR(255) NOT NULL DEFAULT '',
`maxLength` VARCHAR(255) NOT NULL DEFAULT '',
`bsLabelColumns` VARCHAR(255) NOT NULL DEFAULT '',
`bsInputColumns` VARCHAR(255) NOT NULL DEFAULT '',
`bsNoteColumns` VARCHAR(255) NOT NULL DEFAULT '',
`rowLabelInputNote` SET('row', 'label', '/label', 'input', '/input', 'note', '/note', '/row') NOT NULL DEFAULT 'row,label,/label,input,/input,note,/note,/row',
`note` TEXT NOT NULL,
`adminNote` TEXT NOT NULL,
`tooltip` VARCHAR(255) NOT NULL DEFAULT '',
`placeholder` VARCHAR(2048) NOT NULL DEFAULT '',
`value` TEXT NOT NULL,
`sql1` TEXT NOT NULL,
`parameter` TEXT NOT NULL,
`clientJs` TEXT NOT NULL,
`feGroup` VARCHAR(255) NOT NULL DEFAULT '',
`deleted` ENUM('yes', 'no') NOT NULL DEFAULT 'no',
`modified` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`created` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
`checkPattern` VARCHAR(255) NOT NULL DEFAULT '',
`onChange` VARCHAR(255) NOT NULL DEFAULT '',
`ord` INT(11) NOT NULL DEFAULT '0',
`tabindex` INT(11) NOT NULL DEFAULT '0',
`size` VARCHAR(255) NOT NULL DEFAULT '',
`maxLength` VARCHAR(255) NOT NULL DEFAULT '',
`bsLabelColumns` VARCHAR(255) NOT NULL DEFAULT '',
`bsInputColumns` VARCHAR(255) NOT NULL DEFAULT '',
`bsNoteColumns` VARCHAR(255) NOT NULL DEFAULT '',
`rowLabelInputNote` SET('row', 'label', '/label', 'input', '/input', 'note', '/note', '/row') NOT NULL DEFAULT 'row,label,/label,input,/input,note,/note,/row',
`note` TEXT NOT NULL,
`adminNote` TEXT NOT NULL,
`tooltip` VARCHAR(255) NOT NULL DEFAULT '',
`placeholder` VARCHAR(2048) NOT NULL DEFAULT '',
`value` TEXT NOT NULL,
`sql1` TEXT NOT NULL,
`parameter` TEXT NOT NULL,
`clientJs` TEXT NOT NULL,
`feGroup` VARCHAR(255) NOT NULL DEFAULT '',
`deleted` ENUM('yes', 'no') NOT NULL DEFAULT 'no',
`modified` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`created` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
KEY `formId` (`formId`),
......@@ -136,7 +136,7 @@ CREATE TABLE IF NOT EXISTS `Dirty` (
`sip` VARCHAR(255) NOT NULL,
`tableName` VARCHAR(255) NOT NULL,
`recordId` INT(11) NOT NULL,
`expire` DATETIME NOT NULL,
`expire` DATETIME NOT NULL,
`recordModified` DATETIME NOT NULL,
`feUser` VARCHAR(255) NOT NULL,
`qfqUserSessionCookie` VARCHAR(255) NOT NULL,
......@@ -214,7 +214,8 @@ VALUES
(1, 'modified', 'Modified', 'readonly', 'text', 'all', 'native', 370, 0, 20, '', '', '', '', '', 3, '', '', '', 'specialchar', 'no', ''),
(1, 'created', 'Created', 'readonly', 'text', 'all', 'native', 380, 0, 20, '', '', '', '', '', 3, '', '', '', 'specialchar', 'no', ''),
(1, 'multi', 'Multi', 'show', 'fieldset', 'all', 'native', 400, 0, 0, '', '', '', '', '', 4, '', '', '', 'specialchar', 'no', ''),
(1, 'multi', 'Multi', 'show', 'fieldset', 'all', 'native', 400, 0, 0, '', '', '', '', '', 4, '', '', '',
'specialchar', 'no', ''),
(1, 'multiMode', 'Multi Mode', 'show', 'radio', 'all', 'native', 410, 0, 0, '', '', '', '', '', 4, '', '', '',
'specialchar', 'no', ''),
(1, 'multiSql', 'Multi SQL', 'show', 'text', 'all', 'native', 420, '40,3', 0, '', '', '', '', '', 4, '', '', '',
......@@ -322,10 +323,10 @@ CREATE TABLE IF NOT EXISTS `MailLog` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`grId` INT(11) NOT NULL DEFAULT '0',
`xId` INT(11) NOT NULL DEFAULT '0',
`receiver` TEXT NOT NULL,
`receiver` TEXT NOT NULL,
`sender` VARCHAR(255) NOT NULL DEFAULT '',
`subject` VARCHAR(255) NOT NULL DEFAULT '',
`body` TEXT NOT NULL,
`body` TEXT NOT NULL,
`header` VARCHAR(255) NOT NULL DEFAULT '',
`attach` VARCHAR(255) NOT NULL DEFAULT '',
`src` VARCHAR(255) NOT NULL DEFAULT '',
......
Supports Markdown
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