* 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; } }