Skip to content

Commit

Permalink
Add checks that session management doesn't overlap
Browse files Browse the repository at this point in the history
  • Loading branch information
birtles committed Mar 13, 2013
1 parent e9ec6e6 commit 26d229f
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 41 deletions.
64 changes: 51 additions & 13 deletions wall/lib/walls.inc
Expand Up @@ -296,35 +296,71 @@ function getWallIdFromPath($path) {
return $res;
}

function startNewSession($wallId, $datetime) {
function startNewSession($wallId, $sessionId, $datetime) {
// Sanitize input
$wallId = toId($wallId);
$sessionId = toId($sessionId);

// Work out the latest session and if it needs closing
$latestSession = getLatestSession($wallId);

// Is the passed-in session ID correct?
if (@$latestSession['id'] !== $sessionId) {
return false;
}

// Close the latest session if it's open
if (@$latestSession['endDate'] !== null) {
closeLastSession($wallId, $sessionId, $datetime);
}

// Start a new session
$conn =& getDbConnection();
$qwallid = $conn->quote($wallId, 'integer');
$qdatetime = $conn->quote($datetime, 'timestamp');
$query = 'INSERT INTO sessions(wallId,beginDate) VALUES('.$wallId.','.$qdatetime.')';
$res =& $conn->query($query);
$query = 'INSERT INTO sessions(wallId, beginDate)'
. ' VALUES(' . $conn->quote($wallId, 'integer')
. ',' . $conn->quote($datetime, 'timestamp')
. ')';
$res =& $conn->exec($query);
if (PEAR::isError($res)) {
error_log($res->getMessage() . ', ' . $res->getDebugInfo());
throw new KeyedException('db-error');
}
$conn->disconnect();

return true;
}

function closeLastSession($wallId, $datetime) {
function closeLastSession($wallId, $sessionId, $datetime) {
// Sanitize input
$wallId = toId($wallId);
$sessionId = toId($sessionId);

// Check if the passed in sessionID actually matches the latest session (and
// that session is not already closed)
if ($sessionId !== getActiveSessionId($wallId)) {
return false;
}

// Close session
$conn =& getDbConnection();
$qwallid = $conn->quote($wallId, 'integer');
$qdatetime = $conn->quote($datetime, 'timestamp');
//makes temp table for (You can't specify target table 'sessions' for update in FROM clause)
$query = 'UPDATE sessions SET endDate='.$qdatetime.' WHERE endDate IS NULL AND wallId='.$qwallid.' AND sessionId=(SELECT temp.sessionId FROM (SELECT MAX(sessionId) AS sessionID FROM sessions WHERE wallId='.$qwallid.') AS temp)';
$query = 'UPDATE sessions'
. ' SET endDate=' . $conn->quote($datetime, 'timestamp')
. ' WHERE sessionId=' . $conn->quote($sessionId, 'integer');
$res =& $conn->exec($query);
if (PEAR::isError($res)) {
error_log($res->getMessage() . ', ' . $res->getDebugInfo());
throw new KeyedException('db-error');
}

$conn->disconnect();

// Return true if we made some change, false if the session was already closed
return $res > 0;
// Return true since we made a change
return true;
}

function toId($idLike) {
return is_null($idLike) ? null : intval($idLike);
}

// Returns NULL if there is no active session for the wall
Expand All @@ -336,7 +372,7 @@ function getActiveSessionId($wallId) {
$res =& $conn->queryOne(
'SELECT sessionId FROM sessions WHERE'
. ' wallId = ' . $conn->quote($wallId, 'integer')
. ' AND beginDate < ' . $qdate
. ' AND beginDate <= ' . $qdate
. ' AND (endDate IS NULL OR endDate > ' . $qdate . ')',
'integer');
if (PEAR::isError($res)) {
Expand All @@ -361,8 +397,10 @@ function getLatestSession($wallId) {
error_log($row->getMessage() . ', ' . $row->getDebugInfo());
throw new KeyedException('db-error');
}
if (!$row)
return null;
return array(
'id' => $row['sessionid'],
'id' => intval($row['sessionid']),
'start' => $row['begindate'],
'end' => $row['enddate'],
);
Expand Down
24 changes: 18 additions & 6 deletions wall/public/wall-maker/api/closeSession.php
Expand Up @@ -23,15 +23,27 @@
fclose($handle);

// Prepare parameters
$wallId = @$json['wallId'];
if (!isset($wallId)) {
bailWithError('logged-out');
$wallId = @$json['wallId'];
$sessionId = @$json['sessionId'];
if (!isset($wallId) || !isset($sessionId)) {
bailWithError('bad-request');
}

// Close session
$currentdatetime = gmdate("Y-m-d H:i:s");
if (!closeLastSession($wallId, $currentdatetime))
bailWithError('already-closed');
$madeChange = closeLastSession($wallId, $sessionId, $currentdatetime);

// Return the result
print json_encode(getLatestSession($wallId));
// - If we made a change then return the latest session.
// - Otherwise return a parallel-change notification with the latest session in
// the detail.
$latestSession = getLatestSession($wallId);
if ($madeChange) {
print json_encode($latestSession);
} else {
$result['error_key'] = 'parallel-change';
$result['error_detail'] = $latestSession;
print json_encode($result);
}

?>
2 changes: 1 addition & 1 deletion wall/public/wall-maker/api/createWall.php
Expand Up @@ -34,7 +34,7 @@
$result = array('wallId' => $wallId);
// start session
$currentdatetime = gmdate("Y-m-d H:i:s");
startNewSession($wallId, $currentdatetime);
startNewSession($wallId, null, $currentdatetime);

// Return the result
print json_encode($result);
Expand Down
23 changes: 17 additions & 6 deletions wall/public/wall-maker/api/startSession.php
Expand Up @@ -23,15 +23,26 @@
fclose($handle);

// Prepare parameters
$wallId = @$json['wallId'];
if (!isset($wallId)) {
bailWithError('logged-out');
$wallId = @$json['wallId'];
$sessionId = @$json['sessionId'];
if (!isset($wallId) || !isset($sessionId)) {
bailWithError('bad-request');
}

// Start new session
$currentdatetime = gmdate("Y-m-d H:i:s");
closeLastSession($wallId, $currentdatetime);
startNewSession($wallId, $currentdatetime);
$madeChange = startNewSession($wallId, $sessionId, $currentdatetime);

// Return the result
print json_encode(getLatestSession($wallId));
// - If we made a change then return the latest session.
// - Otherwise return a parallel-change notification with the latest session in
// the detail.
$latestSession = getLatestSession($wallId);
if ($madeChange) {
print json_encode($latestSession);
} else {
$result['error_key'] = 'parallel-change';
$result['error_detail'] = $latestSession;
print json_encode($result);
}
?>
12 changes: 12 additions & 0 deletions wall/tests/api/ParaparaTestCase.php
Expand Up @@ -21,6 +21,10 @@ abstract class ParaparaTestCase extends WebTestCase {
// Database connection singleton
static private $conn = null;

// An instance of SimpleTestCase so we can re-use its methods
// (Why WebTestCase doesn't inherit from UnitTestCase is beyond me.)
static protected $unitTestCase = null;

// Path to designs folder
protected $designsPath;

Expand All @@ -29,6 +33,9 @@ function __construct($name = false) {
if (self::$conn === null) {
self::initDb();
}
if (self::$unitTestCase === null) {
self::$unitTestCase = new UnitTestCase();
}
$this->designsPath = dirname(__FILE__) . '/../../public/designs/';
}

Expand Down Expand Up @@ -99,6 +106,11 @@ public static function isNotEmpty($str) {
return trim($str) != '';
}

public function assertEqual($first, $second, $message = '%s') {
self::$unitTestCase->reporter = $this->reporter;
return self::$unitTestCase->assertEqual($first, $second, $message);
}

public function getConnection() {
return self::$conn;
}
Expand Down

0 comments on commit 26d229f

Please sign in to comment.