Commit 144357c1 authored by Sebastian Kummer's avatar Sebastian Kummer

ZP-735 Add option to resync only the hierarchy of a specific user,

device or all. 
When forcing resync, delete first all states of synchronized folders and
afterwards the hierarchy, so the necessary information is still
available.
Reset contentData & ignoredMessages of the device ONLY when removing the
hierarchy synckey, not when setting a new one.

Released under the Affero GNU General Public License (AGPL) version 3.
parent a97725a4
...@@ -542,7 +542,7 @@ class ASDevice extends StateObject { ...@@ -542,7 +542,7 @@ class ASDevice extends StateObject {
if ($folderid === false) { if ($folderid === false) {
$this->hierarchyUuid = $uuid; $this->hierarchyUuid = $uuid;
// when unsetting the hierarchycache, also remove saved contentdata and ignoredmessages // when unsetting the hierarchycache, also remove saved contentdata and ignoredmessages
if ($folderid === false) { if ($folderid === false && $uuid === false) {
$this->contentData = array(); $this->contentData = array();
$this->ignoredMessageIds = array(); $this->ignoredMessageIds = array();
$this->ignoredMessages = array(); $this->ignoredMessages = array();
......
...@@ -557,13 +557,13 @@ class DeviceManager { ...@@ -557,13 +557,13 @@ class DeviceManager {
public function ForceFullResync() { public function ForceFullResync() {
ZLog::Write(LOGLEVEL_INFO, "Full device resync requested"); ZLog::Write(LOGLEVEL_INFO, "Full device resync requested");
// delete hierarchy states
StateManager::UnLinkState($this->device, false);
// delete all other uuids // delete all other uuids
foreach ($this->device->GetAllFolderIds() as $folderid) foreach ($this->device->GetAllFolderIds() as $folderid)
$uuid = StateManager::UnLinkState($this->device, $folderid); $uuid = StateManager::UnLinkState($this->device, $folderid);
// delete hierarchy states
StateManager::UnLinkState($this->device, false);
return true; return true;
} }
...@@ -748,7 +748,7 @@ class DeviceManager { ...@@ -748,7 +748,7 @@ class DeviceManager {
} }
/** /**
* Returns the User Agent. This data is consolidated with data from Request::GetUserAgent() * Returns the User Agent. This data is consolidated with data from Request::GetUserAgent()
* and the data saved in the ASDevice. * and the data saved in the ASDevice.
* *
* @access public * @access public
......
...@@ -429,6 +429,38 @@ class ZPushAdmin { ...@@ -429,6 +429,38 @@ class ZPushAdmin {
return true; return true;
} }
/**
* Removes the hierarchydata of a device of a user so it will be re-synchronizated.
*
* @param string $user user of the device
* @param string $devid device id which should be wiped
*
* @return boolean
* @access public
*/
static public function ResyncHierarchy($user, $devid) {
// load device data
$device = new ASDevice($devid, ASDevice::UNDEFINED, $user, ASDevice::UNDEFINED);
try {
$device->SetData(ZPush::GetStateMachine()->GetState($devid, IStateMachine::DEVICEDATA), false);
if ($device->IsNewDevice()) {
ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::ResyncHierarchy(): data of user '%s' not synchronized on device '%s'. Aborting.",$user, $devid));
return false;
}
// remove hierarchcache, but don't update the device, as the folder states are invalidated
StateManager::UnLinkState($device, false, false);
ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::ResyncHierarchy(): deleted hierarchy states of device '%s' of user '%s'", $devid, $user));
}
catch (StateNotFoundException $e) {
ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::ResyncHierarchy(): state for device '%s' of user '%s' can not be found or saved", $devid, $user));
return false;
}
return true;
}
/** /**
* Clears loop detection data * Clears loop detection data
* *
......
...@@ -140,12 +140,14 @@ class ZPushAdminCLI { ...@@ -140,12 +140,14 @@ class ZPushAdminCLI {
const COMMAND_SHOWLASTSYNC = 8; const COMMAND_SHOWLASTSYNC = 8;
const COMMAND_RESYNCFOLDER = 9; const COMMAND_RESYNCFOLDER = 9;
const COMMAND_FIXSTATES = 10; const COMMAND_FIXSTATES = 10;
const COMMAND_RESYNCHIERARCHY = 11;
const TYPE_OPTION_EMAIL = "email"; const TYPE_OPTION_EMAIL = "email";
const TYPE_OPTION_CALENDAR = "calendar"; const TYPE_OPTION_CALENDAR = "calendar";
const TYPE_OPTION_CONTACT = "contact"; const TYPE_OPTION_CONTACT = "contact";
const TYPE_OPTION_TASK = "task"; const TYPE_OPTION_TASK = "task";
const TYPE_OPTION_NOTE = "note"; const TYPE_OPTION_NOTE = "note";
const TYPE_OPTION_HIERARCHY = "hierarchy";
static private $command; static private $command;
static private $user = false; static private $user = false;
...@@ -179,6 +181,7 @@ class ZPushAdminCLI { ...@@ -179,6 +181,7 @@ class ZPushAdminCLI {
"\tresync -t TYPE -u USER \t\t Resynchronizes all folders of type $types for the user USER.\n" . "\tresync -t TYPE -u USER \t\t Resynchronizes all folders of type $types for the user USER.\n" .
"\tresync -t TYPE -u USER -d DEVICE Resynchronizes all folders of type $types for a specified device and user.\n" . "\tresync -t TYPE -u USER -d DEVICE Resynchronizes all folders of type $types for a specified device and user.\n" .
"\tresync -t FOLDERID -u USER\t Resynchronize the specified folder id only. The USER should be specified for better performance.\n" . "\tresync -t FOLDERID -u USER\t Resynchronize the specified folder id only. The USER should be specified for better performance.\n" .
"\tresync -t hierarchy -u USER\t Resynchronize the hierarchy data for an optional USER and optional DEVICE.\n" .
"\tclearloop\t\t\t Clears system wide loop detection data\n" . "\tclearloop\t\t\t Clears system wide loop detection data\n" .
"\tclearloop -d DEVICE -u USER\t Clears all loop detection data of a device DEVICE and an optional user USER\n" . "\tclearloop -d DEVICE -u USER\t Clears all loop detection data of a device DEVICE and an optional user USER\n" .
"\tfixstates\t\t\t Checks the states for integrity and fixes potential issues\n" . "\tfixstates\t\t\t Checks the states for integrity and fixes potential issues\n" .
...@@ -243,9 +246,10 @@ class ZPushAdminCLI { ...@@ -243,9 +246,10 @@ class ZPushAdminCLI {
self::$type !== self::TYPE_OPTION_CONTACT && self::$type !== self::TYPE_OPTION_CONTACT &&
self::$type !== self::TYPE_OPTION_TASK && self::$type !== self::TYPE_OPTION_TASK &&
self::$type !== self::TYPE_OPTION_NOTE && self::$type !== self::TYPE_OPTION_NOTE &&
self::$type !== self::TYPE_OPTION_HIERARCHY &&
strlen(self::$type) !== 44) { strlen(self::$type) !== 44) {
self::$errormessage = "Wrong 'type'. Possible values are: ". self::$errormessage = "Wrong 'type'. Possible values are: ".
"'".self::TYPE_OPTION_EMAIL."', '".self::TYPE_OPTION_CALENDAR."', '".self::TYPE_OPTION_CONTACT."', '".self::TYPE_OPTION_TASK."', '".self::TYPE_OPTION_NOTE."' ". "'".self::TYPE_OPTION_EMAIL."', '".self::TYPE_OPTION_CALENDAR."', '".self::TYPE_OPTION_CONTACT."', '".self::TYPE_OPTION_TASK."', '".self::TYPE_OPTION_NOTE."', ".self::TYPE_OPTION_HIERARCHY."' ".
"or a 44 byte long folder id (as hex)."; "or a 44 byte long folder id (as hex).";
return; return;
} }
...@@ -300,6 +304,9 @@ class ZPushAdminCLI { ...@@ -300,6 +304,9 @@ class ZPushAdminCLI {
else else
self::$command = self::COMMAND_RESYNCDEVICE; self::$command = self::COMMAND_RESYNCDEVICE;
} }
else if (self::$type === self::TYPE_OPTION_HIERARCHY) {
self::$command = self::COMMAND_RESYNCHIERARCHY;
}
else { else {
self::$command = self::COMMAND_RESYNCFOLDER; self::$command = self::COMMAND_RESYNCFOLDER;
} }
...@@ -410,6 +417,18 @@ class ZPushAdminCLI { ...@@ -410,6 +417,18 @@ class ZPushAdminCLI {
self::CommandResyncFolder(); self::CommandResyncFolder();
break; break;
case self::COMMAND_RESYNCHIERARCHY:
if (self::$device == false && self::$user == false) {
echo "Are you sure you want to re-synchronize the hierarchy of all devices and users [y/N]: ";
$confirm = strtolower(trim(fgets(STDIN)));
if ( !($confirm === 'y' || $confirm === 'yes')) {
echo "Aborted!\n";
exit(1);
}
}
self::CommandResyncHierarchy();
break;
case self::COMMAND_CLEARLOOP: case self::COMMAND_CLEARLOOP:
self::CommandClearLoopDetectionData(); self::CommandClearLoopDetectionData();
break; break;
...@@ -588,6 +607,36 @@ class ZPushAdminCLI { ...@@ -588,6 +607,36 @@ class ZPushAdminCLI {
} }
/**
* Command "Resync hierarchy"
* Resyncs a folder type of a specific device/user or of all users
*
* @return
* @access public
*/
static public function CommandResyncHierarchy() {
// if no device is specified, search for all devices of a user. If user is not set, all devices are returned.
if (self::$device === false) {
$devicelist = ZPushAdmin::ListDevices(self::$user);
if (empty($devicelist)) {
echo "\tno devices/users found\n";
return true;
}
}
else
$devicelist = array(self::$device);
foreach ($devicelist as $deviceId) {
$users = ZPushAdmin::ListUsers($deviceId);
foreach ($users as $user) {
if (self::$user && self::$user != $user)
continue;
self::resyncHierarchy($deviceId, $user);
}
}
}
/** /**
* Command to clear the loop detection data * Command to clear the loop detection data
* Mobiles may enter loop detection (one-by-one synchring due to timeouts / erros). * Mobiles may enter loop detection (one-by-one synchring due to timeouts / erros).
...@@ -670,6 +719,20 @@ class ZPushAdminCLI { ...@@ -670,6 +719,20 @@ class ZPushAdminCLI {
echo sprintf("Resync of %d folders of type %s on device '%s' of user '%s': %s\n", count($folders), $type, $deviceId, $user, ($stat)?'Requested':ZLog::GetLastMessage(LOGLEVEL_ERROR)); echo sprintf("Resync of %d folders of type %s on device '%s' of user '%s': %s\n", count($folders), $type, $deviceId, $user, ($stat)?'Requested':ZLog::GetLastMessage(LOGLEVEL_ERROR));
} }
/**
* Resynchronizes the hierarchy of a device & user
*
* @param string $deviceId the id of the device
* @param string $user the user
*
* @return
* @access private
*/
static private function resyncHierarchy($deviceId, $user) {
$stat = ZPushAdmin::ResyncHierarchy($user, $deviceId);
echo sprintf("Removing hierarchy information for resync on device '%s' of user '%s': %s\n", $deviceId, $user, ($stat)?'Requested':ZLog::GetLastMessage(LOGLEVEL_ERROR));
}
/** /**
* Fixes the states for potential issues * Fixes the states for potential issues
* *
......
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