Commit 0a92783b authored by Carsten  Rose's avatar Carsten Rose
Browse files

Dirty.php: Add status 'extend'. Add check of 'modified'.

Save.php: replace constant
parent 3bc8982d
......@@ -586,6 +586,7 @@ const API_ELEMENT_ATTRIBUTE = 'attr';
const API_ELEMENT_CONTENT = 'content';
const API_LOCK_ACTION_LOCK = 'lock';
const API_LOCK_ACTION_EXTEND = 'extend';
const API_LOCK_ACTION_RELEASE = 'release';
const API_JSON_HIDDEN = 'hidden';
......@@ -1109,6 +1110,9 @@ const DIRTY_MODE_NONE = 'none';
const DIRTY_QFQ_USER_SESSION_COOKIE = 'qfqUserSessionCookie';
const DIRTY_FE_USER = 'feUser';
const DIRTY_EXPIRE = 'expire';
const DIRTY_TABLE_NAME = 'tableName';
const DIRTY_RECORD_ID = 'recordId';
const DIRTY_RECORD_MODIFIED = 'recordModified';
const DIRTY_REMOTE_ADDRESS = 'remoteAddress';
const DIRTY_API_ACTION = 'action'; // Name of parameter in API call of dirty.php?action=...&s=...
const DIRTY_API_ACTION_LOCK = 'lock';
......
......@@ -121,7 +121,7 @@ class Save {
foreach ($tableColumns AS $column) {
// Never save a predefined 'id': autoincrement values will be given by database..
if ($column === 'id') {
if ($column === COLUMN_ID) {
continue;
}
......
......@@ -76,6 +76,7 @@ class Dirty {
switch ($this->client[API_LOCK_ACTION]) {
case API_LOCK_ACTION_LOCK:
case API_LOCK_ACTION_EXTEND:
$answer = $this->acquireDirty($recordId, $tableVars);
break;
case API_LOCK_ACTION_RELEASE:
......@@ -158,6 +159,11 @@ class Dirty {
$status = API_ANSWER_STATUS_CONFLICT;
$at = "at " . $recordDirty[COLUMN_CREATED] . " from " . $recordDirty[DIRTY_REMOTE_ADDRESS];
// Compare modified timestamp
if(false==$this->checkModified($recordDirty[DIRTY_TABLE_NAME],$recordDirty[DIRTY_RECORD_ID], $recordDirty[DIRTY_RECORD_MODIFIED])){
return [API_STATUS => API_ANSWER_STATUS_CONFLICT, API_MESSAGE => 'The record has been modified in the meantime. Please reload the form, edit and save again.'];
}
if ($this->client[CLIENT_COOKIE_QFQ] == $recordDirty[DIRTY_QFQ_USER_SESSION_COOKIE]) {
$msg = "The record has already been locked by you (maybe in another browser tab) $at!";
$status = ($recordDirty[F_DIRTY_MODE] == DIRTY_MODE_EXCLUSIVE) ? API_ANSWER_STATUS_CONFLICT : API_ANSWER_STATUS_CONFLICT_ALLOW_FORCE;
......@@ -188,7 +194,7 @@ class Dirty {
*
* @param string $s SIP given by URL GET
* @param int $recordId extracted from SIP
* @param array $tableVars
* @param array $tableVars columns: F_TABLE_NAME, F_DIRTY_MODE, F_RECORD_LOCK_TIMEOUT_SECONDS
* @param string $feUser
* @return array
* @throws CodeException
......@@ -199,7 +205,7 @@ class Dirty {
$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.");
$record = $this->db->sql("SELECT * FROM $tableName WHERE id=?", ROW_EXPECT_1, [$recordId], "Record to lock not found.");
// Not all tables does have a modified column.
$recordModified = empty($record[COLUMN_MODIFIED]) ? 0 : $record[COLUMN_MODIFIED];
......@@ -211,11 +217,33 @@ class Dirty {
[$s, $tableName, $recordId, $expire, $recordModified, $feUser, $this->client[CLIENT_COOKIE_QFQ], $formDirtyMode,
$this->client[CLIENT_REMOTE_ADDRESS], date('YmdHis')]);
return [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => 'lock',
return [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => '',
API_LOCK_TIMEOUT => $tableVars[F_RECORD_LOCK_TIMEOUT_SECONDS]];
}
/**
* If exist get the column 'modified' from tableName/recordId and compare with $modified.
*
* @param string $tableName
* @param int $recordId
* @param string $modified - timestamp e.g. '2017-07-27 14:06:56'
* @return bool true if column 'modified' is missing or $modified==record['modified'], else false.
* @throws CodeException
* @throws DbException
*/
private function checkModified($tableName, $recordId, $modified) {
$status = true;
$record = $this->db->sql("SELECT * FROM $tableName WHERE id=?", ROW_EXPECT_1, [$recordId], "Record to lock not found.");
if(isset($record[COLUMN_MODIFIED])) {
$status = ($modified==$record[COLUMN_MODIFIED]) ? true : false;
}
return $status;
}
/**
* 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.
......@@ -249,6 +277,7 @@ class Dirty {
return $answer;
}
// This is pessimistic, but secure.
throw new UserFormException("Missing record lock: please reload the form, edit and save again.");
}
......@@ -262,7 +291,10 @@ class Dirty {
// Is the dirtyRecord mine?
if ($recordDirty[DIRTY_QFQ_USER_SESSION_COOKIE] == $this->client[CLIENT_COOKIE_QFQ]) {
//TODO Check ob der Record seit dem Lock veraendert wurde. Falls ja, eine Meldung und Frage was zu tun ist.
if(false==$this->checkModified($tableName, $recordId, $recordDirty[DIRTY_RECORD_MODIFIED])){
return [API_STATUS => API_ANSWER_STATUS_CONFLICT, API_MESSAGE => 'The record has been modified in the meantime. Please reload the form, edit and save again.'];
}
// Clear the lock
$this->deleteDirtyRecord($recordDirty[COLUMN_ID]);
return $answer;
......
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