Commit 27d63c2e authored by skummer's avatar skummer

ZP-308 #time 10h

#comment lowercased all device ids
- added tools directory
- created migration script for z-push-2.0 to 2.1 (lowering all device ids in the states)
- changed IStateMachine interface to get and set state versions
- defined two state versions (for 2.0 and 2.1 M1)
- implemented state versions getter and setter into FileStateMachine
- ZPush::GetStateMachine() checks for correct state versions and throws HTTPReturnCodeException otherwise
- ZPush::GetLatestStateVersion() indicates the latest version of the states implemented
- changed Request to always lowercase the device ID
- changed z-push-admin to always lowercase the entered device ID

git-svn-id: https://z-push.org/svn/z-push/trunk@1613 b7dd7b3b-3a3c-0410-9da9-bee62a6cc5b5
parent 027deb85
......@@ -97,6 +97,9 @@ class ZPush {
// Webservice commands
const COMMAND_WEBSERVICE_DEVICE = -100;
// Latest supported State version
const STATE_VERSION = IStateMachine::STATEVERSION_02;
static private $autoloadBackendPreference = array(
"BackendZarafa",
"BackendCombined",
......@@ -315,8 +318,9 @@ class ZPush {
* which has to be an IStateMachine implementation
*
* @access public
* @return object implementation of IStateMachine
* @throws FatalNotImplementedException
* @throws HTTPReturnCodeException
* @return object implementation of IStateMachine
*/
static public function GetStateMachine() {
if (!isset(ZPush::$stateMachine)) {
......@@ -336,10 +340,25 @@ class ZPush {
include_once('lib/default/filestatemachine.php');
ZPush::$stateMachine = new FileStateMachine();
}
if (ZPush::$stateMachine->GetStateVersion() !== ZPush::GetLatestStateVersion()) {
if (class_exists("TopCollector")) self::GetTopCollector()->AnnounceInformation("Run migration script!", true);
throw new HTTPReturnCodeException(sprintf("The state version available to the %s is not the latest version - please run the state upgrade script. See release notes for more information.", get_class(ZPush::$stateMachine), 503));
}
}
return ZPush::$stateMachine;
}
/**
* Returns the latest version of supported states
*
* @access public
* @return int
*/
static public function GetLatestStateVersion() {
return self::STATE_VERSION;
}
/**
* Returns the DeviceManager object
*
......
......@@ -46,7 +46,10 @@
************************************************/
class FileStateMachine implements IStateMachine {
const VERSION = "version";
private $userfilename;
private $settingsfilename;
/**
* Constructor
......@@ -68,6 +71,7 @@ class FileStateMachine implements IStateMachine {
// checks if the directory exists and tries to create the necessary subfolders if they do not exist
$this->getDirectoryForDevice(Request::GetDeviceID());
$this->userfilename = STATE_DIR . 'users';
$this->settingsfilename = STATE_DIR . 'settings';
if (!touch($this->userfilename))
throw new FatalMisconfigurationException("Not possible to write to the configured state directory.");
......@@ -318,6 +322,39 @@ class FileStateMachine implements IStateMachine {
}
}
/**
* Returns the current version of the state files
*
* @access public
* @return int
*/
public function GetStateVersion() {
if (file_exists($this->settingsfilename))
$settings = unserialize(file_get_contents($this->settingsfilename));
else
$settings = array(self::VERSION => IStateMachine::STATEVERSION_01);
return $settings[self::VERSION];
}
/**
* Sets the current version of the state files
*
* @param int $version the new supported version
*
* @access public
* @return boolean
*/
public function SetStateVersion($version) {
if (file_exists($this->settingsfilename))
$settings = file_get_contents($this->settingsfilename);
else
array(self::VERSION => IStateMachine::STATEVERSION_01);
$settings[self::VERSION] = $version;
return file_put_contents($this->settingsfilename, serialize($settings));
}
/**----------------------------------------------------------------------------------------------------------
* Private FileStateMachine stuff
......
......@@ -61,6 +61,9 @@ interface IStateMachine {
const HIERARCHY = "hc";
const BACKENDSTORAGE = "bs";
const STATEVERSION_01 = "1"; // Z-Push 2.0.x - default value if unset
const STATEVERSION_02 = "2"; // Z-Push 2.1.0 Milestone 1
/**
* Constructor
* @throws FatalMisconfigurationException
......@@ -163,6 +166,24 @@ interface IStateMachine {
* @return array
*/
public function GetAllDevices($username = false);
/**
* Returns the current version of the state files
*
* @access public
* @return int
*/
public function GetStateVersion();
/**
* Sets the current version of the state files
*
* @param int $version the new supported version
*
* @access public
* @return boolean
*/
public function SetStateVersion($version);
}
?>
\ No newline at end of file
......@@ -116,7 +116,7 @@ class Request {
if(isset($_GET["User"]))
self::$getUser = strtolower($_GET["User"]);
if(isset($_GET["DeviceId"]))
self::$devid = self::filterEvilInput($_GET["DeviceId"], self::WORDCHAR_ONLY);
self::$devid = strtolower(self::filterEvilInput($_GET["DeviceId"], self::WORDCHAR_ONLY));
if(isset($_GET["DeviceType"]))
self::$devtype = self::filterEvilInput($_GET["DeviceType"], self::LETTERS_ONLY);
if (isset($_GET["AttachmentName"]))
......@@ -144,7 +144,7 @@ class Request {
self::$getUser = strtolower($query[self::COMMANDPARAM_USER]);
if (!isset(self::$devid) && isset($query['DevID']))
self::$devid = self::filterEvilInput($query['DevID'], self::WORDCHAR_ONLY);
self::$devid = strtolower(self::filterEvilInput($query['DevID'], self::WORDCHAR_ONLY));
if (!isset(self::$devtype) && isset($query['DevType']))
self::$devtype = self::filterEvilInput($query['DevType'], self::LETTERS_ONLY);
......
......@@ -203,9 +203,9 @@ class ZPushAdminCLI {
// get 'device'
if (isset($options['d']) && !empty($options['d']))
self::$device = trim($options['d']);
self::$device = strtolower(trim($options['d']));
else if (isset($options['device']) && !empty($options['device']))
self::$device = trim($options['device']);
self::$device = strtolower(trim($options['device']));
// get 'action'
$action = false;
......@@ -582,7 +582,7 @@ class ZPushAdminCLI {
if ($device->GetDevicePhoneNumber())
echo "Device Phone nr:\t". $device->GetDevicePhoneNumber(). "\n";
if ($device->GetDeviceMobileOperator())
echo "Device Operator:\t\t". $device->GetDeviceMobileOperator(). "\n";
echo "Device Operator:\t". $device->GetDeviceMobileOperator(). "\n";
if ($device->GetDeviceEnableOutboundSMS())
echo "Device Outbound SMS:\t". $device->GetDeviceEnableOutboundSMS(). "\n";
......
#!/usr/bin/php
<?php
/***********************************************
* File : migrate-2.0.x-2.1.0.php
* Project : Z-Push - tools
* Descr : Convertes states from
* Z-Push 2.0.x to Z-Push 2.1.0
*
* Created : 30.11.2012
*
* Copyright 2007 - 2012 Zarafa Deutschland GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation with the following additional
* term according to sec. 7:
*
* According to sec. 7 of the GNU Affero General Public License, version 3,
* the terms of the AGPL are supplemented with the following terms:
*
* "Zarafa" is a registered trademark of Zarafa B.V.
* "Z-Push" is a registered trademark of Zarafa Deutschland GmbH
* The licensing of the Program under the AGPL does not imply a trademark license.
* Therefore any rights, title and interest in our trademarks remain entirely with us.
*
* However, if you propagate an unmodified version of the Program you are
* allowed to use the term "Z-Push" to indicate that you distribute the Program.
* Furthermore you may use our trademarks where it is necessary to indicate
* the intended purpose of a product or service provided you use it in accordance
* with honest practices in industrial or commercial matters.
* If you want to propagate modified versions of the Program under the name "Z-Push",
* you may only do so if you have a written permission by Zarafa Deutschland GmbH
* (to acquire a permission please contact Zarafa at trademark@zarafa.com).
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Consult LICENSE file for details
************************************************/
// Please adjust to match your z-push installation directory, usually /usr/share/z-push
define('ZPUSH_BASE_PATH', "../src");
/************************************************
* MAIN
*/
try {
if (!defined('ZPUSH_BASE_PATH') || !file_exists(ZPUSH_BASE_PATH . "/config.php"))
die("ZPUSH_BASE_PATH not set correctly or no config.php file found\n");
define('BASE_PATH_CLI', ZPUSH_BASE_PATH ."/");
set_include_path(get_include_path() . PATH_SEPARATOR . ZPUSH_BASE_PATH);
include('lib/core/zpushdefs.php');
include('lib/core/zpush.php');
include('lib/core/zlog.php');
include('lib/core/statemanager.php');
include('lib/core/stateobject.php');
include('lib/core/asdevice.php');
include('lib/core/interprocessdata.php');
include('lib/exceptions/exceptions.php');
include('lib/utils/utils.php');
include('lib/request/request.php');
include('lib/request/requestprocessor.php');
include('lib/interface/ibackend.php');
include('lib/interface/ichanges.php');
include('lib/interface/iexportchanges.php');
include('lib/interface/iimportchanges.php');
include('lib/interface/isearchprovider.php');
include('lib/interface/istatemachine.php');
include('config.php');
ZPush::CheckConfig();
$migrate = new StateMigrator20xto210();
if (!$migrate->MigrationNecessary())
die("No migration necessary. Aborting!\n");
$migrate->DoMigration();
}
catch (ZPushException $zpe) {
die(get_class($zpe) . ": ". $zpe->getMessage() . "\n");
}
echo "terminated\n";
class StateMigrator20xto210 {
const FROMVERSION = "1"; // IStateMachine::STATEVERSION_01
const TOVERSION = "2"; // IStateMachine::STATEVERSION_02
private $sm;
/**
* Constructor
*/
public function StateMigrator20xto210() {
$this->sm = false;
}
/**
* Checks if the migration is necessary
*
* @access public
* @throws FatalMisconfigurationException
* @throws FatalNotImplementedException
* @return boolean
*/
public function MigrationNecessary() {
try {
$this->sm = ZPush::GetStateMachine();
}
catch (HTTPReturnCodeException $e) {
echo "Check states: states versions do not match and need to be migrated\n\n";
// we just try to get the statemachine again
// the exception is only thrown the first time
$this->sm = ZPush::GetStateMachine();
}
if (!$this->sm)
throw new FatalMisconfigurationException("Could not get StateMachine from ZPush::GetStateMachine()");
if (!($this->sm instanceof FileStateMachine)) {
throw new FatalNotImplementedException("This conversion script is only able to convert states of the FileStateMachine");
}
if ($this->sm->GetStateVersion() == ZPush::GetLatestStateVersion())
return false;
if ($this->sm->GetStateVersion() !== self::FROMVERSION || ZPush::GetLatestStateVersion() !== self::TOVERSION)
throw new FatalNotImplementedException(sprintf("This script only converts from state version %d to %d. Currently the system is on %d and should go to %d. Please contact support.", self::FROMVERSION, self::TOVERSION, $this->sm->GetStateVersion(), ZPush::GetLatestStateVersion()));
// do migration
return true;
}
/**
* Execute the migration
*
* @access public
* @return true
*/
public function DoMigration() {
// go through all files
$files = glob(STATE_DIR. "/*/*/*", GLOB_NOSORT);
$filetotal = count($files);
$filecount = 0;
$rencount = 0;
$igncount = 0;
foreach ($files as $file) {
$filecount++;
$newfile = strtolower($file);
echo "\033[1G";
if ($file !== $newfile) {
$rencount++;
rename ($file, $newfile);
}
else
$igncount++;
printf("Migrating file %d/%d\t%s", $filecount, $filetotal, $file);
}
echo "\033[1G". sprintf("Migrated total of %d files, %d renamed and %d ignored (as already correct)%s\n\n", $filetotal, $rencount, $igncount, str_repeat(" ", 50));
// get all states of synchronized devices
$alldevices = $this->sm->GetAllDevices(false);
foreach ($alldevices as $devid) {
$lowerDevid = strtolower($devid);
echo "Processing device: ". $devid . "\t";
// update device data
$devState = ZPush::GetStateMachine()->GetState($lowerDevid, IStateMachine::DEVICEDATA);
$newdata = array();
foreach ($devState->devices as $user => $dev) {
if (!isset($dev->deviceidOrg))
$dev->deviceidOrg = $dev->deviceid;
$dev->deviceid = strtolower($dev->deviceid);
$dev->useragenthistory = array();
$newdata[$user] = $dev;
}
$devState->devices = $newdata;
$this->sm->SetState($devState, $lowerDevid, IStateMachine::DEVICEDATA);
// go through the users again: device was updated sucessfully, now we change the global user <-> device link
foreach ($devState->devices as $user => $dev) {
printf("\n\tUn-linking %s with old device id %s", $user, $dev->deviceidOrg);
$this->sm->UnLinkUserDevice($user, $dev->deviceidOrg);
printf("\n\tRe-linking %s with new device id %s", $user, $dev->deviceid);
$this->sm->LinkUserDevice($user, $dev->deviceid);
}
echo "\n\tcompleted\n";
}
echo "\nSetting new StateVersion\n";
$this->sm->SetStateVersion(self::TOVERSION);
echo "Migration completed!\n\n";
return true;
}
}
?>
\ No newline at end of file
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