* Copyright 2001-2012 Strangecode, LLC
*
* This file is part of The Strangecode Codebase.
*
* The Strangecode Codebase is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* The Strangecode Codebase is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* The Strangecode Codebase. If not, see .
*/
/**
* versions.php
*/
require_once dirname(__FILE__) . '/_config.inc.php';
$app->sslOn();
$auth->requireLogin();
require_once 'codebase/lib/Version.inc.php';
require_once 'codebase/lib/Lock.inc.php';
require_once 'codebase/lib/HTML.inc.php';
/******************************************************************************
* CODE CONFIG
*****************************************************************************/
// Since we're using the singleton pattern we can instantiate a Version object earlier with custom parameters.
$version =& Version::getInstance($auth);
$version->setParam(array(
// If true, makes an exact comparison of saved vs. live table schemas. If false, just checks that the saved columns are available.
'db_schema_strict' => false,
));
// Query arguments to retain their values between page requests.
$app->carryQuery('record_table');
$app->carryQuery('record_key');
$app->carryQuery('record_val');
$app->carryQuery('version_title');
// Titles and navigation header.
$nav->add(_("Versions"), null);
/********************************************************************
* MAIN
********************************************************************/
// Request arguments.
$version_id = getFormData('version_id');
$record_table = getFormData('record_table');
$record_key = getFormData('record_key');
$record_val = getFormData('record_val');
if ('cancel' != getFormData('op') && '' == $version_id && ('' == $record_table || '' == $record_key || '' == $record_val)) {
$app->raiseMsg(_("Record not specified for versioning."), MSG_WARNING, __FILE__, __LINE__);
$app->logMsg('Record not specified for versioning.', LOG_WARNING, __FILE__, __LINE__);
$app->dieBoomerangURL();
}
if (getFormData('boomerang', false) && isset($_SERVER['HTTP_REFERER'])) {
// We remember which page we came from so we can go back there.
$app->setBoomerangURL($_SERVER['HTTP_REFERER'], 'version');
}
// What action to take.
switch (getFormData('op')) {
case 'cancel' :
if ($app->validBoomerangURL('version')) {
// Display boomerang page.
$app->dieBoomerangURL('version');
}
// Display default page.
$app->dieURL(false, false);
break;
case 'view' :
// Bounce the user if they don't have access to the specified version record.
requireAllowVersions($version_id);
$data = $version->getData($version_id);
$versionrecord = $version->getVerson($version_id);
$nav->add(sprintf(_("%s Version %s from %s"), $versionrecord['version_title'], $version_id, date(sprintf('%s %s', $app->getParam('date_format'), $app->getParam('time_format')), strtotime($versionrecord['version_datetime']))));
$main_template = 'versions_view.ihtml';
break;
case 'diff' :
// Bounce the user if they don't have access to the specified version record.
requireAllowVersions($version_id);
$data = $version->getData($version_id);
$versionrecord = $version->getVerson($version_id);
$current = $version->getCurrent($record_table, $record_key, $record_val);
if (serialize($data) == serialize($current)) {
$app->raiseMsg(sprintf(_("Version %s is identical to the current record"), $version_id), MSG_NOTICE, __FILE__, __LINE__);
}
$nav->add(sprintf(_("%s Version %s (%s)"), $versionrecord['version_title'], $version_id, date(sprintf('%s %s', $app->getParam('date_format'), $app->getParam('time_format')), strtotime($versionrecord['version_datetime']))));
$main_template = 'versions_diff.ihtml';
break;
case 'restore' :
// Bounce the user if they don't have access to the specified version record.
requireAllowVersions($version_id);
if (!isset($lock) || !is_a($lock, 'Lock')) {
$lock =& Lock::getInstance($auth);
}
$lock->select($record_table, $record_key, $record_val);
if ($lock->isLocked() && !$lock->isMine()) {
$lock->dieErrorPage();
}
if ($v = $version->restore($version_id)) {
// Create version of this restored record as the "current" version.
$version->create($record_table, $record_key, $record_val, $v['version_title']);
$app->raiseMsg(sprintf(_("The record %s has been replaced with %s version %s from %s."), getFormData('version_title'), $v['version_title'], $version_id, $v['version_datetime']), MSG_SUCCESS, __FILE__, __LINE__);
$app->dieBoomerangURL('version', array('break_list_cache'=>'true', false));
} else {
$app->raiseMsg(_("Version restoration failed."), MSG_ERR, __FILE__, __LINE__);
$app->dieURL($_SERVER['PHP_SELF']);
}
break;
default :
$versions = $version->getList($record_table, $record_key, $record_val);
if (is_array($versions) && !empty($versions)) {
// If they have access to them most recent version, show them the whole list.
// Bounce the user if they don't have access to the first version record in the list.
requireAllowVersions($versions[0]['version_id']);
$_POST['version_title'] = $versions[0]['version_title'];
$nav->add(sprintf(_("%s versions of %s"), sizeof($versions), $versions[0]['version_title']));
$main_template = 'versions_list.ihtml';
} else {
$app->raiseMsg(sprintf(_("No saved versions available"), null), MSG_NOTICE, __FILE__, __LINE__);
$app->dieBoomerangURL('version');
}
}
/******************************************************************************
* TEMPLATE INITIALIZATION
*****************************************************************************/
include 'header.inc.html';
include 'codebase/services/templates/' . $main_template;
include 'footer.inc.html';
/*
* A wrapper for Model::requireAllow(…) that checks the saved version and the current record of the current value.
*
* @access public
* @param
* @return
* @author Quinn Comendant
* @version 1.0
* @since 04 Dec 2014 20:11:39
*/
function requireAllowVersions($version_id)
{
global $auth;
$version =& Version::getInstance($auth);
$data = $version->getData($version_id);
$versionrecord = $version->getVerson($version_id);
$current = $version->getCurrent($versionrecord['record_table'], $versionrecord['record_key'], $versionrecord['record_val']);
// All the data objects which have a model class.
switch ($versionrecord['record_table']) {
case 'trigger_tbl':
case 'response_tbl':
case 'participant_tbl':
case 'question_tbl':
case 'survey_tbl':
case 'user_tbl':
case 'payment_tbl':
case 'account_tbl':
case 'question_tbl':
$model_class = ucfirst(str_replace('_tbl', '', $versionrecord['record_table']));
// This will check access to the **current** object (useful if the requested version was moved to another account) as well as access to the **requested** object version. This will fail when requesting old objects if the current object was moved to a different account.
$model_class::requireAllow('read', array_merge(array($data), array($current)));
// Or… less strict: this will check access only to the current object, but will fail if the current object was deleted, thus allowing access to the versioned record (danger).
// $model_class::requireAllow('read', $model_class::get(array($versionrecord['record_key'], $versionrecord['record_val'])));
break;
default:
// FIXME: Allow access by default to other data?
break;
}
}