Test Failed
Push — master ( cd42b5...841446 )
by
unknown
16:44 queued 06:09
created
plugins/files/php/modules/class.hierarchylistmodule.php 2 patches
Indentation   +211 added lines, -211 removed lines patch added patch discarded remove patch
@@ -9,215 +9,215 @@
 block discarded – undo
9 9
  * @extends FilesListModule
10 10
  */
11 11
 class HierarchyListModule extends FilesListModule {
12
-	/**
13
-	 * Creates the notifiers for this module,
14
-	 * and register them to the Bus.
15
-	 */
16
-	public function createNotifiers() {
17
-		$entryid = $this->getEntryID();
18
-		$GLOBALS["bus"]->registerNotifier('filesbrowsernotifier', $entryid);
19
-		$GLOBALS["bus"]->registerNotifier('fileshierarchynotifier', REQUEST_ENTRYID);
20
-	}
21
-
22
-	/**
23
-	 * @return bool|void
24
-	 */
25
-	public function execute() {
26
-		$result = false;
27
-		foreach ($this->data as $actionType => $actionData) {
28
-			if (isset($actionType)) {
29
-				try {
30
-					switch ($actionType) {
31
-						case "list":
32
-							$this->hierarchyList($actionData);
33
-							break;
34
-
35
-						case "updatelist":
36
-							$this->updateHierarchy($actionData);
37
-							break;
38
-
39
-						case "save":
40
-							$this->save($actionData);
41
-							break;
42
-
43
-						case "delete":
44
-							$result = $this->delete($actionData);
45
-							break;
46
-
47
-						default:
48
-							$this->handleUnknownActionType($actionType);
49
-					}
50
-				}
51
-				catch (MAPIException $e) {
52
-					$this->sendFeedback(false, $this->errorDetailsFromException($e));
53
-				}
54
-				catch (AccountException $e) {
55
-					$this->sendFeedback(false, [
56
-						'type' => ERROR_GENERAL,
57
-						'info' => [
58
-							'title' => $e->getTitle(),
59
-							'original_message' => $e->getMessage(),
60
-							'display_message' => $e->getMessage(),
61
-						],
62
-					]);
63
-				}
64
-				catch (BackendException $e) {
65
-					$this->sendFeedback(false, [
66
-						'type' => ERROR_GENERAL,
67
-						'info' => [
68
-							'title' => $e->getTitle(),
69
-							'original_message' => $e->getMessage(),
70
-							'display_message' => $e->getMessage(),
71
-							'code' => $e->getCode(),
72
-						],
73
-					]);
74
-				}
75
-				catch (Exception $e) {
76
-					$this->sendFeedback(false, [
77
-						'type' => ERROR_GENERAL,
78
-						'info' => [
79
-							'title' => $e->getTitle(),
80
-							'original_message' => $e->getMessage(),
81
-							'display_message' => $e->getMessage(),
82
-							'code' => $e->getCode(),
83
-						],
84
-					]);
85
-				}
86
-			}
87
-		}
88
-
89
-		return $result;
90
-	}
91
-
92
-	/**
93
-	 * Generates the hierarchy list. All folders and sub folders are added to response data.
94
-	 *
95
-	 * @param mixed $action
96
-	 */
97
-	public function hierarchyList($action) {
98
-		$isReload = isset($action['reload']) ? $action['reload'] : false;
99
-		$data = $this->getHierarchyList($isReload);
100
-		$this->addActionData("list", $data);
101
-		$GLOBALS["bus"]->addData($this->getResponseData());
102
-	}
103
-
104
-	/**
105
-	 * Function used to retrieve the child folders of given folder id.
106
-	 *
107
-	 * @param {Array} $action The action data which passed in request
108
-	 */
109
-	public function updateHierarchy($action) {
110
-		$nodeId = $action["folder_id"];
111
-		$account = $this->accountFromNode($nodeId);
112
-		$backend = $this->initializeBackend($account, true);
113
-		$subFolders = $this->getSubFolders($nodeId, $backend);
114
-
115
-		$this->addActionData("updatelist", ["item" => $subFolders]);
116
-		$GLOBALS["bus"]->addData($this->getResponseData());
117
-	}
118
-
119
-	/**
120
-	 * @param $actionData
121
-	 *
122
-	 * @throws \Files\Backend\Exception
123
-	 *
124
-	 * @return array|void
125
-	 */
126
-	public function save($actionData) {
127
-		$messageProps = parent::save($actionData);
128
-		if (!empty($messageProps)) {
129
-			// Notify all subfolders for update folder.
130
-			$this->notifySubFolders($messageProps["props"]["folder_id"]);
131
-
132
-			// Need to add message class to update the files grid record through notification
133
-			$messageProps["props"]["message_class"] = "IPM.Files";
134
-			$GLOBALS["bus"]->notify($messageProps["parent_entryid"], OBJECT_SAVE, $messageProps);
135
-		}
136
-	}
137
-
138
-	/**
139
-	 * Deletes the selected files on the backend server.
140
-	 *
141
-	 * @param string $actionType name of the current action
142
-	 * @param array  $actionData all parameters contained in this request
143
-	 *
144
-	 * @throws BackendException if the backend request fails
145
-	 *
146
-	 * @return bool
147
-	 */
148
-	public function delete($actionData) {
149
-		// TODO: Do we need this if block code?
150
-		if (isset($actionData['records']) && is_array($actionData['records'])) {
151
-			foreach ($actionData['records'] as $record) {
152
-				$nodeId = $record['entryid'];
153
-				$relNodeId = substr($nodeId, strpos($nodeId, '/'));
154
-
155
-				$account = $this->accountFromNode($nodeId);
156
-
157
-				// initialize the backend
158
-				$initializedBackend = $this->initializeBackend($account);
159
-
160
-				$initializedBackend->delete($relNodeId);
161
-				// Logger::debug(self::LOG_CONTEXT, "deleted: " . $nodeId . ", worked: " . $result);
162
-
163
-				// clear the cache
164
-				$this->deleteCache($account->getId(), dirname($relNodeId));
165
-
166
-				$GLOBALS["bus"]->notify($record["parent_entryid"], OBJECT_DELETE, [
167
-					"id" => $nodeId,
168
-					"entryid" => $nodeId,
169
-					"parent_entryid" => $record["parent_entryid"],
170
-					"store_entryid" => $record["store_entryid"],
171
-				]);
172
-			}
173
-
174
-			$this->sendFeedback(true);
175
-		}
176
-		else {
177
-			$nodeId = $actionData['folder_id'];
178
-			$relNodeId = substr($nodeId, strpos($nodeId, '/'));
179
-
180
-			$account = $this->accountFromNode($nodeId);
181
-			$accountId = $account->getId();
182
-
183
-			// initialize the backend
184
-			$initializedBackend = $this->initializeBackend($account);
185
-
186
-			try {
187
-				$initializedBackend->delete($relNodeId);
188
-			}
189
-			catch (\Files\Backend\Exception $e) {
190
-				// TODO: this might fails because the file was already deleted.
191
-				// fire error message if any other error occurred.
192
-				// Logger::debug(self::LOG_CONTEXT, "deleted a directory that was no longer available");
193
-			}
194
-
195
-			// Get old cached data.
196
-			$cachedDir = $this->getCache($accountId, dirname($relNodeId));
197
-
198
-			if (isset($cachedDir[$relNodeId]) && !empty($cachedDir[$relNodeId])) {
199
-				// Delete the folder from cached data.
200
-				unset($cachedDir[$relNodeId]);
201
-			}
202
-
203
-			// clear the cache of parent directory.
204
-			$this->deleteCache($accountId, dirname($relNodeId));
205
-			// clear the cache of selected directory.
206
-			$this->deleteCache($accountId, rtrim($relNodeId, '/'));
207
-
208
-			// Set data in cache.
209
-			$this->setCache($accountId, dirname($relNodeId), $cachedDir);
210
-
211
-			$this->sendFeedback(true);
212
-			$GLOBALS["bus"]->notify($actionData["parent_entryid"], OBJECT_DELETE, [
213
-				"id" => $actionData["entryid"],
214
-				"folder_id" => $nodeId,
215
-				"entryid" => $actionData["entryid"],
216
-				"parent_entryid" => $actionData["parent_entryid"],
217
-				"store_entryid" => $actionData["store_entryid"],
218
-			]);
219
-		}
220
-
221
-		return true;
222
-	}
12
+    /**
13
+     * Creates the notifiers for this module,
14
+     * and register them to the Bus.
15
+     */
16
+    public function createNotifiers() {
17
+        $entryid = $this->getEntryID();
18
+        $GLOBALS["bus"]->registerNotifier('filesbrowsernotifier', $entryid);
19
+        $GLOBALS["bus"]->registerNotifier('fileshierarchynotifier', REQUEST_ENTRYID);
20
+    }
21
+
22
+    /**
23
+     * @return bool|void
24
+     */
25
+    public function execute() {
26
+        $result = false;
27
+        foreach ($this->data as $actionType => $actionData) {
28
+            if (isset($actionType)) {
29
+                try {
30
+                    switch ($actionType) {
31
+                        case "list":
32
+                            $this->hierarchyList($actionData);
33
+                            break;
34
+
35
+                        case "updatelist":
36
+                            $this->updateHierarchy($actionData);
37
+                            break;
38
+
39
+                        case "save":
40
+                            $this->save($actionData);
41
+                            break;
42
+
43
+                        case "delete":
44
+                            $result = $this->delete($actionData);
45
+                            break;
46
+
47
+                        default:
48
+                            $this->handleUnknownActionType($actionType);
49
+                    }
50
+                }
51
+                catch (MAPIException $e) {
52
+                    $this->sendFeedback(false, $this->errorDetailsFromException($e));
53
+                }
54
+                catch (AccountException $e) {
55
+                    $this->sendFeedback(false, [
56
+                        'type' => ERROR_GENERAL,
57
+                        'info' => [
58
+                            'title' => $e->getTitle(),
59
+                            'original_message' => $e->getMessage(),
60
+                            'display_message' => $e->getMessage(),
61
+                        ],
62
+                    ]);
63
+                }
64
+                catch (BackendException $e) {
65
+                    $this->sendFeedback(false, [
66
+                        'type' => ERROR_GENERAL,
67
+                        'info' => [
68
+                            'title' => $e->getTitle(),
69
+                            'original_message' => $e->getMessage(),
70
+                            'display_message' => $e->getMessage(),
71
+                            'code' => $e->getCode(),
72
+                        ],
73
+                    ]);
74
+                }
75
+                catch (Exception $e) {
76
+                    $this->sendFeedback(false, [
77
+                        'type' => ERROR_GENERAL,
78
+                        'info' => [
79
+                            'title' => $e->getTitle(),
80
+                            'original_message' => $e->getMessage(),
81
+                            'display_message' => $e->getMessage(),
82
+                            'code' => $e->getCode(),
83
+                        ],
84
+                    ]);
85
+                }
86
+            }
87
+        }
88
+
89
+        return $result;
90
+    }
91
+
92
+    /**
93
+     * Generates the hierarchy list. All folders and sub folders are added to response data.
94
+     *
95
+     * @param mixed $action
96
+     */
97
+    public function hierarchyList($action) {
98
+        $isReload = isset($action['reload']) ? $action['reload'] : false;
99
+        $data = $this->getHierarchyList($isReload);
100
+        $this->addActionData("list", $data);
101
+        $GLOBALS["bus"]->addData($this->getResponseData());
102
+    }
103
+
104
+    /**
105
+     * Function used to retrieve the child folders of given folder id.
106
+     *
107
+     * @param {Array} $action The action data which passed in request
108
+     */
109
+    public function updateHierarchy($action) {
110
+        $nodeId = $action["folder_id"];
111
+        $account = $this->accountFromNode($nodeId);
112
+        $backend = $this->initializeBackend($account, true);
113
+        $subFolders = $this->getSubFolders($nodeId, $backend);
114
+
115
+        $this->addActionData("updatelist", ["item" => $subFolders]);
116
+        $GLOBALS["bus"]->addData($this->getResponseData());
117
+    }
118
+
119
+    /**
120
+     * @param $actionData
121
+     *
122
+     * @throws \Files\Backend\Exception
123
+     *
124
+     * @return array|void
125
+     */
126
+    public function save($actionData) {
127
+        $messageProps = parent::save($actionData);
128
+        if (!empty($messageProps)) {
129
+            // Notify all subfolders for update folder.
130
+            $this->notifySubFolders($messageProps["props"]["folder_id"]);
131
+
132
+            // Need to add message class to update the files grid record through notification
133
+            $messageProps["props"]["message_class"] = "IPM.Files";
134
+            $GLOBALS["bus"]->notify($messageProps["parent_entryid"], OBJECT_SAVE, $messageProps);
135
+        }
136
+    }
137
+
138
+    /**
139
+     * Deletes the selected files on the backend server.
140
+     *
141
+     * @param string $actionType name of the current action
142
+     * @param array  $actionData all parameters contained in this request
143
+     *
144
+     * @throws BackendException if the backend request fails
145
+     *
146
+     * @return bool
147
+     */
148
+    public function delete($actionData) {
149
+        // TODO: Do we need this if block code?
150
+        if (isset($actionData['records']) && is_array($actionData['records'])) {
151
+            foreach ($actionData['records'] as $record) {
152
+                $nodeId = $record['entryid'];
153
+                $relNodeId = substr($nodeId, strpos($nodeId, '/'));
154
+
155
+                $account = $this->accountFromNode($nodeId);
156
+
157
+                // initialize the backend
158
+                $initializedBackend = $this->initializeBackend($account);
159
+
160
+                $initializedBackend->delete($relNodeId);
161
+                // Logger::debug(self::LOG_CONTEXT, "deleted: " . $nodeId . ", worked: " . $result);
162
+
163
+                // clear the cache
164
+                $this->deleteCache($account->getId(), dirname($relNodeId));
165
+
166
+                $GLOBALS["bus"]->notify($record["parent_entryid"], OBJECT_DELETE, [
167
+                    "id" => $nodeId,
168
+                    "entryid" => $nodeId,
169
+                    "parent_entryid" => $record["parent_entryid"],
170
+                    "store_entryid" => $record["store_entryid"],
171
+                ]);
172
+            }
173
+
174
+            $this->sendFeedback(true);
175
+        }
176
+        else {
177
+            $nodeId = $actionData['folder_id'];
178
+            $relNodeId = substr($nodeId, strpos($nodeId, '/'));
179
+
180
+            $account = $this->accountFromNode($nodeId);
181
+            $accountId = $account->getId();
182
+
183
+            // initialize the backend
184
+            $initializedBackend = $this->initializeBackend($account);
185
+
186
+            try {
187
+                $initializedBackend->delete($relNodeId);
188
+            }
189
+            catch (\Files\Backend\Exception $e) {
190
+                // TODO: this might fails because the file was already deleted.
191
+                // fire error message if any other error occurred.
192
+                // Logger::debug(self::LOG_CONTEXT, "deleted a directory that was no longer available");
193
+            }
194
+
195
+            // Get old cached data.
196
+            $cachedDir = $this->getCache($accountId, dirname($relNodeId));
197
+
198
+            if (isset($cachedDir[$relNodeId]) && !empty($cachedDir[$relNodeId])) {
199
+                // Delete the folder from cached data.
200
+                unset($cachedDir[$relNodeId]);
201
+            }
202
+
203
+            // clear the cache of parent directory.
204
+            $this->deleteCache($accountId, dirname($relNodeId));
205
+            // clear the cache of selected directory.
206
+            $this->deleteCache($accountId, rtrim($relNodeId, '/'));
207
+
208
+            // Set data in cache.
209
+            $this->setCache($accountId, dirname($relNodeId), $cachedDir);
210
+
211
+            $this->sendFeedback(true);
212
+            $GLOBALS["bus"]->notify($actionData["parent_entryid"], OBJECT_DELETE, [
213
+                "id" => $actionData["entryid"],
214
+                "folder_id" => $nodeId,
215
+                "entryid" => $actionData["entryid"],
216
+                "parent_entryid" => $actionData["parent_entryid"],
217
+                "store_entryid" => $actionData["store_entryid"],
218
+            ]);
219
+        }
220
+
221
+        return true;
222
+    }
223 223
 }
Please login to merge, or discard this patch.
Braces   +6 added lines, -12 removed lines patch added patch discarded remove patch
@@ -47,11 +47,9 @@  discard block
 block discarded – undo
47 47
 						default:
48 48
 							$this->handleUnknownActionType($actionType);
49 49
 					}
50
-				}
51
-				catch (MAPIException $e) {
50
+				} catch (MAPIException $e) {
52 51
 					$this->sendFeedback(false, $this->errorDetailsFromException($e));
53
-				}
54
-				catch (AccountException $e) {
52
+				} catch (AccountException $e) {
55 53
 					$this->sendFeedback(false, [
56 54
 						'type' => ERROR_GENERAL,
57 55
 						'info' => [
@@ -60,8 +58,7 @@  discard block
 block discarded – undo
60 58
 							'display_message' => $e->getMessage(),
61 59
 						],
62 60
 					]);
63
-				}
64
-				catch (BackendException $e) {
61
+				} catch (BackendException $e) {
65 62
 					$this->sendFeedback(false, [
66 63
 						'type' => ERROR_GENERAL,
67 64
 						'info' => [
@@ -71,8 +68,7 @@  discard block
 block discarded – undo
71 68
 							'code' => $e->getCode(),
72 69
 						],
73 70
 					]);
74
-				}
75
-				catch (Exception $e) {
71
+				} catch (Exception $e) {
76 72
 					$this->sendFeedback(false, [
77 73
 						'type' => ERROR_GENERAL,
78 74
 						'info' => [
@@ -172,8 +168,7 @@  discard block
 block discarded – undo
172 168
 			}
173 169
 
174 170
 			$this->sendFeedback(true);
175
-		}
176
-		else {
171
+		} else {
177 172
 			$nodeId = $actionData['folder_id'];
178 173
 			$relNodeId = substr($nodeId, strpos($nodeId, '/'));
179 174
 
@@ -185,8 +180,7 @@  discard block
 block discarded – undo
185 180
 
186 181
 			try {
187 182
 				$initializedBackend->delete($relNodeId);
188
-			}
189
-			catch (\Files\Backend\Exception $e) {
183
+			} catch (\Files\Backend\Exception $e) {
190 184
 				// TODO: this might fails because the file was already deleted.
191 185
 				// fire error message if any other error occurred.
192 186
 				// Logger::debug(self::LOG_CONTEXT, "deleted a directory that was no longer available");
Please login to merge, or discard this patch.
plugins/files/php/modules/class.fileslistmodule.php 2 patches
Indentation   +738 added lines, -738 removed lines patch added patch discarded remove patch
@@ -23,742 +23,742 @@
 block discarded – undo
23 23
  * @extends ListModule
24 24
  */
25 25
 class FilesListModule extends ListModule {
26
-	public const LOG_CONTEXT = "FilesListModule"; // Context for the Logger
27
-
28
-	// Unauthorized errors of different backends.
29
-	public const SMB_ERR_UNAUTHORIZED = 13;
30
-	public const SMB_ERR_FORBIDDEN = 1;
31
-	public const FTP_WD_OWNCLOUD_ERR_UNAUTHORIZED = 401;
32
-	public const FTP_WD_OWNCLOUD_ERR_FORBIDDEN = 403;
33
-	public const ALL_BACKEND_ERR_NOTFOUND = 404;
34
-
35
-	/**
36
-	 * @var \phpFastCache cache handler
37
-	 */
38
-	public $cache;
39
-
40
-	/**
41
-	 * @var string User id of the currently logged in user. Used to generate unique cache id's.
42
-	 */
43
-	public $uid;
44
-
45
-	/**
46
-	 * @var {Object} The account store holding all available accounts
47
-	 */
48
-	public $accountStore;
49
-
50
-	/**
51
-	 * @var {Object} The backend store holding all available backends
52
-	 */
53
-	public $backendStore;
54
-
55
-	/**
56
-	 * @constructor
57
-	 *
58
-	 * @param $id
59
-	 * @param $data
60
-	 */
61
-	public function __construct($id, $data) {
62
-		parent::__construct($id, $data);
63
-
64
-		// Initialize the account and backendstore
65
-		$this->accountStore = new \Files\Core\AccountStore();
66
-		$this->backendStore = \Files\Backend\BackendStore::getInstance();
67
-
68
-		// Setup the cache
69
-		$config = new RedisConfig();
70
-		$config->setHost(PLUGIN_FILES_REDIS_HOST);
71
-		$config->setPort(PLUGIN_FILES_REDIS_PORT);
72
-		$config->setPassword(PLUGIN_FILES_REDIS_AUTH);
73
-
74
-		$this->cache = CacheManager::getInstance('Redis', $config);
75
-
76
-		// For backward compatibility we will check if the Encryption store exists. If not,
77
-		// we will fall back to the old way of retrieving the password from the session.
78
-		if (class_exists('EncryptionStore')) {
79
-			// Get the username from the Encryption store
80
-			$encryptionStore = \EncryptionStore::getInstance();
81
-			$this->uid = $encryptionStore->get('username');
82
-		}
83
-		else {
84
-			$this->uid = $_SESSION["username"];
85
-		}
86
-		// As of the V6, the following characters can not longer being a part of the key identifier: {}()/\@:
87
-		// If you try to do so, an \phpFastCache\Exceptions\phpFastCacheInvalidArgumentException will be raised.
88
-		// You must replace them with a safe delimiter such as .|-_
89
-		// @see https://github.com/PHPSocialNetwork/phpfastcache/blob/8.1.2/docs/migration/MigratingFromV5ToV6.md
90
-		$this->uid = str_replace(['{', '}', '(', ')', '/', '\\', '@'], '_', $this->uid);
91
-
92
-		Logger::debug(self::LOG_CONTEXT, "[constructor]: executing the module as uid: " . $this->uid);
93
-	}
94
-
95
-	/**
96
-	 * Function get the folder data from backend.
97
-	 *
98
-	 * @param mixed $isReload
99
-	 *
100
-	 * @return array return folders array
101
-	 */
102
-	public function getHierarchyList($isReload = false) {
103
-		$data = [];
104
-		$data["item"] = [];
105
-		$versions = $GLOBALS['PluginManager']->getPluginsVersion();
106
-		$filesVersion = $versions['files'];
107
-
108
-		// Clear cache when version gets changed and update 'files' version in cache.
109
-		if ($isReload || version_compare($this->getVersionFromCache('files'), $filesVersion) !== 0) {
110
-			$this->clearCache();
111
-			$this->setVersionInCache('files', $filesVersion);
112
-		}
113
-
114
-		$accounts = $this->accountStore->getAllAccounts();
115
-		foreach ($accounts as $account) {
116
-			// we have to load all accounts and their folders
117
-			// skip accounts that are not valid
118
-			if ($account->getStatus() !== \Files\Core\Account::STATUS_OK) {
119
-				continue;
120
-			}
121
-
122
-			// build the real node id for this folder
123
-			$realNodeId = "#R#" . $account->getId() . "/";
124
-			$accountName = $account->getName();
125
-			$rootId = $this->createId($realNodeId);
126
-			$nodes = [
127
-				"store_entryid" => $rootId,
128
-				"props" => [
129
-					'entryid' => $rootId,
130
-					'subtree_id' => $rootId,
131
-					'display_name' => $accountName,
132
-					"object_type" => FILES_STORE,
133
-					"status" => $account->getStatus(),
134
-					"status_description" => $account->getStatusDescription(),
135
-					"backend" => $account->getBackend(),
136
-					"backend_config" => $account->getBackendConfig(),
137
-					'backend_features' => $account->getFeatures(),
138
-					'filename' => $accountName,
139
-					'account_sequence' => $account->getSequence(),
140
-					'cannot_change' => $account->getCannotChangeFlag(),
141
-				],
142
-			];
143
-
144
-			$initializedBackend = $this->initializeBackend($account, true);
145
-
146
-			// Get sub folder of root folder.
147
-			$subFolders = $this->getSubFolders($realNodeId, $initializedBackend);
148
-
149
-			array_push($subFolders, [
150
-				'id' => $realNodeId,
151
-				'folder_id' => $realNodeId,
152
-				'entryid' => $rootId,
153
-				'parent_entryid' => $rootId,
154
-				'store_entryid' => $rootId,
155
-				'props' => [
156
-					'path' => $realNodeId,
157
-					'icon_index' => ICON_FOLDER,
158
-					// Fixme : remove text property. we have to use display_name property.
159
-					'text' => $accountName,
160
-					'has_subfolder' => empty($subFolders) === false,
161
-					'object_type' => FILES_FOLDER,
162
-					'filename' => $accountName,
163
-					'display_name' => $accountName,
164
-				],
165
-			]);
166
-
167
-			// TODO: dummy folder which used client side to show the account view when user
168
-			//  switch to home folder using navigation bar.
169
-			array_push($subFolders, [
170
-				'id' => "#R#",
171
-				'folder_id' => "#R#",
172
-				'entryid' => "#R#",
173
-				'parent_entryid' => $rootId,
174
-				'store_entryid' => $rootId,
175
-				'props' => [
176
-					'path' => $realNodeId,
177
-					'icon_index' => ICON_HOME_FOLDER,
178
-					'text' => "Files",
179
-					'has_subfolder' => false,
180
-					'object_type' => FILES_FOLDER,
181
-					'filename' => "Files",
182
-					'display_name' => "Files",
183
-				],
184
-			]);
185
-			$nodes["folders"] = ["item" => $subFolders];
186
-			array_push($data["item"], $nodes);
187
-		}
188
-
189
-		return $data;
190
-	}
191
-
192
-	/**
193
-	 * Function used to get the sub folders of the given folder id.
194
-	 *
195
-	 * @param string $nodeId    the folder id which used to get sub folders
196
-	 * @param array  $backend   The backend which used to retrieve the folders
197
-	 * @param bool   $recursive the recursive true which get the sub folder recursively
198
-	 * @param array  $nodes     the nodes contains the array of nodes
199
-	 *
200
-	 * @return array return the array folders
201
-	 */
202
-	public function getSubFolders($nodeId, $backend, $recursive = false, $nodes = []) {
203
-		// relative node ID. We need to trim off the #R# and account ID
204
-		$relNodeId = substr($nodeId, strpos($nodeId, '/'));
205
-		$nodeIdPrefix = substr($nodeId, 0, strpos($nodeId, '/'));
206
-
207
-		$accountID = $backend->getAccountID();
208
-
209
-		// remove the trailing slash for the cache key
210
-		$cachePath = rtrim($relNodeId, '/');
211
-		if ($cachePath === "") {
212
-			$cachePath = "/";
213
-		}
214
-
215
-		$backendDisplayName = $backend->backendDisplayName;
216
-		$backendVersion = $backend->backendVersion;
217
-		$cacheVersion = $this->getVersionFromCache($backendDisplayName, $accountID);
218
-		$dir = $this->getCache($accountID, $cachePath);
219
-
220
-		// Get new data from backend when cache is empty or the version of backend got changed.
221
-		if (is_null($dir) || version_compare($backendVersion, $cacheVersion) !== 0) {
222
-			$this->setVersionInCache($backendDisplayName, $backendVersion, $accountID);
223
-			$dir = $backend->ls($relNodeId);
224
-		}
225
-
226
-		if ($dir) {
227
-			$updateCache = false;
228
-			foreach ($dir as $id => $node) {
229
-				$objectType = strcmp($node['resourcetype'], "collection") !== 0 ? FILES_FILE : FILES_FOLDER;
230
-
231
-				// Only get the Folder item.
232
-				if ($objectType !== FILES_FOLDER) {
233
-					continue;
234
-				}
235
-
236
-				// Check if foldernames have a trailing slash, if not, add one!
237
-				if (!StringUtil::endsWith($id, "/")) {
238
-					unset($dir[$id]);
239
-					$id .= "/";
240
-					$dir[$id] = $node;
241
-				}
242
-
243
-				$size = $node['getcontentlength'] === null ? -1 : intval($node['getcontentlength']);
244
-				// folder's dont have a size
245
-				$size = $objectType == FILES_FILE ? $size : -1;
246
-
247
-				$realID = $nodeIdPrefix . $id;
248
-				$filename = stringToUTF8Encode(basename($id));
249
-
250
-				if (!isset($node['entryid']) || !isset($node['parent_entryid']) || !isset($node['store_entryid'])) {
251
-					$parentNode = $this->getParentNode($cachePath, $accountID);
252
-
253
-					$entryid = $this->createId($realID);
254
-					$parentEntryid = $parentNode !== false && isset($parentNode['entryid']) ? $parentNode['entryid'] : $this->createId($nodeId);
255
-					$storeEntryid = $this->createId($nodeIdPrefix . '/');
256
-
257
-					$dir[$id]['entryid'] = $entryid;
258
-					$dir[$id]['parent_entryid'] = $parentEntryid;
259
-					$dir[$id]['store_entryid'] = $storeEntryid;
260
-
261
-					$updateCache = true;
262
-				}
263
-				else {
264
-					$entryid = $node['entryid'];
265
-					$parentEntryid = $node['parent_entryid'];
266
-					$storeEntryid = $node['store_entryid'];
267
-				}
268
-
269
-				$nodeHasSubFolder = $this->hasSubFolder($id, $accountID, $backend);
270
-				// Skip displaying folder whose data is unaccesable.
271
-				// Also update the cache.
272
-				if (is_null($nodeHasSubFolder)) {
273
-					unset($dir[$id]);
274
-					$updateCache = true;
275
-				}
276
-				else {
277
-					array_push($nodes, [
278
-						'id' => $realID,
279
-						'folder_id' => $realID,
280
-						'entryid' => $entryid,
281
-						'parent_entryid' => $parentEntryid,
282
-						'store_entryid' => $storeEntryid,
283
-						'props' => [
284
-							'path' => $nodeId,
285
-							'message_size' => $size,
286
-							'text' => $filename,
287
-							'object_type' => $objectType,
288
-							'icon_index' => ICON_FOLDER,
289
-							'filename' => $filename,
290
-							'display_name' => $filename,
291
-							'lastmodified' => strtotime($node['getlastmodified']) * 1000,
292
-							'has_subfolder' => $nodeHasSubFolder,
293
-						],
294
-					]);
295
-				}
296
-
297
-				// We need to call this function recursively when user rename the folder.
298
-				// we have to send all sub folder as server side notification so grommunio Web
299
-				// can update the sub folder as per it's parent folder is renamed.
300
-				if ($objectType === FILES_FOLDER && $recursive) {
301
-					$nodes = $this->getSubFolders($realID, $backend, true, $nodes);
302
-				}
303
-			}
304
-
305
-			if ($updateCache) {
306
-				$this->setCache($accountID, $cachePath, $dir);
307
-			}
308
-		}
309
-
310
-		return $nodes;
311
-	}
312
-
313
-	/**
314
-	 * Function which used to get the parent folder of selected folder.
315
-	 *
316
-	 * @param string $cachePath the cache path of selected folder
317
-	 * @param string $accountID the account ID in which folder is belongs
318
-	 *
319
-	 * @return array|bool return the parent folder data else false
320
-	 */
321
-	public function getParentNode($cachePath, $accountID) {
322
-		$parentNode = dirname($cachePath, 1);
323
-
324
-		// remove the trailing slash for the cache key
325
-		$parentNode = rtrim($parentNode, '/');
326
-		if ($parentNode === "") {
327
-			$parentNode = "/";
328
-		}
329
-		$dir = $this->getCache($accountID, $parentNode);
330
-
331
-		if (!is_null($dir) && isset($dir[$cachePath . '/'])) {
332
-			return $dir[$cachePath . '/'];
333
-		}
334
-
335
-		return false;
336
-	}
337
-
338
-	/**
339
-	 * Function create the unique id.
340
-	 *
341
-	 * @param {string} $id The folder id
342
-	 *
343
-	 * @return return generated a hash value
344
-	 */
345
-	public function createId($id) {
346
-		return hash("tiger192,3", $id);
347
-	}
348
-
349
-	/**
350
-	 * Function will check that given folder has sub folder or not.
351
-	 * This will retrurn null when there's an exception retrieving folder data.
352
-	 *
353
-	 * @param {String} $id The $id is id of selected folder
354
-	 * @param $accountID
355
-	 * @param $backend
356
-	 *
357
-	 * @return bool or null when unable to access folder data
358
-	 */
359
-	public function hasSubFolder($id, $accountID, $backend) {
360
-		$cachePath = rtrim($id, '/');
361
-		if ($cachePath === "") {
362
-			$cachePath = "/";
363
-		}
364
-
365
-		$dir = $this->getCache($accountID, $cachePath);
366
-		if (is_null($dir)) {
367
-			try {
368
-				$dir = $backend->ls($id);
369
-				$this->setCache($accountID, $cachePath, $dir);
370
-			}
371
-			catch (Exception $e) {
372
-				$errorCode = $e->getCode();
373
-
374
-				// If folder not found or folder doesn't have enough access then don't display that folder.
375
-				if ($errorCode === self::SMB_ERR_UNAUTHORIZED ||
376
-				$errorCode === self::SMB_ERR_FORBIDDEN ||
377
-				$errorCode === self::FTP_WD_OWNCLOUD_ERR_UNAUTHORIZED ||
378
-				$errorCode === self::FTP_WD_OWNCLOUD_ERR_FORBIDDEN ||
379
-				$errorCode === self::ALL_BACKEND_ERR_NOTFOUND) {
380
-					if ($errorCode === self::ALL_BACKEND_ERR_NOTFOUND) {
381
-						Logger::error(self::LOG_CONTEXT, '[hasSubFolder]: folder ' . $id . ' not found');
382
-					}
383
-					else {
384
-						Logger::error(self::LOG_CONTEXT, '[hasSubFolder]: Access denied for folder ' . $id);
385
-					}
386
-
387
-					return null;
388
-				}
389
-				// rethrow exception if its not related to access permission.
390
-				throw $e;
391
-			}
392
-		}
393
-
394
-		if ($dir) {
395
-			foreach ($dir as $id => $node) {
396
-				if (strcmp($node['resourcetype'], "collection") === 0) {
397
-					// we have a folder
398
-					return true;
399
-				}
400
-			}
401
-		}
402
-
403
-		return false;
404
-	}
405
-
406
-	/**
407
-	 * @param $actionType
408
-	 * @param $actionData
409
-	 *
410
-	 * @throws \Files\Backend\Exception
411
-	 */
412
-	public function save($actionData) {
413
-		$response = [];
414
-		$props = $actionData["props"];
415
-		$messageProps = [];
416
-		if (isset($actionData["entryid"]) && empty($actionData["entryid"])) {
417
-			$path = isset($props['path']) && !empty($props['path']) ? $props['path'] : "/";
418
-
419
-			$relDirname = substr($path, strpos($path, '/'));
420
-			$relDirname = $relDirname . $props["display_name"] . '/';
421
-			$account = $this->accountFromNode($path);
422
-
423
-			// initialize the backend
424
-			$initializedBackend = $this->initializeBackend($account, true);
425
-			$relDirname = stringToUTF8Encode($relDirname);
426
-			$result = $initializedBackend->mkcol($relDirname); // create it !
427
-
428
-			$filesPath = substr($path, strpos($path, '/'));
429
-			$dir = $initializedBackend->ls($filesPath);
430
-
431
-			$id = $path . $props["display_name"] . '/';
432
-
433
-			$actionId = $account->getId();
434
-
435
-			$entryid = $this->createId($id);
436
-			$parentEntryid = $actionData["parent_entryid"];
437
-			$storeEntryid = $this->createId('#R#' . $actionId . '/');
438
-
439
-			$cachePath = rtrim($relDirname, '/');
440
-			if ($cachePath === "") {
441
-				$cachePath = "/";
442
-			}
443
-
444
-			if (isset($dir[$relDirname]) && !empty($dir[$relDirname])) {
445
-				$newDir = $dir[$relDirname];
446
-				$newDir['entryid'] = $entryid;
447
-				$newDir['parent_entryid'] = $parentEntryid;
448
-				$newDir['store_entryid'] = $storeEntryid;
449
-
450
-				// Get old cached data.
451
-				$cachedDir = $this->getCache($actionId, dirname($cachePath, 1));
452
-
453
-				// Insert newly created folder info with entryid, parentEntryid and storeEntryid
454
-				// in already cached data.
455
-				$cachedDir[$relDirname] = $newDir;
456
-				$dir = $cachedDir;
457
-			}
458
-
459
-			// Delete old cache.
460
-			$this->deleteCache($actionId, dirname($relDirname));
461
-
462
-			// Set data in cache.
463
-			$this->setCache($actionId, dirname($relDirname), $dir);
464
-
465
-			if ($result) {
466
-				$folder = [
467
-					'props' => [
468
-						'path' => $path,
469
-						'filename' => $props["display_name"],
470
-						'display_name' => $props["display_name"],
471
-						'text' => $props["display_name"],
472
-						'object_type' => $props['object_type'],
473
-						'has_subfolder' => false,
474
-					],
475
-					'id' => rawurldecode($id),
476
-					'folder_id' => rawurldecode($id),
477
-					'entryid' => $entryid,
478
-					'parent_entryid' => $parentEntryid,
479
-					'store_entryid' => $storeEntryid,
480
-				];
481
-				$response = $folder;
482
-			}
483
-		}
484
-		else {
485
-			// Rename/update the folder/file name
486
-			$folderId = $actionData['message_action']["source_folder_id"];
487
-			// rename/update the folder or files name.
488
-			$parentEntryid = $actionData["parent_entryid"];
489
-
490
-			$isfolder = "";
491
-			if (substr($folderId, -1) == '/') {
492
-				$isfolder = "/"; // we have a folder...
493
-			}
494
-
495
-			$src = rtrim($folderId, '/');
496
-			$dstdir = dirname($src) == "/" ? "" : dirname($src);
497
-			$dst = $dstdir . "/" . rtrim($props['filename'], '/');
498
-
499
-			$relDst = substr($dst, strpos($dst, '/'));
500
-			$relSrc = substr($src, strpos($src, '/'));
501
-
502
-			$account = $this->accountFromNode($src);
503
-
504
-			// initialize the backend
505
-			$initializedBackend = $this->initializeBackend($account);
506
-
507
-			$result = $initializedBackend->move($relSrc, $relDst, false);
508
-
509
-			// get the cache data of parent directory.
510
-			$dir = $this->getCache($account->getId(), dirname($relSrc));
511
-			if (isset($dir[$relSrc . "/"]) && !empty($dir[$relSrc . "/"])) {
512
-				$srcDir = $dir[$relSrc . "/"];
513
-				unset($dir[$relSrc . "/"]);
514
-				$dir[$relDst . "/"] = $srcDir;
515
-
516
-				// Update only rename folder info in php cache.
517
-				$this->setCache($account->getId(), dirname($relSrc), $dir);
518
-
519
-				$this->updateCacheAfterRename($relSrc, $relDst, $account->getId());
520
-			}
521
-			else {
522
-				// clear the cache
523
-				$this->deleteCache($account->getId(), dirname($relSrc));
524
-			}
525
-
526
-			if ($result) {
527
-				/* create the response object */
528
-				$folder = [];
529
-
530
-				// some requests might not contain a new filename... so dont update the store
531
-				if (isset($props['filename'])) {
532
-					$folder = [
533
-						'props' => [
534
-							'folder_id' => rawurldecode($dst . $isfolder),
535
-							'path' => rawurldecode($dstdir),
536
-							'filename' => $props['filename'],
537
-							'display_name' => $props['filename'],
538
-						],
539
-						'entryid' => $actionData["entryid"],
540
-						'parent_entryid' => $parentEntryid,
541
-						'store_entryid' => $actionData["store_entryid"],
542
-					];
543
-				}
544
-				$response['item'] = $folder;
545
-				$messageProps = $folder;
546
-			}
547
-		}
548
-
549
-		$this->addActionData("update", $response);
550
-		$GLOBALS["bus"]->addData($this->getResponseData());
551
-
552
-		return $messageProps;
553
-	}
554
-
555
-	/**
556
-	 * Update the cache of renamed folder and it's sub folders.
557
-	 *
558
-	 * @param {String} $oldPath The $oldPath is path of folder before rename
559
-	 * @param {String} $newPath The $newPath is path of folder after rename
560
-	 * @param {String} $accountId The id of an account in which renamed folder is belongs
561
-	 */
562
-	public function updateCacheAfterRename($oldPath, $newPath, $accountId) {
563
-		// remove the trailing slash for the cache key
564
-		$cachePath = rtrim($oldPath, '/');
565
-		if ($cachePath === "") {
566
-			$cachePath = "/";
567
-		}
568
-
569
-		$dir = $this->getCache($accountId, $cachePath);
570
-		if ($dir) {
571
-			foreach ($dir as $id => $node) {
572
-				$newId = str_replace(dirname($id), $newPath, $id);
573
-				unset($dir[$id]);
574
-				$dir[$newId] = $node;
575
-
576
-				$type = FILES_FILE;
577
-
578
-				if (strcmp($node['resourcetype'], "collection") == 0) { // we have a folder
579
-					$type = FILES_FOLDER;
580
-				}
581
-
582
-				if ($type === FILES_FOLDER) {
583
-					$this->updateCacheAfterRename($id, rtrim($newId, '/'), $accountId);
584
-				}
585
-			}
586
-			$this->deleteCache($accountId, $cachePath);
587
-			$this->setCache($accountId, $newPath, $dir);
588
-		}
589
-	}
590
-
591
-	/**
592
-	 * Function used to notify the sub folder of selected/modified folder.
593
-	 *
594
-	 * @param {String} $folderID The $folderID of a folder which is modified
595
-	 */
596
-	public function notifySubFolders($folderID) {
597
-		$account = $this->accountFromNode($folderID);
598
-		$initializedBackend = $this->initializeBackend($account, true);
599
-		$folderData = $this->getSubFolders($folderID, $initializedBackend, true);
600
-
601
-		if (!empty($folderData)) {
602
-			$GLOBALS["bus"]->notify(REQUEST_ENTRYID, OBJECT_SAVE, $folderData);
603
-		}
604
-	}
605
-
606
-	/**
607
-	 * Get the account id from a node id.
608
-	 *
609
-	 * @param {String} $nodeID Id of the file or folder to operate on
610
-	 *
611
-	 * @return {String} The account id extracted from $nodeId
612
-	 */
613
-	public function accountIDFromNode($nodeID) {
614
-		return substr($nodeID, 3, (strpos($nodeID, '/') - 3)); // parse account id from node id
615
-	}
616
-
617
-	/**
618
-	 * Get the account from a node id.
619
-	 *
620
-	 * @param {String} $nodeId ID of the file or folder to operate on
621
-	 * @param mixed $nodeID
622
-	 *
623
-	 * @return {String} The account for $nodeId
624
-	 */
625
-	public function accountFromNode($nodeID) {
626
-		return $this->accountStore->getAccount($this->accountIDFromNode($nodeID));
627
-	}
628
-
629
-	/**
630
-	 * Create a key used to store data in the cache.
631
-	 *
632
-	 * @param {String} $accountID Id of the account of the data to cache
633
-	 * @param {String} $path Path of the file or folder to create the cache element for
634
-	 *
635
-	 * @return {String} The created key
636
-	 */
637
-	public function makeCacheKey($accountID, $path) {
638
-		return $this->uid . md5($accountID . $path);
639
-	}
640
-
641
-	/**
642
-	 * Get version data form the cache.
643
-	 *
644
-	 * @param {String} $displayName display name of the backend or file plugin
645
-	 * @param {String} $accountID Id of the account of the data to cache
646
-	 *
647
-	 * @return {String} version data or null if nothing was found
648
-	 */
649
-	public function getVersionFromCache($displayName, $accountID = '') {
650
-		$key = $this->uid . $accountID . $displayName;
651
-
652
-		return $this->cache->getItem($key)->get();
653
-	}
654
-
655
-	/**
656
-	 * Set version data in the cache only when version data has been changed.
657
-	 *
658
-	 * @param {String} $displayName display name of the backend or file plugin
659
-	 * @param {String} $version version info of backend or file plugin which needs to be cached
660
-	 * @param {String} $accountID Id of the account of the data to cache
661
-	 */
662
-	public function setVersionInCache($displayName, $version, $accountID = '') {
663
-		$olderVersionFromCache = $this->getVersionFromCache($displayName, $accountID);
664
-		// If version of files/backend is same then return.
665
-		if (version_compare($olderVersionFromCache, $version) === 0) {
666
-			return;
667
-		}
668
-
669
-		$key = $this->uid . $accountID . $displayName;
670
-		$this->cache->save($this->cache->getItem($key)->set($version));
671
-	}
672
-
673
-	/**
674
-	 * Initialize the backend for the given account.
675
-	 *
676
-	 * @param {Object} $account The account object the backend should be initialized for
677
-	 * @param {Bool} $setID Should the accountID be set in the backend object, or not. Defaults to false.
678
-	 *
679
-	 * @return {Object} The initialized backend
680
-	 */
681
-	public function initializeBackend($account, $setID = false) {
682
-		$backend = $this->backendStore->getInstanceOfBackend($account->getBackend());
683
-		$backend->init_backend($account->getBackendConfig());
684
-		if ($setID) {
685
-			$backend->setAccountID($account->getId());
686
-		}
687
-		$backend->open();
688
-
689
-		return $backend;
690
-	}
691
-
692
-	/**
693
-	 * Save directory data in the cache.
694
-	 *
695
-	 * @param {String} $accountID Id of the account of the data to cache
696
-	 * @param {String} $path Path of the file or folder to create the cache element for
697
-	 * @param {String} $data Data to be cached
698
-	 */
699
-	public function setCache($accountID, $path, $data) {
700
-		$key = $this->makeCacheKey($accountID, $path);
701
-		Logger::debug(self::LOG_CONTEXT, "Setting cache for node: " . $accountID . $path . " ## " . $key);
702
-		$this->cache->save($this->cache->getItem($key)->set($data));
703
-	}
704
-
705
-	/**
706
-	 * Get directotry data form the cache.
707
-	 *
708
-	 * @param {String} $accountID Id of the account of the data to get
709
-	 * @param {String} $path Path of the file or folder to retrieve the cache element for
710
-	 *
711
-	 * @return {String} The directory data or null if nothing was found
712
-	 */
713
-	public function getCache($accountID, $path) {
714
-		$key = $this->makeCacheKey($accountID, $path);
715
-		Logger::debug(self::LOG_CONTEXT, "Getting cache for node: " . $accountID . $path . " ## " . $key);
716
-
717
-		return $this->cache->getItem($key)->get();
718
-	}
719
-
720
-	/**
721
-	 * Remove data from the cache.
722
-	 *
723
-	 * @param {String} $accountID Id of the account to delete the cache for
724
-	 * @param {String} $path Path of the file or folder to delete the cache element
725
-	 */
726
-	public function deleteCache($accountID, $path) {
727
-		$key = $this->makeCacheKey($accountID, $path);
728
-		Logger::debug(self::LOG_CONTEXT, "Removing cache for node: " . $accountID . $path . " ## " . $key);
729
-		$this->cache->deleteItem($key);
730
-	}
731
-
732
-	/**
733
-	 * Function clear the cache.
734
-	 */
735
-	public function clearCache() {
736
-		$this->cache->clear();
737
-	}
738
-
739
-	/**
740
-	 * Function which returns MAPI Message Store Object. It
741
-	 * searches in the variable $action for a storeid.
742
-	 *
743
-	 * @param array $action the XML data retrieved from the client
744
-	 *
745
-	 * @return object MAPI Message Store Object, false if storeid is not found in the $action variable
746
-	 */
747
-	public function getActionStore($action) {
748
-		$store = false;
749
-
750
-		if (isset($action["store_entryid"]) && !empty($action["store_entryid"])) {
751
-			if (is_array($action["store_entryid"])) {
752
-				$store = [];
753
-				foreach ($action["store_entryid"] as $store_id) {
754
-					array_push($store, $store_id);
755
-				}
756
-			}
757
-			else {
758
-				$store = $action["store_entryid"];
759
-			}
760
-		}
761
-
762
-		return $store;
763
-	}
26
+    public const LOG_CONTEXT = "FilesListModule"; // Context for the Logger
27
+
28
+    // Unauthorized errors of different backends.
29
+    public const SMB_ERR_UNAUTHORIZED = 13;
30
+    public const SMB_ERR_FORBIDDEN = 1;
31
+    public const FTP_WD_OWNCLOUD_ERR_UNAUTHORIZED = 401;
32
+    public const FTP_WD_OWNCLOUD_ERR_FORBIDDEN = 403;
33
+    public const ALL_BACKEND_ERR_NOTFOUND = 404;
34
+
35
+    /**
36
+     * @var \phpFastCache cache handler
37
+     */
38
+    public $cache;
39
+
40
+    /**
41
+     * @var string User id of the currently logged in user. Used to generate unique cache id's.
42
+     */
43
+    public $uid;
44
+
45
+    /**
46
+     * @var {Object} The account store holding all available accounts
47
+     */
48
+    public $accountStore;
49
+
50
+    /**
51
+     * @var {Object} The backend store holding all available backends
52
+     */
53
+    public $backendStore;
54
+
55
+    /**
56
+     * @constructor
57
+     *
58
+     * @param $id
59
+     * @param $data
60
+     */
61
+    public function __construct($id, $data) {
62
+        parent::__construct($id, $data);
63
+
64
+        // Initialize the account and backendstore
65
+        $this->accountStore = new \Files\Core\AccountStore();
66
+        $this->backendStore = \Files\Backend\BackendStore::getInstance();
67
+
68
+        // Setup the cache
69
+        $config = new RedisConfig();
70
+        $config->setHost(PLUGIN_FILES_REDIS_HOST);
71
+        $config->setPort(PLUGIN_FILES_REDIS_PORT);
72
+        $config->setPassword(PLUGIN_FILES_REDIS_AUTH);
73
+
74
+        $this->cache = CacheManager::getInstance('Redis', $config);
75
+
76
+        // For backward compatibility we will check if the Encryption store exists. If not,
77
+        // we will fall back to the old way of retrieving the password from the session.
78
+        if (class_exists('EncryptionStore')) {
79
+            // Get the username from the Encryption store
80
+            $encryptionStore = \EncryptionStore::getInstance();
81
+            $this->uid = $encryptionStore->get('username');
82
+        }
83
+        else {
84
+            $this->uid = $_SESSION["username"];
85
+        }
86
+        // As of the V6, the following characters can not longer being a part of the key identifier: {}()/\@:
87
+        // If you try to do so, an \phpFastCache\Exceptions\phpFastCacheInvalidArgumentException will be raised.
88
+        // You must replace them with a safe delimiter such as .|-_
89
+        // @see https://github.com/PHPSocialNetwork/phpfastcache/blob/8.1.2/docs/migration/MigratingFromV5ToV6.md
90
+        $this->uid = str_replace(['{', '}', '(', ')', '/', '\\', '@'], '_', $this->uid);
91
+
92
+        Logger::debug(self::LOG_CONTEXT, "[constructor]: executing the module as uid: " . $this->uid);
93
+    }
94
+
95
+    /**
96
+     * Function get the folder data from backend.
97
+     *
98
+     * @param mixed $isReload
99
+     *
100
+     * @return array return folders array
101
+     */
102
+    public function getHierarchyList($isReload = false) {
103
+        $data = [];
104
+        $data["item"] = [];
105
+        $versions = $GLOBALS['PluginManager']->getPluginsVersion();
106
+        $filesVersion = $versions['files'];
107
+
108
+        // Clear cache when version gets changed and update 'files' version in cache.
109
+        if ($isReload || version_compare($this->getVersionFromCache('files'), $filesVersion) !== 0) {
110
+            $this->clearCache();
111
+            $this->setVersionInCache('files', $filesVersion);
112
+        }
113
+
114
+        $accounts = $this->accountStore->getAllAccounts();
115
+        foreach ($accounts as $account) {
116
+            // we have to load all accounts and their folders
117
+            // skip accounts that are not valid
118
+            if ($account->getStatus() !== \Files\Core\Account::STATUS_OK) {
119
+                continue;
120
+            }
121
+
122
+            // build the real node id for this folder
123
+            $realNodeId = "#R#" . $account->getId() . "/";
124
+            $accountName = $account->getName();
125
+            $rootId = $this->createId($realNodeId);
126
+            $nodes = [
127
+                "store_entryid" => $rootId,
128
+                "props" => [
129
+                    'entryid' => $rootId,
130
+                    'subtree_id' => $rootId,
131
+                    'display_name' => $accountName,
132
+                    "object_type" => FILES_STORE,
133
+                    "status" => $account->getStatus(),
134
+                    "status_description" => $account->getStatusDescription(),
135
+                    "backend" => $account->getBackend(),
136
+                    "backend_config" => $account->getBackendConfig(),
137
+                    'backend_features' => $account->getFeatures(),
138
+                    'filename' => $accountName,
139
+                    'account_sequence' => $account->getSequence(),
140
+                    'cannot_change' => $account->getCannotChangeFlag(),
141
+                ],
142
+            ];
143
+
144
+            $initializedBackend = $this->initializeBackend($account, true);
145
+
146
+            // Get sub folder of root folder.
147
+            $subFolders = $this->getSubFolders($realNodeId, $initializedBackend);
148
+
149
+            array_push($subFolders, [
150
+                'id' => $realNodeId,
151
+                'folder_id' => $realNodeId,
152
+                'entryid' => $rootId,
153
+                'parent_entryid' => $rootId,
154
+                'store_entryid' => $rootId,
155
+                'props' => [
156
+                    'path' => $realNodeId,
157
+                    'icon_index' => ICON_FOLDER,
158
+                    // Fixme : remove text property. we have to use display_name property.
159
+                    'text' => $accountName,
160
+                    'has_subfolder' => empty($subFolders) === false,
161
+                    'object_type' => FILES_FOLDER,
162
+                    'filename' => $accountName,
163
+                    'display_name' => $accountName,
164
+                ],
165
+            ]);
166
+
167
+            // TODO: dummy folder which used client side to show the account view when user
168
+            //  switch to home folder using navigation bar.
169
+            array_push($subFolders, [
170
+                'id' => "#R#",
171
+                'folder_id' => "#R#",
172
+                'entryid' => "#R#",
173
+                'parent_entryid' => $rootId,
174
+                'store_entryid' => $rootId,
175
+                'props' => [
176
+                    'path' => $realNodeId,
177
+                    'icon_index' => ICON_HOME_FOLDER,
178
+                    'text' => "Files",
179
+                    'has_subfolder' => false,
180
+                    'object_type' => FILES_FOLDER,
181
+                    'filename' => "Files",
182
+                    'display_name' => "Files",
183
+                ],
184
+            ]);
185
+            $nodes["folders"] = ["item" => $subFolders];
186
+            array_push($data["item"], $nodes);
187
+        }
188
+
189
+        return $data;
190
+    }
191
+
192
+    /**
193
+     * Function used to get the sub folders of the given folder id.
194
+     *
195
+     * @param string $nodeId    the folder id which used to get sub folders
196
+     * @param array  $backend   The backend which used to retrieve the folders
197
+     * @param bool   $recursive the recursive true which get the sub folder recursively
198
+     * @param array  $nodes     the nodes contains the array of nodes
199
+     *
200
+     * @return array return the array folders
201
+     */
202
+    public function getSubFolders($nodeId, $backend, $recursive = false, $nodes = []) {
203
+        // relative node ID. We need to trim off the #R# and account ID
204
+        $relNodeId = substr($nodeId, strpos($nodeId, '/'));
205
+        $nodeIdPrefix = substr($nodeId, 0, strpos($nodeId, '/'));
206
+
207
+        $accountID = $backend->getAccountID();
208
+
209
+        // remove the trailing slash for the cache key
210
+        $cachePath = rtrim($relNodeId, '/');
211
+        if ($cachePath === "") {
212
+            $cachePath = "/";
213
+        }
214
+
215
+        $backendDisplayName = $backend->backendDisplayName;
216
+        $backendVersion = $backend->backendVersion;
217
+        $cacheVersion = $this->getVersionFromCache($backendDisplayName, $accountID);
218
+        $dir = $this->getCache($accountID, $cachePath);
219
+
220
+        // Get new data from backend when cache is empty or the version of backend got changed.
221
+        if (is_null($dir) || version_compare($backendVersion, $cacheVersion) !== 0) {
222
+            $this->setVersionInCache($backendDisplayName, $backendVersion, $accountID);
223
+            $dir = $backend->ls($relNodeId);
224
+        }
225
+
226
+        if ($dir) {
227
+            $updateCache = false;
228
+            foreach ($dir as $id => $node) {
229
+                $objectType = strcmp($node['resourcetype'], "collection") !== 0 ? FILES_FILE : FILES_FOLDER;
230
+
231
+                // Only get the Folder item.
232
+                if ($objectType !== FILES_FOLDER) {
233
+                    continue;
234
+                }
235
+
236
+                // Check if foldernames have a trailing slash, if not, add one!
237
+                if (!StringUtil::endsWith($id, "/")) {
238
+                    unset($dir[$id]);
239
+                    $id .= "/";
240
+                    $dir[$id] = $node;
241
+                }
242
+
243
+                $size = $node['getcontentlength'] === null ? -1 : intval($node['getcontentlength']);
244
+                // folder's dont have a size
245
+                $size = $objectType == FILES_FILE ? $size : -1;
246
+
247
+                $realID = $nodeIdPrefix . $id;
248
+                $filename = stringToUTF8Encode(basename($id));
249
+
250
+                if (!isset($node['entryid']) || !isset($node['parent_entryid']) || !isset($node['store_entryid'])) {
251
+                    $parentNode = $this->getParentNode($cachePath, $accountID);
252
+
253
+                    $entryid = $this->createId($realID);
254
+                    $parentEntryid = $parentNode !== false && isset($parentNode['entryid']) ? $parentNode['entryid'] : $this->createId($nodeId);
255
+                    $storeEntryid = $this->createId($nodeIdPrefix . '/');
256
+
257
+                    $dir[$id]['entryid'] = $entryid;
258
+                    $dir[$id]['parent_entryid'] = $parentEntryid;
259
+                    $dir[$id]['store_entryid'] = $storeEntryid;
260
+
261
+                    $updateCache = true;
262
+                }
263
+                else {
264
+                    $entryid = $node['entryid'];
265
+                    $parentEntryid = $node['parent_entryid'];
266
+                    $storeEntryid = $node['store_entryid'];
267
+                }
268
+
269
+                $nodeHasSubFolder = $this->hasSubFolder($id, $accountID, $backend);
270
+                // Skip displaying folder whose data is unaccesable.
271
+                // Also update the cache.
272
+                if (is_null($nodeHasSubFolder)) {
273
+                    unset($dir[$id]);
274
+                    $updateCache = true;
275
+                }
276
+                else {
277
+                    array_push($nodes, [
278
+                        'id' => $realID,
279
+                        'folder_id' => $realID,
280
+                        'entryid' => $entryid,
281
+                        'parent_entryid' => $parentEntryid,
282
+                        'store_entryid' => $storeEntryid,
283
+                        'props' => [
284
+                            'path' => $nodeId,
285
+                            'message_size' => $size,
286
+                            'text' => $filename,
287
+                            'object_type' => $objectType,
288
+                            'icon_index' => ICON_FOLDER,
289
+                            'filename' => $filename,
290
+                            'display_name' => $filename,
291
+                            'lastmodified' => strtotime($node['getlastmodified']) * 1000,
292
+                            'has_subfolder' => $nodeHasSubFolder,
293
+                        ],
294
+                    ]);
295
+                }
296
+
297
+                // We need to call this function recursively when user rename the folder.
298
+                // we have to send all sub folder as server side notification so grommunio Web
299
+                // can update the sub folder as per it's parent folder is renamed.
300
+                if ($objectType === FILES_FOLDER && $recursive) {
301
+                    $nodes = $this->getSubFolders($realID, $backend, true, $nodes);
302
+                }
303
+            }
304
+
305
+            if ($updateCache) {
306
+                $this->setCache($accountID, $cachePath, $dir);
307
+            }
308
+        }
309
+
310
+        return $nodes;
311
+    }
312
+
313
+    /**
314
+     * Function which used to get the parent folder of selected folder.
315
+     *
316
+     * @param string $cachePath the cache path of selected folder
317
+     * @param string $accountID the account ID in which folder is belongs
318
+     *
319
+     * @return array|bool return the parent folder data else false
320
+     */
321
+    public function getParentNode($cachePath, $accountID) {
322
+        $parentNode = dirname($cachePath, 1);
323
+
324
+        // remove the trailing slash for the cache key
325
+        $parentNode = rtrim($parentNode, '/');
326
+        if ($parentNode === "") {
327
+            $parentNode = "/";
328
+        }
329
+        $dir = $this->getCache($accountID, $parentNode);
330
+
331
+        if (!is_null($dir) && isset($dir[$cachePath . '/'])) {
332
+            return $dir[$cachePath . '/'];
333
+        }
334
+
335
+        return false;
336
+    }
337
+
338
+    /**
339
+     * Function create the unique id.
340
+     *
341
+     * @param {string} $id The folder id
342
+     *
343
+     * @return return generated a hash value
344
+     */
345
+    public function createId($id) {
346
+        return hash("tiger192,3", $id);
347
+    }
348
+
349
+    /**
350
+     * Function will check that given folder has sub folder or not.
351
+     * This will retrurn null when there's an exception retrieving folder data.
352
+     *
353
+     * @param {String} $id The $id is id of selected folder
354
+     * @param $accountID
355
+     * @param $backend
356
+     *
357
+     * @return bool or null when unable to access folder data
358
+     */
359
+    public function hasSubFolder($id, $accountID, $backend) {
360
+        $cachePath = rtrim($id, '/');
361
+        if ($cachePath === "") {
362
+            $cachePath = "/";
363
+        }
364
+
365
+        $dir = $this->getCache($accountID, $cachePath);
366
+        if (is_null($dir)) {
367
+            try {
368
+                $dir = $backend->ls($id);
369
+                $this->setCache($accountID, $cachePath, $dir);
370
+            }
371
+            catch (Exception $e) {
372
+                $errorCode = $e->getCode();
373
+
374
+                // If folder not found or folder doesn't have enough access then don't display that folder.
375
+                if ($errorCode === self::SMB_ERR_UNAUTHORIZED ||
376
+                $errorCode === self::SMB_ERR_FORBIDDEN ||
377
+                $errorCode === self::FTP_WD_OWNCLOUD_ERR_UNAUTHORIZED ||
378
+                $errorCode === self::FTP_WD_OWNCLOUD_ERR_FORBIDDEN ||
379
+                $errorCode === self::ALL_BACKEND_ERR_NOTFOUND) {
380
+                    if ($errorCode === self::ALL_BACKEND_ERR_NOTFOUND) {
381
+                        Logger::error(self::LOG_CONTEXT, '[hasSubFolder]: folder ' . $id . ' not found');
382
+                    }
383
+                    else {
384
+                        Logger::error(self::LOG_CONTEXT, '[hasSubFolder]: Access denied for folder ' . $id);
385
+                    }
386
+
387
+                    return null;
388
+                }
389
+                // rethrow exception if its not related to access permission.
390
+                throw $e;
391
+            }
392
+        }
393
+
394
+        if ($dir) {
395
+            foreach ($dir as $id => $node) {
396
+                if (strcmp($node['resourcetype'], "collection") === 0) {
397
+                    // we have a folder
398
+                    return true;
399
+                }
400
+            }
401
+        }
402
+
403
+        return false;
404
+    }
405
+
406
+    /**
407
+     * @param $actionType
408
+     * @param $actionData
409
+     *
410
+     * @throws \Files\Backend\Exception
411
+     */
412
+    public function save($actionData) {
413
+        $response = [];
414
+        $props = $actionData["props"];
415
+        $messageProps = [];
416
+        if (isset($actionData["entryid"]) && empty($actionData["entryid"])) {
417
+            $path = isset($props['path']) && !empty($props['path']) ? $props['path'] : "/";
418
+
419
+            $relDirname = substr($path, strpos($path, '/'));
420
+            $relDirname = $relDirname . $props["display_name"] . '/';
421
+            $account = $this->accountFromNode($path);
422
+
423
+            // initialize the backend
424
+            $initializedBackend = $this->initializeBackend($account, true);
425
+            $relDirname = stringToUTF8Encode($relDirname);
426
+            $result = $initializedBackend->mkcol($relDirname); // create it !
427
+
428
+            $filesPath = substr($path, strpos($path, '/'));
429
+            $dir = $initializedBackend->ls($filesPath);
430
+
431
+            $id = $path . $props["display_name"] . '/';
432
+
433
+            $actionId = $account->getId();
434
+
435
+            $entryid = $this->createId($id);
436
+            $parentEntryid = $actionData["parent_entryid"];
437
+            $storeEntryid = $this->createId('#R#' . $actionId . '/');
438
+
439
+            $cachePath = rtrim($relDirname, '/');
440
+            if ($cachePath === "") {
441
+                $cachePath = "/";
442
+            }
443
+
444
+            if (isset($dir[$relDirname]) && !empty($dir[$relDirname])) {
445
+                $newDir = $dir[$relDirname];
446
+                $newDir['entryid'] = $entryid;
447
+                $newDir['parent_entryid'] = $parentEntryid;
448
+                $newDir['store_entryid'] = $storeEntryid;
449
+
450
+                // Get old cached data.
451
+                $cachedDir = $this->getCache($actionId, dirname($cachePath, 1));
452
+
453
+                // Insert newly created folder info with entryid, parentEntryid and storeEntryid
454
+                // in already cached data.
455
+                $cachedDir[$relDirname] = $newDir;
456
+                $dir = $cachedDir;
457
+            }
458
+
459
+            // Delete old cache.
460
+            $this->deleteCache($actionId, dirname($relDirname));
461
+
462
+            // Set data in cache.
463
+            $this->setCache($actionId, dirname($relDirname), $dir);
464
+
465
+            if ($result) {
466
+                $folder = [
467
+                    'props' => [
468
+                        'path' => $path,
469
+                        'filename' => $props["display_name"],
470
+                        'display_name' => $props["display_name"],
471
+                        'text' => $props["display_name"],
472
+                        'object_type' => $props['object_type'],
473
+                        'has_subfolder' => false,
474
+                    ],
475
+                    'id' => rawurldecode($id),
476
+                    'folder_id' => rawurldecode($id),
477
+                    'entryid' => $entryid,
478
+                    'parent_entryid' => $parentEntryid,
479
+                    'store_entryid' => $storeEntryid,
480
+                ];
481
+                $response = $folder;
482
+            }
483
+        }
484
+        else {
485
+            // Rename/update the folder/file name
486
+            $folderId = $actionData['message_action']["source_folder_id"];
487
+            // rename/update the folder or files name.
488
+            $parentEntryid = $actionData["parent_entryid"];
489
+
490
+            $isfolder = "";
491
+            if (substr($folderId, -1) == '/') {
492
+                $isfolder = "/"; // we have a folder...
493
+            }
494
+
495
+            $src = rtrim($folderId, '/');
496
+            $dstdir = dirname($src) == "/" ? "" : dirname($src);
497
+            $dst = $dstdir . "/" . rtrim($props['filename'], '/');
498
+
499
+            $relDst = substr($dst, strpos($dst, '/'));
500
+            $relSrc = substr($src, strpos($src, '/'));
501
+
502
+            $account = $this->accountFromNode($src);
503
+
504
+            // initialize the backend
505
+            $initializedBackend = $this->initializeBackend($account);
506
+
507
+            $result = $initializedBackend->move($relSrc, $relDst, false);
508
+
509
+            // get the cache data of parent directory.
510
+            $dir = $this->getCache($account->getId(), dirname($relSrc));
511
+            if (isset($dir[$relSrc . "/"]) && !empty($dir[$relSrc . "/"])) {
512
+                $srcDir = $dir[$relSrc . "/"];
513
+                unset($dir[$relSrc . "/"]);
514
+                $dir[$relDst . "/"] = $srcDir;
515
+
516
+                // Update only rename folder info in php cache.
517
+                $this->setCache($account->getId(), dirname($relSrc), $dir);
518
+
519
+                $this->updateCacheAfterRename($relSrc, $relDst, $account->getId());
520
+            }
521
+            else {
522
+                // clear the cache
523
+                $this->deleteCache($account->getId(), dirname($relSrc));
524
+            }
525
+
526
+            if ($result) {
527
+                /* create the response object */
528
+                $folder = [];
529
+
530
+                // some requests might not contain a new filename... so dont update the store
531
+                if (isset($props['filename'])) {
532
+                    $folder = [
533
+                        'props' => [
534
+                            'folder_id' => rawurldecode($dst . $isfolder),
535
+                            'path' => rawurldecode($dstdir),
536
+                            'filename' => $props['filename'],
537
+                            'display_name' => $props['filename'],
538
+                        ],
539
+                        'entryid' => $actionData["entryid"],
540
+                        'parent_entryid' => $parentEntryid,
541
+                        'store_entryid' => $actionData["store_entryid"],
542
+                    ];
543
+                }
544
+                $response['item'] = $folder;
545
+                $messageProps = $folder;
546
+            }
547
+        }
548
+
549
+        $this->addActionData("update", $response);
550
+        $GLOBALS["bus"]->addData($this->getResponseData());
551
+
552
+        return $messageProps;
553
+    }
554
+
555
+    /**
556
+     * Update the cache of renamed folder and it's sub folders.
557
+     *
558
+     * @param {String} $oldPath The $oldPath is path of folder before rename
559
+     * @param {String} $newPath The $newPath is path of folder after rename
560
+     * @param {String} $accountId The id of an account in which renamed folder is belongs
561
+     */
562
+    public function updateCacheAfterRename($oldPath, $newPath, $accountId) {
563
+        // remove the trailing slash for the cache key
564
+        $cachePath = rtrim($oldPath, '/');
565
+        if ($cachePath === "") {
566
+            $cachePath = "/";
567
+        }
568
+
569
+        $dir = $this->getCache($accountId, $cachePath);
570
+        if ($dir) {
571
+            foreach ($dir as $id => $node) {
572
+                $newId = str_replace(dirname($id), $newPath, $id);
573
+                unset($dir[$id]);
574
+                $dir[$newId] = $node;
575
+
576
+                $type = FILES_FILE;
577
+
578
+                if (strcmp($node['resourcetype'], "collection") == 0) { // we have a folder
579
+                    $type = FILES_FOLDER;
580
+                }
581
+
582
+                if ($type === FILES_FOLDER) {
583
+                    $this->updateCacheAfterRename($id, rtrim($newId, '/'), $accountId);
584
+                }
585
+            }
586
+            $this->deleteCache($accountId, $cachePath);
587
+            $this->setCache($accountId, $newPath, $dir);
588
+        }
589
+    }
590
+
591
+    /**
592
+     * Function used to notify the sub folder of selected/modified folder.
593
+     *
594
+     * @param {String} $folderID The $folderID of a folder which is modified
595
+     */
596
+    public function notifySubFolders($folderID) {
597
+        $account = $this->accountFromNode($folderID);
598
+        $initializedBackend = $this->initializeBackend($account, true);
599
+        $folderData = $this->getSubFolders($folderID, $initializedBackend, true);
600
+
601
+        if (!empty($folderData)) {
602
+            $GLOBALS["bus"]->notify(REQUEST_ENTRYID, OBJECT_SAVE, $folderData);
603
+        }
604
+    }
605
+
606
+    /**
607
+     * Get the account id from a node id.
608
+     *
609
+     * @param {String} $nodeID Id of the file or folder to operate on
610
+     *
611
+     * @return {String} The account id extracted from $nodeId
612
+     */
613
+    public function accountIDFromNode($nodeID) {
614
+        return substr($nodeID, 3, (strpos($nodeID, '/') - 3)); // parse account id from node id
615
+    }
616
+
617
+    /**
618
+     * Get the account from a node id.
619
+     *
620
+     * @param {String} $nodeId ID of the file or folder to operate on
621
+     * @param mixed $nodeID
622
+     *
623
+     * @return {String} The account for $nodeId
624
+     */
625
+    public function accountFromNode($nodeID) {
626
+        return $this->accountStore->getAccount($this->accountIDFromNode($nodeID));
627
+    }
628
+
629
+    /**
630
+     * Create a key used to store data in the cache.
631
+     *
632
+     * @param {String} $accountID Id of the account of the data to cache
633
+     * @param {String} $path Path of the file or folder to create the cache element for
634
+     *
635
+     * @return {String} The created key
636
+     */
637
+    public function makeCacheKey($accountID, $path) {
638
+        return $this->uid . md5($accountID . $path);
639
+    }
640
+
641
+    /**
642
+     * Get version data form the cache.
643
+     *
644
+     * @param {String} $displayName display name of the backend or file plugin
645
+     * @param {String} $accountID Id of the account of the data to cache
646
+     *
647
+     * @return {String} version data or null if nothing was found
648
+     */
649
+    public function getVersionFromCache($displayName, $accountID = '') {
650
+        $key = $this->uid . $accountID . $displayName;
651
+
652
+        return $this->cache->getItem($key)->get();
653
+    }
654
+
655
+    /**
656
+     * Set version data in the cache only when version data has been changed.
657
+     *
658
+     * @param {String} $displayName display name of the backend or file plugin
659
+     * @param {String} $version version info of backend or file plugin which needs to be cached
660
+     * @param {String} $accountID Id of the account of the data to cache
661
+     */
662
+    public function setVersionInCache($displayName, $version, $accountID = '') {
663
+        $olderVersionFromCache = $this->getVersionFromCache($displayName, $accountID);
664
+        // If version of files/backend is same then return.
665
+        if (version_compare($olderVersionFromCache, $version) === 0) {
666
+            return;
667
+        }
668
+
669
+        $key = $this->uid . $accountID . $displayName;
670
+        $this->cache->save($this->cache->getItem($key)->set($version));
671
+    }
672
+
673
+    /**
674
+     * Initialize the backend for the given account.
675
+     *
676
+     * @param {Object} $account The account object the backend should be initialized for
677
+     * @param {Bool} $setID Should the accountID be set in the backend object, or not. Defaults to false.
678
+     *
679
+     * @return {Object} The initialized backend
680
+     */
681
+    public function initializeBackend($account, $setID = false) {
682
+        $backend = $this->backendStore->getInstanceOfBackend($account->getBackend());
683
+        $backend->init_backend($account->getBackendConfig());
684
+        if ($setID) {
685
+            $backend->setAccountID($account->getId());
686
+        }
687
+        $backend->open();
688
+
689
+        return $backend;
690
+    }
691
+
692
+    /**
693
+     * Save directory data in the cache.
694
+     *
695
+     * @param {String} $accountID Id of the account of the data to cache
696
+     * @param {String} $path Path of the file or folder to create the cache element for
697
+     * @param {String} $data Data to be cached
698
+     */
699
+    public function setCache($accountID, $path, $data) {
700
+        $key = $this->makeCacheKey($accountID, $path);
701
+        Logger::debug(self::LOG_CONTEXT, "Setting cache for node: " . $accountID . $path . " ## " . $key);
702
+        $this->cache->save($this->cache->getItem($key)->set($data));
703
+    }
704
+
705
+    /**
706
+     * Get directotry data form the cache.
707
+     *
708
+     * @param {String} $accountID Id of the account of the data to get
709
+     * @param {String} $path Path of the file or folder to retrieve the cache element for
710
+     *
711
+     * @return {String} The directory data or null if nothing was found
712
+     */
713
+    public function getCache($accountID, $path) {
714
+        $key = $this->makeCacheKey($accountID, $path);
715
+        Logger::debug(self::LOG_CONTEXT, "Getting cache for node: " . $accountID . $path . " ## " . $key);
716
+
717
+        return $this->cache->getItem($key)->get();
718
+    }
719
+
720
+    /**
721
+     * Remove data from the cache.
722
+     *
723
+     * @param {String} $accountID Id of the account to delete the cache for
724
+     * @param {String} $path Path of the file or folder to delete the cache element
725
+     */
726
+    public function deleteCache($accountID, $path) {
727
+        $key = $this->makeCacheKey($accountID, $path);
728
+        Logger::debug(self::LOG_CONTEXT, "Removing cache for node: " . $accountID . $path . " ## " . $key);
729
+        $this->cache->deleteItem($key);
730
+    }
731
+
732
+    /**
733
+     * Function clear the cache.
734
+     */
735
+    public function clearCache() {
736
+        $this->cache->clear();
737
+    }
738
+
739
+    /**
740
+     * Function which returns MAPI Message Store Object. It
741
+     * searches in the variable $action for a storeid.
742
+     *
743
+     * @param array $action the XML data retrieved from the client
744
+     *
745
+     * @return object MAPI Message Store Object, false if storeid is not found in the $action variable
746
+     */
747
+    public function getActionStore($action) {
748
+        $store = false;
749
+
750
+        if (isset($action["store_entryid"]) && !empty($action["store_entryid"])) {
751
+            if (is_array($action["store_entryid"])) {
752
+                $store = [];
753
+                foreach ($action["store_entryid"] as $store_id) {
754
+                    array_push($store, $store_id);
755
+                }
756
+            }
757
+            else {
758
+                $store = $action["store_entryid"];
759
+            }
760
+        }
761
+
762
+        return $store;
763
+    }
764 764
 }
Please login to merge, or discard this patch.
Braces   +8 added lines, -16 removed lines patch added patch discarded remove patch
@@ -79,8 +79,7 @@  discard block
 block discarded – undo
79 79
 			// Get the username from the Encryption store
80 80
 			$encryptionStore = \EncryptionStore::getInstance();
81 81
 			$this->uid = $encryptionStore->get('username');
82
-		}
83
-		else {
82
+		} else {
84 83
 			$this->uid = $_SESSION["username"];
85 84
 		}
86 85
 		// As of the V6, the following characters can not longer being a part of the key identifier: {}()/\@:
@@ -259,8 +258,7 @@  discard block
 block discarded – undo
259 258
 					$dir[$id]['store_entryid'] = $storeEntryid;
260 259
 
261 260
 					$updateCache = true;
262
-				}
263
-				else {
261
+				} else {
264 262
 					$entryid = $node['entryid'];
265 263
 					$parentEntryid = $node['parent_entryid'];
266 264
 					$storeEntryid = $node['store_entryid'];
@@ -272,8 +270,7 @@  discard block
 block discarded – undo
272 270
 				if (is_null($nodeHasSubFolder)) {
273 271
 					unset($dir[$id]);
274 272
 					$updateCache = true;
275
-				}
276
-				else {
273
+				} else {
277 274
 					array_push($nodes, [
278 275
 						'id' => $realID,
279 276
 						'folder_id' => $realID,
@@ -367,8 +364,7 @@  discard block
 block discarded – undo
367 364
 			try {
368 365
 				$dir = $backend->ls($id);
369 366
 				$this->setCache($accountID, $cachePath, $dir);
370
-			}
371
-			catch (Exception $e) {
367
+			} catch (Exception $e) {
372 368
 				$errorCode = $e->getCode();
373 369
 
374 370
 				// If folder not found or folder doesn't have enough access then don't display that folder.
@@ -379,8 +375,7 @@  discard block
 block discarded – undo
379 375
 				$errorCode === self::ALL_BACKEND_ERR_NOTFOUND) {
380 376
 					if ($errorCode === self::ALL_BACKEND_ERR_NOTFOUND) {
381 377
 						Logger::error(self::LOG_CONTEXT, '[hasSubFolder]: folder ' . $id . ' not found');
382
-					}
383
-					else {
378
+					} else {
384 379
 						Logger::error(self::LOG_CONTEXT, '[hasSubFolder]: Access denied for folder ' . $id);
385 380
 					}
386 381
 
@@ -480,8 +475,7 @@  discard block
 block discarded – undo
480 475
 				];
481 476
 				$response = $folder;
482 477
 			}
483
-		}
484
-		else {
478
+		} else {
485 479
 			// Rename/update the folder/file name
486 480
 			$folderId = $actionData['message_action']["source_folder_id"];
487 481
 			// rename/update the folder or files name.
@@ -517,8 +511,7 @@  discard block
 block discarded – undo
517 511
 				$this->setCache($account->getId(), dirname($relSrc), $dir);
518 512
 
519 513
 				$this->updateCacheAfterRename($relSrc, $relDst, $account->getId());
520
-			}
521
-			else {
514
+			} else {
522 515
 				// clear the cache
523 516
 				$this->deleteCache($account->getId(), dirname($relSrc));
524 517
 			}
@@ -753,8 +746,7 @@  discard block
 block discarded – undo
753 746
 				foreach ($action["store_entryid"] as $store_id) {
754 747
 					array_push($store, $store_id);
755 748
 				}
756
-			}
757
-			else {
749
+			} else {
758 750
 				$store = $action["store_entryid"];
759 751
 			}
760 752
 		}
Please login to merge, or discard this patch.
plugins/files/php/notifiers/class.filesbrowsernotifier.php 1 patch
Indentation   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -6,33 +6,33 @@
 block discarded – undo
6 6
  * Generates notifications update Files Grid contents.
7 7
  */
8 8
 class FilesBrowserNotifier extends Notifier {
9
-	/**
10
-	 * @return Number the event which this module handles
11
-	 */
12
-	public function getEvents() {
13
-		return OBJECT_DELETE | OBJECT_SAVE;
14
-	}
9
+    /**
10
+     * @return Number the event which this module handles
11
+     */
12
+    public function getEvents() {
13
+        return OBJECT_DELETE | OBJECT_SAVE;
14
+    }
15 15
 
16
-	/**
17
-	 * If an event elsewhere has occurred, it enters in this method. This method
18
-	 * executes one ore more actions, depends on the event.
19
-	 *
20
-	 * @param int    $event   event
21
-	 * @param string $entryid entryid
22
-	 * @param array  $data    array of data
23
-	 * @param mixed  $props
24
-	 */
25
-	public function update($event, $entryid, $props) {
26
-		switch ($event) {
27
-			case OBJECT_DELETE:
28
-				$this->addNotificationActionData("delete", ["item" => [$props]]);
29
-				$GLOBALS["bus"]->addData($this->createNotificationResponseData());
30
-				break;
16
+    /**
17
+     * If an event elsewhere has occurred, it enters in this method. This method
18
+     * executes one ore more actions, depends on the event.
19
+     *
20
+     * @param int    $event   event
21
+     * @param string $entryid entryid
22
+     * @param array  $data    array of data
23
+     * @param mixed  $props
24
+     */
25
+    public function update($event, $entryid, $props) {
26
+        switch ($event) {
27
+            case OBJECT_DELETE:
28
+                $this->addNotificationActionData("delete", ["item" => [$props]]);
29
+                $GLOBALS["bus"]->addData($this->createNotificationResponseData());
30
+                break;
31 31
 
32
-			case OBJECT_SAVE:
33
-				$this->addNotificationActionData("update", ["item" => [$props]]);
34
-				$GLOBALS["bus"]->addData($this->createNotificationResponseData());
35
-				break;
36
-		}
37
-	}
32
+            case OBJECT_SAVE:
33
+                $this->addNotificationActionData("update", ["item" => [$props]]);
34
+                $GLOBALS["bus"]->addData($this->createNotificationResponseData());
35
+                break;
36
+        }
37
+    }
38 38
 }
Please login to merge, or discard this patch.
plugins/files/php/notifiers/class.fileshierarchynotifier.php 1 patch
Indentation   +28 added lines, -28 removed lines patch added patch discarded remove patch
@@ -6,34 +6,34 @@
 block discarded – undo
6 6
  * Generates notifications update Files hierarchy contents.
7 7
  */
8 8
 class FilesHierarchyNotifier extends Notifier {
9
-	/**
10
-	 * @return Number the event which this module handles
11
-	 */
12
-	public function getEvents() {
13
-		return OBJECT_DELETE | OBJECT_SAVE;
14
-	}
9
+    /**
10
+     * @return Number the event which this module handles
11
+     */
12
+    public function getEvents() {
13
+        return OBJECT_DELETE | OBJECT_SAVE;
14
+    }
15 15
 
16
-	/**
17
-	 * If an event elsewhere has occurred, it enters in this method. This method
18
-	 * executes one ore more actions, depends on the event.
19
-	 *
20
-	 * @param int    $event   event
21
-	 * @param string $entryid entryid
22
-	 * @param array  $data    array of data
23
-	 * @param mixed  $props
24
-	 */
25
-	public function update($event, $entryid, $props) {
26
-		switch ($event) {
27
-			case OBJECT_DELETE:
28
-				$props["folderdelete"] = 1;
29
-				$this->addNotificationActionData("folders", ["item" => [$props]]);
30
-				$GLOBALS["bus"]->addData($this->createNotificationResponseData());
31
-				break;
16
+    /**
17
+     * If an event elsewhere has occurred, it enters in this method. This method
18
+     * executes one ore more actions, depends on the event.
19
+     *
20
+     * @param int    $event   event
21
+     * @param string $entryid entryid
22
+     * @param array  $data    array of data
23
+     * @param mixed  $props
24
+     */
25
+    public function update($event, $entryid, $props) {
26
+        switch ($event) {
27
+            case OBJECT_DELETE:
28
+                $props["folderdelete"] = 1;
29
+                $this->addNotificationActionData("folders", ["item" => [$props]]);
30
+                $GLOBALS["bus"]->addData($this->createNotificationResponseData());
31
+                break;
32 32
 
33
-			case OBJECT_SAVE:
34
-				$this->addNotificationActionData("folders", ["item" => $props]);
35
-				$GLOBALS["bus"]->addData($this->createNotificationResponseData());
36
-				break;
37
-		}
38
-	}
33
+            case OBJECT_SAVE:
34
+                $this->addNotificationActionData("folders", ["item" => $props]);
35
+                $GLOBALS["bus"]->addData($this->createNotificationResponseData());
36
+                break;
37
+        }
38
+    }
39 39
 }
Please login to merge, or discard this patch.
plugins/files/php/Files/Backend/class.exception.php 1 patch
Indentation   +37 added lines, -37 removed lines patch added patch discarded remove patch
@@ -9,45 +9,45 @@
 block discarded – undo
9 9
 namespace Files\Backend;
10 10
 
11 11
 class Exception extends \Exception {
12
-	/**
13
-	 * The exception title to show as a message box title at client side.
14
-	 */
15
-	public $title;
12
+    /**
13
+     * The exception title to show as a message box title at client side.
14
+     */
15
+    public $title;
16 16
 
17
-	/**
18
-	 * @constructor
19
-	 *
20
-	 * @param string $message The error message
21
-	 * @param int    $code    The error code
22
-	 */
23
-	public function __construct($message, $code = 0) {
24
-		parent::__construct($message, $code);
25
-	}
17
+    /**
18
+     * @constructor
19
+     *
20
+     * @param string $message The error message
21
+     * @param int    $code    The error code
22
+     */
23
+    public function __construct($message, $code = 0) {
24
+        parent::__construct($message, $code);
25
+    }
26 26
 
27
-	/**
28
-	 * Overrides the toString method.
29
-	 *
30
-	 * @return string Error code and message
31
-	 */
32
-	public function __toString() {
33
-		return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
34
-	}
27
+    /**
28
+     * Overrides the toString method.
29
+     *
30
+     * @return string Error code and message
31
+     */
32
+    public function __toString() {
33
+        return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
34
+    }
35 35
 
36
-	/**
37
-	 * Function sets title of an exception that will be sent to the client side
38
-	 * to show it to user.
39
-	 *
40
-	 * @param string $title title of an exception
41
-	 */
42
-	public function setTitle($title) {
43
-		$this->title = $title;
44
-	}
36
+    /**
37
+     * Function sets title of an exception that will be sent to the client side
38
+     * to show it to user.
39
+     *
40
+     * @param string $title title of an exception
41
+     */
42
+    public function setTitle($title) {
43
+        $this->title = $title;
44
+    }
45 45
 
46
-	/**
47
-	 * @return string returns title that should be sent to client to display as a message box
48
-	 *                title
49
-	 */
50
-	public function getTitle() {
51
-		return $this->title;
52
-	}
46
+    /**
47
+     * @return string returns title that should be sent to client to display as a message box
48
+     *                title
49
+     */
50
+    public function getTitle() {
51
+        return $this->title;
52
+    }
53 53
 }
Please login to merge, or discard this patch.
plugins/files/php/Files/Backend/class.abstract_js_loader.php 1 patch
Indentation   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -3,11 +3,11 @@
 block discarded – undo
3 3
 namespace Files\Backend;
4 4
 
5 5
 abstract class AbstractJSLoader {
6
-	protected $jsBuffer = "";
6
+    protected $jsBuffer = "";
7 7
 
8
-	// path to js folder
9
-	protected $JS_PATH;
8
+    // path to js folder
9
+    protected $JS_PATH;
10 10
 
11
-	// get combined javascript string
12
-	abstract public function get_combined_js($debug = false);
11
+    // get combined javascript string
12
+    abstract public function get_combined_js($debug = false);
13 13
 }
Please login to merge, or discard this patch.
plugins/files/php/Files/Backend/interface.oauth.php 1 patch
Indentation   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -3,10 +3,10 @@
 block discarded – undo
3 3
 namespace Files\Backend;
4 4
 
5 5
 interface iFeatureOAUTH {
6
-	/**
7
-	 * Update the stored access token.
8
-	 *
9
-	 * @param $newtoken
10
-	 */
11
-	public function changeAccessToken($newtoken);
6
+    /**
7
+     * Update the stored access token.
8
+     *
9
+     * @param $newtoken
10
+     */
11
+    public function changeAccessToken($newtoken);
12 12
 }
Please login to merge, or discard this patch.
plugins/files/php/Files/Backend/interface.streaming.php 1 patch
Indentation   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -3,21 +3,21 @@
 block discarded – undo
3 3
 namespace Files\Backend;
4 4
 
5 5
 interface iFeatureStreaming {
6
-	/**
7
-	 * Open a readable stream to a remote file.
8
-	 *
9
-	 * @param string $path
10
-	 *
11
-	 * @return resource a read only stream with the contents of the remote file
12
-	 */
13
-	public function getStreamreader($path);
6
+    /**
7
+     * Open a readable stream to a remote file.
8
+     *
9
+     * @param string $path
10
+     *
11
+     * @return resource a read only stream with the contents of the remote file
12
+     */
13
+    public function getStreamreader($path);
14 14
 
15
-	/**
16
-	 * Open a writable stream to a remote file.
17
-	 *
18
-	 * @param string $path
19
-	 *
20
-	 * @return resource a write only stream to upload a remote file
21
-	 */
22
-	public function getStreamwriter($path);
15
+    /**
16
+     * Open a writable stream to a remote file.
17
+     *
18
+     * @param string $path
19
+     *
20
+     * @return resource a write only stream to upload a remote file
21
+     */
22
+    public function getStreamwriter($path);
23 23
 }
Please login to merge, or discard this patch.
plugins/files/php/Files/Backend/interface.sharing.php 1 patch
Indentation   +67 added lines, -67 removed lines patch added patch discarded remove patch
@@ -3,74 +3,74 @@
 block discarded – undo
3 3
 namespace Files\Backend;
4 4
 
5 5
 interface iFeatureSharing {
6
-	/**
7
-	 * Get all shares in the specified folder.
8
-	 *
9
-	 * Returned value should like:
10
-	 *
11
-	 * array(
12
-	 *  path1 => array(
13
-	 *      id1 => details1,
14
-	 *      id2 => details2
15
-	 *  ),
16
-	 *  path2 => array(
17
-	 *      id1 => ....
18
-	 *  )
19
-	 * )
20
-	 *
21
-	 * @param $path
22
-	 *
23
-	 * @return array
24
-	 */
25
-	public function getShares($path);
6
+    /**
7
+     * Get all shares in the specified folder.
8
+     *
9
+     * Returned value should like:
10
+     *
11
+     * array(
12
+     *  path1 => array(
13
+     *      id1 => details1,
14
+     *      id2 => details2
15
+     *  ),
16
+     *  path2 => array(
17
+     *      id1 => ....
18
+     *  )
19
+     * )
20
+     *
21
+     * @param $path
22
+     *
23
+     * @return array
24
+     */
25
+    public function getShares($path);
26 26
 
27
-	/**
28
-	 * Get details about the shared files/folders.
29
-	 *
30
-	 * Returned value should like:
31
-	 *
32
-	 * array(
33
-	 *  path1 => array(
34
-	 *      id1 => details1,
35
-	 *      id2 => details2
36
-	 *  ),
37
-	 *  path2 => array(
38
-	 *      id1 => ....
39
-	 *  )
40
-	 * )
41
-	 *
42
-	 * @param $patharray Simple array with path's to files or folders
43
-	 *
44
-	 * @return array
45
-	 */
46
-	public function sharingDetails($patharray);
27
+    /**
28
+     * Get details about the shared files/folders.
29
+     *
30
+     * Returned value should like:
31
+     *
32
+     * array(
33
+     *  path1 => array(
34
+     *      id1 => details1,
35
+     *      id2 => details2
36
+     *  ),
37
+     *  path2 => array(
38
+     *      id1 => ....
39
+     *  )
40
+     * )
41
+     *
42
+     * @param $patharray Simple array with path's to files or folders
43
+     *
44
+     * @return array
45
+     */
46
+    public function sharingDetails($patharray);
47 47
 
48
-	/**
49
-	 * Share one or multiple files.
50
-	 * As the sharing dialog might differ for different backends, it is implemented as
51
-	 * MetaForm - meaning that the argumentnames/count might differ.
52
-	 * That's the cause why this function uses an array as parameter.
53
-	 *
54
-	 * $shareparams should look somehow like this:
55
-	 *
56
-	 * array(
57
-	 *      "path1" => options1,
58
-	 *      "path2" => options2
59
-	 * )
60
-	 *
61
-	 * @param $shareparams
62
-	 * @param bool $update
63
-	 *
64
-	 * @return bool
65
-	 */
66
-	public function share($shareparams, $update = false);
48
+    /**
49
+     * Share one or multiple files.
50
+     * As the sharing dialog might differ for different backends, it is implemented as
51
+     * MetaForm - meaning that the argumentnames/count might differ.
52
+     * That's the cause why this function uses an array as parameter.
53
+     *
54
+     * $shareparams should look somehow like this:
55
+     *
56
+     * array(
57
+     *      "path1" => options1,
58
+     *      "path2" => options2
59
+     * )
60
+     *
61
+     * @param $shareparams
62
+     * @param bool $update
63
+     *
64
+     * @return bool
65
+     */
66
+    public function share($shareparams, $update = false);
67 67
 
68
-	/**
69
-	 * Disable sharing for the given files/folders.
70
-	 *
71
-	 * @param $patharray Simple array with path's to files or folders
72
-	 *
73
-	 * @return bool
74
-	 */
75
-	public function unshare($patharray);
68
+    /**
69
+     * Disable sharing for the given files/folders.
70
+     *
71
+     * @param $patharray Simple array with path's to files or folders
72
+     *
73
+     * @return bool
74
+     */
75
+    public function unshare($patharray);
76 76
 }
Please login to merge, or discard this patch.