Commit bc86a936 authored by Sebastian Kummer's avatar Sebastian Kummer

ZP-1072 Save different parentids in ASDevice->AddAdditionalFolder(),

consider parentid when checking for duplicate names (may not occur in
the same folder), order folders correctly, transport parentids when
building SyncObjects for FolderSync.

Released under the Affero GNU General Public License (AGPL) version 3.
parent 4260a916
...@@ -855,7 +855,8 @@ class ASDevice extends StateObject { ...@@ -855,7 +855,8 @@ class ASDevice extends StateObject {
* @param string $name the name of the additional folder (has to be unique for all folders on the device). * @param string $name the name of the additional folder (has to be unique for all folders on the device).
* @param string $type AS foldertype of SYNC_FOLDER_TYPE_USER_* * @param string $type AS foldertype of SYNC_FOLDER_TYPE_USER_*
* @param int $flags Additional flags, like DeviceManager::FLD_FLAGS_REPLYASUSER * @param int $flags Additional flags, like DeviceManager::FLD_FLAGS_REPLYASUSER
* //TODO document $parentid and $checkDups (or remove this) * @param string $parentid the parentid of this folder.
* @param boolean $checkDups indicates if duplicate names and ids should be verified. Default: true
* *
* @access public * @access public
* @return boolean * @return boolean
...@@ -879,16 +880,29 @@ class ASDevice extends StateObject { ...@@ -879,16 +880,29 @@ class ASDevice extends StateObject {
return false; return false;
} }
// check if a folder with that Name is already in the list // check if a folder with that Name is already in the list and that it's parent exists
$parentFound = false;
foreach ($this->additionalfolders as $k => $folder) { foreach ($this->additionalfolders as $k => $folder) {
if ($folder['name'] == $name) { // TODO: this parentid check should go into fixstates!
ZLog::Write(LOGLEVEL_ERROR, sprintf("ASDevice->AddAdditionalFolder(): folder can not be added because there is already an additional folder with the same name: '%s'", $name)); if (!isset($folder['parentid'])) $folder['parentid'] = "0";
if ($folder['name'] == $name && $folder['parentid'] == $parentid) {
ZLog::Write(LOGLEVEL_ERROR, sprintf("ASDevice->AddAdditionalFolder(): folder can not be added because there is already an additional folder with the same name in the same folder: '%s'", $name));
return false; return false;
} }
if ($folder['folderid'] == $parentid) {
$parentFound = true;
}
}
if ($parentid != '0' && !$parentFound) {
ZLog::Write(LOGLEVEL_ERROR, sprintf("ASDevice->AddAdditionalFolder(): folder can not be added because the parent folder '%s' can not be found: '%s'", $parentid, $folderid));
return false;
} }
// check if a folder with this ID or Name is already known on the device (regular folder) // check if a folder with this ID or Name is already known on the device (regular folder)
if ($checkDups) { if ($checkDups) {
// in order to check for the parent-ids we need a shortid
$parentShortId = $this->GetFolderIdForBackendId($parentid, false, null, null);
foreach($this->GetHierarchyCache()->ExportFolders() as $syncedFolderid => $folder) { foreach($this->GetHierarchyCache()->ExportFolders() as $syncedFolderid => $folder) {
if ($syncedFolderid === $folderid || $folder->BackendId === $folderid) { if ($syncedFolderid === $folderid || $folder->BackendId === $folderid) {
ZLog::Write(LOGLEVEL_ERROR, sprintf("ASDevice->AddAdditionalFolder(): folder can not be added because there is already a folder with the same folder id synchronized: '%s'", $folderid)); ZLog::Write(LOGLEVEL_ERROR, sprintf("ASDevice->AddAdditionalFolder(): folder can not be added because there is already a folder with the same folder id synchronized: '%s'", $folderid));
...@@ -896,8 +910,8 @@ class ASDevice extends StateObject { ...@@ -896,8 +910,8 @@ class ASDevice extends StateObject {
} }
// $folder is a SyncFolder object here // $folder is a SyncFolder object here
if ($folder->displayname == $name) { if ($folder->displayname == $name && ($folder->parentid == $parentid || $folder->parentid == $parentShortId)) {
ZLog::Write(LOGLEVEL_ERROR, sprintf("ASDevice->AddAdditionalFolder(): folder can not be added because there is already a folder with the same name synchronized: '%s'", $name)); ZLog::Write(LOGLEVEL_ERROR, sprintf("ASDevice->AddAdditionalFolder(): folder can not be added because there is already a folder with the same name synchronized in the same parent: '%s'", $name));
return false; return false;
} }
} }
...@@ -908,12 +922,16 @@ class ASDevice extends StateObject { ...@@ -908,12 +922,16 @@ class ASDevice extends StateObject {
$af[$folderid] = array( $af[$folderid] = array(
'store' => $store, 'store' => $store,
'folderid' => $folderid, 'folderid' => $folderid,
'parentid' => $parentid,
'name' => $name, 'name' => $name,
'type' => $type, 'type' => $type,
'flags' => $flags, 'flags' => $flags,
); );
$this->additionalfolders = $af; $this->additionalfolders = $af;
// generate an interger folderid for it
$id = $this->GetFolderIdForBackendId($folderid, true, DeviceManager::FLD_ORIGIN_SHARED, $name);
return true; return true;
} }
...@@ -1024,8 +1042,39 @@ class ASDevice extends StateObject { ...@@ -1024,8 +1042,39 @@ class ASDevice extends StateObject {
// set remaining additional folders // set remaining additional folders
$this->additionalfolders = $newAF; $this->additionalfolders = $newAF;
// low level add // transform our array in a key/value array where folderids are keys and do some basic checks
$toOrder = array();
$ordered = array();
$validTypes = array(SYNC_FOLDER_TYPE_USER_CONTACT, SYNC_FOLDER_TYPE_USER_APPOINTMENT, SYNC_FOLDER_TYPE_USER_TASK, SYNC_FOLDER_TYPE_USER_MAIL, SYNC_FOLDER_TYPE_USER_NOTE, SYNC_FOLDER_TYPE_USER_JOURNAL);
foreach($folders as $f) { foreach($folders as $f) {
// fail early
if (!$f['folderid'] || !$f['name']) {
ZLog::Write(LOGLEVEL_ERROR, sprintf("ASDevice->SetAdditionalFolderList(): No valid folderid ('%s') or name ('%s') sent. Aborting. ", $f['folderid'], $f['name']));
return false;
}
// check if type is of a additional user type
if (!in_array($f['type'], $validTypes)) {
ZLog::Write(LOGLEVEL_ERROR, sprintf("ASDevice->SetAdditionalFolderList(): folder (id: '%s' - name: '%s') can not be added because the specified type '%s' is not a permitted user type.", $f['folderid'], $f['name'], $f['type']));
return false;
}
$toOrder[$f['folderid']] = $f;
}
// order the array, so folders with leafs come first
$this->orderAdditionalFoldersHierarchically($toOrder, $ordered);
// if there are folders that are not be positioned in the tree, we can't add them!
if (!empty($toOrder)) {
$s = "";
foreach($toOrder as $f) {
$s .= sprintf("'%s'(%s) ", $f['name'], $f['folderid']);
}
ZLog::Write(LOGLEVEL_ERROR, "ASDevice->SetAdditionalFolderList(): cannot proceed as these folders have invalid parentids (not found): ". $s);
return false;
}
foreach($ordered as $f) {
$status = $this->AddAdditionalFolder($store, $f['folderid'], $f['name'], $f['type'], $f['flags'], $f['parentid'], !isset($noDupsCheck[$f['folderid']])); $status = $this->AddAdditionalFolder($store, $f['folderid'], $f['name'], $f['type'], $f['flags'], $f['parentid'], !isset($noDupsCheck[$f['folderid']]));
ZLog::Write(LOGLEVEL_DEBUG, sprintf("ASDevice->SetAdditionalFolderList(): set folder '%s' in additional folders list with status: %s", $f['name'], Utils::PrintAsString($status))); ZLog::Write(LOGLEVEL_DEBUG, sprintf("ASDevice->SetAdditionalFolderList(): set folder '%s' in additional folders list with status: %s", $f['name'], Utils::PrintAsString($status)));
// break if a folder can not be added // break if a folder can not be added
...@@ -1033,10 +1082,31 @@ class ASDevice extends StateObject { ...@@ -1033,10 +1082,31 @@ class ASDevice extends StateObject {
return false; return false;
} }
} }
return true; return true;
} }
/**
* Orders a list of folders so the parents are first in the array, all leaves come afterwards.
*
* @param array $toOrderFolders an array of folders, where the folderids are keys. This array should be empty at the end.
* @param array $orderedFolders the ordered array
* @param string $parentid the parentid to start with, if not set '0' (main folders) is used.
*/
private function orderAdditionalFoldersHierarchically(&$toOrderFolders, &$orderedFolders, $parentid = '0') {
// loop through the remaining folders that need to be ordered
foreach($toOrderFolders as $folder) {
// move folders with the matching parentid to the ordered array
if ($folder['parentid'] == $parentid) {
$fid = $folder['folderid'];
$orderedFolders[$fid] = $folder;
unset($toOrderFolders[$fid]);
reset($toOrderFolders);
// call recursively to move/order the leaves as well
$this->orderAdditionalFoldersHierarchically($toOrderFolders, $orderedFolders, $fid);
}
}
}
/** /**
* Generates the AS folder hash from the backend folder id, type and name. * Generates the AS folder hash from the backend folder id, type and name.
* *
......
...@@ -499,8 +499,12 @@ class DeviceManager { ...@@ -499,8 +499,12 @@ class DeviceManager {
$df['flags'] = 0; $df['flags'] = 0;
ZLog::Write(LOGLEVEL_WARN, sprintf("DeviceManager->GetAdditionalUserSyncFolders(): Additional folder '%s' has no flags. Please run 'z-push-admin -a fixstates' to fix this issue.", $df['name'])); ZLog::Write(LOGLEVEL_WARN, sprintf("DeviceManager->GetAdditionalUserSyncFolders(): Additional folder '%s' has no flags. Please run 'z-push-admin -a fixstates' to fix this issue.", $df['name']));
} }
if (!isset($df['parentid'])) {
$df['parentid'] = '0';
ZLog::Write(LOGLEVEL_WARN, sprintf("DeviceManager->GetAdditionalUserSyncFolders(): Additional folder '%s' has no parentid. // TODO FIX: Please run 'z-push-admin -a fixstates' to fix this issue.", $df['name']));
}
$folder = $this->getAdditionalSyncFolderObject($df['store'], $df['folderid'], $df['name'], $df['type'], $df['flags'], DeviceManager::FLD_ORIGIN_SHARED); $folder = $this->getAdditionalSyncFolderObject($df['store'], $df['folderid'], $df['parentid'], $df['name'], $df['type'], $df['flags'], DeviceManager::FLD_ORIGIN_SHARED);
$folders[$folder->BackendId] = $folder; $folders[$folder->BackendId] = $folder;
} }
...@@ -508,7 +512,7 @@ class DeviceManager { ...@@ -508,7 +512,7 @@ class DeviceManager {
if (KOE_CAPABILITY_GAB && $this->IsKoe() && KOE_GAB_STORE != "" && KOE_GAB_NAME != "") { if (KOE_CAPABILITY_GAB && $this->IsKoe() && KOE_GAB_STORE != "" && KOE_GAB_NAME != "") {
// if KOE_GAB_FOLDERID is set, use it // if KOE_GAB_FOLDERID is set, use it
if (KOE_GAB_FOLDERID != "") { if (KOE_GAB_FOLDERID != "") {
$folder = $this->getAdditionalSyncFolderObject(KOE_GAB_STORE, KOE_GAB_FOLDERID, KOE_GAB_NAME, SYNC_FOLDER_TYPE_USER_APPOINTMENT, 0, DeviceManager::FLD_ORIGIN_GAB); $folder = $this->getAdditionalSyncFolderObject(KOE_GAB_STORE, KOE_GAB_FOLDERID, '0', KOE_GAB_NAME, SYNC_FOLDER_TYPE_USER_APPOINTMENT, 0, DeviceManager::FLD_ORIGIN_GAB);
$folders[$folder->BackendId] = $folder; $folders[$folder->BackendId] = $folder;
} }
else { else {
...@@ -525,7 +529,7 @@ class DeviceManager { ...@@ -525,7 +529,7 @@ class DeviceManager {
} }
if ($backendGabId) { if ($backendGabId) {
$folders[$backendGabId] = $this->getAdditionalSyncFolderObject(KOE_GAB_STORE, $backendGabId, KOE_GAB_NAME, SYNC_FOLDER_TYPE_USER_APPOINTMENT, 0, DeviceManager::FLD_ORIGIN_GAB); $folders[$backendGabId] = $this->getAdditionalSyncFolderObject(KOE_GAB_STORE, $backendGabId, '0', KOE_GAB_NAME, SYNC_FOLDER_TYPE_USER_APPOINTMENT, 0, DeviceManager::FLD_ORIGIN_GAB);
} }
} }
} }
...@@ -1191,11 +1195,11 @@ class DeviceManager { ...@@ -1191,11 +1195,11 @@ class DeviceManager {
* @access private * @access private
* @returns SyncFolder * @returns SyncFolder
*/ */
private function getAdditionalSyncFolderObject($store, $folderid, $name, $type, $flags, $folderOrigin) { private function getAdditionalSyncFolderObject($store, $folderid, $parentid, $name, $type, $flags, $folderOrigin) {
$folder = new SyncFolder(); $folder = new SyncFolder();
$folder->BackendId = $folderid; $folder->BackendId = $folderid;
$folder->serverid = $this->GetFolderIdForBackendId($folder->BackendId, true, $folderOrigin, $name); $folder->serverid = $this->GetFolderIdForBackendId($folder->BackendId, true, $folderOrigin, $name);
$folder->parentid = 0; // only top folders are supported $folder->parentid = $this->GetFolderIdForBackendId($parentid);
$folder->displayname = $name; $folder->displayname = $name;
$folder->type = $type; $folder->type = $type;
// save store as custom property which is not streamed directly to the device // save store as custom property which is not streamed directly to the device
......
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