<?php
/*
+---------------------------------------------------------------------------+
| OpenX v2.4                                                                |
| ==========                                                                |
|                                                                           |
| Copyright (c) 2003-2008 OpenX Limited                                     |
| For contact details, see: http://www.openx.org/                           |
|                                                                           |
| This program 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 2 of the License, or         |
| (at your option) any later version.                                       |
|                                                                           |
| This program 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 this program; if not, write to the Free Software               |
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA |
+---------------------------------------------------------------------------+
/**
 * OpenX Schema Management Utility
 *
 * @author     Monique Szpak <monique.szpak@openx.org>
 *
 * $Id: UpgradeAuditor.php 21461 2008-06-18 10:39:50Z david.keen@openx.org $
 *
 */

define('UPGRADE_ACTION_UPGRADE_SUCCEEDED',                      1);
define('UPGRADE_ACTION_UPGRADE_FAILED',                         0);

define('UPGRADE_ACTION_ROLLBACK_SUCCEEDED',                     2);
define('UPGRADE_ACTION_ROLLBACK_FAILED',                        3);


require_once MAX_PATH.'/lib/OA/DB.php';
require_once MAX_PATH.'/lib/OA/DB/Table.php';
require_once(MAX_PATH.'/lib/OA/Upgrade/DB_UpgradeAuditor.php');
require_once MAX_PATH.'/lib/OA/Upgrade/BaseUpgradeAuditor.php';

class OA_UpgradeAuditor extends OA_BaseUpgradeAuditor
{
    var $oLogger;
    var $oDbh;
    var $oDBAuditor;

    var $logTable   = 'upgrade_action';
    var $action_table_xml_filename   = '/etc/upgrade_action.xml';

    var $prefix = '';

    var $aParams = array();

    var $aEvents = array();

    /**
     * php5 class constructor
     *
     * simpletest throws a BadGroupTest error
     * Redefining already defined constructor for class
     * when both constructors are present
     *
     */
//    function __construct()
//    {
//    }

    /**
     * php4 class constructor
     *
     */
    function OA_UpgradeAuditor()
    {
    	$this->OA_BaseUpgradeAuditor();
    }

    function init(&$oDbh, $oLogger='')
    {
        $this->oDbh = $oDbh;
        $this->prefix = $GLOBALS['_MAX']['CONF']['table']['prefix'];
        // so that this class can log to the caller's log
        // and write it's own log if necessary (testing)
        if ($oLogger)
        {
            $this->oLogger= $oLogger;
        }
        $this->oDBAuditor = new OA_DB_UpgradeAuditor();
        $this->oDBAuditor->init($this->oDbh, $this->oLogger);
        return $this->_checkCreateAuditTable();
    }


    function getNextUpgradeActionId()
    {
        $aAuditTableStatus = $this->oDBAuditor->getTableStatus($this->logTable);
        if ((!is_array($aAuditTableStatus) || (count($aAuditTableStatus)<1)) || (!isset($aAuditTableStatus[0]['auto_increment'])))
        {
            return false;
        }
        return $aAuditTableStatus[0]['auto_increment'];
    }

    function setUpgradeActionId()
    {
        $this->oDBAuditor->auditId = $this->getNextUpgradeActionId();
    }

    function getUpgradeActionId()
    {
        return $this->oDBAuditor->auditId;
    }

    /**
     * write a message to the logfile
     *
     * @param string $message
     */
    function log($message)
    {
        if ($this->oLogger)
        {
            $this->oLogger->log($message);
        }
    }

    /**
     * write an error to the log file
     *
     * @param string $message
     */
    function logError($message)
    {
        if ($this->oLogger)
        {
            $this->oLogger->logError($message);
        }
    }

    function isPearError($message)
    {
        if ($this->oLogger)
        {
            return $this->oLogger->isPearError($message);
        }
        return false;
    }

    /**
     * return all columns from upgrade_action table for given upgrade_action_id
     *
     * @param integer $id
     * @return array
     */
    function queryAuditByUpgradeId($id)
    {
        $query = "SELECT * FROM {$this->prefix}{$this->logTable} WHERE upgrade_action_id = {$id}";
        $aResult = $this->oDbh->queryAll($query);
        if ($this->isPearError($aResult, "error querying database audit table"))
        {
            return array();
        }
        return $aResult;
    }

    /**
     * return all columns from database_action table for given upgrade_action_id
     *
     * @param integer $id
     * @return array
     */
    function queryAuditArtifactsByUpgradeId($id)
    {
        $aResult = $this->oDBAuditor->queryAuditByUpgradeId($id);
        if ($this->isPearError($aResult, "error querying upgrade audit table"))
        {
            return false;
        }
        return $aResult;
    }

    /**
     * main backup tables query method
     *
     * @param integer $id
     * @return array
     */
    function queryAuditBackupTablesByUpgradeId($id)
    {
        $aResult = $this->oDBAuditor->queryAuditBackupTablesByUpgradeId($id);
        if ($this->isPearError($aResult, "error querying upgrade audit table"))
        {
            return false;
        }
        $aResult = $this->getBackupTableStatus($aResult);
        return $aResult;
    }

    /**
     * get list of tables that were added for an upgrade_action_id
     *
     * @param integer $id
     * @return array
     */
    function queryAuditAddedTablesByUpgradeId($id)
    {
        $aResult = $this->oDBAuditor->queryAuditAddedTablesByUpgradeId($id);
        if ($this->isPearError($aResult, "error querying upgrade audit table"))
        {
            return false;
        }
        return $aResult;
    }

    /**
     * used by queryAuditBackupTablesByUpgradeId(0
     *
     * @param array $aTables
     * @return array
     */
    function getBackupTableStatus($aTables)
    {
        foreach ($aTables AS $k => $aRec)
        {
            $aStatus = $this->oDBAuditor->getTableStatus($aRec['tablename_backup']);
            $aTables[$k]['backup_size']   = $aStatus[0]['data_length']/1024;
            $aTables[$k]['backup_rows']   = $aStatus[0]['rows'];
        }
        return $aTables;
    }

    /**
     * main audit query method
     * return all columns from the upgrade_action table
     * along with a count of the backup table artifacts for each upgrade_action_id
     *
     * @return array
     */
    function queryAuditAllDescending()
    {
        $query = "SELECT u.*, COUNT(d.upgrade_action_id) AS backups"
                 ." FROM {$this->prefix}{$this->logTable} AS u"
                ." LEFT JOIN {$this->prefix}{$this->oDBAuditor->logTable} AS d ON u.upgrade_action_id = d.upgrade_action_id"
                ." AND d.action=30 AND d.info2 IS NULL"
                ." GROUP BY u.upgrade_action_id"
                ." ORDER BY u.upgrade_action_id DESC";

        $aResult = $this->oDbh->queryAll($query);
        if ($this->isPearError($aResult, "error querying upgrade audit table"))
        {
            return false;
        }
        return $aResult;
    }

    /**
     * drops all backup artifacts for given upgrade_id
     * logs a reason
     *
     * @param integer $upgrade_id
     * @param string $reason
     * @return boolean
     */
    function cleanAuditArtifacts($upgrade_id, $reason = 'cleaned')
    {
        $aResult = $this->queryAuditByUpgradeId($upgrade_id);
        $aResultDB = $this->queryAuditBackupTablesByUpgradeId($upgrade_id);

        foreach ($aResultDB AS $k => $aTable)
        {
            $result = $this->oDbh->manager->dropTable($this->prefix.$aTable['tablename_backup']);
            if ($this->isPearError($result,'error dropping backup table'))
            {
                return false;
            }
            $this->oDBAuditor->updateAuditBackupDroppedById($aTable['database_action_id'],'cleaned by user');
        }

        foreach ($aResult AS $k => $aRec)
        {
            if ($aRec['logfile'] && file_exists(MAX_PATH.'/var/'.$aRec['logfile']))
            {
                if (!@unlink(MAX_PATH.'/var/'.$aRec['logfile']))
                {
                    return false;
                }
                $this->updateAuditBackupLogDroppedById($upgrade_id, 'cleaned by user');
            }
            else
            {
                $this->updateAuditBackupLogDroppedById($upgrade_id, 'file not found');
            }
            if ($aRec['confbackup'] && file_exists(MAX_PATH.'/var/'.$aRec['confbackup']))
            {
                if (!@unlink(MAX_PATH.'/var/'.$aRec['confbackup']))
                {
                    return false;
                }
                $this->updateAuditBackupConfDroppedById($upgrade_id, 'cleaned by user');
            }
            else
            {
                $this->updateAuditBackupConfDroppedById($upgrade_id, 'file not found');
            }
        }

        return true;
    }

    /**
     * replace the backup conf column with reason for deletion
     *
     * @param integer $upgrade_action_id
     * @param string $reason
     * @return boolean
     */
    function updateAuditBackupConfDroppedById($upgrade_action_id, $reason = 'dropped')
    {
        $query = "UPDATE {$this->prefix}{$this->logTable} SET confbackup='{$reason}' WHERE upgrade_action_id='{$upgrade_action_id}'";

        $result = $this->oDbh->exec($query);

        if ($this->isPearError($result, "error updating {$this->prefix}{$this->logTables}"))
        {
            return false;
        }
        return true;
    }

    /**
     * replace the logfile column with reason for deletion
     *
     * @param integer $upgrade_action_id
     * @param string $reason
     * @return boolean
     */
     function updateAuditBackupLogDroppedById($upgrade_action_id, $reason = 'dropped')
    {
        $query = "UPDATE {$this->prefix}{$this->logTable} SET logfile='{$reason}' WHERE upgrade_action_id='{$upgrade_action_id}'";

        $result = $this->oDbh->exec($query);

        if ($this->isPearError($result, "error updating {$this->prefix}{$this->logTables}"))
        {
            return false;
        }
        return true;
    }

}

?>