Completed
Push — master ( aeed32...1ef465 )
by
unknown
36:30 queued 09:43
created
lib/public/Files/Folder.php 1 patch
Indentation   +203 added lines, -203 removed lines patch added patch discarded remove patch
@@ -16,207 +16,207 @@
 block discarded – undo
16 16
  * @since 6.0.0
17 17
  */
18 18
 interface Folder extends Node {
19
-	/**
20
-	 * Get the full path of an item in the folder within owncloud's filesystem
21
-	 *
22
-	 * @param string $path relative path of an item in the folder
23
-	 * @return string
24
-	 * @throws \OCP\Files\NotPermittedException
25
-	 * @since 6.0.0
26
-	 */
27
-	public function getFullPath($path);
28
-
29
-	/**
30
-	 * Get the path of an item in the folder relative to the folder
31
-	 *
32
-	 * @param string $path absolute path of an item in the folder
33
-	 * @throws \OCP\Files\NotFoundException
34
-	 * @return string|null
35
-	 * @since 6.0.0
36
-	 */
37
-	public function getRelativePath($path);
38
-
39
-	/**
40
-	 * check if a node is a (grand-)child of the folder
41
-	 *
42
-	 * @param \OCP\Files\Node $node
43
-	 * @return bool
44
-	 * @since 6.0.0
45
-	 */
46
-	public function isSubNode($node);
47
-
48
-	/**
49
-	 * get the content of this directory
50
-	 *
51
-	 * @throws \OCP\Files\NotFoundException
52
-	 * @return \OCP\Files\Node[]
53
-	 * @since 6.0.0
54
-	 */
55
-	public function getDirectoryListing();
56
-
57
-	/**
58
-	 * Get the node at $path
59
-	 *
60
-	 * @param string $path relative path of the file or folder
61
-	 * @return \OCP\Files\Node
62
-	 * @throws \OCP\Files\NotFoundException
63
-	 * @throws \OCP\Files\NotPermittedException
64
-	 * @since 6.0.0
65
-	 */
66
-	public function get($path);
67
-
68
-	/**
69
-	 * Get or create new folder if the folder does not already exist.
70
-	 *
71
-	 * @param string $path relative path of the file or folder
72
-	 * @throw \OCP\Files\NotPermittedException
73
-	 * @since 33.0.0
74
-	 */
75
-	public function getOrCreateFolder(string $path, int $maxRetries = 5): Folder;
76
-
77
-	/**
78
-	 * Check if a file or folder exists in the folder
79
-	 *
80
-	 * @param string $path relative path of the file or folder
81
-	 * @return bool
82
-	 * @since 6.0.0
83
-	 */
84
-	public function nodeExists($path);
85
-
86
-	/**
87
-	 * Create a new folder
88
-	 *
89
-	 * @param string $path relative path of the new folder
90
-	 * @return \OCP\Files\Folder
91
-	 * @throws \OCP\Files\NotPermittedException
92
-	 * @since 6.0.0
93
-	 */
94
-	public function newFolder($path);
95
-
96
-	/**
97
-	 * Create a new file
98
-	 *
99
-	 * @param string $path relative path of the new file
100
-	 * @param string|resource|null $content content for the new file, since 19.0.0
101
-	 * @return \OCP\Files\File
102
-	 * @throws \OCP\Files\NotPermittedException
103
-	 * @since 6.0.0
104
-	 */
105
-	public function newFile($path, $content = null);
106
-
107
-	/**
108
-	 * search for files with the name matching $query
109
-	 *
110
-	 * @param string|ISearchQuery $query
111
-	 * @return \OCP\Files\Node[]
112
-	 * @since 6.0.0
113
-	 */
114
-	public function search($query);
115
-
116
-	/**
117
-	 * search for files by mimetype
118
-	 * $mimetype can either be a full mimetype (image/png) or a wildcard mimetype (image)
119
-	 *
120
-	 * @param string $mimetype
121
-	 * @return \OCP\Files\Node[]
122
-	 * @since 6.0.0
123
-	 */
124
-	public function searchByMime($mimetype);
125
-
126
-	/**
127
-	 * search for files by tag
128
-	 *
129
-	 * @param string|int $tag tag name or tag id
130
-	 * @param string $userId owner of the tags
131
-	 * @return \OCP\Files\Node[]
132
-	 * @since 8.0.0
133
-	 */
134
-	public function searchByTag($tag, $userId);
135
-
136
-	/**
137
-	 * search for files by system tag
138
-	 *
139
-	 * @param string|int $tag tag name
140
-	 * @param string $userId user id to ensure access on returned nodes
141
-	 * @return \OCP\Files\Node[]
142
-	 * @since 28.0.0
143
-	 */
144
-	public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0);
145
-
146
-	/**
147
-	 * get a file or folder inside the folder by its internal id
148
-	 *
149
-	 * This method could return multiple entries. For example once the file/folder
150
-	 * is shared or mounted (files_external) to the user multiple times.
151
-	 *
152
-	 * Note that the different entries can have different permissions.
153
-	 *
154
-	 * @param int $id
155
-	 * @return \OCP\Files\Node[]
156
-	 * @since 6.0.0
157
-	 */
158
-	public function getById($id);
159
-
160
-	/**
161
-	 * get a file or folder inside the folder by its internal id
162
-	 *
163
-	 * Unlike getById, this method only returns a single node even if the user has
164
-	 * access to the file with the requested id multiple times.
165
-	 *
166
-	 * This method provides no guarantee about which of the nodes in returned and the
167
-	 * returned node might, for example, have less permissions than other nodes for the same file
168
-	 *
169
-	 * Apps that require accurate information about the users access to the file should use getById
170
-	 * instead of pick the correct node out of the result.
171
-	 *
172
-	 * @param int $id
173
-	 * @return Node|null
174
-	 * @since 29.0.0
175
-	 */
176
-	public function getFirstNodeById(int $id): ?Node;
177
-
178
-	/**
179
-	 * Get the amount of free space inside the folder
180
-	 *
181
-	 * @return int
182
-	 * @since 6.0.0
183
-	 */
184
-	public function getFreeSpace();
185
-
186
-	/**
187
-	 * Check if new files or folders can be created within the folder
188
-	 *
189
-	 * @return bool
190
-	 * @since 6.0.0
191
-	 */
192
-	public function isCreatable();
193
-
194
-	/**
195
-	 * Add a suffix to the name in case the file exists
196
-	 *
197
-	 * @param string $name
198
-	 * @return string
199
-	 * @throws NotPermittedException
200
-	 * @since 8.1.0
201
-	 */
202
-	public function getNonExistingName($name);
203
-
204
-	/**
205
-	 * @param int $limit
206
-	 * @param int $offset
207
-	 * @return \OCP\Files\Node[]
208
-	 * @since 9.1.0
209
-	 */
210
-	public function getRecent($limit, $offset = 0);
211
-
212
-	/**
213
-	 * Verify if the given path is valid and allowed from this folder.
214
-	 *
215
-	 * @param string $path the path from this folder
216
-	 * @param string $fileName
217
-	 * @param bool $readonly Check only if the path is allowed for read-only access
218
-	 * @throws InvalidPathException
219
-	 * @since 32.0.0
220
-	 */
221
-	public function verifyPath($fileName, $readonly = false): void;
19
+    /**
20
+     * Get the full path of an item in the folder within owncloud's filesystem
21
+     *
22
+     * @param string $path relative path of an item in the folder
23
+     * @return string
24
+     * @throws \OCP\Files\NotPermittedException
25
+     * @since 6.0.0
26
+     */
27
+    public function getFullPath($path);
28
+
29
+    /**
30
+     * Get the path of an item in the folder relative to the folder
31
+     *
32
+     * @param string $path absolute path of an item in the folder
33
+     * @throws \OCP\Files\NotFoundException
34
+     * @return string|null
35
+     * @since 6.0.0
36
+     */
37
+    public function getRelativePath($path);
38
+
39
+    /**
40
+     * check if a node is a (grand-)child of the folder
41
+     *
42
+     * @param \OCP\Files\Node $node
43
+     * @return bool
44
+     * @since 6.0.0
45
+     */
46
+    public function isSubNode($node);
47
+
48
+    /**
49
+     * get the content of this directory
50
+     *
51
+     * @throws \OCP\Files\NotFoundException
52
+     * @return \OCP\Files\Node[]
53
+     * @since 6.0.0
54
+     */
55
+    public function getDirectoryListing();
56
+
57
+    /**
58
+     * Get the node at $path
59
+     *
60
+     * @param string $path relative path of the file or folder
61
+     * @return \OCP\Files\Node
62
+     * @throws \OCP\Files\NotFoundException
63
+     * @throws \OCP\Files\NotPermittedException
64
+     * @since 6.0.0
65
+     */
66
+    public function get($path);
67
+
68
+    /**
69
+     * Get or create new folder if the folder does not already exist.
70
+     *
71
+     * @param string $path relative path of the file or folder
72
+     * @throw \OCP\Files\NotPermittedException
73
+     * @since 33.0.0
74
+     */
75
+    public function getOrCreateFolder(string $path, int $maxRetries = 5): Folder;
76
+
77
+    /**
78
+     * Check if a file or folder exists in the folder
79
+     *
80
+     * @param string $path relative path of the file or folder
81
+     * @return bool
82
+     * @since 6.0.0
83
+     */
84
+    public function nodeExists($path);
85
+
86
+    /**
87
+     * Create a new folder
88
+     *
89
+     * @param string $path relative path of the new folder
90
+     * @return \OCP\Files\Folder
91
+     * @throws \OCP\Files\NotPermittedException
92
+     * @since 6.0.0
93
+     */
94
+    public function newFolder($path);
95
+
96
+    /**
97
+     * Create a new file
98
+     *
99
+     * @param string $path relative path of the new file
100
+     * @param string|resource|null $content content for the new file, since 19.0.0
101
+     * @return \OCP\Files\File
102
+     * @throws \OCP\Files\NotPermittedException
103
+     * @since 6.0.0
104
+     */
105
+    public function newFile($path, $content = null);
106
+
107
+    /**
108
+     * search for files with the name matching $query
109
+     *
110
+     * @param string|ISearchQuery $query
111
+     * @return \OCP\Files\Node[]
112
+     * @since 6.0.0
113
+     */
114
+    public function search($query);
115
+
116
+    /**
117
+     * search for files by mimetype
118
+     * $mimetype can either be a full mimetype (image/png) or a wildcard mimetype (image)
119
+     *
120
+     * @param string $mimetype
121
+     * @return \OCP\Files\Node[]
122
+     * @since 6.0.0
123
+     */
124
+    public function searchByMime($mimetype);
125
+
126
+    /**
127
+     * search for files by tag
128
+     *
129
+     * @param string|int $tag tag name or tag id
130
+     * @param string $userId owner of the tags
131
+     * @return \OCP\Files\Node[]
132
+     * @since 8.0.0
133
+     */
134
+    public function searchByTag($tag, $userId);
135
+
136
+    /**
137
+     * search for files by system tag
138
+     *
139
+     * @param string|int $tag tag name
140
+     * @param string $userId user id to ensure access on returned nodes
141
+     * @return \OCP\Files\Node[]
142
+     * @since 28.0.0
143
+     */
144
+    public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0);
145
+
146
+    /**
147
+     * get a file or folder inside the folder by its internal id
148
+     *
149
+     * This method could return multiple entries. For example once the file/folder
150
+     * is shared or mounted (files_external) to the user multiple times.
151
+     *
152
+     * Note that the different entries can have different permissions.
153
+     *
154
+     * @param int $id
155
+     * @return \OCP\Files\Node[]
156
+     * @since 6.0.0
157
+     */
158
+    public function getById($id);
159
+
160
+    /**
161
+     * get a file or folder inside the folder by its internal id
162
+     *
163
+     * Unlike getById, this method only returns a single node even if the user has
164
+     * access to the file with the requested id multiple times.
165
+     *
166
+     * This method provides no guarantee about which of the nodes in returned and the
167
+     * returned node might, for example, have less permissions than other nodes for the same file
168
+     *
169
+     * Apps that require accurate information about the users access to the file should use getById
170
+     * instead of pick the correct node out of the result.
171
+     *
172
+     * @param int $id
173
+     * @return Node|null
174
+     * @since 29.0.0
175
+     */
176
+    public function getFirstNodeById(int $id): ?Node;
177
+
178
+    /**
179
+     * Get the amount of free space inside the folder
180
+     *
181
+     * @return int
182
+     * @since 6.0.0
183
+     */
184
+    public function getFreeSpace();
185
+
186
+    /**
187
+     * Check if new files or folders can be created within the folder
188
+     *
189
+     * @return bool
190
+     * @since 6.0.0
191
+     */
192
+    public function isCreatable();
193
+
194
+    /**
195
+     * Add a suffix to the name in case the file exists
196
+     *
197
+     * @param string $name
198
+     * @return string
199
+     * @throws NotPermittedException
200
+     * @since 8.1.0
201
+     */
202
+    public function getNonExistingName($name);
203
+
204
+    /**
205
+     * @param int $limit
206
+     * @param int $offset
207
+     * @return \OCP\Files\Node[]
208
+     * @since 9.1.0
209
+     */
210
+    public function getRecent($limit, $offset = 0);
211
+
212
+    /**
213
+     * Verify if the given path is valid and allowed from this folder.
214
+     *
215
+     * @param string $path the path from this folder
216
+     * @param string $fileName
217
+     * @param bool $readonly Check only if the path is allowed for read-only access
218
+     * @throws InvalidPathException
219
+     * @since 32.0.0
220
+     */
221
+    public function verifyPath($fileName, $readonly = false): void;
222 222
 }
Please login to merge, or discard this patch.
lib/public/Files/Template/ITemplateManager.php 1 patch
Indentation   +61 added lines, -61 removed lines patch added patch discarded remove patch
@@ -28,73 +28,73 @@
 block discarded – undo
28 28
  */
29 29
 #[Consumable(since: '21.0.0')]
30 30
 interface ITemplateManager {
31
-	/**
32
-	 * Register a template type support
33
-	 *
34
-	 * @param callable(): TemplateFileCreator $callback A callback which returns the TemplateFileCreator instance to register
35
-	 * @since 21.0.0
36
-	 */
37
-	public function registerTemplateFileCreator(callable $callback): void;
31
+    /**
32
+     * Register a template type support
33
+     *
34
+     * @param callable(): TemplateFileCreator $callback A callback which returns the TemplateFileCreator instance to register
35
+     * @since 21.0.0
36
+     */
37
+    public function registerTemplateFileCreator(callable $callback): void;
38 38
 
39
-	/**
40
-	 * Get a list of available file creators
41
-	 *
42
-	 * @return array
43
-	 * @since 21.0.0
44
-	 */
45
-	public function listCreators(): array;
39
+    /**
40
+     * Get a list of available file creators
41
+     *
42
+     * @return array
43
+     * @since 21.0.0
44
+     */
45
+    public function listCreators(): array;
46 46
 
47
-	/**
48
-	 * Get a list of available file creators and their offered templates
49
-	 *
50
-	 * @return list<array{app: string, label: string, extension: string, iconClass: ?string, iconSvgInline: ?string, mimetypes: list<string>, ratio: ?float, actionLabel: string, templates: list<Template>}>
51
-	 * @since 21.0.0
52
-	 */
53
-	public function listTemplates(): array;
47
+    /**
48
+     * Get a list of available file creators and their offered templates
49
+     *
50
+     * @return list<array{app: string, label: string, extension: string, iconClass: ?string, iconSvgInline: ?string, mimetypes: list<string>, ratio: ?float, actionLabel: string, templates: list<Template>}>
51
+     * @since 21.0.0
52
+     */
53
+    public function listTemplates(): array;
54 54
 
55
-	/**
56
-	 * Get the fields for a given template
57
-	 *
58
-	 * @param int $fileId
59
-	 * @return array
60
-	 * @since 32.0.0
61
-	 */
62
-	public function listTemplateFields(int $fileId): array;
55
+    /**
56
+     * Get the fields for a given template
57
+     *
58
+     * @param int $fileId
59
+     * @return array
60
+     * @since 32.0.0
61
+     */
62
+    public function listTemplateFields(int $fileId): array;
63 63
 
64
-	/**
65
-	 * @return bool
66
-	 * @since 21.0.0
67
-	 */
68
-	public function hasTemplateDirectory(): bool;
64
+    /**
65
+     * @return bool
66
+     * @since 21.0.0
67
+     */
68
+    public function hasTemplateDirectory(): bool;
69 69
 
70
-	/**
71
-	 * @param string $path
72
-	 * @return void
73
-	 * @since 21.0.0
74
-	 */
75
-	public function setTemplatePath(string $path): void;
70
+    /**
71
+     * @param string $path
72
+     * @return void
73
+     * @since 21.0.0
74
+     */
75
+    public function setTemplatePath(string $path): void;
76 76
 
77
-	/**
78
-	 * @return string
79
-	 * @since 21.0.0
80
-	 */
81
-	public function getTemplatePath(): string;
77
+    /**
78
+     * @return string
79
+     * @since 21.0.0
80
+     */
81
+    public function getTemplatePath(): string;
82 82
 
83
-	/**
84
-	 * @param string|null $path
85
-	 * @param string|null $userId
86
-	 * @since 21.0.0
87
-	 */
88
-	public function initializeTemplateDirectory(?string $path = null, ?string $userId = null, $copyTemplates = true): string;
83
+    /**
84
+     * @param string|null $path
85
+     * @param string|null $userId
86
+     * @since 21.0.0
87
+     */
88
+    public function initializeTemplateDirectory(?string $path = null, ?string $userId = null, $copyTemplates = true): string;
89 89
 
90
-	/**
91
-	 * @param string $filePath
92
-	 * @param string $templateId
93
-	 * @param string $templateType
94
-	 * @param array $templateFields Since 30.0.0
95
-	 * @return FilesTemplateFile
96
-	 * @throws GenericFileException
97
-	 * @since 21.0.0
98
-	 */
99
-	public function createFromTemplate(string $filePath, string $templateId = '', string $templateType = 'user', array $templateFields = []): array;
90
+    /**
91
+     * @param string $filePath
92
+     * @param string $templateId
93
+     * @param string $templateType
94
+     * @param array $templateFields Since 30.0.0
95
+     * @return FilesTemplateFile
96
+     * @throws GenericFileException
97
+     * @since 21.0.0
98
+     */
99
+    public function createFromTemplate(string $filePath, string $templateId = '', string $templateType = 'user', array $templateFields = []): array;
100 100
 }
Please login to merge, or discard this patch.
lib/composer/composer/installed.php 1 patch
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -5,7 +5,7 @@  discard block
 block discarded – undo
5 5
         'version' => 'dev-master',
6 6
         'reference' => '8c12590cf6f93ce7aa41f17817b3791e524da39e',
7 7
         'type' => 'library',
8
-        'install_path' => __DIR__ . '/../../../',
8
+        'install_path' => __DIR__.'/../../../',
9 9
         'aliases' => array(),
10 10
         'dev' => false,
11 11
     ),
@@ -15,7 +15,7 @@  discard block
 block discarded – undo
15 15
             'version' => 'dev-master',
16 16
             'reference' => '8c12590cf6f93ce7aa41f17817b3791e524da39e',
17 17
             'type' => 'library',
18
-            'install_path' => __DIR__ . '/../../../',
18
+            'install_path' => __DIR__.'/../../../',
19 19
             'aliases' => array(),
20 20
             'dev_requirement' => false,
21 21
         ),
Please login to merge, or discard this patch.
lib/composer/composer/InstalledVersions.php 1 patch
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -169,7 +169,7 @@  discard block
 block discarded – undo
169 169
             return implode(' || ', $ranges);
170 170
         }
171 171
 
172
-        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
172
+        throw new \OutOfBoundsException('Package "'.$packageName.'" is not installed');
173 173
     }
174 174
 
175 175
     /**
@@ -190,7 +190,7 @@  discard block
 block discarded – undo
190 190
             return $installed['versions'][$packageName]['version'];
191 191
         }
192 192
 
193
-        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
193
+        throw new \OutOfBoundsException('Package "'.$packageName.'" is not installed');
194 194
     }
195 195
 
196 196
     /**
@@ -211,7 +211,7 @@  discard block
 block discarded – undo
211 211
             return $installed['versions'][$packageName]['pretty_version'];
212 212
         }
213 213
 
214
-        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
214
+        throw new \OutOfBoundsException('Package "'.$packageName.'" is not installed');
215 215
     }
216 216
 
217 217
     /**
@@ -232,7 +232,7 @@  discard block
 block discarded – undo
232 232
             return $installed['versions'][$packageName]['reference'];
233 233
         }
234 234
 
235
-        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
235
+        throw new \OutOfBoundsException('Package "'.$packageName.'" is not installed');
236 236
     }
237 237
 
238 238
     /**
@@ -249,7 +249,7 @@  discard block
 block discarded – undo
249 249
             return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
250 250
         }
251 251
 
252
-        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
252
+        throw new \OutOfBoundsException('Package "'.$packageName.'" is not installed');
253 253
     }
254 254
 
255 255
     /**
@@ -277,8 +277,8 @@  discard block
 block discarded – undo
277 277
         if (null === self::$installed) {
278 278
             // only require the installed.php file if this file is loaded from its dumped location,
279 279
             // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
280
-            if (substr(__DIR__, -8, 1) !== 'C' && is_file(__DIR__ . '/installed.php')) {
281
-                self::$installed = include __DIR__ . '/installed.php';
280
+            if (substr(__DIR__, -8, 1) !== 'C' && is_file(__DIR__.'/installed.php')) {
281
+                self::$installed = include __DIR__.'/installed.php';
282 282
             } else {
283 283
                 self::$installed = array();
284 284
             }
@@ -378,9 +378,9 @@  discard block
 block discarded – undo
378 378
         if (null === self::$installed) {
379 379
             // only require the installed.php file if this file is loaded from its dumped location,
380 380
             // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
381
-            if (substr(__DIR__, -8, 1) !== 'C' && is_file(__DIR__ . '/installed.php')) {
381
+            if (substr(__DIR__, -8, 1) !== 'C' && is_file(__DIR__.'/installed.php')) {
382 382
                 /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
383
-                $required = require __DIR__ . '/installed.php';
383
+                $required = require __DIR__.'/installed.php';
384 384
                 self::$installed = $required;
385 385
             } else {
386 386
                 self::$installed = array();
Please login to merge, or discard this patch.
lib/private/Files/Node/Folder.php 2 patches
Indentation   +475 added lines, -475 removed lines patch added patch discarded remove patch
@@ -31,479 +31,479 @@
 block discarded – undo
31 31
 
32 32
 class Folder extends Node implements IFolder {
33 33
 
34
-	private ?IUserManager $userManager = null;
35
-
36
-	private bool $wasDeleted = false;
37
-
38
-	/**
39
-	 * Creates a Folder that represents a non-existing path
40
-	 *
41
-	 * @param string $path path
42
-	 * @return NonExistingFolder non-existing node
43
-	 */
44
-	protected function createNonExistingNode($path) {
45
-		return new NonExistingFolder($this->root, $this->view, $path);
46
-	}
47
-
48
-	/**
49
-	 * @param string $path path relative to the folder
50
-	 * @return string
51
-	 * @throws \OCP\Files\NotPermittedException
52
-	 */
53
-	public function getFullPath($path) {
54
-		$path = $this->normalizePath($path);
55
-		if (!$this->isValidPath($path)) {
56
-			throw new NotPermittedException('Invalid path "' . $path . '"');
57
-		}
58
-		return $this->path . $path;
59
-	}
60
-
61
-	/**
62
-	 * @param string $path
63
-	 * @return string|null
64
-	 */
65
-	public function getRelativePath($path) {
66
-		return PathHelper::getRelativePath($this->getPath(), $path);
67
-	}
68
-
69
-	/**
70
-	 * check if a node is a (grand-)child of the folder
71
-	 *
72
-	 * @param \OC\Files\Node\Node $node
73
-	 * @return bool
74
-	 */
75
-	public function isSubNode($node) {
76
-		return str_starts_with($node->getPath(), $this->path . '/');
77
-	}
78
-
79
-	/**
80
-	 * get the content of this directory
81
-	 *
82
-	 * @return Node[]
83
-	 * @throws \OCP\Files\NotFoundException
84
-	 */
85
-	public function getDirectoryListing() {
86
-		$folderContent = $this->view->getDirectoryContent($this->path, '', $this->getFileInfo(false));
87
-
88
-		return array_map(function (FileInfo $info) {
89
-			if ($info->getMimetype() === FileInfo::MIMETYPE_FOLDER) {
90
-				return new Folder($this->root, $this->view, $info->getPath(), $info, $this);
91
-			} else {
92
-				return new File($this->root, $this->view, $info->getPath(), $info, $this);
93
-			}
94
-		}, $folderContent);
95
-	}
96
-
97
-	protected function createNode(string $path, ?FileInfo $info = null, bool $infoHasSubMountsIncluded = true): INode {
98
-		if (is_null($info)) {
99
-			$isDir = $this->view->is_dir($path);
100
-		} else {
101
-			$isDir = $info->getType() === FileInfo::TYPE_FOLDER;
102
-		}
103
-		$parent = dirname($path) === $this->getPath() ? $this : null;
104
-		if ($isDir) {
105
-			return new Folder($this->root, $this->view, $path, $info, $parent, $infoHasSubMountsIncluded);
106
-		} else {
107
-			return new File($this->root, $this->view, $path, $info, $parent);
108
-		}
109
-	}
110
-
111
-	public function get($path) {
112
-		return $this->root->get($this->getFullPath($path));
113
-	}
114
-
115
-	public function nodeExists($path) {
116
-		try {
117
-			$this->get($path);
118
-			return true;
119
-		} catch (NotFoundException|NotPermittedException) {
120
-			return false;
121
-		}
122
-	}
123
-
124
-	/**
125
-	 * @param string $path
126
-	 * @return \OC\Files\Node\Folder
127
-	 * @throws \OCP\Files\NotPermittedException
128
-	 */
129
-	public function newFolder($path) {
130
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
131
-			$fullPath = $this->getFullPath($path);
132
-			$nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath);
133
-			$this->sendHooks(['preWrite', 'preCreate'], [$nonExisting]);
134
-			if (!$this->view->mkdir($fullPath)) {
135
-				// maybe another concurrent process created the folder already
136
-				if (!$this->view->is_dir($fullPath)) {
137
-					throw new NotPermittedException('Could not create folder "' . $fullPath . '"');
138
-				} else {
139
-					// we need to ensure we don't return before the concurrent request has finished updating the cache
140
-					$tries = 5;
141
-					while (!$this->view->getFileInfo($fullPath)) {
142
-						if ($tries < 1) {
143
-							throw new NotPermittedException('Could not create folder "' . $fullPath . '", folder exists but unable to get cache entry');
144
-						}
145
-						usleep(5 * 1000);
146
-						$tries--;
147
-					}
148
-				}
149
-			}
150
-			$parent = dirname($fullPath) === $this->getPath() ? $this : null;
151
-			$node = new Folder($this->root, $this->view, $fullPath, null, $parent);
152
-			$this->sendHooks(['postWrite', 'postCreate'], [$node]);
153
-			return $node;
154
-		} else {
155
-			throw new NotPermittedException('No create permission for folder "' . $path . '"');
156
-		}
157
-	}
158
-
159
-	/**
160
-	 * @param string $path
161
-	 * @param string | resource | null $content
162
-	 * @return \OC\Files\Node\File
163
-	 * @throws \OCP\Files\NotPermittedException
164
-	 */
165
-	public function newFile($path, $content = null) {
166
-		if ($path === '') {
167
-			throw new NotPermittedException('Could not create as provided path is empty');
168
-		}
169
-		$this->recreateIfNeeded();
170
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
171
-			$fullPath = $this->getFullPath($path);
172
-			$nonExisting = new NonExistingFile($this->root, $this->view, $fullPath);
173
-			$this->sendHooks(['preWrite', 'preCreate'], [$nonExisting]);
174
-			if ($content !== null) {
175
-				$result = $this->view->file_put_contents($fullPath, $content);
176
-			} else {
177
-				$result = $this->view->touch($fullPath);
178
-			}
179
-			if ($result === false) {
180
-				throw new NotPermittedException('Could not create path "' . $fullPath . '"');
181
-			}
182
-			$node = new File($this->root, $this->view, $fullPath, null, $this);
183
-			$this->sendHooks(['postWrite', 'postCreate'], [$node]);
184
-			return $node;
185
-		}
186
-		throw new NotPermittedException('No create permission for path "' . $path . '"');
187
-	}
188
-
189
-	private function queryFromOperator(ISearchOperator $operator, ?string $uid = null, int $limit = 0, int $offset = 0): ISearchQuery {
190
-		if ($uid === null) {
191
-			$user = null;
192
-		} else {
193
-			/** @var IUserManager $userManager */
194
-			$userManager = \OCP\Server::get(IUserManager::class);
195
-			$user = $userManager->get($uid);
196
-		}
197
-		return new SearchQuery($operator, $limit, $offset, [], $user);
198
-	}
199
-
200
-	/**
201
-	 * search for files with the name matching $query
202
-	 *
203
-	 * @param string|ISearchQuery $query
204
-	 * @return \OC\Files\Node\Node[]
205
-	 */
206
-	public function search($query) {
207
-		if (is_string($query)) {
208
-			$query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', '%' . $query . '%'));
209
-		}
210
-
211
-		// search is handled by a single query covering all caches that this folder contains
212
-		// this is done by collect
213
-
214
-		$limitToHome = $query->limitToHome();
215
-		if ($limitToHome && count(explode('/', $this->path)) !== 3) {
216
-			throw new \InvalidArgumentException('searching by owner is only allowed in the users home folder');
217
-		}
218
-
219
-		/** @var QuerySearchHelper $searchHelper */
220
-		$searchHelper = \OC::$server->get(QuerySearchHelper::class);
221
-		[$caches, $mountByMountPoint] = $searchHelper->getCachesAndMountPointsForSearch($this->root, $this->path, $limitToHome);
222
-		$resultsPerCache = $searchHelper->searchInCaches($query, $caches);
223
-
224
-		// loop through all results per-cache, constructing the FileInfo object from the CacheEntry and merge them all
225
-		$files = array_merge(...array_map(function (array $results, string $relativeMountPoint) use ($mountByMountPoint) {
226
-			$mount = $mountByMountPoint[$relativeMountPoint];
227
-			return array_map(function (ICacheEntry $result) use ($relativeMountPoint, $mount) {
228
-				return $this->cacheEntryToFileInfo($mount, $relativeMountPoint, $result);
229
-			}, $results);
230
-		}, array_values($resultsPerCache), array_keys($resultsPerCache)));
231
-
232
-		// don't include this folder in the results
233
-		$files = array_values(array_filter($files, function (FileInfo $file) {
234
-			return $file->getPath() !== $this->getPath();
235
-		}));
236
-
237
-		// since results were returned per-cache, they are no longer fully sorted
238
-		$order = $query->getOrder();
239
-		if ($order) {
240
-			usort($files, function (FileInfo $a, FileInfo $b) use ($order) {
241
-				foreach ($order as $orderField) {
242
-					$cmp = $orderField->sortFileInfo($a, $b);
243
-					if ($cmp !== 0) {
244
-						return $cmp;
245
-					}
246
-				}
247
-				return 0;
248
-			});
249
-		}
250
-
251
-		return array_map(function (FileInfo $file) {
252
-			return $this->createNode($file->getPath(), $file);
253
-		}, $files);
254
-	}
255
-
256
-	private function cacheEntryToFileInfo(IMountPoint $mount, string $appendRoot, ICacheEntry $cacheEntry): FileInfo {
257
-		$cacheEntry['internalPath'] = $cacheEntry['path'];
258
-		$cacheEntry['path'] = rtrim($appendRoot . $cacheEntry->getPath(), '/');
259
-		$subPath = $cacheEntry['path'] !== '' ? '/' . $cacheEntry['path'] : '';
260
-		$storage = $mount->getStorage();
261
-
262
-		$owner = null;
263
-		$ownerId = $storage->getOwner($cacheEntry['internalPath']);
264
-		if ($ownerId !== false) {
265
-			// Cache the user manager (for performance)
266
-			if ($this->userManager === null) {
267
-				$this->userManager = \OCP\Server::get(IUserManager::class);
268
-			}
269
-			$owner = new LazyUser($ownerId, $this->userManager);
270
-		}
271
-
272
-		return new \OC\Files\FileInfo(
273
-			$this->path . $subPath,
274
-			$storage,
275
-			$cacheEntry['internalPath'],
276
-			$cacheEntry,
277
-			$mount,
278
-			$owner,
279
-		);
280
-	}
281
-
282
-	/**
283
-	 * search for files by mimetype
284
-	 *
285
-	 * @param string $mimetype
286
-	 * @return Node[]
287
-	 */
288
-	public function searchByMime($mimetype) {
289
-		if (!str_contains($mimetype, '/')) {
290
-			$query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_LIKE, 'mimetype', $mimetype . '/%'));
291
-		} else {
292
-			$query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mimetype', $mimetype));
293
-		}
294
-		return $this->search($query);
295
-	}
296
-
297
-	/**
298
-	 * search for files by tag
299
-	 *
300
-	 * @param string|int $tag name or tag id
301
-	 * @param string $userId owner of the tags
302
-	 * @return Node[]
303
-	 */
304
-	public function searchByTag($tag, $userId) {
305
-		$query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'tagname', $tag), $userId);
306
-		return $this->search($query);
307
-	}
308
-
309
-	public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0): array {
310
-		$query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'systemtag', $tagName), $userId, $limit, $offset);
311
-		return $this->search($query);
312
-	}
313
-
314
-	/**
315
-	 * @param int $id
316
-	 * @return \OCP\Files\Node[]
317
-	 */
318
-	public function getById($id) {
319
-		return $this->root->getByIdInPath((int)$id, $this->getPath());
320
-	}
321
-
322
-	public function getFirstNodeById(int $id): ?\OCP\Files\Node {
323
-		return $this->root->getFirstNodeByIdInPath($id, $this->getPath());
324
-	}
325
-
326
-	public function getAppDataDirectoryName(): string {
327
-		$instanceId = \OC::$server->getConfig()->getSystemValueString('instanceid');
328
-		return 'appdata_' . $instanceId;
329
-	}
330
-
331
-	/**
332
-	 * In case the path we are currently in is inside the appdata_* folder,
333
-	 * the original getById method does not work, because it can only look inside
334
-	 * the user's mount points. But the user has no mount point for the root storage.
335
-	 *
336
-	 * So in that case we directly check the mount of the root if it contains
337
-	 * the id. If it does we check if the path is inside the path we are working
338
-	 * in.
339
-	 *
340
-	 * @param int $id
341
-	 * @return array
342
-	 */
343
-	protected function getByIdInRootMount(int $id): array {
344
-		if (!method_exists($this->root, 'createNode')) {
345
-			// Always expected to be false. Being a method of Folder, this is
346
-			// always implemented. For it is an internal method and should not
347
-			// be exposed and made public, it is not part of an interface.
348
-			return [];
349
-		}
350
-		$mount = $this->root->getMount('');
351
-		$storage = $mount->getStorage();
352
-		$cacheEntry = $storage?->getCache($this->path)->get($id);
353
-		if (!$cacheEntry) {
354
-			return [];
355
-		}
356
-
357
-		$absolutePath = '/' . ltrim($cacheEntry->getPath(), '/');
358
-		$currentPath = rtrim($this->path, '/') . '/';
359
-
360
-		if (!str_starts_with($absolutePath, $currentPath)) {
361
-			return [];
362
-		}
363
-
364
-		return [$this->root->createNode(
365
-			$absolutePath, new \OC\Files\FileInfo(
366
-				$absolutePath,
367
-				$storage,
368
-				$cacheEntry->getPath(),
369
-				$cacheEntry,
370
-				$mount
371
-			))];
372
-	}
373
-
374
-	public function getFreeSpace() {
375
-		return $this->view->free_space($this->path);
376
-	}
377
-
378
-	public function delete() {
379
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
380
-			$this->sendHooks(['preDelete']);
381
-			$fileInfo = $this->getFileInfo();
382
-			$this->view->rmdir($this->path);
383
-			$nonExisting = new NonExistingFolder($this->root, $this->view, $this->path, $fileInfo);
384
-			$this->sendHooks(['postDelete'], [$nonExisting]);
385
-			$this->wasDeleted = true;
386
-		} else {
387
-			throw new NotPermittedException('No delete permission for path "' . $this->path . '"');
388
-		}
389
-	}
390
-
391
-	/**
392
-	 * Add a suffix to the name in case the file exists
393
-	 *
394
-	 * @param string $name
395
-	 * @return string
396
-	 * @throws NotPermittedException
397
-	 */
398
-	public function getNonExistingName($name) {
399
-		$uniqueName = \OC_Helper::buildNotExistingFileNameForView($this->getPath(), $name, $this->view);
400
-		return trim($this->getRelativePath($uniqueName), '/');
401
-	}
402
-
403
-	/**
404
-	 * @param int $limit
405
-	 * @param int $offset
406
-	 * @return INode[]
407
-	 */
408
-	public function getRecent($limit, $offset = 0) {
409
-		$filterOutNonEmptyFolder = new SearchBinaryOperator(
410
-			// filter out non empty folders
411
-			ISearchBinaryOperator::OPERATOR_OR,
412
-			[
413
-				new SearchBinaryOperator(
414
-					ISearchBinaryOperator::OPERATOR_NOT,
415
-					[
416
-						new SearchComparison(
417
-							ISearchComparison::COMPARE_EQUAL,
418
-							'mimetype',
419
-							FileInfo::MIMETYPE_FOLDER
420
-						),
421
-					]
422
-				),
423
-				new SearchComparison(
424
-					ISearchComparison::COMPARE_EQUAL,
425
-					'size',
426
-					0
427
-				),
428
-			]
429
-		);
430
-
431
-		$filterNonRecentFiles = new SearchComparison(
432
-			ISearchComparison::COMPARE_GREATER_THAN,
433
-			'mtime',
434
-			strtotime('-2 week')
435
-		);
436
-		if ($offset === 0 && $limit <= 100) {
437
-			$query = new SearchQuery(
438
-				new SearchBinaryOperator(
439
-					ISearchBinaryOperator::OPERATOR_AND,
440
-					[
441
-						$filterOutNonEmptyFolder,
442
-						$filterNonRecentFiles,
443
-					],
444
-				),
445
-				$limit,
446
-				$offset,
447
-				[
448
-					new SearchOrder(
449
-						ISearchOrder::DIRECTION_DESCENDING,
450
-						'mtime'
451
-					),
452
-				]
453
-			);
454
-		} else {
455
-			$query = new SearchQuery(
456
-				$filterOutNonEmptyFolder,
457
-				$limit,
458
-				$offset,
459
-				[
460
-					new SearchOrder(
461
-						ISearchOrder::DIRECTION_DESCENDING,
462
-						'mtime'
463
-					),
464
-				]
465
-			);
466
-		}
467
-
468
-		return $this->search($query);
469
-	}
470
-
471
-	public function verifyPath($fileName, $readonly = false): void {
472
-		$this->view->verifyPath(
473
-			$this->getPath(),
474
-			$fileName,
475
-			$readonly,
476
-		);
477
-	}
478
-
479
-	private function recreateIfNeeded(): void {
480
-		if ($this->wasDeleted) {
481
-			$this->newFolder('');
482
-			$this->wasDeleted = false;
483
-		}
484
-	}
485
-
486
-	#[Override]
487
-	public function getOrCreateFolder(string $path, int $maxRetries = 5): IFolder {
488
-		$i = 0;
489
-		while (true) {
490
-			$path = $i === 0 ? $path : $path . ' (' . $i . ')';
491
-			try {
492
-				$folder = $this->get($path);
493
-				if ($folder instanceof IFolder) {
494
-					return $folder;
495
-				}
496
-			} catch (NotFoundException) {
497
-				$folder = dirname($path) === '.' ? $this : $this->get(dirname($path));
498
-				if (!($folder instanceof Folder)) {
499
-					throw new NotPermittedException("Unable to create folder $path. Parent is not a directory.");
500
-				}
501
-				return $folder->newFolder(basename($path));
502
-			}
503
-			$i++;
504
-			if ($i === $maxRetries) {
505
-				throw new NotPermittedException('Unable to load or create folder.');
506
-			}
507
-		}
508
-	}
34
+    private ?IUserManager $userManager = null;
35
+
36
+    private bool $wasDeleted = false;
37
+
38
+    /**
39
+     * Creates a Folder that represents a non-existing path
40
+     *
41
+     * @param string $path path
42
+     * @return NonExistingFolder non-existing node
43
+     */
44
+    protected function createNonExistingNode($path) {
45
+        return new NonExistingFolder($this->root, $this->view, $path);
46
+    }
47
+
48
+    /**
49
+     * @param string $path path relative to the folder
50
+     * @return string
51
+     * @throws \OCP\Files\NotPermittedException
52
+     */
53
+    public function getFullPath($path) {
54
+        $path = $this->normalizePath($path);
55
+        if (!$this->isValidPath($path)) {
56
+            throw new NotPermittedException('Invalid path "' . $path . '"');
57
+        }
58
+        return $this->path . $path;
59
+    }
60
+
61
+    /**
62
+     * @param string $path
63
+     * @return string|null
64
+     */
65
+    public function getRelativePath($path) {
66
+        return PathHelper::getRelativePath($this->getPath(), $path);
67
+    }
68
+
69
+    /**
70
+     * check if a node is a (grand-)child of the folder
71
+     *
72
+     * @param \OC\Files\Node\Node $node
73
+     * @return bool
74
+     */
75
+    public function isSubNode($node) {
76
+        return str_starts_with($node->getPath(), $this->path . '/');
77
+    }
78
+
79
+    /**
80
+     * get the content of this directory
81
+     *
82
+     * @return Node[]
83
+     * @throws \OCP\Files\NotFoundException
84
+     */
85
+    public function getDirectoryListing() {
86
+        $folderContent = $this->view->getDirectoryContent($this->path, '', $this->getFileInfo(false));
87
+
88
+        return array_map(function (FileInfo $info) {
89
+            if ($info->getMimetype() === FileInfo::MIMETYPE_FOLDER) {
90
+                return new Folder($this->root, $this->view, $info->getPath(), $info, $this);
91
+            } else {
92
+                return new File($this->root, $this->view, $info->getPath(), $info, $this);
93
+            }
94
+        }, $folderContent);
95
+    }
96
+
97
+    protected function createNode(string $path, ?FileInfo $info = null, bool $infoHasSubMountsIncluded = true): INode {
98
+        if (is_null($info)) {
99
+            $isDir = $this->view->is_dir($path);
100
+        } else {
101
+            $isDir = $info->getType() === FileInfo::TYPE_FOLDER;
102
+        }
103
+        $parent = dirname($path) === $this->getPath() ? $this : null;
104
+        if ($isDir) {
105
+            return new Folder($this->root, $this->view, $path, $info, $parent, $infoHasSubMountsIncluded);
106
+        } else {
107
+            return new File($this->root, $this->view, $path, $info, $parent);
108
+        }
109
+    }
110
+
111
+    public function get($path) {
112
+        return $this->root->get($this->getFullPath($path));
113
+    }
114
+
115
+    public function nodeExists($path) {
116
+        try {
117
+            $this->get($path);
118
+            return true;
119
+        } catch (NotFoundException|NotPermittedException) {
120
+            return false;
121
+        }
122
+    }
123
+
124
+    /**
125
+     * @param string $path
126
+     * @return \OC\Files\Node\Folder
127
+     * @throws \OCP\Files\NotPermittedException
128
+     */
129
+    public function newFolder($path) {
130
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
131
+            $fullPath = $this->getFullPath($path);
132
+            $nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath);
133
+            $this->sendHooks(['preWrite', 'preCreate'], [$nonExisting]);
134
+            if (!$this->view->mkdir($fullPath)) {
135
+                // maybe another concurrent process created the folder already
136
+                if (!$this->view->is_dir($fullPath)) {
137
+                    throw new NotPermittedException('Could not create folder "' . $fullPath . '"');
138
+                } else {
139
+                    // we need to ensure we don't return before the concurrent request has finished updating the cache
140
+                    $tries = 5;
141
+                    while (!$this->view->getFileInfo($fullPath)) {
142
+                        if ($tries < 1) {
143
+                            throw new NotPermittedException('Could not create folder "' . $fullPath . '", folder exists but unable to get cache entry');
144
+                        }
145
+                        usleep(5 * 1000);
146
+                        $tries--;
147
+                    }
148
+                }
149
+            }
150
+            $parent = dirname($fullPath) === $this->getPath() ? $this : null;
151
+            $node = new Folder($this->root, $this->view, $fullPath, null, $parent);
152
+            $this->sendHooks(['postWrite', 'postCreate'], [$node]);
153
+            return $node;
154
+        } else {
155
+            throw new NotPermittedException('No create permission for folder "' . $path . '"');
156
+        }
157
+    }
158
+
159
+    /**
160
+     * @param string $path
161
+     * @param string | resource | null $content
162
+     * @return \OC\Files\Node\File
163
+     * @throws \OCP\Files\NotPermittedException
164
+     */
165
+    public function newFile($path, $content = null) {
166
+        if ($path === '') {
167
+            throw new NotPermittedException('Could not create as provided path is empty');
168
+        }
169
+        $this->recreateIfNeeded();
170
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
171
+            $fullPath = $this->getFullPath($path);
172
+            $nonExisting = new NonExistingFile($this->root, $this->view, $fullPath);
173
+            $this->sendHooks(['preWrite', 'preCreate'], [$nonExisting]);
174
+            if ($content !== null) {
175
+                $result = $this->view->file_put_contents($fullPath, $content);
176
+            } else {
177
+                $result = $this->view->touch($fullPath);
178
+            }
179
+            if ($result === false) {
180
+                throw new NotPermittedException('Could not create path "' . $fullPath . '"');
181
+            }
182
+            $node = new File($this->root, $this->view, $fullPath, null, $this);
183
+            $this->sendHooks(['postWrite', 'postCreate'], [$node]);
184
+            return $node;
185
+        }
186
+        throw new NotPermittedException('No create permission for path "' . $path . '"');
187
+    }
188
+
189
+    private function queryFromOperator(ISearchOperator $operator, ?string $uid = null, int $limit = 0, int $offset = 0): ISearchQuery {
190
+        if ($uid === null) {
191
+            $user = null;
192
+        } else {
193
+            /** @var IUserManager $userManager */
194
+            $userManager = \OCP\Server::get(IUserManager::class);
195
+            $user = $userManager->get($uid);
196
+        }
197
+        return new SearchQuery($operator, $limit, $offset, [], $user);
198
+    }
199
+
200
+    /**
201
+     * search for files with the name matching $query
202
+     *
203
+     * @param string|ISearchQuery $query
204
+     * @return \OC\Files\Node\Node[]
205
+     */
206
+    public function search($query) {
207
+        if (is_string($query)) {
208
+            $query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', '%' . $query . '%'));
209
+        }
210
+
211
+        // search is handled by a single query covering all caches that this folder contains
212
+        // this is done by collect
213
+
214
+        $limitToHome = $query->limitToHome();
215
+        if ($limitToHome && count(explode('/', $this->path)) !== 3) {
216
+            throw new \InvalidArgumentException('searching by owner is only allowed in the users home folder');
217
+        }
218
+
219
+        /** @var QuerySearchHelper $searchHelper */
220
+        $searchHelper = \OC::$server->get(QuerySearchHelper::class);
221
+        [$caches, $mountByMountPoint] = $searchHelper->getCachesAndMountPointsForSearch($this->root, $this->path, $limitToHome);
222
+        $resultsPerCache = $searchHelper->searchInCaches($query, $caches);
223
+
224
+        // loop through all results per-cache, constructing the FileInfo object from the CacheEntry and merge them all
225
+        $files = array_merge(...array_map(function (array $results, string $relativeMountPoint) use ($mountByMountPoint) {
226
+            $mount = $mountByMountPoint[$relativeMountPoint];
227
+            return array_map(function (ICacheEntry $result) use ($relativeMountPoint, $mount) {
228
+                return $this->cacheEntryToFileInfo($mount, $relativeMountPoint, $result);
229
+            }, $results);
230
+        }, array_values($resultsPerCache), array_keys($resultsPerCache)));
231
+
232
+        // don't include this folder in the results
233
+        $files = array_values(array_filter($files, function (FileInfo $file) {
234
+            return $file->getPath() !== $this->getPath();
235
+        }));
236
+
237
+        // since results were returned per-cache, they are no longer fully sorted
238
+        $order = $query->getOrder();
239
+        if ($order) {
240
+            usort($files, function (FileInfo $a, FileInfo $b) use ($order) {
241
+                foreach ($order as $orderField) {
242
+                    $cmp = $orderField->sortFileInfo($a, $b);
243
+                    if ($cmp !== 0) {
244
+                        return $cmp;
245
+                    }
246
+                }
247
+                return 0;
248
+            });
249
+        }
250
+
251
+        return array_map(function (FileInfo $file) {
252
+            return $this->createNode($file->getPath(), $file);
253
+        }, $files);
254
+    }
255
+
256
+    private function cacheEntryToFileInfo(IMountPoint $mount, string $appendRoot, ICacheEntry $cacheEntry): FileInfo {
257
+        $cacheEntry['internalPath'] = $cacheEntry['path'];
258
+        $cacheEntry['path'] = rtrim($appendRoot . $cacheEntry->getPath(), '/');
259
+        $subPath = $cacheEntry['path'] !== '' ? '/' . $cacheEntry['path'] : '';
260
+        $storage = $mount->getStorage();
261
+
262
+        $owner = null;
263
+        $ownerId = $storage->getOwner($cacheEntry['internalPath']);
264
+        if ($ownerId !== false) {
265
+            // Cache the user manager (for performance)
266
+            if ($this->userManager === null) {
267
+                $this->userManager = \OCP\Server::get(IUserManager::class);
268
+            }
269
+            $owner = new LazyUser($ownerId, $this->userManager);
270
+        }
271
+
272
+        return new \OC\Files\FileInfo(
273
+            $this->path . $subPath,
274
+            $storage,
275
+            $cacheEntry['internalPath'],
276
+            $cacheEntry,
277
+            $mount,
278
+            $owner,
279
+        );
280
+    }
281
+
282
+    /**
283
+     * search for files by mimetype
284
+     *
285
+     * @param string $mimetype
286
+     * @return Node[]
287
+     */
288
+    public function searchByMime($mimetype) {
289
+        if (!str_contains($mimetype, '/')) {
290
+            $query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_LIKE, 'mimetype', $mimetype . '/%'));
291
+        } else {
292
+            $query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mimetype', $mimetype));
293
+        }
294
+        return $this->search($query);
295
+    }
296
+
297
+    /**
298
+     * search for files by tag
299
+     *
300
+     * @param string|int $tag name or tag id
301
+     * @param string $userId owner of the tags
302
+     * @return Node[]
303
+     */
304
+    public function searchByTag($tag, $userId) {
305
+        $query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'tagname', $tag), $userId);
306
+        return $this->search($query);
307
+    }
308
+
309
+    public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0): array {
310
+        $query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'systemtag', $tagName), $userId, $limit, $offset);
311
+        return $this->search($query);
312
+    }
313
+
314
+    /**
315
+     * @param int $id
316
+     * @return \OCP\Files\Node[]
317
+     */
318
+    public function getById($id) {
319
+        return $this->root->getByIdInPath((int)$id, $this->getPath());
320
+    }
321
+
322
+    public function getFirstNodeById(int $id): ?\OCP\Files\Node {
323
+        return $this->root->getFirstNodeByIdInPath($id, $this->getPath());
324
+    }
325
+
326
+    public function getAppDataDirectoryName(): string {
327
+        $instanceId = \OC::$server->getConfig()->getSystemValueString('instanceid');
328
+        return 'appdata_' . $instanceId;
329
+    }
330
+
331
+    /**
332
+     * In case the path we are currently in is inside the appdata_* folder,
333
+     * the original getById method does not work, because it can only look inside
334
+     * the user's mount points. But the user has no mount point for the root storage.
335
+     *
336
+     * So in that case we directly check the mount of the root if it contains
337
+     * the id. If it does we check if the path is inside the path we are working
338
+     * in.
339
+     *
340
+     * @param int $id
341
+     * @return array
342
+     */
343
+    protected function getByIdInRootMount(int $id): array {
344
+        if (!method_exists($this->root, 'createNode')) {
345
+            // Always expected to be false. Being a method of Folder, this is
346
+            // always implemented. For it is an internal method and should not
347
+            // be exposed and made public, it is not part of an interface.
348
+            return [];
349
+        }
350
+        $mount = $this->root->getMount('');
351
+        $storage = $mount->getStorage();
352
+        $cacheEntry = $storage?->getCache($this->path)->get($id);
353
+        if (!$cacheEntry) {
354
+            return [];
355
+        }
356
+
357
+        $absolutePath = '/' . ltrim($cacheEntry->getPath(), '/');
358
+        $currentPath = rtrim($this->path, '/') . '/';
359
+
360
+        if (!str_starts_with($absolutePath, $currentPath)) {
361
+            return [];
362
+        }
363
+
364
+        return [$this->root->createNode(
365
+            $absolutePath, new \OC\Files\FileInfo(
366
+                $absolutePath,
367
+                $storage,
368
+                $cacheEntry->getPath(),
369
+                $cacheEntry,
370
+                $mount
371
+            ))];
372
+    }
373
+
374
+    public function getFreeSpace() {
375
+        return $this->view->free_space($this->path);
376
+    }
377
+
378
+    public function delete() {
379
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
380
+            $this->sendHooks(['preDelete']);
381
+            $fileInfo = $this->getFileInfo();
382
+            $this->view->rmdir($this->path);
383
+            $nonExisting = new NonExistingFolder($this->root, $this->view, $this->path, $fileInfo);
384
+            $this->sendHooks(['postDelete'], [$nonExisting]);
385
+            $this->wasDeleted = true;
386
+        } else {
387
+            throw new NotPermittedException('No delete permission for path "' . $this->path . '"');
388
+        }
389
+    }
390
+
391
+    /**
392
+     * Add a suffix to the name in case the file exists
393
+     *
394
+     * @param string $name
395
+     * @return string
396
+     * @throws NotPermittedException
397
+     */
398
+    public function getNonExistingName($name) {
399
+        $uniqueName = \OC_Helper::buildNotExistingFileNameForView($this->getPath(), $name, $this->view);
400
+        return trim($this->getRelativePath($uniqueName), '/');
401
+    }
402
+
403
+    /**
404
+     * @param int $limit
405
+     * @param int $offset
406
+     * @return INode[]
407
+     */
408
+    public function getRecent($limit, $offset = 0) {
409
+        $filterOutNonEmptyFolder = new SearchBinaryOperator(
410
+            // filter out non empty folders
411
+            ISearchBinaryOperator::OPERATOR_OR,
412
+            [
413
+                new SearchBinaryOperator(
414
+                    ISearchBinaryOperator::OPERATOR_NOT,
415
+                    [
416
+                        new SearchComparison(
417
+                            ISearchComparison::COMPARE_EQUAL,
418
+                            'mimetype',
419
+                            FileInfo::MIMETYPE_FOLDER
420
+                        ),
421
+                    ]
422
+                ),
423
+                new SearchComparison(
424
+                    ISearchComparison::COMPARE_EQUAL,
425
+                    'size',
426
+                    0
427
+                ),
428
+            ]
429
+        );
430
+
431
+        $filterNonRecentFiles = new SearchComparison(
432
+            ISearchComparison::COMPARE_GREATER_THAN,
433
+            'mtime',
434
+            strtotime('-2 week')
435
+        );
436
+        if ($offset === 0 && $limit <= 100) {
437
+            $query = new SearchQuery(
438
+                new SearchBinaryOperator(
439
+                    ISearchBinaryOperator::OPERATOR_AND,
440
+                    [
441
+                        $filterOutNonEmptyFolder,
442
+                        $filterNonRecentFiles,
443
+                    ],
444
+                ),
445
+                $limit,
446
+                $offset,
447
+                [
448
+                    new SearchOrder(
449
+                        ISearchOrder::DIRECTION_DESCENDING,
450
+                        'mtime'
451
+                    ),
452
+                ]
453
+            );
454
+        } else {
455
+            $query = new SearchQuery(
456
+                $filterOutNonEmptyFolder,
457
+                $limit,
458
+                $offset,
459
+                [
460
+                    new SearchOrder(
461
+                        ISearchOrder::DIRECTION_DESCENDING,
462
+                        'mtime'
463
+                    ),
464
+                ]
465
+            );
466
+        }
467
+
468
+        return $this->search($query);
469
+    }
470
+
471
+    public function verifyPath($fileName, $readonly = false): void {
472
+        $this->view->verifyPath(
473
+            $this->getPath(),
474
+            $fileName,
475
+            $readonly,
476
+        );
477
+    }
478
+
479
+    private function recreateIfNeeded(): void {
480
+        if ($this->wasDeleted) {
481
+            $this->newFolder('');
482
+            $this->wasDeleted = false;
483
+        }
484
+    }
485
+
486
+    #[Override]
487
+    public function getOrCreateFolder(string $path, int $maxRetries = 5): IFolder {
488
+        $i = 0;
489
+        while (true) {
490
+            $path = $i === 0 ? $path : $path . ' (' . $i . ')';
491
+            try {
492
+                $folder = $this->get($path);
493
+                if ($folder instanceof IFolder) {
494
+                    return $folder;
495
+                }
496
+            } catch (NotFoundException) {
497
+                $folder = dirname($path) === '.' ? $this : $this->get(dirname($path));
498
+                if (!($folder instanceof Folder)) {
499
+                    throw new NotPermittedException("Unable to create folder $path. Parent is not a directory.");
500
+                }
501
+                return $folder->newFolder(basename($path));
502
+            }
503
+            $i++;
504
+            if ($i === $maxRetries) {
505
+                throw new NotPermittedException('Unable to load or create folder.');
506
+            }
507
+        }
508
+    }
509 509
 }
Please login to merge, or discard this patch.
Spacing   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -53,9 +53,9 @@  discard block
 block discarded – undo
53 53
 	public function getFullPath($path) {
54 54
 		$path = $this->normalizePath($path);
55 55
 		if (!$this->isValidPath($path)) {
56
-			throw new NotPermittedException('Invalid path "' . $path . '"');
56
+			throw new NotPermittedException('Invalid path "'.$path.'"');
57 57
 		}
58
-		return $this->path . $path;
58
+		return $this->path.$path;
59 59
 	}
60 60
 
61 61
 	/**
@@ -73,7 +73,7 @@  discard block
 block discarded – undo
73 73
 	 * @return bool
74 74
 	 */
75 75
 	public function isSubNode($node) {
76
-		return str_starts_with($node->getPath(), $this->path . '/');
76
+		return str_starts_with($node->getPath(), $this->path.'/');
77 77
 	}
78 78
 
79 79
 	/**
@@ -85,7 +85,7 @@  discard block
 block discarded – undo
85 85
 	public function getDirectoryListing() {
86 86
 		$folderContent = $this->view->getDirectoryContent($this->path, '', $this->getFileInfo(false));
87 87
 
88
-		return array_map(function (FileInfo $info) {
88
+		return array_map(function(FileInfo $info) {
89 89
 			if ($info->getMimetype() === FileInfo::MIMETYPE_FOLDER) {
90 90
 				return new Folder($this->root, $this->view, $info->getPath(), $info, $this);
91 91
 			} else {
@@ -116,7 +116,7 @@  discard block
 block discarded – undo
116 116
 		try {
117 117
 			$this->get($path);
118 118
 			return true;
119
-		} catch (NotFoundException|NotPermittedException) {
119
+		} catch (NotFoundException | NotPermittedException) {
120 120
 			return false;
121 121
 		}
122 122
 	}
@@ -134,13 +134,13 @@  discard block
 block discarded – undo
134 134
 			if (!$this->view->mkdir($fullPath)) {
135 135
 				// maybe another concurrent process created the folder already
136 136
 				if (!$this->view->is_dir($fullPath)) {
137
-					throw new NotPermittedException('Could not create folder "' . $fullPath . '"');
137
+					throw new NotPermittedException('Could not create folder "'.$fullPath.'"');
138 138
 				} else {
139 139
 					// we need to ensure we don't return before the concurrent request has finished updating the cache
140 140
 					$tries = 5;
141 141
 					while (!$this->view->getFileInfo($fullPath)) {
142 142
 						if ($tries < 1) {
143
-							throw new NotPermittedException('Could not create folder "' . $fullPath . '", folder exists but unable to get cache entry');
143
+							throw new NotPermittedException('Could not create folder "'.$fullPath.'", folder exists but unable to get cache entry');
144 144
 						}
145 145
 						usleep(5 * 1000);
146 146
 						$tries--;
@@ -152,7 +152,7 @@  discard block
 block discarded – undo
152 152
 			$this->sendHooks(['postWrite', 'postCreate'], [$node]);
153 153
 			return $node;
154 154
 		} else {
155
-			throw new NotPermittedException('No create permission for folder "' . $path . '"');
155
+			throw new NotPermittedException('No create permission for folder "'.$path.'"');
156 156
 		}
157 157
 	}
158 158
 
@@ -177,13 +177,13 @@  discard block
 block discarded – undo
177 177
 				$result = $this->view->touch($fullPath);
178 178
 			}
179 179
 			if ($result === false) {
180
-				throw new NotPermittedException('Could not create path "' . $fullPath . '"');
180
+				throw new NotPermittedException('Could not create path "'.$fullPath.'"');
181 181
 			}
182 182
 			$node = new File($this->root, $this->view, $fullPath, null, $this);
183 183
 			$this->sendHooks(['postWrite', 'postCreate'], [$node]);
184 184
 			return $node;
185 185
 		}
186
-		throw new NotPermittedException('No create permission for path "' . $path . '"');
186
+		throw new NotPermittedException('No create permission for path "'.$path.'"');
187 187
 	}
188 188
 
189 189
 	private function queryFromOperator(ISearchOperator $operator, ?string $uid = null, int $limit = 0, int $offset = 0): ISearchQuery {
@@ -205,7 +205,7 @@  discard block
 block discarded – undo
205 205
 	 */
206 206
 	public function search($query) {
207 207
 		if (is_string($query)) {
208
-			$query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', '%' . $query . '%'));
208
+			$query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', '%'.$query.'%'));
209 209
 		}
210 210
 
211 211
 		// search is handled by a single query covering all caches that this folder contains
@@ -222,22 +222,22 @@  discard block
 block discarded – undo
222 222
 		$resultsPerCache = $searchHelper->searchInCaches($query, $caches);
223 223
 
224 224
 		// loop through all results per-cache, constructing the FileInfo object from the CacheEntry and merge them all
225
-		$files = array_merge(...array_map(function (array $results, string $relativeMountPoint) use ($mountByMountPoint) {
225
+		$files = array_merge(...array_map(function(array $results, string $relativeMountPoint) use ($mountByMountPoint) {
226 226
 			$mount = $mountByMountPoint[$relativeMountPoint];
227
-			return array_map(function (ICacheEntry $result) use ($relativeMountPoint, $mount) {
227
+			return array_map(function(ICacheEntry $result) use ($relativeMountPoint, $mount) {
228 228
 				return $this->cacheEntryToFileInfo($mount, $relativeMountPoint, $result);
229 229
 			}, $results);
230 230
 		}, array_values($resultsPerCache), array_keys($resultsPerCache)));
231 231
 
232 232
 		// don't include this folder in the results
233
-		$files = array_values(array_filter($files, function (FileInfo $file) {
233
+		$files = array_values(array_filter($files, function(FileInfo $file) {
234 234
 			return $file->getPath() !== $this->getPath();
235 235
 		}));
236 236
 
237 237
 		// since results were returned per-cache, they are no longer fully sorted
238 238
 		$order = $query->getOrder();
239 239
 		if ($order) {
240
-			usort($files, function (FileInfo $a, FileInfo $b) use ($order) {
240
+			usort($files, function(FileInfo $a, FileInfo $b) use ($order) {
241 241
 				foreach ($order as $orderField) {
242 242
 					$cmp = $orderField->sortFileInfo($a, $b);
243 243
 					if ($cmp !== 0) {
@@ -248,15 +248,15 @@  discard block
 block discarded – undo
248 248
 			});
249 249
 		}
250 250
 
251
-		return array_map(function (FileInfo $file) {
251
+		return array_map(function(FileInfo $file) {
252 252
 			return $this->createNode($file->getPath(), $file);
253 253
 		}, $files);
254 254
 	}
255 255
 
256 256
 	private function cacheEntryToFileInfo(IMountPoint $mount, string $appendRoot, ICacheEntry $cacheEntry): FileInfo {
257 257
 		$cacheEntry['internalPath'] = $cacheEntry['path'];
258
-		$cacheEntry['path'] = rtrim($appendRoot . $cacheEntry->getPath(), '/');
259
-		$subPath = $cacheEntry['path'] !== '' ? '/' . $cacheEntry['path'] : '';
258
+		$cacheEntry['path'] = rtrim($appendRoot.$cacheEntry->getPath(), '/');
259
+		$subPath = $cacheEntry['path'] !== '' ? '/'.$cacheEntry['path'] : '';
260 260
 		$storage = $mount->getStorage();
261 261
 
262 262
 		$owner = null;
@@ -270,7 +270,7 @@  discard block
 block discarded – undo
270 270
 		}
271 271
 
272 272
 		return new \OC\Files\FileInfo(
273
-			$this->path . $subPath,
273
+			$this->path.$subPath,
274 274
 			$storage,
275 275
 			$cacheEntry['internalPath'],
276 276
 			$cacheEntry,
@@ -287,7 +287,7 @@  discard block
 block discarded – undo
287 287
 	 */
288 288
 	public function searchByMime($mimetype) {
289 289
 		if (!str_contains($mimetype, '/')) {
290
-			$query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_LIKE, 'mimetype', $mimetype . '/%'));
290
+			$query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_LIKE, 'mimetype', $mimetype.'/%'));
291 291
 		} else {
292 292
 			$query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mimetype', $mimetype));
293 293
 		}
@@ -316,7 +316,7 @@  discard block
 block discarded – undo
316 316
 	 * @return \OCP\Files\Node[]
317 317
 	 */
318 318
 	public function getById($id) {
319
-		return $this->root->getByIdInPath((int)$id, $this->getPath());
319
+		return $this->root->getByIdInPath((int) $id, $this->getPath());
320 320
 	}
321 321
 
322 322
 	public function getFirstNodeById(int $id): ?\OCP\Files\Node {
@@ -325,7 +325,7 @@  discard block
 block discarded – undo
325 325
 
326 326
 	public function getAppDataDirectoryName(): string {
327 327
 		$instanceId = \OC::$server->getConfig()->getSystemValueString('instanceid');
328
-		return 'appdata_' . $instanceId;
328
+		return 'appdata_'.$instanceId;
329 329
 	}
330 330
 
331 331
 	/**
@@ -354,8 +354,8 @@  discard block
 block discarded – undo
354 354
 			return [];
355 355
 		}
356 356
 
357
-		$absolutePath = '/' . ltrim($cacheEntry->getPath(), '/');
358
-		$currentPath = rtrim($this->path, '/') . '/';
357
+		$absolutePath = '/'.ltrim($cacheEntry->getPath(), '/');
358
+		$currentPath = rtrim($this->path, '/').'/';
359 359
 
360 360
 		if (!str_starts_with($absolutePath, $currentPath)) {
361 361
 			return [];
@@ -384,7 +384,7 @@  discard block
 block discarded – undo
384 384
 			$this->sendHooks(['postDelete'], [$nonExisting]);
385 385
 			$this->wasDeleted = true;
386 386
 		} else {
387
-			throw new NotPermittedException('No delete permission for path "' . $this->path . '"');
387
+			throw new NotPermittedException('No delete permission for path "'.$this->path.'"');
388 388
 		}
389 389
 	}
390 390
 
@@ -487,7 +487,7 @@  discard block
 block discarded – undo
487 487
 	public function getOrCreateFolder(string $path, int $maxRetries = 5): IFolder {
488 488
 		$i = 0;
489 489
 		while (true) {
490
-			$path = $i === 0 ? $path : $path . ' (' . $i . ')';
490
+			$path = $i === 0 ? $path : $path.' ('.$i.')';
491 491
 			try {
492 492
 				$folder = $this->get($path);
493 493
 				if ($folder instanceof IFolder) {
Please login to merge, or discard this patch.
lib/private/Files/Node/LazyFolder.php 1 patch
Indentation   +543 added lines, -543 removed lines patch added patch discarded remove patch
@@ -25,547 +25,547 @@
 block discarded – undo
25 25
  * @package OC\Files\Node
26 26
  */
27 27
 class LazyFolder implements Folder {
28
-	/** @var \Closure(): Folder */
29
-	private \Closure $folderClosure;
30
-	protected ?Folder $folder = null;
31
-	protected IRootFolder $rootFolder;
32
-	protected array $data;
33
-
34
-	/**
35
-	 * @param IRootFolder $rootFolder
36
-	 * @param \Closure(): Folder $folderClosure
37
-	 * @param array $data
38
-	 */
39
-	public function __construct(IRootFolder $rootFolder, \Closure $folderClosure, array $data = []) {
40
-		$this->rootFolder = $rootFolder;
41
-		$this->folderClosure = $folderClosure;
42
-		$this->data = $data;
43
-	}
44
-
45
-	protected function getRootFolder(): IRootFolder {
46
-		return $this->rootFolder;
47
-	}
48
-
49
-	protected function getRealFolder(): Folder {
50
-		if ($this->folder === null) {
51
-			$this->folder = call_user_func($this->folderClosure);
52
-		}
53
-		return $this->folder;
54
-	}
55
-
56
-	/**
57
-	 * Magic method to first get the real rootFolder and then
58
-	 * call $method with $args on it
59
-	 *
60
-	 * @param $method
61
-	 * @param $args
62
-	 * @return mixed
63
-	 */
64
-	public function __call($method, $args) {
65
-		return call_user_func_array([$this->getRealFolder(), $method], $args);
66
-	}
67
-
68
-	/**
69
-	 * @inheritDoc
70
-	 */
71
-	public function getUser() {
72
-		return $this->__call(__FUNCTION__, func_get_args());
73
-	}
74
-
75
-	/**
76
-	 * @inheritDoc
77
-	 */
78
-	public function listen($scope, $method, callable $callback) {
79
-		$this->__call(__FUNCTION__, func_get_args());
80
-	}
81
-
82
-	/**
83
-	 * @inheritDoc
84
-	 */
85
-	public function removeListener($scope = null, $method = null, ?callable $callback = null) {
86
-		$this->__call(__FUNCTION__, func_get_args());
87
-	}
88
-
89
-	/**
90
-	 * @inheritDoc
91
-	 */
92
-	public function emit($scope, $method, $arguments = []) {
93
-		$this->__call(__FUNCTION__, func_get_args());
94
-	}
95
-
96
-	/**
97
-	 * @inheritDoc
98
-	 */
99
-	public function mount($storage, $mountPoint, $arguments = []) {
100
-		$this->__call(__FUNCTION__, func_get_args());
101
-	}
102
-
103
-	/**
104
-	 * @inheritDoc
105
-	 */
106
-	public function getMount(string $mountPoint): IMountPoint {
107
-		return $this->__call(__FUNCTION__, func_get_args());
108
-	}
109
-
110
-	/**
111
-	 * @return IMountPoint[]
112
-	 */
113
-	public function getMountsIn(string $mountPoint): array {
114
-		return $this->__call(__FUNCTION__, func_get_args());
115
-	}
116
-
117
-	/**
118
-	 * @inheritDoc
119
-	 */
120
-	public function getMountByStorageId($storageId) {
121
-		return $this->__call(__FUNCTION__, func_get_args());
122
-	}
123
-
124
-	/**
125
-	 * @inheritDoc
126
-	 */
127
-	public function getMountByNumericStorageId($numericId) {
128
-		return $this->__call(__FUNCTION__, func_get_args());
129
-	}
130
-
131
-	/**
132
-	 * @inheritDoc
133
-	 */
134
-	public function unMount($mount) {
135
-		$this->__call(__FUNCTION__, func_get_args());
136
-	}
137
-
138
-	public function get($path) {
139
-		return $this->getRootFolder()->get($this->getFullPath($path));
140
-	}
141
-
142
-	#[Override]
143
-	public function getOrCreateFolder(string $path, int $maxRetries = 5): Folder {
144
-		return $this->getRootFolder()->getOrCreateFolder($this->getFullPath($path), $maxRetries);
145
-	}
146
-
147
-	/**
148
-	 * @inheritDoc
149
-	 */
150
-	public function rename($targetPath) {
151
-		return $this->__call(__FUNCTION__, func_get_args());
152
-	}
153
-
154
-	/**
155
-	 * @inheritDoc
156
-	 */
157
-	public function delete() {
158
-		return $this->__call(__FUNCTION__, func_get_args());
159
-	}
160
-
161
-	/**
162
-	 * @inheritDoc
163
-	 */
164
-	public function copy($targetPath) {
165
-		return $this->__call(__FUNCTION__, func_get_args());
166
-	}
167
-
168
-	/**
169
-	 * @inheritDoc
170
-	 */
171
-	public function touch($mtime = null) {
172
-		$this->__call(__FUNCTION__, func_get_args());
173
-	}
174
-
175
-	/**
176
-	 * @inheritDoc
177
-	 */
178
-	public function getStorage() {
179
-		return $this->__call(__FUNCTION__, func_get_args());
180
-	}
181
-
182
-	/**
183
-	 * @inheritDoc
184
-	 */
185
-	public function getPath() {
186
-		if (isset($this->data['path'])) {
187
-			return $this->data['path'];
188
-		}
189
-		return $this->__call(__FUNCTION__, func_get_args());
190
-	}
191
-
192
-	/**
193
-	 * @inheritDoc
194
-	 */
195
-	public function getInternalPath() {
196
-		return $this->__call(__FUNCTION__, func_get_args());
197
-	}
198
-
199
-	/**
200
-	 * @inheritDoc
201
-	 */
202
-	public function getId() {
203
-		if (isset($this->data['fileid'])) {
204
-			return $this->data['fileid'];
205
-		}
206
-		return $this->__call(__FUNCTION__, func_get_args());
207
-	}
208
-
209
-	/**
210
-	 * @inheritDoc
211
-	 */
212
-	public function stat() {
213
-		return $this->__call(__FUNCTION__, func_get_args());
214
-	}
215
-
216
-	/**
217
-	 * @inheritDoc
218
-	 */
219
-	public function getMTime() {
220
-		if (isset($this->data['mtime'])) {
221
-			return $this->data['mtime'];
222
-		}
223
-		return $this->__call(__FUNCTION__, func_get_args());
224
-	}
225
-
226
-	/**
227
-	 * @inheritDoc
228
-	 */
229
-	public function getSize($includeMounts = true): int|float {
230
-		if (isset($this->data['size'])) {
231
-			return $this->data['size'];
232
-		}
233
-		return $this->__call(__FUNCTION__, func_get_args());
234
-	}
235
-
236
-	/**
237
-	 * @inheritDoc
238
-	 */
239
-	public function getEtag() {
240
-		if (isset($this->data['etag'])) {
241
-			return $this->data['etag'];
242
-		}
243
-		return $this->__call(__FUNCTION__, func_get_args());
244
-	}
245
-
246
-	/**
247
-	 * @inheritDoc
248
-	 */
249
-	public function getPermissions() {
250
-		if (isset($this->data['permissions'])) {
251
-			return $this->data['permissions'];
252
-		}
253
-		return $this->__call(__FUNCTION__, func_get_args());
254
-	}
255
-
256
-	/**
257
-	 * @inheritDoc
258
-	 */
259
-	public function isReadable() {
260
-		if (isset($this->data['permissions'])) {
261
-			return ($this->data['permissions'] & Constants::PERMISSION_READ) == Constants::PERMISSION_READ;
262
-		}
263
-		return $this->__call(__FUNCTION__, func_get_args());
264
-	}
265
-
266
-	/**
267
-	 * @inheritDoc
268
-	 */
269
-	public function isUpdateable() {
270
-		if (isset($this->data['permissions'])) {
271
-			return ($this->data['permissions'] & Constants::PERMISSION_UPDATE) == Constants::PERMISSION_UPDATE;
272
-		}
273
-		return $this->__call(__FUNCTION__, func_get_args());
274
-	}
275
-
276
-	/**
277
-	 * @inheritDoc
278
-	 */
279
-	public function isDeletable() {
280
-		if (isset($this->data['permissions'])) {
281
-			return ($this->data['permissions'] & Constants::PERMISSION_DELETE) == Constants::PERMISSION_DELETE;
282
-		}
283
-		return $this->__call(__FUNCTION__, func_get_args());
284
-	}
285
-
286
-	/**
287
-	 * @inheritDoc
288
-	 */
289
-	public function isShareable() {
290
-		if (isset($this->data['permissions'])) {
291
-			return ($this->data['permissions'] & Constants::PERMISSION_SHARE) == Constants::PERMISSION_SHARE;
292
-		}
293
-		return $this->__call(__FUNCTION__, func_get_args());
294
-	}
295
-
296
-	/**
297
-	 * @inheritDoc
298
-	 */
299
-	public function getParent() {
300
-		return $this->__call(__FUNCTION__, func_get_args());
301
-	}
302
-
303
-	/**
304
-	 * @inheritDoc
305
-	 */
306
-	public function getName() {
307
-		if (isset($this->data['path'])) {
308
-			return basename($this->data['path']);
309
-		}
310
-		if (isset($this->data['name'])) {
311
-			return $this->data['name'];
312
-		}
313
-		return $this->__call(__FUNCTION__, func_get_args());
314
-	}
315
-
316
-	/**
317
-	 * @inheritDoc
318
-	 */
319
-	public function getUserFolder($userId) {
320
-		return $this->__call(__FUNCTION__, func_get_args());
321
-	}
322
-
323
-	public function getMimetype(): string {
324
-		if (isset($this->data['mimetype'])) {
325
-			return $this->data['mimetype'];
326
-		}
327
-		return $this->__call(__FUNCTION__, func_get_args());
328
-	}
329
-
330
-	/**
331
-	 * @inheritDoc
332
-	 */
333
-	public function getMimePart() {
334
-		if (isset($this->data['mimetype'])) {
335
-			[$part,] = explode('/', $this->data['mimetype']);
336
-			return $part;
337
-		}
338
-		return $this->__call(__FUNCTION__, func_get_args());
339
-	}
340
-
341
-	/**
342
-	 * @inheritDoc
343
-	 */
344
-	public function isEncrypted() {
345
-		return $this->__call(__FUNCTION__, func_get_args());
346
-	}
347
-
348
-	/**
349
-	 * @inheritDoc
350
-	 */
351
-	public function getType() {
352
-		if (isset($this->data['type'])) {
353
-			return $this->data['type'];
354
-		}
355
-		return $this->__call(__FUNCTION__, func_get_args());
356
-	}
357
-
358
-	/**
359
-	 * @inheritDoc
360
-	 */
361
-	public function isShared() {
362
-		return $this->__call(__FUNCTION__, func_get_args());
363
-	}
364
-
365
-	/**
366
-	 * @inheritDoc
367
-	 */
368
-	public function isMounted() {
369
-		return $this->__call(__FUNCTION__, func_get_args());
370
-	}
371
-
372
-	/**
373
-	 * @inheritDoc
374
-	 */
375
-	public function getMountPoint() {
376
-		return $this->__call(__FUNCTION__, func_get_args());
377
-	}
378
-
379
-	/**
380
-	 * @inheritDoc
381
-	 */
382
-	public function getOwner() {
383
-		return $this->__call(__FUNCTION__, func_get_args());
384
-	}
385
-
386
-	/**
387
-	 * @inheritDoc
388
-	 */
389
-	public function getChecksum() {
390
-		return $this->__call(__FUNCTION__, func_get_args());
391
-	}
392
-
393
-	public function getExtension(): string {
394
-		return $this->__call(__FUNCTION__, func_get_args());
395
-	}
396
-
397
-	/**
398
-	 * @inheritDoc
399
-	 */
400
-	public function getFullPath($path) {
401
-		if (isset($this->data['path'])) {
402
-			$path = PathHelper::normalizePath($path);
403
-			if (!Filesystem::isValidPath($path)) {
404
-				throw new NotPermittedException('Invalid path "' . $path . '"');
405
-			}
406
-			return $this->data['path'] . $path;
407
-		}
408
-		return $this->__call(__FUNCTION__, func_get_args());
409
-	}
410
-
411
-	/**
412
-	 * @inheritDoc
413
-	 */
414
-	public function isSubNode($node) {
415
-		return $this->__call(__FUNCTION__, func_get_args());
416
-	}
417
-
418
-	/**
419
-	 * @inheritDoc
420
-	 */
421
-	public function getDirectoryListing() {
422
-		return $this->__call(__FUNCTION__, func_get_args());
423
-	}
424
-
425
-	public function nodeExists($path) {
426
-		return $this->__call(__FUNCTION__, func_get_args());
427
-	}
428
-
429
-	/**
430
-	 * @inheritDoc
431
-	 */
432
-	public function newFolder($path) {
433
-		return $this->__call(__FUNCTION__, func_get_args());
434
-	}
435
-
436
-	/**
437
-	 * @inheritDoc
438
-	 */
439
-	public function newFile($path, $content = null) {
440
-		return $this->__call(__FUNCTION__, func_get_args());
441
-	}
442
-
443
-	/**
444
-	 * @inheritDoc
445
-	 */
446
-	public function search($query) {
447
-		return $this->__call(__FUNCTION__, func_get_args());
448
-	}
449
-
450
-	/**
451
-	 * @inheritDoc
452
-	 */
453
-	public function searchByMime($mimetype) {
454
-		return $this->__call(__FUNCTION__, func_get_args());
455
-	}
456
-
457
-	/**
458
-	 * @inheritDoc
459
-	 */
460
-	public function searchByTag($tag, $userId) {
461
-		return $this->__call(__FUNCTION__, func_get_args());
462
-	}
463
-
464
-	public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0) {
465
-		return $this->__call(__FUNCTION__, func_get_args());
466
-	}
467
-
468
-	/**
469
-	 * @inheritDoc
470
-	 */
471
-	public function getById($id) {
472
-		return $this->getRootFolder()->getByIdInPath((int)$id, $this->getPath());
473
-	}
474
-
475
-	public function getFirstNodeById(int $id): ?\OCP\Files\Node {
476
-		return $this->getRootFolder()->getFirstNodeByIdInPath($id, $this->getPath());
477
-	}
478
-
479
-	/**
480
-	 * @inheritDoc
481
-	 */
482
-	public function getFreeSpace() {
483
-		return $this->__call(__FUNCTION__, func_get_args());
484
-	}
485
-
486
-	/**
487
-	 * @inheritDoc
488
-	 */
489
-	public function isCreatable() {
490
-		return $this->__call(__FUNCTION__, func_get_args());
491
-	}
492
-
493
-	/**
494
-	 * @inheritDoc
495
-	 */
496
-	public function getNonExistingName($name) {
497
-		return $this->__call(__FUNCTION__, func_get_args());
498
-	}
499
-
500
-	/**
501
-	 * @inheritDoc
502
-	 */
503
-	public function move($targetPath) {
504
-		return $this->__call(__FUNCTION__, func_get_args());
505
-	}
506
-
507
-	/**
508
-	 * @inheritDoc
509
-	 */
510
-	public function lock($type) {
511
-		return $this->__call(__FUNCTION__, func_get_args());
512
-	}
513
-
514
-	/**
515
-	 * @inheritDoc
516
-	 */
517
-	public function changeLock($targetType) {
518
-		return $this->__call(__FUNCTION__, func_get_args());
519
-	}
520
-
521
-	/**
522
-	 * @inheritDoc
523
-	 */
524
-	public function unlock($type) {
525
-		return $this->__call(__FUNCTION__, func_get_args());
526
-	}
527
-
528
-	/**
529
-	 * @inheritDoc
530
-	 */
531
-	public function getRecent($limit, $offset = 0) {
532
-		return $this->__call(__FUNCTION__, func_get_args());
533
-	}
534
-
535
-	/**
536
-	 * @inheritDoc
537
-	 */
538
-	public function getCreationTime(): int {
539
-		return $this->__call(__FUNCTION__, func_get_args());
540
-	}
541
-
542
-	/**
543
-	 * @inheritDoc
544
-	 */
545
-	public function getUploadTime(): int {
546
-		return $this->__call(__FUNCTION__, func_get_args());
547
-	}
548
-
549
-	public function getRelativePath($path) {
550
-		return PathHelper::getRelativePath($this->getPath(), $path);
551
-	}
552
-
553
-	public function getParentId(): int {
554
-		if (isset($this->data['parent'])) {
555
-			return $this->data['parent'];
556
-		}
557
-		return $this->__call(__FUNCTION__, func_get_args());
558
-	}
559
-
560
-	/**
561
-	 * @inheritDoc
562
-	 * @return array<string, int|string|bool|float|string[]|int[]>
563
-	 */
564
-	public function getMetadata(): array {
565
-		return $this->data['metadata'] ?? $this->__call(__FUNCTION__, func_get_args());
566
-	}
567
-
568
-	public function verifyPath($fileName, $readonly = false): void {
569
-		$this->__call(__FUNCTION__, func_get_args());
570
-	}
28
+    /** @var \Closure(): Folder */
29
+    private \Closure $folderClosure;
30
+    protected ?Folder $folder = null;
31
+    protected IRootFolder $rootFolder;
32
+    protected array $data;
33
+
34
+    /**
35
+     * @param IRootFolder $rootFolder
36
+     * @param \Closure(): Folder $folderClosure
37
+     * @param array $data
38
+     */
39
+    public function __construct(IRootFolder $rootFolder, \Closure $folderClosure, array $data = []) {
40
+        $this->rootFolder = $rootFolder;
41
+        $this->folderClosure = $folderClosure;
42
+        $this->data = $data;
43
+    }
44
+
45
+    protected function getRootFolder(): IRootFolder {
46
+        return $this->rootFolder;
47
+    }
48
+
49
+    protected function getRealFolder(): Folder {
50
+        if ($this->folder === null) {
51
+            $this->folder = call_user_func($this->folderClosure);
52
+        }
53
+        return $this->folder;
54
+    }
55
+
56
+    /**
57
+     * Magic method to first get the real rootFolder and then
58
+     * call $method with $args on it
59
+     *
60
+     * @param $method
61
+     * @param $args
62
+     * @return mixed
63
+     */
64
+    public function __call($method, $args) {
65
+        return call_user_func_array([$this->getRealFolder(), $method], $args);
66
+    }
67
+
68
+    /**
69
+     * @inheritDoc
70
+     */
71
+    public function getUser() {
72
+        return $this->__call(__FUNCTION__, func_get_args());
73
+    }
74
+
75
+    /**
76
+     * @inheritDoc
77
+     */
78
+    public function listen($scope, $method, callable $callback) {
79
+        $this->__call(__FUNCTION__, func_get_args());
80
+    }
81
+
82
+    /**
83
+     * @inheritDoc
84
+     */
85
+    public function removeListener($scope = null, $method = null, ?callable $callback = null) {
86
+        $this->__call(__FUNCTION__, func_get_args());
87
+    }
88
+
89
+    /**
90
+     * @inheritDoc
91
+     */
92
+    public function emit($scope, $method, $arguments = []) {
93
+        $this->__call(__FUNCTION__, func_get_args());
94
+    }
95
+
96
+    /**
97
+     * @inheritDoc
98
+     */
99
+    public function mount($storage, $mountPoint, $arguments = []) {
100
+        $this->__call(__FUNCTION__, func_get_args());
101
+    }
102
+
103
+    /**
104
+     * @inheritDoc
105
+     */
106
+    public function getMount(string $mountPoint): IMountPoint {
107
+        return $this->__call(__FUNCTION__, func_get_args());
108
+    }
109
+
110
+    /**
111
+     * @return IMountPoint[]
112
+     */
113
+    public function getMountsIn(string $mountPoint): array {
114
+        return $this->__call(__FUNCTION__, func_get_args());
115
+    }
116
+
117
+    /**
118
+     * @inheritDoc
119
+     */
120
+    public function getMountByStorageId($storageId) {
121
+        return $this->__call(__FUNCTION__, func_get_args());
122
+    }
123
+
124
+    /**
125
+     * @inheritDoc
126
+     */
127
+    public function getMountByNumericStorageId($numericId) {
128
+        return $this->__call(__FUNCTION__, func_get_args());
129
+    }
130
+
131
+    /**
132
+     * @inheritDoc
133
+     */
134
+    public function unMount($mount) {
135
+        $this->__call(__FUNCTION__, func_get_args());
136
+    }
137
+
138
+    public function get($path) {
139
+        return $this->getRootFolder()->get($this->getFullPath($path));
140
+    }
141
+
142
+    #[Override]
143
+    public function getOrCreateFolder(string $path, int $maxRetries = 5): Folder {
144
+        return $this->getRootFolder()->getOrCreateFolder($this->getFullPath($path), $maxRetries);
145
+    }
146
+
147
+    /**
148
+     * @inheritDoc
149
+     */
150
+    public function rename($targetPath) {
151
+        return $this->__call(__FUNCTION__, func_get_args());
152
+    }
153
+
154
+    /**
155
+     * @inheritDoc
156
+     */
157
+    public function delete() {
158
+        return $this->__call(__FUNCTION__, func_get_args());
159
+    }
160
+
161
+    /**
162
+     * @inheritDoc
163
+     */
164
+    public function copy($targetPath) {
165
+        return $this->__call(__FUNCTION__, func_get_args());
166
+    }
167
+
168
+    /**
169
+     * @inheritDoc
170
+     */
171
+    public function touch($mtime = null) {
172
+        $this->__call(__FUNCTION__, func_get_args());
173
+    }
174
+
175
+    /**
176
+     * @inheritDoc
177
+     */
178
+    public function getStorage() {
179
+        return $this->__call(__FUNCTION__, func_get_args());
180
+    }
181
+
182
+    /**
183
+     * @inheritDoc
184
+     */
185
+    public function getPath() {
186
+        if (isset($this->data['path'])) {
187
+            return $this->data['path'];
188
+        }
189
+        return $this->__call(__FUNCTION__, func_get_args());
190
+    }
191
+
192
+    /**
193
+     * @inheritDoc
194
+     */
195
+    public function getInternalPath() {
196
+        return $this->__call(__FUNCTION__, func_get_args());
197
+    }
198
+
199
+    /**
200
+     * @inheritDoc
201
+     */
202
+    public function getId() {
203
+        if (isset($this->data['fileid'])) {
204
+            return $this->data['fileid'];
205
+        }
206
+        return $this->__call(__FUNCTION__, func_get_args());
207
+    }
208
+
209
+    /**
210
+     * @inheritDoc
211
+     */
212
+    public function stat() {
213
+        return $this->__call(__FUNCTION__, func_get_args());
214
+    }
215
+
216
+    /**
217
+     * @inheritDoc
218
+     */
219
+    public function getMTime() {
220
+        if (isset($this->data['mtime'])) {
221
+            return $this->data['mtime'];
222
+        }
223
+        return $this->__call(__FUNCTION__, func_get_args());
224
+    }
225
+
226
+    /**
227
+     * @inheritDoc
228
+     */
229
+    public function getSize($includeMounts = true): int|float {
230
+        if (isset($this->data['size'])) {
231
+            return $this->data['size'];
232
+        }
233
+        return $this->__call(__FUNCTION__, func_get_args());
234
+    }
235
+
236
+    /**
237
+     * @inheritDoc
238
+     */
239
+    public function getEtag() {
240
+        if (isset($this->data['etag'])) {
241
+            return $this->data['etag'];
242
+        }
243
+        return $this->__call(__FUNCTION__, func_get_args());
244
+    }
245
+
246
+    /**
247
+     * @inheritDoc
248
+     */
249
+    public function getPermissions() {
250
+        if (isset($this->data['permissions'])) {
251
+            return $this->data['permissions'];
252
+        }
253
+        return $this->__call(__FUNCTION__, func_get_args());
254
+    }
255
+
256
+    /**
257
+     * @inheritDoc
258
+     */
259
+    public function isReadable() {
260
+        if (isset($this->data['permissions'])) {
261
+            return ($this->data['permissions'] & Constants::PERMISSION_READ) == Constants::PERMISSION_READ;
262
+        }
263
+        return $this->__call(__FUNCTION__, func_get_args());
264
+    }
265
+
266
+    /**
267
+     * @inheritDoc
268
+     */
269
+    public function isUpdateable() {
270
+        if (isset($this->data['permissions'])) {
271
+            return ($this->data['permissions'] & Constants::PERMISSION_UPDATE) == Constants::PERMISSION_UPDATE;
272
+        }
273
+        return $this->__call(__FUNCTION__, func_get_args());
274
+    }
275
+
276
+    /**
277
+     * @inheritDoc
278
+     */
279
+    public function isDeletable() {
280
+        if (isset($this->data['permissions'])) {
281
+            return ($this->data['permissions'] & Constants::PERMISSION_DELETE) == Constants::PERMISSION_DELETE;
282
+        }
283
+        return $this->__call(__FUNCTION__, func_get_args());
284
+    }
285
+
286
+    /**
287
+     * @inheritDoc
288
+     */
289
+    public function isShareable() {
290
+        if (isset($this->data['permissions'])) {
291
+            return ($this->data['permissions'] & Constants::PERMISSION_SHARE) == Constants::PERMISSION_SHARE;
292
+        }
293
+        return $this->__call(__FUNCTION__, func_get_args());
294
+    }
295
+
296
+    /**
297
+     * @inheritDoc
298
+     */
299
+    public function getParent() {
300
+        return $this->__call(__FUNCTION__, func_get_args());
301
+    }
302
+
303
+    /**
304
+     * @inheritDoc
305
+     */
306
+    public function getName() {
307
+        if (isset($this->data['path'])) {
308
+            return basename($this->data['path']);
309
+        }
310
+        if (isset($this->data['name'])) {
311
+            return $this->data['name'];
312
+        }
313
+        return $this->__call(__FUNCTION__, func_get_args());
314
+    }
315
+
316
+    /**
317
+     * @inheritDoc
318
+     */
319
+    public function getUserFolder($userId) {
320
+        return $this->__call(__FUNCTION__, func_get_args());
321
+    }
322
+
323
+    public function getMimetype(): string {
324
+        if (isset($this->data['mimetype'])) {
325
+            return $this->data['mimetype'];
326
+        }
327
+        return $this->__call(__FUNCTION__, func_get_args());
328
+    }
329
+
330
+    /**
331
+     * @inheritDoc
332
+     */
333
+    public function getMimePart() {
334
+        if (isset($this->data['mimetype'])) {
335
+            [$part,] = explode('/', $this->data['mimetype']);
336
+            return $part;
337
+        }
338
+        return $this->__call(__FUNCTION__, func_get_args());
339
+    }
340
+
341
+    /**
342
+     * @inheritDoc
343
+     */
344
+    public function isEncrypted() {
345
+        return $this->__call(__FUNCTION__, func_get_args());
346
+    }
347
+
348
+    /**
349
+     * @inheritDoc
350
+     */
351
+    public function getType() {
352
+        if (isset($this->data['type'])) {
353
+            return $this->data['type'];
354
+        }
355
+        return $this->__call(__FUNCTION__, func_get_args());
356
+    }
357
+
358
+    /**
359
+     * @inheritDoc
360
+     */
361
+    public function isShared() {
362
+        return $this->__call(__FUNCTION__, func_get_args());
363
+    }
364
+
365
+    /**
366
+     * @inheritDoc
367
+     */
368
+    public function isMounted() {
369
+        return $this->__call(__FUNCTION__, func_get_args());
370
+    }
371
+
372
+    /**
373
+     * @inheritDoc
374
+     */
375
+    public function getMountPoint() {
376
+        return $this->__call(__FUNCTION__, func_get_args());
377
+    }
378
+
379
+    /**
380
+     * @inheritDoc
381
+     */
382
+    public function getOwner() {
383
+        return $this->__call(__FUNCTION__, func_get_args());
384
+    }
385
+
386
+    /**
387
+     * @inheritDoc
388
+     */
389
+    public function getChecksum() {
390
+        return $this->__call(__FUNCTION__, func_get_args());
391
+    }
392
+
393
+    public function getExtension(): string {
394
+        return $this->__call(__FUNCTION__, func_get_args());
395
+    }
396
+
397
+    /**
398
+     * @inheritDoc
399
+     */
400
+    public function getFullPath($path) {
401
+        if (isset($this->data['path'])) {
402
+            $path = PathHelper::normalizePath($path);
403
+            if (!Filesystem::isValidPath($path)) {
404
+                throw new NotPermittedException('Invalid path "' . $path . '"');
405
+            }
406
+            return $this->data['path'] . $path;
407
+        }
408
+        return $this->__call(__FUNCTION__, func_get_args());
409
+    }
410
+
411
+    /**
412
+     * @inheritDoc
413
+     */
414
+    public function isSubNode($node) {
415
+        return $this->__call(__FUNCTION__, func_get_args());
416
+    }
417
+
418
+    /**
419
+     * @inheritDoc
420
+     */
421
+    public function getDirectoryListing() {
422
+        return $this->__call(__FUNCTION__, func_get_args());
423
+    }
424
+
425
+    public function nodeExists($path) {
426
+        return $this->__call(__FUNCTION__, func_get_args());
427
+    }
428
+
429
+    /**
430
+     * @inheritDoc
431
+     */
432
+    public function newFolder($path) {
433
+        return $this->__call(__FUNCTION__, func_get_args());
434
+    }
435
+
436
+    /**
437
+     * @inheritDoc
438
+     */
439
+    public function newFile($path, $content = null) {
440
+        return $this->__call(__FUNCTION__, func_get_args());
441
+    }
442
+
443
+    /**
444
+     * @inheritDoc
445
+     */
446
+    public function search($query) {
447
+        return $this->__call(__FUNCTION__, func_get_args());
448
+    }
449
+
450
+    /**
451
+     * @inheritDoc
452
+     */
453
+    public function searchByMime($mimetype) {
454
+        return $this->__call(__FUNCTION__, func_get_args());
455
+    }
456
+
457
+    /**
458
+     * @inheritDoc
459
+     */
460
+    public function searchByTag($tag, $userId) {
461
+        return $this->__call(__FUNCTION__, func_get_args());
462
+    }
463
+
464
+    public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0) {
465
+        return $this->__call(__FUNCTION__, func_get_args());
466
+    }
467
+
468
+    /**
469
+     * @inheritDoc
470
+     */
471
+    public function getById($id) {
472
+        return $this->getRootFolder()->getByIdInPath((int)$id, $this->getPath());
473
+    }
474
+
475
+    public function getFirstNodeById(int $id): ?\OCP\Files\Node {
476
+        return $this->getRootFolder()->getFirstNodeByIdInPath($id, $this->getPath());
477
+    }
478
+
479
+    /**
480
+     * @inheritDoc
481
+     */
482
+    public function getFreeSpace() {
483
+        return $this->__call(__FUNCTION__, func_get_args());
484
+    }
485
+
486
+    /**
487
+     * @inheritDoc
488
+     */
489
+    public function isCreatable() {
490
+        return $this->__call(__FUNCTION__, func_get_args());
491
+    }
492
+
493
+    /**
494
+     * @inheritDoc
495
+     */
496
+    public function getNonExistingName($name) {
497
+        return $this->__call(__FUNCTION__, func_get_args());
498
+    }
499
+
500
+    /**
501
+     * @inheritDoc
502
+     */
503
+    public function move($targetPath) {
504
+        return $this->__call(__FUNCTION__, func_get_args());
505
+    }
506
+
507
+    /**
508
+     * @inheritDoc
509
+     */
510
+    public function lock($type) {
511
+        return $this->__call(__FUNCTION__, func_get_args());
512
+    }
513
+
514
+    /**
515
+     * @inheritDoc
516
+     */
517
+    public function changeLock($targetType) {
518
+        return $this->__call(__FUNCTION__, func_get_args());
519
+    }
520
+
521
+    /**
522
+     * @inheritDoc
523
+     */
524
+    public function unlock($type) {
525
+        return $this->__call(__FUNCTION__, func_get_args());
526
+    }
527
+
528
+    /**
529
+     * @inheritDoc
530
+     */
531
+    public function getRecent($limit, $offset = 0) {
532
+        return $this->__call(__FUNCTION__, func_get_args());
533
+    }
534
+
535
+    /**
536
+     * @inheritDoc
537
+     */
538
+    public function getCreationTime(): int {
539
+        return $this->__call(__FUNCTION__, func_get_args());
540
+    }
541
+
542
+    /**
543
+     * @inheritDoc
544
+     */
545
+    public function getUploadTime(): int {
546
+        return $this->__call(__FUNCTION__, func_get_args());
547
+    }
548
+
549
+    public function getRelativePath($path) {
550
+        return PathHelper::getRelativePath($this->getPath(), $path);
551
+    }
552
+
553
+    public function getParentId(): int {
554
+        if (isset($this->data['parent'])) {
555
+            return $this->data['parent'];
556
+        }
557
+        return $this->__call(__FUNCTION__, func_get_args());
558
+    }
559
+
560
+    /**
561
+     * @inheritDoc
562
+     * @return array<string, int|string|bool|float|string[]|int[]>
563
+     */
564
+    public function getMetadata(): array {
565
+        return $this->data['metadata'] ?? $this->__call(__FUNCTION__, func_get_args());
566
+    }
567
+
568
+    public function verifyPath($fileName, $readonly = false): void {
569
+        $this->__call(__FUNCTION__, func_get_args());
570
+    }
571 571
 }
Please login to merge, or discard this patch.
lib/private/Files/Template/TemplateManager.php 2 patches
Indentation   +366 added lines, -366 removed lines patch added patch discarded remove patch
@@ -40,372 +40,372 @@
 block discarded – undo
40 40
  * @psalm-import-type FilesTemplateFile from ResponseDefinitions
41 41
  */
42 42
 class TemplateManager implements ITemplateManager {
43
-	/** @var list<callable(): TemplateFileCreator> */
44
-	private array $registeredTypes = [];
45
-	/** @var list<TemplateFileCreator> */
46
-	private array $types = [];
47
-	/** @var array<class-string<ICustomTemplateProvider>, ICustomTemplateProvider>|null */
48
-	private ?array $providers = null;
49
-	private IL10n $l10n;
50
-	private ?string $userId;
51
-
52
-	public function __construct(
53
-		private readonly ContainerInterface $serverContainer,
54
-		private readonly IEventDispatcher $eventDispatcher,
55
-		private readonly Coordinator $bootstrapCoordinator,
56
-		private readonly IRootFolder $rootFolder,
57
-		IUserSession $userSession,
58
-		private readonly IUserManager $userManager,
59
-		private readonly IPreview $previewManager,
60
-		private readonly IConfig $config,
61
-		private readonly IFactory $l10nFactory,
62
-		private readonly LoggerInterface $logger,
63
-		private readonly IFilenameValidator $filenameValidator,
64
-	) {
65
-		$this->l10n = $l10nFactory->get('lib');
66
-		$this->userId = $userSession->getUser()?->getUID();
67
-	}
68
-
69
-	#[Override]
70
-	public function registerTemplateFileCreator(callable $callback): void {
71
-		$this->registeredTypes[] = $callback;
72
-	}
73
-
74
-	/**
75
-	 * @return array<class-string<ICustomTemplateProvider>, ICustomTemplateProvider>
76
-	 */
77
-	private function getRegisteredProviders(): array {
78
-		if ($this->providers !== null) {
79
-			return $this->providers;
80
-		}
81
-
82
-		$context = $this->bootstrapCoordinator->getRegistrationContext();
83
-
84
-		$this->providers = [];
85
-		foreach ($context->getTemplateProviders() as $provider) {
86
-			$class = $provider->getService();
87
-			$this->providers[$class] = $this->serverContainer->get($class);
88
-		}
89
-		return $this->providers;
90
-	}
91
-
92
-	/**
93
-	 * @return list<TemplateFileCreator>
94
-	 */
95
-	private function getTypes(): array {
96
-		if (!empty($this->types)) {
97
-			return $this->types;
98
-		}
99
-		$this->eventDispatcher->dispatchTyped(new RegisterTemplateCreatorEvent($this));
100
-		foreach ($this->registeredTypes as $registeredType) {
101
-			$this->types[] = $registeredType();
102
-		}
103
-		return $this->types;
104
-	}
105
-
106
-	#[Override]
107
-	public function listCreators(): array {
108
-		$types = $this->getTypes();
109
-		usort($types, function (TemplateFileCreator $a, TemplateFileCreator $b) {
110
-			return $a->getOrder() - $b->getOrder();
111
-		});
112
-		return $types;
113
-	}
114
-
115
-	#[Override]
116
-	public function listTemplates(): array {
117
-		return array_values(array_map(function (TemplateFileCreator $entry) {
118
-			return array_merge($entry->jsonSerialize(), [
119
-				'templates' => $this->getTemplateFiles($entry)
120
-			]);
121
-		}, $this->listCreators()));
122
-	}
123
-
124
-	#[Override]
125
-	public function listTemplateFields(int $fileId): array {
126
-		foreach ($this->listCreators() as $creator) {
127
-			$fields = $this->getTemplateFields($creator, $fileId);
128
-			if (empty($fields)) {
129
-				continue;
130
-			}
131
-
132
-			return $fields;
133
-		}
134
-
135
-		return [];
136
-	}
137
-
138
-	#[Override]
139
-	public function createFromTemplate(string $filePath, string $templateId = '', string $templateType = 'user', array $templateFields = []): array {
140
-		$userFolder = $this->rootFolder->getUserFolder($this->userId);
141
-		try {
142
-			$userFolder->get($filePath);
143
-			throw new GenericFileException($this->l10n->t('File already exists'));
144
-		} catch (NotFoundException $e) {
145
-		}
146
-		try {
147
-			if (!$userFolder->nodeExists(dirname($filePath))) {
148
-				throw new GenericFileException($this->l10n->t('Invalid path'));
149
-			}
150
-			/** @var Folder $folder */
151
-			$folder = $userFolder->get(dirname($filePath));
152
-			$template = null;
153
-			if ($templateType === 'user' && $templateId !== '') {
154
-				$template = $userFolder->get($templateId);
155
-			} else {
156
-				$matchingProvider = array_filter($this->getRegisteredProviders(), function (ICustomTemplateProvider $provider) use ($templateType) {
157
-					return $templateType === get_class($provider);
158
-				});
159
-				$provider = array_shift($matchingProvider);
160
-				if ($provider) {
161
-					$template = $provider->getCustomTemplate($templateId);
162
-				}
163
-			}
164
-
165
-			$filename = basename($filePath);
166
-			$this->filenameValidator->validateFilename($filename);
167
-			$targetFile = $folder->newFile($filename, ($template instanceof File ? $template->fopen('rb') : null));
168
-
169
-			$this->eventDispatcher->dispatchTyped(new FileCreatedFromTemplateEvent($template, $targetFile, $templateFields));
170
-			/** @var File $file */
171
-			$file = $userFolder->get($filePath);
172
-			return $this->formatFile($file);
173
-		} catch (\Exception $e) {
174
-			$this->logger->error($e->getMessage(), ['exception' => $e]);
175
-			throw new GenericFileException($this->l10n->t('Failed to create file from template'));
176
-		}
177
-	}
178
-
179
-	/**
180
-	 * @throws \OCP\Files\NotFoundException
181
-	 * @throws \OCP\Files\NotPermittedException
182
-	 * @throws \OC\User\NoUserException
183
-	 */
184
-	private function getTemplateFolder(): Folder {
185
-		if ($this->getTemplatePath() !== '') {
186
-			$path = $this->rootFolder->getUserFolder($this->userId)->get($this->getTemplatePath());
187
-			if ($path instanceof Folder) {
188
-				return $path;
189
-			}
190
-		}
191
-		throw new NotFoundException();
192
-	}
193
-
194
-	/**
195
-	 * @return list<Template>
196
-	 */
197
-	private function getTemplateFiles(TemplateFileCreator $type): array {
198
-		$templates = array_merge(
199
-			$this->getProviderTemplates($type),
200
-			$this->getUserTemplates($type)
201
-		);
202
-
203
-		$this->eventDispatcher->dispatchTyped(new BeforeGetTemplatesEvent($templates, false));
204
-
205
-		return $templates;
206
-	}
207
-
208
-	/**
209
-	 * @return list<Template>
210
-	 */
211
-	private function getProviderTemplates(TemplateFileCreator $type): array {
212
-		$templates = [];
213
-		foreach ($this->getRegisteredProviders() as $provider) {
214
-			foreach ($type->getMimetypes() as $mimetype) {
215
-				foreach ($provider->getCustomTemplates($mimetype) as $template) {
216
-					$templates[] = $template;
217
-				}
218
-			}
219
-		}
220
-
221
-		return $templates;
222
-	}
223
-
224
-	/**
225
-	 * @return list<Template>
226
-	 */
227
-	private function getUserTemplates(TemplateFileCreator $type): array {
228
-		$templates = [];
229
-
230
-		try {
231
-			$userTemplateFolder = $this->getTemplateFolder();
232
-		} catch (\Exception $e) {
233
-			return $templates;
234
-		}
235
-
236
-		foreach ($type->getMimetypes() as $mimetype) {
237
-			foreach ($userTemplateFolder->searchByMime($mimetype) as $templateFile) {
238
-				if (!($templateFile instanceof File)) {
239
-					continue;
240
-				}
241
-				$template = new Template(
242
-					'user',
243
-					$this->rootFolder->getUserFolder($this->userId)->getRelativePath($templateFile->getPath()),
244
-					$templateFile
245
-				);
246
-				$template->setHasPreview($this->previewManager->isAvailable($templateFile));
247
-				$templates[] = $template;
248
-			}
249
-		}
250
-
251
-		return $templates;
252
-	}
253
-
254
-	/*
43
+    /** @var list<callable(): TemplateFileCreator> */
44
+    private array $registeredTypes = [];
45
+    /** @var list<TemplateFileCreator> */
46
+    private array $types = [];
47
+    /** @var array<class-string<ICustomTemplateProvider>, ICustomTemplateProvider>|null */
48
+    private ?array $providers = null;
49
+    private IL10n $l10n;
50
+    private ?string $userId;
51
+
52
+    public function __construct(
53
+        private readonly ContainerInterface $serverContainer,
54
+        private readonly IEventDispatcher $eventDispatcher,
55
+        private readonly Coordinator $bootstrapCoordinator,
56
+        private readonly IRootFolder $rootFolder,
57
+        IUserSession $userSession,
58
+        private readonly IUserManager $userManager,
59
+        private readonly IPreview $previewManager,
60
+        private readonly IConfig $config,
61
+        private readonly IFactory $l10nFactory,
62
+        private readonly LoggerInterface $logger,
63
+        private readonly IFilenameValidator $filenameValidator,
64
+    ) {
65
+        $this->l10n = $l10nFactory->get('lib');
66
+        $this->userId = $userSession->getUser()?->getUID();
67
+    }
68
+
69
+    #[Override]
70
+    public function registerTemplateFileCreator(callable $callback): void {
71
+        $this->registeredTypes[] = $callback;
72
+    }
73
+
74
+    /**
75
+     * @return array<class-string<ICustomTemplateProvider>, ICustomTemplateProvider>
76
+     */
77
+    private function getRegisteredProviders(): array {
78
+        if ($this->providers !== null) {
79
+            return $this->providers;
80
+        }
81
+
82
+        $context = $this->bootstrapCoordinator->getRegistrationContext();
83
+
84
+        $this->providers = [];
85
+        foreach ($context->getTemplateProviders() as $provider) {
86
+            $class = $provider->getService();
87
+            $this->providers[$class] = $this->serverContainer->get($class);
88
+        }
89
+        return $this->providers;
90
+    }
91
+
92
+    /**
93
+     * @return list<TemplateFileCreator>
94
+     */
95
+    private function getTypes(): array {
96
+        if (!empty($this->types)) {
97
+            return $this->types;
98
+        }
99
+        $this->eventDispatcher->dispatchTyped(new RegisterTemplateCreatorEvent($this));
100
+        foreach ($this->registeredTypes as $registeredType) {
101
+            $this->types[] = $registeredType();
102
+        }
103
+        return $this->types;
104
+    }
105
+
106
+    #[Override]
107
+    public function listCreators(): array {
108
+        $types = $this->getTypes();
109
+        usort($types, function (TemplateFileCreator $a, TemplateFileCreator $b) {
110
+            return $a->getOrder() - $b->getOrder();
111
+        });
112
+        return $types;
113
+    }
114
+
115
+    #[Override]
116
+    public function listTemplates(): array {
117
+        return array_values(array_map(function (TemplateFileCreator $entry) {
118
+            return array_merge($entry->jsonSerialize(), [
119
+                'templates' => $this->getTemplateFiles($entry)
120
+            ]);
121
+        }, $this->listCreators()));
122
+    }
123
+
124
+    #[Override]
125
+    public function listTemplateFields(int $fileId): array {
126
+        foreach ($this->listCreators() as $creator) {
127
+            $fields = $this->getTemplateFields($creator, $fileId);
128
+            if (empty($fields)) {
129
+                continue;
130
+            }
131
+
132
+            return $fields;
133
+        }
134
+
135
+        return [];
136
+    }
137
+
138
+    #[Override]
139
+    public function createFromTemplate(string $filePath, string $templateId = '', string $templateType = 'user', array $templateFields = []): array {
140
+        $userFolder = $this->rootFolder->getUserFolder($this->userId);
141
+        try {
142
+            $userFolder->get($filePath);
143
+            throw new GenericFileException($this->l10n->t('File already exists'));
144
+        } catch (NotFoundException $e) {
145
+        }
146
+        try {
147
+            if (!$userFolder->nodeExists(dirname($filePath))) {
148
+                throw new GenericFileException($this->l10n->t('Invalid path'));
149
+            }
150
+            /** @var Folder $folder */
151
+            $folder = $userFolder->get(dirname($filePath));
152
+            $template = null;
153
+            if ($templateType === 'user' && $templateId !== '') {
154
+                $template = $userFolder->get($templateId);
155
+            } else {
156
+                $matchingProvider = array_filter($this->getRegisteredProviders(), function (ICustomTemplateProvider $provider) use ($templateType) {
157
+                    return $templateType === get_class($provider);
158
+                });
159
+                $provider = array_shift($matchingProvider);
160
+                if ($provider) {
161
+                    $template = $provider->getCustomTemplate($templateId);
162
+                }
163
+            }
164
+
165
+            $filename = basename($filePath);
166
+            $this->filenameValidator->validateFilename($filename);
167
+            $targetFile = $folder->newFile($filename, ($template instanceof File ? $template->fopen('rb') : null));
168
+
169
+            $this->eventDispatcher->dispatchTyped(new FileCreatedFromTemplateEvent($template, $targetFile, $templateFields));
170
+            /** @var File $file */
171
+            $file = $userFolder->get($filePath);
172
+            return $this->formatFile($file);
173
+        } catch (\Exception $e) {
174
+            $this->logger->error($e->getMessage(), ['exception' => $e]);
175
+            throw new GenericFileException($this->l10n->t('Failed to create file from template'));
176
+        }
177
+    }
178
+
179
+    /**
180
+     * @throws \OCP\Files\NotFoundException
181
+     * @throws \OCP\Files\NotPermittedException
182
+     * @throws \OC\User\NoUserException
183
+     */
184
+    private function getTemplateFolder(): Folder {
185
+        if ($this->getTemplatePath() !== '') {
186
+            $path = $this->rootFolder->getUserFolder($this->userId)->get($this->getTemplatePath());
187
+            if ($path instanceof Folder) {
188
+                return $path;
189
+            }
190
+        }
191
+        throw new NotFoundException();
192
+    }
193
+
194
+    /**
195
+     * @return list<Template>
196
+     */
197
+    private function getTemplateFiles(TemplateFileCreator $type): array {
198
+        $templates = array_merge(
199
+            $this->getProviderTemplates($type),
200
+            $this->getUserTemplates($type)
201
+        );
202
+
203
+        $this->eventDispatcher->dispatchTyped(new BeforeGetTemplatesEvent($templates, false));
204
+
205
+        return $templates;
206
+    }
207
+
208
+    /**
209
+     * @return list<Template>
210
+     */
211
+    private function getProviderTemplates(TemplateFileCreator $type): array {
212
+        $templates = [];
213
+        foreach ($this->getRegisteredProviders() as $provider) {
214
+            foreach ($type->getMimetypes() as $mimetype) {
215
+                foreach ($provider->getCustomTemplates($mimetype) as $template) {
216
+                    $templates[] = $template;
217
+                }
218
+            }
219
+        }
220
+
221
+        return $templates;
222
+    }
223
+
224
+    /**
225
+     * @return list<Template>
226
+     */
227
+    private function getUserTemplates(TemplateFileCreator $type): array {
228
+        $templates = [];
229
+
230
+        try {
231
+            $userTemplateFolder = $this->getTemplateFolder();
232
+        } catch (\Exception $e) {
233
+            return $templates;
234
+        }
235
+
236
+        foreach ($type->getMimetypes() as $mimetype) {
237
+            foreach ($userTemplateFolder->searchByMime($mimetype) as $templateFile) {
238
+                if (!($templateFile instanceof File)) {
239
+                    continue;
240
+                }
241
+                $template = new Template(
242
+                    'user',
243
+                    $this->rootFolder->getUserFolder($this->userId)->getRelativePath($templateFile->getPath()),
244
+                    $templateFile
245
+                );
246
+                $template->setHasPreview($this->previewManager->isAvailable($templateFile));
247
+                $templates[] = $template;
248
+            }
249
+        }
250
+
251
+        return $templates;
252
+    }
253
+
254
+    /*
255 255
 	 * @return list<Field>
256 256
 	 */
257
-	private function getTemplateFields(TemplateFileCreator $type, int $fileId): array {
258
-		$providerTemplates = $this->getProviderTemplates($type);
259
-		$userTemplates = $this->getUserTemplates($type);
260
-
261
-		$matchedTemplates = array_filter(
262
-			array_merge($providerTemplates, $userTemplates),
263
-			fn (Template $template): bool => $template->jsonSerialize()['fileid'] === $fileId);
264
-
265
-		if (empty($matchedTemplates)) {
266
-			return [];
267
-		}
268
-
269
-		$this->eventDispatcher->dispatchTyped(new BeforeGetTemplatesEvent($matchedTemplates, true));
270
-
271
-		return array_values(array_map(static fn (Template $template): array => $template->jsonSerialize()['fields'] ?? [], $matchedTemplates));
272
-	}
273
-
274
-	/**
275
-	 * @return FilesTemplateFile
276
-	 * @throws NotFoundException
277
-	 * @throws \OCP\Files\InvalidPathException
278
-	 */
279
-	private function formatFile(File $file): array {
280
-		return [
281
-			'basename' => $file->getName(),
282
-			'etag' => $file->getEtag(),
283
-			'fileid' => $file->getId() ?? -1,
284
-			'filename' => $this->rootFolder->getUserFolder($this->userId)->getRelativePath($file->getPath()),
285
-			'lastmod' => $file->getMTime(),
286
-			'mime' => $file->getMimetype(),
287
-			'size' => $file->getSize(),
288
-			'type' => $file->getType(),
289
-			'hasPreview' => $this->previewManager->isAvailable($file),
290
-			'permissions' => $file->getPermissions(),
291
-		];
292
-	}
293
-
294
-	public function hasTemplateDirectory(): bool {
295
-		try {
296
-			$this->getTemplateFolder();
297
-			return true;
298
-		} catch (\Exception $e) {
299
-		}
300
-		return false;
301
-	}
302
-
303
-	#[Override]
304
-	public function setTemplatePath(string $path): void {
305
-		$this->config->setUserValue($this->userId, 'core', 'templateDirectory', $path);
306
-	}
307
-
308
-	#[Override]
309
-	public function getTemplatePath(): string {
310
-		return $this->config->getUserValue($this->userId, 'core', 'templateDirectory', '');
311
-	}
312
-
313
-	#[Override]
314
-	public function initializeTemplateDirectory(?string $path = null, ?string $userId = null, $copyTemplates = true): string {
315
-		if ($userId !== null) {
316
-			$this->userId = $userId;
317
-		}
318
-
319
-		$defaultSkeletonDirectory = \OC::$SERVERROOT . '/core/skeleton';
320
-		$defaultTemplateDirectory = \OC::$SERVERROOT . '/core/skeleton/Templates';
321
-		$skeletonPath = $this->config->getSystemValueString('skeletondirectory', $defaultSkeletonDirectory);
322
-		$skeletonTemplatePath = $this->config->getSystemValueString('templatedirectory', $defaultTemplateDirectory);
323
-		$isDefaultSkeleton = $skeletonPath === $defaultSkeletonDirectory;
324
-		$isDefaultTemplates = $skeletonTemplatePath === $defaultTemplateDirectory;
325
-		$userLang = $this->l10nFactory->getUserLanguage($this->userManager->get($this->userId));
326
-
327
-		if ($skeletonTemplatePath === '') {
328
-			$this->setTemplatePath('');
329
-			return '';
330
-		}
331
-
332
-		try {
333
-			$l10n = $this->l10nFactory->get('lib', $userLang);
334
-			$userFolder = $this->rootFolder->getUserFolder($this->userId);
335
-			$userTemplatePath = $path ?? $this->config->getAppValue('core', 'defaultTemplateDirectory', $l10n->t('Templates')) . '/';
336
-
337
-			// Initial user setup without a provided path
338
-			if ($path === null) {
339
-				// All locations are default so we just need to rename the directory to the users language
340
-				if ($isDefaultSkeleton && $isDefaultTemplates) {
341
-					if (!$userFolder->nodeExists('Templates')) {
342
-						return '';
343
-					}
344
-					$newPath = Filesystem::normalizePath($userFolder->getPath() . '/' . $userTemplatePath);
345
-					if ($newPath !== $userFolder->get('Templates')->getPath()) {
346
-						$userFolder->get('Templates')->move($newPath);
347
-					}
348
-					$this->setTemplatePath($userTemplatePath);
349
-					return $userTemplatePath;
350
-				}
351
-
352
-				if ($isDefaultSkeleton && !empty($skeletonTemplatePath) && !$isDefaultTemplates && $userFolder->nodeExists('Templates')) {
353
-					$shippedSkeletonTemplates = $userFolder->get('Templates');
354
-					$shippedSkeletonTemplates->delete();
355
-				}
356
-			}
357
-
358
-			$folder = $userFolder->getOrCreateFolder($userTemplatePath);
359
-
360
-			$folderIsEmpty = count($folder->getDirectoryListing()) === 0;
361
-
362
-			if (!$copyTemplates) {
363
-				$this->setTemplatePath($userTemplatePath);
364
-				return $userTemplatePath;
365
-			}
366
-
367
-			if (!$isDefaultTemplates && $folderIsEmpty) {
368
-				$localizedSkeletonTemplatePath = $this->getLocalizedTemplatePath($skeletonTemplatePath, $userLang);
369
-				if (!empty($localizedSkeletonTemplatePath) && file_exists($localizedSkeletonTemplatePath)) {
370
-					\OC_Util::copyr($localizedSkeletonTemplatePath, $folder);
371
-					$userFolder->getStorage()->getScanner()->scan($folder->getInternalPath(), Scanner::SCAN_RECURSIVE);
372
-					$this->setTemplatePath($userTemplatePath);
373
-					return $userTemplatePath;
374
-				}
375
-			}
376
-
377
-			if ($path !== null && $isDefaultSkeleton && $isDefaultTemplates && $folderIsEmpty) {
378
-				$localizedSkeletonPath = $this->getLocalizedTemplatePath($skeletonPath . '/Templates', $userLang);
379
-				if (!empty($localizedSkeletonPath) && file_exists($localizedSkeletonPath)) {
380
-					\OC_Util::copyr($localizedSkeletonPath, $folder);
381
-					$userFolder->getStorage()->getScanner()->scan($folder->getInternalPath(), Scanner::SCAN_RECURSIVE);
382
-					$this->setTemplatePath($userTemplatePath);
383
-					return $userTemplatePath;
384
-				}
385
-			}
386
-
387
-			$this->setTemplatePath($path ?? '');
388
-			return $this->getTemplatePath();
389
-		} catch (\Throwable $e) {
390
-			$this->logger->error('Failed to initialize templates directory to user language ' . $userLang . ' for ' . $userId, ['app' => 'files_templates', 'exception' => $e]);
391
-		}
392
-		$this->setTemplatePath('');
393
-		return $this->getTemplatePath();
394
-	}
395
-
396
-	private function getLocalizedTemplatePath(string $skeletonTemplatePath, string $userLang): string {
397
-		$localizedSkeletonTemplatePath = str_replace('{lang}', $userLang, $skeletonTemplatePath);
398
-
399
-		if (!file_exists($localizedSkeletonTemplatePath)) {
400
-			$dialectStart = strpos($userLang, '_');
401
-			if ($dialectStart !== false) {
402
-				$localizedSkeletonTemplatePath = str_replace('{lang}', substr($userLang, 0, $dialectStart), $skeletonTemplatePath);
403
-			}
404
-			if ($dialectStart === false || !file_exists($localizedSkeletonTemplatePath)) {
405
-				$localizedSkeletonTemplatePath = str_replace('{lang}', 'default', $skeletonTemplatePath);
406
-			}
407
-		}
408
-
409
-		return $localizedSkeletonTemplatePath;
410
-	}
257
+    private function getTemplateFields(TemplateFileCreator $type, int $fileId): array {
258
+        $providerTemplates = $this->getProviderTemplates($type);
259
+        $userTemplates = $this->getUserTemplates($type);
260
+
261
+        $matchedTemplates = array_filter(
262
+            array_merge($providerTemplates, $userTemplates),
263
+            fn (Template $template): bool => $template->jsonSerialize()['fileid'] === $fileId);
264
+
265
+        if (empty($matchedTemplates)) {
266
+            return [];
267
+        }
268
+
269
+        $this->eventDispatcher->dispatchTyped(new BeforeGetTemplatesEvent($matchedTemplates, true));
270
+
271
+        return array_values(array_map(static fn (Template $template): array => $template->jsonSerialize()['fields'] ?? [], $matchedTemplates));
272
+    }
273
+
274
+    /**
275
+     * @return FilesTemplateFile
276
+     * @throws NotFoundException
277
+     * @throws \OCP\Files\InvalidPathException
278
+     */
279
+    private function formatFile(File $file): array {
280
+        return [
281
+            'basename' => $file->getName(),
282
+            'etag' => $file->getEtag(),
283
+            'fileid' => $file->getId() ?? -1,
284
+            'filename' => $this->rootFolder->getUserFolder($this->userId)->getRelativePath($file->getPath()),
285
+            'lastmod' => $file->getMTime(),
286
+            'mime' => $file->getMimetype(),
287
+            'size' => $file->getSize(),
288
+            'type' => $file->getType(),
289
+            'hasPreview' => $this->previewManager->isAvailable($file),
290
+            'permissions' => $file->getPermissions(),
291
+        ];
292
+    }
293
+
294
+    public function hasTemplateDirectory(): bool {
295
+        try {
296
+            $this->getTemplateFolder();
297
+            return true;
298
+        } catch (\Exception $e) {
299
+        }
300
+        return false;
301
+    }
302
+
303
+    #[Override]
304
+    public function setTemplatePath(string $path): void {
305
+        $this->config->setUserValue($this->userId, 'core', 'templateDirectory', $path);
306
+    }
307
+
308
+    #[Override]
309
+    public function getTemplatePath(): string {
310
+        return $this->config->getUserValue($this->userId, 'core', 'templateDirectory', '');
311
+    }
312
+
313
+    #[Override]
314
+    public function initializeTemplateDirectory(?string $path = null, ?string $userId = null, $copyTemplates = true): string {
315
+        if ($userId !== null) {
316
+            $this->userId = $userId;
317
+        }
318
+
319
+        $defaultSkeletonDirectory = \OC::$SERVERROOT . '/core/skeleton';
320
+        $defaultTemplateDirectory = \OC::$SERVERROOT . '/core/skeleton/Templates';
321
+        $skeletonPath = $this->config->getSystemValueString('skeletondirectory', $defaultSkeletonDirectory);
322
+        $skeletonTemplatePath = $this->config->getSystemValueString('templatedirectory', $defaultTemplateDirectory);
323
+        $isDefaultSkeleton = $skeletonPath === $defaultSkeletonDirectory;
324
+        $isDefaultTemplates = $skeletonTemplatePath === $defaultTemplateDirectory;
325
+        $userLang = $this->l10nFactory->getUserLanguage($this->userManager->get($this->userId));
326
+
327
+        if ($skeletonTemplatePath === '') {
328
+            $this->setTemplatePath('');
329
+            return '';
330
+        }
331
+
332
+        try {
333
+            $l10n = $this->l10nFactory->get('lib', $userLang);
334
+            $userFolder = $this->rootFolder->getUserFolder($this->userId);
335
+            $userTemplatePath = $path ?? $this->config->getAppValue('core', 'defaultTemplateDirectory', $l10n->t('Templates')) . '/';
336
+
337
+            // Initial user setup without a provided path
338
+            if ($path === null) {
339
+                // All locations are default so we just need to rename the directory to the users language
340
+                if ($isDefaultSkeleton && $isDefaultTemplates) {
341
+                    if (!$userFolder->nodeExists('Templates')) {
342
+                        return '';
343
+                    }
344
+                    $newPath = Filesystem::normalizePath($userFolder->getPath() . '/' . $userTemplatePath);
345
+                    if ($newPath !== $userFolder->get('Templates')->getPath()) {
346
+                        $userFolder->get('Templates')->move($newPath);
347
+                    }
348
+                    $this->setTemplatePath($userTemplatePath);
349
+                    return $userTemplatePath;
350
+                }
351
+
352
+                if ($isDefaultSkeleton && !empty($skeletonTemplatePath) && !$isDefaultTemplates && $userFolder->nodeExists('Templates')) {
353
+                    $shippedSkeletonTemplates = $userFolder->get('Templates');
354
+                    $shippedSkeletonTemplates->delete();
355
+                }
356
+            }
357
+
358
+            $folder = $userFolder->getOrCreateFolder($userTemplatePath);
359
+
360
+            $folderIsEmpty = count($folder->getDirectoryListing()) === 0;
361
+
362
+            if (!$copyTemplates) {
363
+                $this->setTemplatePath($userTemplatePath);
364
+                return $userTemplatePath;
365
+            }
366
+
367
+            if (!$isDefaultTemplates && $folderIsEmpty) {
368
+                $localizedSkeletonTemplatePath = $this->getLocalizedTemplatePath($skeletonTemplatePath, $userLang);
369
+                if (!empty($localizedSkeletonTemplatePath) && file_exists($localizedSkeletonTemplatePath)) {
370
+                    \OC_Util::copyr($localizedSkeletonTemplatePath, $folder);
371
+                    $userFolder->getStorage()->getScanner()->scan($folder->getInternalPath(), Scanner::SCAN_RECURSIVE);
372
+                    $this->setTemplatePath($userTemplatePath);
373
+                    return $userTemplatePath;
374
+                }
375
+            }
376
+
377
+            if ($path !== null && $isDefaultSkeleton && $isDefaultTemplates && $folderIsEmpty) {
378
+                $localizedSkeletonPath = $this->getLocalizedTemplatePath($skeletonPath . '/Templates', $userLang);
379
+                if (!empty($localizedSkeletonPath) && file_exists($localizedSkeletonPath)) {
380
+                    \OC_Util::copyr($localizedSkeletonPath, $folder);
381
+                    $userFolder->getStorage()->getScanner()->scan($folder->getInternalPath(), Scanner::SCAN_RECURSIVE);
382
+                    $this->setTemplatePath($userTemplatePath);
383
+                    return $userTemplatePath;
384
+                }
385
+            }
386
+
387
+            $this->setTemplatePath($path ?? '');
388
+            return $this->getTemplatePath();
389
+        } catch (\Throwable $e) {
390
+            $this->logger->error('Failed to initialize templates directory to user language ' . $userLang . ' for ' . $userId, ['app' => 'files_templates', 'exception' => $e]);
391
+        }
392
+        $this->setTemplatePath('');
393
+        return $this->getTemplatePath();
394
+    }
395
+
396
+    private function getLocalizedTemplatePath(string $skeletonTemplatePath, string $userLang): string {
397
+        $localizedSkeletonTemplatePath = str_replace('{lang}', $userLang, $skeletonTemplatePath);
398
+
399
+        if (!file_exists($localizedSkeletonTemplatePath)) {
400
+            $dialectStart = strpos($userLang, '_');
401
+            if ($dialectStart !== false) {
402
+                $localizedSkeletonTemplatePath = str_replace('{lang}', substr($userLang, 0, $dialectStart), $skeletonTemplatePath);
403
+            }
404
+            if ($dialectStart === false || !file_exists($localizedSkeletonTemplatePath)) {
405
+                $localizedSkeletonTemplatePath = str_replace('{lang}', 'default', $skeletonTemplatePath);
406
+            }
407
+        }
408
+
409
+        return $localizedSkeletonTemplatePath;
410
+    }
411 411
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -106,7 +106,7 @@  discard block
 block discarded – undo
106 106
 	#[Override]
107 107
 	public function listCreators(): array {
108 108
 		$types = $this->getTypes();
109
-		usort($types, function (TemplateFileCreator $a, TemplateFileCreator $b) {
109
+		usort($types, function(TemplateFileCreator $a, TemplateFileCreator $b) {
110 110
 			return $a->getOrder() - $b->getOrder();
111 111
 		});
112 112
 		return $types;
@@ -114,7 +114,7 @@  discard block
 block discarded – undo
114 114
 
115 115
 	#[Override]
116 116
 	public function listTemplates(): array {
117
-		return array_values(array_map(function (TemplateFileCreator $entry) {
117
+		return array_values(array_map(function(TemplateFileCreator $entry) {
118 118
 			return array_merge($entry->jsonSerialize(), [
119 119
 				'templates' => $this->getTemplateFiles($entry)
120 120
 			]);
@@ -153,7 +153,7 @@  discard block
 block discarded – undo
153 153
 			if ($templateType === 'user' && $templateId !== '') {
154 154
 				$template = $userFolder->get($templateId);
155 155
 			} else {
156
-				$matchingProvider = array_filter($this->getRegisteredProviders(), function (ICustomTemplateProvider $provider) use ($templateType) {
156
+				$matchingProvider = array_filter($this->getRegisteredProviders(), function(ICustomTemplateProvider $provider) use ($templateType) {
157 157
 					return $templateType === get_class($provider);
158 158
 				});
159 159
 				$provider = array_shift($matchingProvider);
@@ -316,8 +316,8 @@  discard block
 block discarded – undo
316 316
 			$this->userId = $userId;
317 317
 		}
318 318
 
319
-		$defaultSkeletonDirectory = \OC::$SERVERROOT . '/core/skeleton';
320
-		$defaultTemplateDirectory = \OC::$SERVERROOT . '/core/skeleton/Templates';
319
+		$defaultSkeletonDirectory = \OC::$SERVERROOT.'/core/skeleton';
320
+		$defaultTemplateDirectory = \OC::$SERVERROOT.'/core/skeleton/Templates';
321 321
 		$skeletonPath = $this->config->getSystemValueString('skeletondirectory', $defaultSkeletonDirectory);
322 322
 		$skeletonTemplatePath = $this->config->getSystemValueString('templatedirectory', $defaultTemplateDirectory);
323 323
 		$isDefaultSkeleton = $skeletonPath === $defaultSkeletonDirectory;
@@ -332,7 +332,7 @@  discard block
 block discarded – undo
332 332
 		try {
333 333
 			$l10n = $this->l10nFactory->get('lib', $userLang);
334 334
 			$userFolder = $this->rootFolder->getUserFolder($this->userId);
335
-			$userTemplatePath = $path ?? $this->config->getAppValue('core', 'defaultTemplateDirectory', $l10n->t('Templates')) . '/';
335
+			$userTemplatePath = $path ?? $this->config->getAppValue('core', 'defaultTemplateDirectory', $l10n->t('Templates')).'/';
336 336
 
337 337
 			// Initial user setup without a provided path
338 338
 			if ($path === null) {
@@ -341,7 +341,7 @@  discard block
 block discarded – undo
341 341
 					if (!$userFolder->nodeExists('Templates')) {
342 342
 						return '';
343 343
 					}
344
-					$newPath = Filesystem::normalizePath($userFolder->getPath() . '/' . $userTemplatePath);
344
+					$newPath = Filesystem::normalizePath($userFolder->getPath().'/'.$userTemplatePath);
345 345
 					if ($newPath !== $userFolder->get('Templates')->getPath()) {
346 346
 						$userFolder->get('Templates')->move($newPath);
347 347
 					}
@@ -375,7 +375,7 @@  discard block
 block discarded – undo
375 375
 			}
376 376
 
377 377
 			if ($path !== null && $isDefaultSkeleton && $isDefaultTemplates && $folderIsEmpty) {
378
-				$localizedSkeletonPath = $this->getLocalizedTemplatePath($skeletonPath . '/Templates', $userLang);
378
+				$localizedSkeletonPath = $this->getLocalizedTemplatePath($skeletonPath.'/Templates', $userLang);
379 379
 				if (!empty($localizedSkeletonPath) && file_exists($localizedSkeletonPath)) {
380 380
 					\OC_Util::copyr($localizedSkeletonPath, $folder);
381 381
 					$userFolder->getStorage()->getScanner()->scan($folder->getInternalPath(), Scanner::SCAN_RECURSIVE);
@@ -387,7 +387,7 @@  discard block
 block discarded – undo
387 387
 			$this->setTemplatePath($path ?? '');
388 388
 			return $this->getTemplatePath();
389 389
 		} catch (\Throwable $e) {
390
-			$this->logger->error('Failed to initialize templates directory to user language ' . $userLang . ' for ' . $userId, ['app' => 'files_templates', 'exception' => $e]);
390
+			$this->logger->error('Failed to initialize templates directory to user language '.$userLang.' for '.$userId, ['app' => 'files_templates', 'exception' => $e]);
391 391
 		}
392 392
 		$this->setTemplatePath('');
393 393
 		return $this->getTemplatePath();
Please login to merge, or discard this patch.
tests/lib/Files/Node/FileTest.php 1 patch
Indentation   +290 added lines, -290 removed lines patch added patch discarded remove patch
@@ -26,294 +26,294 @@
 block discarded – undo
26 26
  */
27 27
 #[\PHPUnit\Framework\Attributes\Group('DB')]
28 28
 class FileTest extends NodeTestCase {
29
-	protected function createTestNode(IRootFolder $root, View&MockObject $view, string $path, array $data = [], string $internalPath = '', ?IStorage $storage = null): File {
30
-		if ($data || $internalPath || $storage) {
31
-			return new File($root, $view, $path, $this->getFileInfo($data, $internalPath, $storage));
32
-		} else {
33
-			return new File($root, $view, $path);
34
-		}
35
-	}
36
-
37
-	protected function getNodeClass(): string {
38
-		return File::class;
39
-	}
40
-
41
-	protected function getNonExistingNodeClass(): string {
42
-		return NonExistingFile::class;
43
-	}
44
-
45
-	protected function getViewDeleteMethod(): string {
46
-		return 'unlink';
47
-	}
48
-
49
-	public function testGetContent(): void {
50
-		/** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */
51
-		$root = $this->getMockBuilder(Root::class)
52
-			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig])
53
-			->getMock();
54
-
55
-		$hook = function ($file): void {
56
-			throw new \Exception('Hooks are not supposed to be called');
57
-		};
58
-
59
-		$root->listen('\OC\Files', 'preWrite', $hook);
60
-		$root->listen('\OC\Files', 'postWrite', $hook);
61
-
62
-		$this->view->expects($this->once())
63
-			->method('file_get_contents')
64
-			->with('/bar/foo')
65
-			->willReturn('bar');
66
-
67
-		$this->view->expects($this->once())
68
-			->method('getFileInfo')
69
-			->with('/bar/foo')
70
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_READ]));
71
-
72
-		$node = new File($root, $this->view, '/bar/foo');
73
-		$this->assertEquals('bar', $node->getContent());
74
-	}
75
-
76
-
77
-	public function testGetContentNotPermitted(): void {
78
-		$this->expectException(NotPermittedException::class);
79
-
80
-		/** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */
81
-		$root = $this->getMockBuilder(Root::class)
82
-			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig])
83
-			->getMock();
84
-
85
-		$root->expects($this->any())
86
-			->method('getUser')
87
-			->willReturn($this->user);
88
-
89
-		$this->view->expects($this->once())
90
-			->method('getFileInfo')
91
-			->with('/bar/foo')
92
-			->willReturn($this->getFileInfo(['permissions' => 0]));
93
-
94
-		$node = new File($root, $this->view, '/bar/foo');
95
-		$node->getContent();
96
-	}
97
-
98
-	public function testPutContent(): void {
99
-		/** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */
100
-		$root = $this->getMockBuilder(Root::class)
101
-			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig])
102
-			->getMock();
103
-
104
-		$root->expects($this->any())
105
-			->method('getUser')
106
-			->willReturn($this->user);
107
-
108
-		$this->view->expects($this->once())
109
-			->method('getFileInfo')
110
-			->with('/bar/foo')
111
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL]));
112
-
113
-		$this->view->expects($this->once())
114
-			->method('file_put_contents')
115
-			->with('/bar/foo', 'bar')
116
-			->willReturn(true);
117
-
118
-		$node = new File($root, $this->view, '/bar/foo');
119
-		$node->putContent('bar');
120
-	}
121
-
122
-
123
-	public function testPutContentNotPermitted(): void {
124
-		$this->expectException(NotPermittedException::class);
125
-
126
-		/** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */
127
-		$root = $this->getMockBuilder(Root::class)
128
-			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig])
129
-			->getMock();
130
-
131
-		$this->view->expects($this->once())
132
-			->method('getFileInfo')
133
-			->with('/bar/foo')
134
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_READ]));
135
-
136
-		$node = new File($root, $this->view, '/bar/foo');
137
-		$node->putContent('bar');
138
-	}
139
-
140
-	public function testGetMimeType(): void {
141
-		/** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */
142
-		$root = $this->getMockBuilder(Root::class)
143
-			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig])
144
-			->getMock();
145
-
146
-		$this->view->expects($this->once())
147
-			->method('getFileInfo')
148
-			->with('/bar/foo')
149
-			->willReturn($this->getFileInfo(['mimetype' => 'text/plain']));
150
-
151
-		$node = new File($root, $this->view, '/bar/foo');
152
-		$this->assertEquals('text/plain', $node->getMimeType());
153
-	}
154
-
155
-	public function testFOpenRead(): void {
156
-		$stream = fopen('php://memory', 'w+');
157
-		fwrite($stream, 'bar');
158
-		rewind($stream);
159
-
160
-		$root = new Root(
161
-			$this->manager,
162
-			$this->view,
163
-			$this->user,
164
-			$this->userMountCache,
165
-			$this->logger,
166
-			$this->userManager,
167
-			$this->eventDispatcher,
168
-			$this->cacheFactory,
169
-			$this->appConfig,
170
-		);
171
-
172
-		$hook = function ($file): void {
173
-			throw new \Exception('Hooks are not supposed to be called');
174
-		};
175
-
176
-		$root->listen('\OC\Files', 'preWrite', $hook);
177
-		$root->listen('\OC\Files', 'postWrite', $hook);
178
-
179
-		$this->view->expects($this->once())
180
-			->method('fopen')
181
-			->with('/bar/foo', 'r')
182
-			->willReturn($stream);
183
-
184
-		$this->view->expects($this->once())
185
-			->method('getFileInfo')
186
-			->with('/bar/foo')
187
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL]));
188
-
189
-		$node = new File($root, $this->view, '/bar/foo');
190
-		$fh = $node->fopen('r');
191
-		$this->assertEquals($stream, $fh);
192
-		$this->assertEquals('bar', fread($fh, 3));
193
-	}
194
-
195
-	public function testFOpenWrite(): void {
196
-		$stream = fopen('php://memory', 'w+');
197
-
198
-		$root = new Root(
199
-			$this->manager,
200
-			$this->view,
201
-			$this->user,
202
-			$this->userMountCache,
203
-			$this->logger,
204
-			$this->userManager,
205
-			$this->eventDispatcher,
206
-			$this->cacheFactory,
207
-			$this->appConfig,
208
-		);
209
-		$hooksCalled = 0;
210
-		$hook = function ($file) use (&$hooksCalled): void {
211
-			$hooksCalled++;
212
-		};
213
-
214
-		$root->listen('\OC\Files', 'preWrite', $hook);
215
-		$root->listen('\OC\Files', 'postWrite', $hook);
216
-
217
-		$this->view->expects($this->once())
218
-			->method('fopen')
219
-			->with('/bar/foo', 'w')
220
-			->willReturn($stream);
221
-
222
-		$this->view->expects($this->once())
223
-			->method('getFileInfo')
224
-			->with('/bar/foo')
225
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL]));
226
-
227
-		$node = new File($root, $this->view, '/bar/foo');
228
-		$fh = $node->fopen('w');
229
-		$this->assertEquals($stream, $fh);
230
-		fwrite($fh, 'bar');
231
-		rewind($fh);
232
-		$this->assertEquals('bar', fread($stream, 3));
233
-		$this->assertEquals(2, $hooksCalled);
234
-	}
235
-
236
-
237
-	public function testFOpenReadNotPermitted(): void {
238
-		$this->expectException(NotPermittedException::class);
239
-
240
-		$root = new Root(
241
-			$this->manager,
242
-			$this->view,
243
-			$this->user,
244
-			$this->userMountCache,
245
-			$this->logger,
246
-			$this->userManager,
247
-			$this->eventDispatcher,
248
-			$this->cacheFactory,
249
-			$this->appConfig,
250
-		);
251
-		$hook = function ($file): void {
252
-			throw new \Exception('Hooks are not supposed to be called');
253
-		};
254
-
255
-		$this->view->expects($this->once())
256
-			->method('getFileInfo')
257
-			->with('/bar/foo')
258
-			->willReturn($this->getFileInfo(['permissions' => 0]));
259
-
260
-		$node = new File($root, $this->view, '/bar/foo');
261
-		$node->fopen('r');
262
-	}
263
-
264
-
265
-	public function testFOpenReadWriteNoReadPermissions(): void {
266
-		$this->expectException(NotPermittedException::class);
267
-
268
-		$root = new Root(
269
-			$this->manager,
270
-			$this->view,
271
-			$this->user,
272
-			$this->userMountCache,
273
-			$this->logger,
274
-			$this->userManager,
275
-			$this->eventDispatcher,
276
-			$this->cacheFactory,
277
-			$this->appConfig,
278
-		);
279
-		$hook = function (): void {
280
-			throw new \Exception('Hooks are not supposed to be called');
281
-		};
282
-
283
-		$this->view->expects($this->once())
284
-			->method('getFileInfo')
285
-			->with('/bar/foo')
286
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_UPDATE]));
287
-
288
-		$node = new File($root, $this->view, '/bar/foo');
289
-		$node->fopen('w');
290
-	}
291
-
292
-
293
-	public function testFOpenReadWriteNoWritePermissions(): void {
294
-		$this->expectException(NotPermittedException::class);
295
-
296
-		$root = new Root(
297
-			$this->manager,
298
-			$this->view,
299
-			$this->user,
300
-			$this->userMountCache,
301
-			$this->logger,
302
-			$this->userManager,
303
-			$this->eventDispatcher,
304
-			$this->cacheFactory,
305
-			$this->appConfig,
306
-		);
307
-		$hook = function (): void {
308
-			throw new \Exception('Hooks are not supposed to be called');
309
-		};
310
-
311
-		$this->view->expects($this->once())
312
-			->method('getFileInfo')
313
-			->with('/bar/foo')
314
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_READ]));
315
-
316
-		$node = new File($root, $this->view, '/bar/foo');
317
-		$node->fopen('w');
318
-	}
29
+    protected function createTestNode(IRootFolder $root, View&MockObject $view, string $path, array $data = [], string $internalPath = '', ?IStorage $storage = null): File {
30
+        if ($data || $internalPath || $storage) {
31
+            return new File($root, $view, $path, $this->getFileInfo($data, $internalPath, $storage));
32
+        } else {
33
+            return new File($root, $view, $path);
34
+        }
35
+    }
36
+
37
+    protected function getNodeClass(): string {
38
+        return File::class;
39
+    }
40
+
41
+    protected function getNonExistingNodeClass(): string {
42
+        return NonExistingFile::class;
43
+    }
44
+
45
+    protected function getViewDeleteMethod(): string {
46
+        return 'unlink';
47
+    }
48
+
49
+    public function testGetContent(): void {
50
+        /** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */
51
+        $root = $this->getMockBuilder(Root::class)
52
+            ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig])
53
+            ->getMock();
54
+
55
+        $hook = function ($file): void {
56
+            throw new \Exception('Hooks are not supposed to be called');
57
+        };
58
+
59
+        $root->listen('\OC\Files', 'preWrite', $hook);
60
+        $root->listen('\OC\Files', 'postWrite', $hook);
61
+
62
+        $this->view->expects($this->once())
63
+            ->method('file_get_contents')
64
+            ->with('/bar/foo')
65
+            ->willReturn('bar');
66
+
67
+        $this->view->expects($this->once())
68
+            ->method('getFileInfo')
69
+            ->with('/bar/foo')
70
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_READ]));
71
+
72
+        $node = new File($root, $this->view, '/bar/foo');
73
+        $this->assertEquals('bar', $node->getContent());
74
+    }
75
+
76
+
77
+    public function testGetContentNotPermitted(): void {
78
+        $this->expectException(NotPermittedException::class);
79
+
80
+        /** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */
81
+        $root = $this->getMockBuilder(Root::class)
82
+            ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig])
83
+            ->getMock();
84
+
85
+        $root->expects($this->any())
86
+            ->method('getUser')
87
+            ->willReturn($this->user);
88
+
89
+        $this->view->expects($this->once())
90
+            ->method('getFileInfo')
91
+            ->with('/bar/foo')
92
+            ->willReturn($this->getFileInfo(['permissions' => 0]));
93
+
94
+        $node = new File($root, $this->view, '/bar/foo');
95
+        $node->getContent();
96
+    }
97
+
98
+    public function testPutContent(): void {
99
+        /** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */
100
+        $root = $this->getMockBuilder(Root::class)
101
+            ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig])
102
+            ->getMock();
103
+
104
+        $root->expects($this->any())
105
+            ->method('getUser')
106
+            ->willReturn($this->user);
107
+
108
+        $this->view->expects($this->once())
109
+            ->method('getFileInfo')
110
+            ->with('/bar/foo')
111
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL]));
112
+
113
+        $this->view->expects($this->once())
114
+            ->method('file_put_contents')
115
+            ->with('/bar/foo', 'bar')
116
+            ->willReturn(true);
117
+
118
+        $node = new File($root, $this->view, '/bar/foo');
119
+        $node->putContent('bar');
120
+    }
121
+
122
+
123
+    public function testPutContentNotPermitted(): void {
124
+        $this->expectException(NotPermittedException::class);
125
+
126
+        /** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */
127
+        $root = $this->getMockBuilder(Root::class)
128
+            ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig])
129
+            ->getMock();
130
+
131
+        $this->view->expects($this->once())
132
+            ->method('getFileInfo')
133
+            ->with('/bar/foo')
134
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_READ]));
135
+
136
+        $node = new File($root, $this->view, '/bar/foo');
137
+        $node->putContent('bar');
138
+    }
139
+
140
+    public function testGetMimeType(): void {
141
+        /** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */
142
+        $root = $this->getMockBuilder(Root::class)
143
+            ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig])
144
+            ->getMock();
145
+
146
+        $this->view->expects($this->once())
147
+            ->method('getFileInfo')
148
+            ->with('/bar/foo')
149
+            ->willReturn($this->getFileInfo(['mimetype' => 'text/plain']));
150
+
151
+        $node = new File($root, $this->view, '/bar/foo');
152
+        $this->assertEquals('text/plain', $node->getMimeType());
153
+    }
154
+
155
+    public function testFOpenRead(): void {
156
+        $stream = fopen('php://memory', 'w+');
157
+        fwrite($stream, 'bar');
158
+        rewind($stream);
159
+
160
+        $root = new Root(
161
+            $this->manager,
162
+            $this->view,
163
+            $this->user,
164
+            $this->userMountCache,
165
+            $this->logger,
166
+            $this->userManager,
167
+            $this->eventDispatcher,
168
+            $this->cacheFactory,
169
+            $this->appConfig,
170
+        );
171
+
172
+        $hook = function ($file): void {
173
+            throw new \Exception('Hooks are not supposed to be called');
174
+        };
175
+
176
+        $root->listen('\OC\Files', 'preWrite', $hook);
177
+        $root->listen('\OC\Files', 'postWrite', $hook);
178
+
179
+        $this->view->expects($this->once())
180
+            ->method('fopen')
181
+            ->with('/bar/foo', 'r')
182
+            ->willReturn($stream);
183
+
184
+        $this->view->expects($this->once())
185
+            ->method('getFileInfo')
186
+            ->with('/bar/foo')
187
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL]));
188
+
189
+        $node = new File($root, $this->view, '/bar/foo');
190
+        $fh = $node->fopen('r');
191
+        $this->assertEquals($stream, $fh);
192
+        $this->assertEquals('bar', fread($fh, 3));
193
+    }
194
+
195
+    public function testFOpenWrite(): void {
196
+        $stream = fopen('php://memory', 'w+');
197
+
198
+        $root = new Root(
199
+            $this->manager,
200
+            $this->view,
201
+            $this->user,
202
+            $this->userMountCache,
203
+            $this->logger,
204
+            $this->userManager,
205
+            $this->eventDispatcher,
206
+            $this->cacheFactory,
207
+            $this->appConfig,
208
+        );
209
+        $hooksCalled = 0;
210
+        $hook = function ($file) use (&$hooksCalled): void {
211
+            $hooksCalled++;
212
+        };
213
+
214
+        $root->listen('\OC\Files', 'preWrite', $hook);
215
+        $root->listen('\OC\Files', 'postWrite', $hook);
216
+
217
+        $this->view->expects($this->once())
218
+            ->method('fopen')
219
+            ->with('/bar/foo', 'w')
220
+            ->willReturn($stream);
221
+
222
+        $this->view->expects($this->once())
223
+            ->method('getFileInfo')
224
+            ->with('/bar/foo')
225
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL]));
226
+
227
+        $node = new File($root, $this->view, '/bar/foo');
228
+        $fh = $node->fopen('w');
229
+        $this->assertEquals($stream, $fh);
230
+        fwrite($fh, 'bar');
231
+        rewind($fh);
232
+        $this->assertEquals('bar', fread($stream, 3));
233
+        $this->assertEquals(2, $hooksCalled);
234
+    }
235
+
236
+
237
+    public function testFOpenReadNotPermitted(): void {
238
+        $this->expectException(NotPermittedException::class);
239
+
240
+        $root = new Root(
241
+            $this->manager,
242
+            $this->view,
243
+            $this->user,
244
+            $this->userMountCache,
245
+            $this->logger,
246
+            $this->userManager,
247
+            $this->eventDispatcher,
248
+            $this->cacheFactory,
249
+            $this->appConfig,
250
+        );
251
+        $hook = function ($file): void {
252
+            throw new \Exception('Hooks are not supposed to be called');
253
+        };
254
+
255
+        $this->view->expects($this->once())
256
+            ->method('getFileInfo')
257
+            ->with('/bar/foo')
258
+            ->willReturn($this->getFileInfo(['permissions' => 0]));
259
+
260
+        $node = new File($root, $this->view, '/bar/foo');
261
+        $node->fopen('r');
262
+    }
263
+
264
+
265
+    public function testFOpenReadWriteNoReadPermissions(): void {
266
+        $this->expectException(NotPermittedException::class);
267
+
268
+        $root = new Root(
269
+            $this->manager,
270
+            $this->view,
271
+            $this->user,
272
+            $this->userMountCache,
273
+            $this->logger,
274
+            $this->userManager,
275
+            $this->eventDispatcher,
276
+            $this->cacheFactory,
277
+            $this->appConfig,
278
+        );
279
+        $hook = function (): void {
280
+            throw new \Exception('Hooks are not supposed to be called');
281
+        };
282
+
283
+        $this->view->expects($this->once())
284
+            ->method('getFileInfo')
285
+            ->with('/bar/foo')
286
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_UPDATE]));
287
+
288
+        $node = new File($root, $this->view, '/bar/foo');
289
+        $node->fopen('w');
290
+    }
291
+
292
+
293
+    public function testFOpenReadWriteNoWritePermissions(): void {
294
+        $this->expectException(NotPermittedException::class);
295
+
296
+        $root = new Root(
297
+            $this->manager,
298
+            $this->view,
299
+            $this->user,
300
+            $this->userMountCache,
301
+            $this->logger,
302
+            $this->userManager,
303
+            $this->eventDispatcher,
304
+            $this->cacheFactory,
305
+            $this->appConfig,
306
+        );
307
+        $hook = function (): void {
308
+            throw new \Exception('Hooks are not supposed to be called');
309
+        };
310
+
311
+        $this->view->expects($this->once())
312
+            ->method('getFileInfo')
313
+            ->with('/bar/foo')
314
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_READ]));
315
+
316
+        $node = new File($root, $this->view, '/bar/foo');
317
+        $node->fopen('w');
318
+    }
319 319
 }
Please login to merge, or discard this patch.
tests/lib/Files/Node/NodeTestCase.php 1 patch
Indentation   +699 added lines, -699 removed lines patch added patch discarded remove patch
@@ -39,746 +39,746 @@
 block discarded – undo
39 39
  * @package Test\Files\Node
40 40
  */
41 41
 abstract class NodeTestCase extends \Test\TestCase {
42
-	protected IUser&MockObject $user;
43
-	protected Manager&MockObject $manager;
44
-	protected View&MockObject $view;
45
-	protected Root&MockObject $root;
46
-	protected IUserMountCache&MockObject $userMountCache;
47
-	protected LoggerInterface&MockObject $logger;
48
-	protected IUserManager&MockObject $userManager;
49
-	protected IEventDispatcher&MockObject $eventDispatcher;
50
-	protected ICacheFactory&MockObject $cacheFactory;
51
-	protected IAppConfig&MockObject $appConfig;
52
-
53
-	protected function setUp(): void {
54
-		parent::setUp();
55
-
56
-		$this->user = $this->createMock(IUser::class);
57
-		$this->manager = $this->getMockBuilder(Manager::class)
58
-			->disableOriginalConstructor()
59
-			->getMock();
60
-		$this->view = $this->getMockBuilder(View::class)
61
-			->disableOriginalConstructor()
62
-			->getMock();
63
-		$this->view->expects($this->any())
64
-			->method('getRoot')
65
-			->willReturn('');
66
-		$this->userMountCache = $this->getMockBuilder('\OCP\Files\Config\IUserMountCache')
67
-			->disableOriginalConstructor()
68
-			->getMock();
69
-		$this->logger = $this->createMock(LoggerInterface::class);
70
-		$this->userManager = $this->createMock(IUserManager::class);
71
-		$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
72
-		$this->cacheFactory = $this->createMock(ICacheFactory::class);
73
-		$this->cacheFactory->method('createLocal')
74
-			->willReturnCallback(function () {
75
-				return new ArrayCache();
76
-			});
77
-		$this->appConfig = $this->createMock(IAppConfig::class);
78
-
79
-		$this->root = $this->getMockBuilder(Root::class)
80
-			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig])
81
-			->getMock();
82
-	}
83
-
84
-	/**
85
-	 * @return View|\PHPUnit\Framework\MockObject\MockObject $view
86
-	 */
87
-	protected function getRootViewMock() {
88
-		$view = $this->createMock(View::class);
89
-		$view->expects($this->any())
90
-			->method('getRoot')
91
-			->willReturn('');
92
-		return $view;
93
-	}
94
-
95
-	abstract protected function createTestNode(IRootFolder $root, View&MockObject $view, string $path, array $data = [], string $internalPath = '', ?IStorage $storage = null): Node;
96
-
97
-	/**
98
-	 * @return class-string<Node>
99
-	 */
100
-	abstract protected function getNodeClass(): string;
101
-
102
-	/**
103
-	 * @return class-string<Node>
104
-	 */
105
-	abstract protected function getNonExistingNodeClass(): string;
106
-
107
-	/**
108
-	 * @return string
109
-	 */
110
-	abstract protected function getViewDeleteMethod(): string;
111
-
112
-	protected function getMockStorage(): IStorage&MockObject {
113
-		$storage = $this->getMockBuilder(IStorage::class)
114
-			->disableOriginalConstructor()
115
-			->getMock();
116
-		$storage->expects($this->any())
117
-			->method('getId')
118
-			->willReturn('home::someuser');
119
-		return $storage;
120
-	}
121
-
122
-	protected function getFileInfo($data, $internalPath = '', ?IStorage $storage = null) {
123
-		$mount = $this->createMock(IMountPoint::class);
124
-		$mount->method('getStorage')
125
-			->willReturn($storage);
126
-		return new FileInfo('', $this->getMockStorage(), $internalPath, $data, $mount);
127
-	}
128
-
129
-	public function testDelete(): void {
130
-		$this->root->expects($this->exactly(2))
131
-			->method('emit')
132
-			->willReturn(true);
133
-		$this->root->expects($this->any())
134
-			->method('getUser')
135
-			->willReturn($this->user);
136
-
137
-		$this->view->expects($this->once())
138
-			->method('getFileInfo')
139
-			->with('/bar/foo')
140
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL]));
141
-
142
-		$this->view->expects($this->once())
143
-			->method($this->getViewDeleteMethod())
144
-			->with('/bar/foo')
145
-			->willReturn(true);
146
-
147
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
148
-		$node->delete();
149
-	}
150
-
151
-	public function testDeleteHooks(): void {
152
-		$test = $this;
153
-		$hooksRun = 0;
154
-		/**
155
-		 * @param \OC\Files\Node\File $node
156
-		 */
157
-		$preListener = function ($node) use (&$test, &$hooksRun): void {
158
-			$test->assertInstanceOf($this->getNodeClass(), $node);
159
-			$test->assertEquals('foo', $node->getInternalPath());
160
-			$test->assertEquals('/bar/foo', $node->getPath());
161
-			$test->assertEquals(1, $node->getId());
162
-			$hooksRun++;
163
-		};
164
-
165
-		/**
166
-		 * @param \OC\Files\Node\File $node
167
-		 */
168
-		$postListener = function ($node) use (&$test, &$hooksRun): void {
169
-			$test->assertInstanceOf($this->getNonExistingNodeClass(), $node);
170
-			$test->assertEquals('foo', $node->getInternalPath());
171
-			$test->assertEquals('/bar/foo', $node->getPath());
172
-			$test->assertEquals(1, $node->getId());
173
-			$test->assertEquals('text/plain', $node->getMimeType());
174
-			$hooksRun++;
175
-		};
176
-
177
-		$root = new Root(
178
-			$this->manager,
179
-			$this->view,
180
-			$this->user,
181
-			$this->userMountCache,
182
-			$this->logger,
183
-			$this->userManager,
184
-			$this->eventDispatcher,
185
-			$this->cacheFactory,
186
-			$this->createMock(IAppConfig::class),
187
-		);
188
-
189
-		$root->listen('\OC\Files', 'preDelete', $preListener);
190
-		$root->listen('\OC\Files', 'postDelete', $postListener);
191
-
192
-		$this->view->expects($this->any())
193
-			->method('getFileInfo')
194
-			->with('/bar/foo')
195
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL, 'fileid' => 1, 'mimetype' => 'text/plain'], 'foo'));
196
-
197
-		$this->view->expects($this->once())
198
-			->method($this->getViewDeleteMethod())
199
-			->with('/bar/foo')
200
-			->willReturn(true);
201
-
202
-		$node = $this->createTestNode($root, $this->view, '/bar/foo');
203
-		$node->delete();
204
-		$this->assertEquals(2, $hooksRun);
205
-	}
206
-
207
-
208
-	public function testDeleteNotPermitted(): void {
209
-		$this->expectException(NotPermittedException::class);
210
-
211
-		$this->root->expects($this->any())
212
-			->method('getUser')
213
-			->willReturn($this->user);
214
-
215
-		$this->view->expects($this->once())
216
-			->method('getFileInfo')
217
-			->with('/bar/foo')
218
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_READ]));
219
-
220
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
221
-		$node->delete();
222
-	}
223
-
224
-
225
-	public function testStat(): void {
226
-		$this->root->expects($this->any())
227
-			->method('getUser')
228
-			->willReturn($this->user);
229
-
230
-		$stat = [
231
-			'fileid' => 1,
232
-			'size' => 100,
233
-			'etag' => 'qwerty',
234
-			'mtime' => 50,
235
-			'permissions' => 0
236
-		];
237
-
238
-		$this->view->expects($this->once())
239
-			->method('stat')
240
-			->with('/bar/foo')
241
-			->willReturn($stat);
242
-
243
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
244
-		$this->assertEquals($stat, $node->stat());
245
-	}
246
-
247
-	public function testGetId(): void {
248
-		$this->root->expects($this->any())
249
-			->method('getUser')
250
-			->willReturn($this->user);
251
-
252
-		$stat = $this->getFileInfo([
253
-			'fileid' => 1,
254
-			'size' => 100,
255
-			'etag' => 'qwerty',
256
-			'mtime' => 50
257
-		]);
258
-
259
-		$this->view->expects($this->once())
260
-			->method('getFileInfo')
261
-			->with('/bar/foo')
262
-			->willReturn($stat);
263
-
264
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
265
-		$this->assertEquals(1, $node->getId());
266
-	}
267
-
268
-	public function testGetSize(): void {
269
-		$this->root->expects($this->any())
270
-			->method('getUser')
271
-			->willReturn($this->user);
272
-
273
-
274
-		$stat = $this->getFileInfo([
275
-			'fileid' => 1,
276
-			'size' => 100,
277
-			'etag' => 'qwerty',
278
-			'mtime' => 50
279
-		]);
280
-
281
-		$this->view->expects($this->once())
282
-			->method('getFileInfo')
283
-			->with('/bar/foo')
284
-			->willReturn($stat);
285
-
286
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
287
-		$this->assertEquals(100, $node->getSize());
288
-	}
289
-
290
-	public function testGetEtag(): void {
291
-		$this->root->expects($this->any())
292
-			->method('getUser')
293
-			->willReturn($this->user);
294
-
295
-		$stat = $this->getFileInfo([
296
-			'fileid' => 1,
297
-			'size' => 100,
298
-			'etag' => 'qwerty',
299
-			'mtime' => 50
300
-		]);
301
-
302
-		$this->view->expects($this->once())
303
-			->method('getFileInfo')
304
-			->with('/bar/foo')
305
-			->willReturn($stat);
306
-
307
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
308
-		$this->assertEquals('qwerty', $node->getEtag());
309
-	}
310
-
311
-	public function testGetMTime(): void {
312
-		$this->root->expects($this->any())
313
-			->method('getUser')
314
-			->willReturn($this->user);
315
-
316
-		$stat = $this->getFileInfo([
317
-			'fileid' => 1,
318
-			'size' => 100,
319
-			'etag' => 'qwerty',
320
-			'mtime' => 50
321
-		]);
322
-
323
-		$this->view->expects($this->once())
324
-			->method('getFileInfo')
325
-			->with('/bar/foo')
326
-			->willReturn($stat);
327
-
328
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
329
-		$this->assertEquals(50, $node->getMTime());
330
-	}
331
-
332
-	public function testGetStorage(): void {
333
-		$this->root->expects($this->any())
334
-			->method('getUser')
335
-			->willReturn($this->user);
336
-		/**
337
-		 * @var Storage|\PHPUnit\Framework\MockObject\MockObject $storage
338
-		 */
339
-		$storage = $this->getMockBuilder('\OC\Files\Storage\Storage')
340
-			->disableOriginalConstructor()
341
-			->getMock();
342
-
343
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo', [], 'foo', $storage);
344
-		$this->assertEquals($storage, $node->getStorage());
345
-	}
346
-
347
-	public function testGetPath(): void {
348
-		$this->root->expects($this->any())
349
-			->method('getUser')
350
-			->willReturn($this->user);
351
-
352
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
353
-		$this->assertEquals('/bar/foo', $node->getPath());
354
-	}
355
-
356
-	public function testGetInternalPath(): void {
357
-		$this->root->expects($this->any())
358
-			->method('getUser')
359
-			->willReturn($this->user);
360
-		/**
361
-		 * @var Storage|\PHPUnit\Framework\MockObject\MockObject $storage
362
-		 */
363
-		$storage = $this->getMockBuilder('\OC\Files\Storage\Storage')
364
-			->disableOriginalConstructor()
365
-			->getMock();
366
-
367
-		$this->view->expects($this->once())
368
-			->method('getFileInfo')
369
-			->with('/bar/foo')
370
-			->willReturn($this->getFileInfo([], 'foo'));
371
-
372
-
373
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
374
-		$this->assertEquals('foo', $node->getInternalPath());
375
-	}
376
-
377
-	public function testGetName(): void {
378
-		$this->root->expects($this->any())
379
-			->method('getUser')
380
-			->willReturn($this->user);
381
-
382
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
383
-		$this->assertEquals('foo', $node->getName());
384
-	}
385
-
386
-	public function testTouchSetMTime(): void {
387
-		$this->root->expects($this->any())
388
-			->method('getUser')
389
-			->willReturn($this->user);
390
-
391
-		$this->view->expects($this->once())
392
-			->method('touch')
393
-			->with('/bar/foo', 100)
394
-			->willReturn(true);
395
-
396
-		$this->view->expects($this->once())
397
-			->method('getFileInfo')
398
-			->with('/bar/foo')
399
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL]));
400
-
401
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
402
-		$node->touch(100);
403
-		$this->assertEquals(100, $node->getMTime());
404
-	}
405
-
406
-	public function testTouchHooks(): void {
407
-		$test = $this;
408
-		$hooksRun = 0;
409
-		/**
410
-		 * @param \OC\Files\Node\File $node
411
-		 */
412
-		$preListener = function ($node) use (&$test, &$hooksRun): void {
413
-			$test->assertEquals('foo', $node->getInternalPath());
414
-			$test->assertEquals('/bar/foo', $node->getPath());
415
-			$hooksRun++;
416
-		};
417
-
418
-		/**
419
-		 * @param \OC\Files\Node\File $node
420
-		 */
421
-		$postListener = function ($node) use (&$test, &$hooksRun): void {
422
-			$test->assertEquals('foo', $node->getInternalPath());
423
-			$test->assertEquals('/bar/foo', $node->getPath());
424
-			$hooksRun++;
425
-		};
426
-
427
-		$root = new Root(
428
-			$this->manager,
429
-			$this->view,
430
-			$this->user,
431
-			$this->userMountCache,
432
-			$this->logger,
433
-			$this->userManager,
434
-			$this->eventDispatcher,
435
-			$this->cacheFactory,
436
-			$this->createMock(IAppConfig::class),
437
-		);
438
-		$root->listen('\OC\Files', 'preTouch', $preListener);
439
-		$root->listen('\OC\Files', 'postTouch', $postListener);
440
-
441
-		$this->view->expects($this->once())
442
-			->method('touch')
443
-			->with('/bar/foo', 100)
444
-			->willReturn(true);
445
-
446
-		$this->view->expects($this->any())
447
-			->method('getFileInfo')
448
-			->with('/bar/foo')
449
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL], 'foo'));
450
-
451
-		$node = $this->createTestNode($root, $this->view, '/bar/foo');
452
-		$node->touch(100);
453
-		$this->assertEquals(2, $hooksRun);
454
-	}
455
-
456
-
457
-	public function testTouchNotPermitted(): void {
458
-		$this->expectException(NotPermittedException::class);
459
-
460
-		$this->root->expects($this->any())
461
-			->method('getUser')
462
-			->willReturn($this->user);
463
-
464
-		$this->view->expects($this->any())
465
-			->method('getFileInfo')
466
-			->with('/bar/foo')
467
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_READ]));
468
-
469
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
470
-		$node->touch(100);
471
-	}
472
-
473
-
474
-	public function testInvalidPath(): void {
475
-		$this->expectException(InvalidPathException::class);
476
-
477
-		$node = $this->createTestNode($this->root, $this->view, '/../foo');
478
-		$node->getFileInfo();
479
-	}
480
-
481
-	public function testCopySameStorage(): void {
482
-		$this->view->expects($this->any())
483
-			->method('copy')
484
-			->with('/bar/foo', '/bar/asd')
485
-			->willReturn(true);
486
-
487
-		$this->view->expects($this->any())
488
-			->method('getFileInfo')
489
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL, 'fileid' => 3]));
490
-
491
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
492
-		$parentNode = new Folder($this->root, $this->view, '/bar');
493
-		$newNode = $this->createTestNode($this->root, $this->view, '/bar/asd');
494
-
495
-		$this->root->method('get')
496
-			->willReturnMap([
497
-				['/bar/asd', $newNode],
498
-				['/bar', $parentNode]
499
-			]);
500
-
501
-		$target = $node->copy('/bar/asd');
502
-		$this->assertInstanceOf($this->getNodeClass(), $target);
503
-		$this->assertEquals(3, $target->getId());
504
-	}
505
-
506
-
507
-	public function testCopyNotPermitted(): void {
508
-		$this->expectException(NotPermittedException::class);
509
-
510
-		/**
511
-		 * @var Storage|\PHPUnit\Framework\MockObject\MockObject $storage
512
-		 */
513
-		$storage = $this->createMock('\OC\Files\Storage\Storage');
514
-
515
-		$this->root->expects($this->never())
516
-			->method('getMount');
517
-
518
-		$storage->expects($this->never())
519
-			->method('copy');
520
-
521
-		$this->view->expects($this->any())
522
-			->method('getFileInfo')
523
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_READ, 'fileid' => 3]));
524
-
525
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
526
-		$parentNode = new Folder($this->root, $this->view, '/bar');
527
-
528
-		$this->root->expects($this->once())
529
-			->method('get')
530
-			->willReturnMap([
531
-				['/bar', $parentNode]
532
-			]);
533
-
534
-		$node->copy('/bar/asd');
535
-	}
536
-
537
-
538
-	public function testCopyNoParent(): void {
539
-		$this->expectException(NotFoundException::class);
42
+    protected IUser&MockObject $user;
43
+    protected Manager&MockObject $manager;
44
+    protected View&MockObject $view;
45
+    protected Root&MockObject $root;
46
+    protected IUserMountCache&MockObject $userMountCache;
47
+    protected LoggerInterface&MockObject $logger;
48
+    protected IUserManager&MockObject $userManager;
49
+    protected IEventDispatcher&MockObject $eventDispatcher;
50
+    protected ICacheFactory&MockObject $cacheFactory;
51
+    protected IAppConfig&MockObject $appConfig;
52
+
53
+    protected function setUp(): void {
54
+        parent::setUp();
55
+
56
+        $this->user = $this->createMock(IUser::class);
57
+        $this->manager = $this->getMockBuilder(Manager::class)
58
+            ->disableOriginalConstructor()
59
+            ->getMock();
60
+        $this->view = $this->getMockBuilder(View::class)
61
+            ->disableOriginalConstructor()
62
+            ->getMock();
63
+        $this->view->expects($this->any())
64
+            ->method('getRoot')
65
+            ->willReturn('');
66
+        $this->userMountCache = $this->getMockBuilder('\OCP\Files\Config\IUserMountCache')
67
+            ->disableOriginalConstructor()
68
+            ->getMock();
69
+        $this->logger = $this->createMock(LoggerInterface::class);
70
+        $this->userManager = $this->createMock(IUserManager::class);
71
+        $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
72
+        $this->cacheFactory = $this->createMock(ICacheFactory::class);
73
+        $this->cacheFactory->method('createLocal')
74
+            ->willReturnCallback(function () {
75
+                return new ArrayCache();
76
+            });
77
+        $this->appConfig = $this->createMock(IAppConfig::class);
78
+
79
+        $this->root = $this->getMockBuilder(Root::class)
80
+            ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig])
81
+            ->getMock();
82
+    }
83
+
84
+    /**
85
+     * @return View|\PHPUnit\Framework\MockObject\MockObject $view
86
+     */
87
+    protected function getRootViewMock() {
88
+        $view = $this->createMock(View::class);
89
+        $view->expects($this->any())
90
+            ->method('getRoot')
91
+            ->willReturn('');
92
+        return $view;
93
+    }
94
+
95
+    abstract protected function createTestNode(IRootFolder $root, View&MockObject $view, string $path, array $data = [], string $internalPath = '', ?IStorage $storage = null): Node;
96
+
97
+    /**
98
+     * @return class-string<Node>
99
+     */
100
+    abstract protected function getNodeClass(): string;
101
+
102
+    /**
103
+     * @return class-string<Node>
104
+     */
105
+    abstract protected function getNonExistingNodeClass(): string;
106
+
107
+    /**
108
+     * @return string
109
+     */
110
+    abstract protected function getViewDeleteMethod(): string;
111
+
112
+    protected function getMockStorage(): IStorage&MockObject {
113
+        $storage = $this->getMockBuilder(IStorage::class)
114
+            ->disableOriginalConstructor()
115
+            ->getMock();
116
+        $storage->expects($this->any())
117
+            ->method('getId')
118
+            ->willReturn('home::someuser');
119
+        return $storage;
120
+    }
121
+
122
+    protected function getFileInfo($data, $internalPath = '', ?IStorage $storage = null) {
123
+        $mount = $this->createMock(IMountPoint::class);
124
+        $mount->method('getStorage')
125
+            ->willReturn($storage);
126
+        return new FileInfo('', $this->getMockStorage(), $internalPath, $data, $mount);
127
+    }
128
+
129
+    public function testDelete(): void {
130
+        $this->root->expects($this->exactly(2))
131
+            ->method('emit')
132
+            ->willReturn(true);
133
+        $this->root->expects($this->any())
134
+            ->method('getUser')
135
+            ->willReturn($this->user);
136
+
137
+        $this->view->expects($this->once())
138
+            ->method('getFileInfo')
139
+            ->with('/bar/foo')
140
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL]));
141
+
142
+        $this->view->expects($this->once())
143
+            ->method($this->getViewDeleteMethod())
144
+            ->with('/bar/foo')
145
+            ->willReturn(true);
146
+
147
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
148
+        $node->delete();
149
+    }
150
+
151
+    public function testDeleteHooks(): void {
152
+        $test = $this;
153
+        $hooksRun = 0;
154
+        /**
155
+         * @param \OC\Files\Node\File $node
156
+         */
157
+        $preListener = function ($node) use (&$test, &$hooksRun): void {
158
+            $test->assertInstanceOf($this->getNodeClass(), $node);
159
+            $test->assertEquals('foo', $node->getInternalPath());
160
+            $test->assertEquals('/bar/foo', $node->getPath());
161
+            $test->assertEquals(1, $node->getId());
162
+            $hooksRun++;
163
+        };
164
+
165
+        /**
166
+         * @param \OC\Files\Node\File $node
167
+         */
168
+        $postListener = function ($node) use (&$test, &$hooksRun): void {
169
+            $test->assertInstanceOf($this->getNonExistingNodeClass(), $node);
170
+            $test->assertEquals('foo', $node->getInternalPath());
171
+            $test->assertEquals('/bar/foo', $node->getPath());
172
+            $test->assertEquals(1, $node->getId());
173
+            $test->assertEquals('text/plain', $node->getMimeType());
174
+            $hooksRun++;
175
+        };
176
+
177
+        $root = new Root(
178
+            $this->manager,
179
+            $this->view,
180
+            $this->user,
181
+            $this->userMountCache,
182
+            $this->logger,
183
+            $this->userManager,
184
+            $this->eventDispatcher,
185
+            $this->cacheFactory,
186
+            $this->createMock(IAppConfig::class),
187
+        );
188
+
189
+        $root->listen('\OC\Files', 'preDelete', $preListener);
190
+        $root->listen('\OC\Files', 'postDelete', $postListener);
191
+
192
+        $this->view->expects($this->any())
193
+            ->method('getFileInfo')
194
+            ->with('/bar/foo')
195
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL, 'fileid' => 1, 'mimetype' => 'text/plain'], 'foo'));
196
+
197
+        $this->view->expects($this->once())
198
+            ->method($this->getViewDeleteMethod())
199
+            ->with('/bar/foo')
200
+            ->willReturn(true);
201
+
202
+        $node = $this->createTestNode($root, $this->view, '/bar/foo');
203
+        $node->delete();
204
+        $this->assertEquals(2, $hooksRun);
205
+    }
206
+
207
+
208
+    public function testDeleteNotPermitted(): void {
209
+        $this->expectException(NotPermittedException::class);
210
+
211
+        $this->root->expects($this->any())
212
+            ->method('getUser')
213
+            ->willReturn($this->user);
214
+
215
+        $this->view->expects($this->once())
216
+            ->method('getFileInfo')
217
+            ->with('/bar/foo')
218
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_READ]));
219
+
220
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
221
+        $node->delete();
222
+    }
223
+
224
+
225
+    public function testStat(): void {
226
+        $this->root->expects($this->any())
227
+            ->method('getUser')
228
+            ->willReturn($this->user);
229
+
230
+        $stat = [
231
+            'fileid' => 1,
232
+            'size' => 100,
233
+            'etag' => 'qwerty',
234
+            'mtime' => 50,
235
+            'permissions' => 0
236
+        ];
237
+
238
+        $this->view->expects($this->once())
239
+            ->method('stat')
240
+            ->with('/bar/foo')
241
+            ->willReturn($stat);
242
+
243
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
244
+        $this->assertEquals($stat, $node->stat());
245
+    }
246
+
247
+    public function testGetId(): void {
248
+        $this->root->expects($this->any())
249
+            ->method('getUser')
250
+            ->willReturn($this->user);
251
+
252
+        $stat = $this->getFileInfo([
253
+            'fileid' => 1,
254
+            'size' => 100,
255
+            'etag' => 'qwerty',
256
+            'mtime' => 50
257
+        ]);
258
+
259
+        $this->view->expects($this->once())
260
+            ->method('getFileInfo')
261
+            ->with('/bar/foo')
262
+            ->willReturn($stat);
263
+
264
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
265
+        $this->assertEquals(1, $node->getId());
266
+    }
267
+
268
+    public function testGetSize(): void {
269
+        $this->root->expects($this->any())
270
+            ->method('getUser')
271
+            ->willReturn($this->user);
272
+
273
+
274
+        $stat = $this->getFileInfo([
275
+            'fileid' => 1,
276
+            'size' => 100,
277
+            'etag' => 'qwerty',
278
+            'mtime' => 50
279
+        ]);
280
+
281
+        $this->view->expects($this->once())
282
+            ->method('getFileInfo')
283
+            ->with('/bar/foo')
284
+            ->willReturn($stat);
285
+
286
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
287
+        $this->assertEquals(100, $node->getSize());
288
+    }
289
+
290
+    public function testGetEtag(): void {
291
+        $this->root->expects($this->any())
292
+            ->method('getUser')
293
+            ->willReturn($this->user);
294
+
295
+        $stat = $this->getFileInfo([
296
+            'fileid' => 1,
297
+            'size' => 100,
298
+            'etag' => 'qwerty',
299
+            'mtime' => 50
300
+        ]);
301
+
302
+        $this->view->expects($this->once())
303
+            ->method('getFileInfo')
304
+            ->with('/bar/foo')
305
+            ->willReturn($stat);
306
+
307
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
308
+        $this->assertEquals('qwerty', $node->getEtag());
309
+    }
310
+
311
+    public function testGetMTime(): void {
312
+        $this->root->expects($this->any())
313
+            ->method('getUser')
314
+            ->willReturn($this->user);
315
+
316
+        $stat = $this->getFileInfo([
317
+            'fileid' => 1,
318
+            'size' => 100,
319
+            'etag' => 'qwerty',
320
+            'mtime' => 50
321
+        ]);
322
+
323
+        $this->view->expects($this->once())
324
+            ->method('getFileInfo')
325
+            ->with('/bar/foo')
326
+            ->willReturn($stat);
327
+
328
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
329
+        $this->assertEquals(50, $node->getMTime());
330
+    }
331
+
332
+    public function testGetStorage(): void {
333
+        $this->root->expects($this->any())
334
+            ->method('getUser')
335
+            ->willReturn($this->user);
336
+        /**
337
+         * @var Storage|\PHPUnit\Framework\MockObject\MockObject $storage
338
+         */
339
+        $storage = $this->getMockBuilder('\OC\Files\Storage\Storage')
340
+            ->disableOriginalConstructor()
341
+            ->getMock();
342
+
343
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo', [], 'foo', $storage);
344
+        $this->assertEquals($storage, $node->getStorage());
345
+    }
346
+
347
+    public function testGetPath(): void {
348
+        $this->root->expects($this->any())
349
+            ->method('getUser')
350
+            ->willReturn($this->user);
351
+
352
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
353
+        $this->assertEquals('/bar/foo', $node->getPath());
354
+    }
355
+
356
+    public function testGetInternalPath(): void {
357
+        $this->root->expects($this->any())
358
+            ->method('getUser')
359
+            ->willReturn($this->user);
360
+        /**
361
+         * @var Storage|\PHPUnit\Framework\MockObject\MockObject $storage
362
+         */
363
+        $storage = $this->getMockBuilder('\OC\Files\Storage\Storage')
364
+            ->disableOriginalConstructor()
365
+            ->getMock();
366
+
367
+        $this->view->expects($this->once())
368
+            ->method('getFileInfo')
369
+            ->with('/bar/foo')
370
+            ->willReturn($this->getFileInfo([], 'foo'));
371
+
372
+
373
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
374
+        $this->assertEquals('foo', $node->getInternalPath());
375
+    }
376
+
377
+    public function testGetName(): void {
378
+        $this->root->expects($this->any())
379
+            ->method('getUser')
380
+            ->willReturn($this->user);
381
+
382
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
383
+        $this->assertEquals('foo', $node->getName());
384
+    }
385
+
386
+    public function testTouchSetMTime(): void {
387
+        $this->root->expects($this->any())
388
+            ->method('getUser')
389
+            ->willReturn($this->user);
390
+
391
+        $this->view->expects($this->once())
392
+            ->method('touch')
393
+            ->with('/bar/foo', 100)
394
+            ->willReturn(true);
395
+
396
+        $this->view->expects($this->once())
397
+            ->method('getFileInfo')
398
+            ->with('/bar/foo')
399
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL]));
400
+
401
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
402
+        $node->touch(100);
403
+        $this->assertEquals(100, $node->getMTime());
404
+    }
405
+
406
+    public function testTouchHooks(): void {
407
+        $test = $this;
408
+        $hooksRun = 0;
409
+        /**
410
+         * @param \OC\Files\Node\File $node
411
+         */
412
+        $preListener = function ($node) use (&$test, &$hooksRun): void {
413
+            $test->assertEquals('foo', $node->getInternalPath());
414
+            $test->assertEquals('/bar/foo', $node->getPath());
415
+            $hooksRun++;
416
+        };
417
+
418
+        /**
419
+         * @param \OC\Files\Node\File $node
420
+         */
421
+        $postListener = function ($node) use (&$test, &$hooksRun): void {
422
+            $test->assertEquals('foo', $node->getInternalPath());
423
+            $test->assertEquals('/bar/foo', $node->getPath());
424
+            $hooksRun++;
425
+        };
426
+
427
+        $root = new Root(
428
+            $this->manager,
429
+            $this->view,
430
+            $this->user,
431
+            $this->userMountCache,
432
+            $this->logger,
433
+            $this->userManager,
434
+            $this->eventDispatcher,
435
+            $this->cacheFactory,
436
+            $this->createMock(IAppConfig::class),
437
+        );
438
+        $root->listen('\OC\Files', 'preTouch', $preListener);
439
+        $root->listen('\OC\Files', 'postTouch', $postListener);
440
+
441
+        $this->view->expects($this->once())
442
+            ->method('touch')
443
+            ->with('/bar/foo', 100)
444
+            ->willReturn(true);
445
+
446
+        $this->view->expects($this->any())
447
+            ->method('getFileInfo')
448
+            ->with('/bar/foo')
449
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL], 'foo'));
450
+
451
+        $node = $this->createTestNode($root, $this->view, '/bar/foo');
452
+        $node->touch(100);
453
+        $this->assertEquals(2, $hooksRun);
454
+    }
455
+
456
+
457
+    public function testTouchNotPermitted(): void {
458
+        $this->expectException(NotPermittedException::class);
459
+
460
+        $this->root->expects($this->any())
461
+            ->method('getUser')
462
+            ->willReturn($this->user);
463
+
464
+        $this->view->expects($this->any())
465
+            ->method('getFileInfo')
466
+            ->with('/bar/foo')
467
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_READ]));
468
+
469
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
470
+        $node->touch(100);
471
+    }
472
+
473
+
474
+    public function testInvalidPath(): void {
475
+        $this->expectException(InvalidPathException::class);
476
+
477
+        $node = $this->createTestNode($this->root, $this->view, '/../foo');
478
+        $node->getFileInfo();
479
+    }
480
+
481
+    public function testCopySameStorage(): void {
482
+        $this->view->expects($this->any())
483
+            ->method('copy')
484
+            ->with('/bar/foo', '/bar/asd')
485
+            ->willReturn(true);
486
+
487
+        $this->view->expects($this->any())
488
+            ->method('getFileInfo')
489
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL, 'fileid' => 3]));
490
+
491
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
492
+        $parentNode = new Folder($this->root, $this->view, '/bar');
493
+        $newNode = $this->createTestNode($this->root, $this->view, '/bar/asd');
494
+
495
+        $this->root->method('get')
496
+            ->willReturnMap([
497
+                ['/bar/asd', $newNode],
498
+                ['/bar', $parentNode]
499
+            ]);
500
+
501
+        $target = $node->copy('/bar/asd');
502
+        $this->assertInstanceOf($this->getNodeClass(), $target);
503
+        $this->assertEquals(3, $target->getId());
504
+    }
505
+
506
+
507
+    public function testCopyNotPermitted(): void {
508
+        $this->expectException(NotPermittedException::class);
509
+
510
+        /**
511
+         * @var Storage|\PHPUnit\Framework\MockObject\MockObject $storage
512
+         */
513
+        $storage = $this->createMock('\OC\Files\Storage\Storage');
514
+
515
+        $this->root->expects($this->never())
516
+            ->method('getMount');
517
+
518
+        $storage->expects($this->never())
519
+            ->method('copy');
520
+
521
+        $this->view->expects($this->any())
522
+            ->method('getFileInfo')
523
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_READ, 'fileid' => 3]));
524
+
525
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
526
+        $parentNode = new Folder($this->root, $this->view, '/bar');
527
+
528
+        $this->root->expects($this->once())
529
+            ->method('get')
530
+            ->willReturnMap([
531
+                ['/bar', $parentNode]
532
+            ]);
533
+
534
+        $node->copy('/bar/asd');
535
+    }
536
+
537
+
538
+    public function testCopyNoParent(): void {
539
+        $this->expectException(NotFoundException::class);
540 540
 
541
-		$this->view->expects($this->never())
542
-			->method('copy');
543
-
544
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
545
-
546
-		$this->root->expects($this->once())
547
-			->method('get')
548
-			->with('/bar/asd')
549
-			->willThrowException(new NotFoundException());
550
-
551
-		$node->copy('/bar/asd/foo');
552
-	}
553
-
554
-
555
-	public function testCopyParentIsFile(): void {
556
-		$this->expectException(NotPermittedException::class);
557
-
558
-		$this->view->expects($this->never())
559
-			->method('copy');
560
-
561
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
562
-		$parentNode = new File($this->root, $this->view, '/bar');
563
-
564
-		$this->root->expects($this->once())
565
-			->method('get')
566
-			->willReturnMap([
567
-				['/bar', $parentNode]
568
-			]);
569
-
570
-		$node->copy('/bar/asd');
571
-	}
572
-
573
-	public function testMoveSameStorage(): void {
574
-		$this->view->expects($this->any())
575
-			->method('rename')
576
-			->with('/bar/foo', '/bar/asd')
577
-			->willReturn(true);
578
-
579
-		$this->view->expects($this->any())
580
-			->method('getFileInfo')
581
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL, 'fileid' => 1]));
582
-
583
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
584
-		$parentNode = new Folder($this->root, $this->view, '/bar');
585
-
586
-		$this->root->expects($this->any())
587
-			->method('get')
588
-			->willReturnMap([['/bar', $parentNode], ['/bar/asd', $node]]);
589
-
590
-		$target = $node->move('/bar/asd');
591
-		$this->assertInstanceOf($this->getNodeClass(), $target);
592
-		$this->assertEquals(1, $target->getId());
593
-		$this->assertEquals('/bar/asd', $node->getPath());
594
-	}
595
-
596
-	public static function moveOrCopyProvider(): array {
597
-		return [
598
-			['move', 'rename', 'preRename', 'postRename'],
599
-			['copy', 'copy', 'preCopy', 'postCopy'],
600
-		];
601
-	}
541
+        $this->view->expects($this->never())
542
+            ->method('copy');
543
+
544
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
545
+
546
+        $this->root->expects($this->once())
547
+            ->method('get')
548
+            ->with('/bar/asd')
549
+            ->willThrowException(new NotFoundException());
550
+
551
+        $node->copy('/bar/asd/foo');
552
+    }
553
+
554
+
555
+    public function testCopyParentIsFile(): void {
556
+        $this->expectException(NotPermittedException::class);
557
+
558
+        $this->view->expects($this->never())
559
+            ->method('copy');
560
+
561
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
562
+        $parentNode = new File($this->root, $this->view, '/bar');
563
+
564
+        $this->root->expects($this->once())
565
+            ->method('get')
566
+            ->willReturnMap([
567
+                ['/bar', $parentNode]
568
+            ]);
569
+
570
+        $node->copy('/bar/asd');
571
+    }
572
+
573
+    public function testMoveSameStorage(): void {
574
+        $this->view->expects($this->any())
575
+            ->method('rename')
576
+            ->with('/bar/foo', '/bar/asd')
577
+            ->willReturn(true);
578
+
579
+        $this->view->expects($this->any())
580
+            ->method('getFileInfo')
581
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL, 'fileid' => 1]));
582
+
583
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
584
+        $parentNode = new Folder($this->root, $this->view, '/bar');
585
+
586
+        $this->root->expects($this->any())
587
+            ->method('get')
588
+            ->willReturnMap([['/bar', $parentNode], ['/bar/asd', $node]]);
589
+
590
+        $target = $node->move('/bar/asd');
591
+        $this->assertInstanceOf($this->getNodeClass(), $target);
592
+        $this->assertEquals(1, $target->getId());
593
+        $this->assertEquals('/bar/asd', $node->getPath());
594
+    }
595
+
596
+    public static function moveOrCopyProvider(): array {
597
+        return [
598
+            ['move', 'rename', 'preRename', 'postRename'],
599
+            ['copy', 'copy', 'preCopy', 'postCopy'],
600
+        ];
601
+    }
602 602
 
603
-	/**
604
-	 * @param string $operationMethod
605
-	 * @param string $viewMethod
606
-	 * @param string $preHookName
607
-	 * @param string $postHookName
608
-	 */
609
-	#[\PHPUnit\Framework\Attributes\DataProvider('moveOrCopyProvider')]
610
-	public function testMoveCopyHooks($operationMethod, $viewMethod, $preHookName, $postHookName): void {
611
-		/** @var IRootFolder|\PHPUnit\Framework\MockObject\MockObject $root */
612
-		$root = $this->getMockBuilder(Root::class)
613
-			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig])
614
-			->onlyMethods(['get'])
615
-			->getMock();
616
-
617
-		$this->view->expects($this->any())
618
-			->method($viewMethod)
619
-			->with('/bar/foo', '/bar/asd')
620
-			->willReturn(true);
603
+    /**
604
+     * @param string $operationMethod
605
+     * @param string $viewMethod
606
+     * @param string $preHookName
607
+     * @param string $postHookName
608
+     */
609
+    #[\PHPUnit\Framework\Attributes\DataProvider('moveOrCopyProvider')]
610
+    public function testMoveCopyHooks($operationMethod, $viewMethod, $preHookName, $postHookName): void {
611
+        /** @var IRootFolder|\PHPUnit\Framework\MockObject\MockObject $root */
612
+        $root = $this->getMockBuilder(Root::class)
613
+            ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory, $this->appConfig])
614
+            ->onlyMethods(['get'])
615
+            ->getMock();
616
+
617
+        $this->view->expects($this->any())
618
+            ->method($viewMethod)
619
+            ->with('/bar/foo', '/bar/asd')
620
+            ->willReturn(true);
621 621
 
622
-		$this->view->expects($this->any())
623
-			->method('getFileInfo')
624
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL, 'fileid' => 1]));
622
+        $this->view->expects($this->any())
623
+            ->method('getFileInfo')
624
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL, 'fileid' => 1]));
625 625
 
626
-		/**
627
-		 * @var \OC\Files\Node\File|\PHPUnit\Framework\MockObject\MockObject $node
628
-		 */
629
-		$node = $this->createTestNode($root, $this->view, '/bar/foo');
630
-		$parentNode = new Folder($root, $this->view, '/bar');
631
-		$targetTestNode = $this->createTestNode($root, $this->view, '/bar/asd');
626
+        /**
627
+         * @var \OC\Files\Node\File|\PHPUnit\Framework\MockObject\MockObject $node
628
+         */
629
+        $node = $this->createTestNode($root, $this->view, '/bar/foo');
630
+        $parentNode = new Folder($root, $this->view, '/bar');
631
+        $targetTestNode = $this->createTestNode($root, $this->view, '/bar/asd');
632 632
 
633
-		$root->expects($this->any())
634
-			->method('get')
635
-			->willReturnMap([['/bar', $parentNode], ['/bar/asd', $targetTestNode]]);
633
+        $root->expects($this->any())
634
+            ->method('get')
635
+            ->willReturnMap([['/bar', $parentNode], ['/bar/asd', $targetTestNode]]);
636 636
 
637
-		$hooksRun = 0;
637
+        $hooksRun = 0;
638 638
 
639
-		$preListener = function (Node $sourceNode, Node $targetNode) use (&$hooksRun, $node): void {
640
-			$this->assertSame($node, $sourceNode);
641
-			$this->assertInstanceOf($this->getNodeClass(), $sourceNode);
642
-			$this->assertInstanceOf($this->getNonExistingNodeClass(), $targetNode);
643
-			$this->assertEquals('/bar/asd', $targetNode->getPath());
644
-			$hooksRun++;
645
-		};
646
-
647
-		$postListener = function (Node $sourceNode, Node $targetNode) use (&$hooksRun, $node, $targetTestNode): void {
648
-			$this->assertSame($node, $sourceNode);
649
-			$this->assertNotSame($node, $targetNode);
650
-			$this->assertSame($targetTestNode, $targetNode);
651
-			$this->assertInstanceOf($this->getNodeClass(), $sourceNode);
652
-			$this->assertInstanceOf($this->getNodeClass(), $targetNode);
653
-			$hooksRun++;
654
-		};
655
-
656
-		$preWriteListener = function (Node $targetNode) use (&$hooksRun): void {
657
-			$this->assertInstanceOf($this->getNonExistingNodeClass(), $targetNode);
658
-			$this->assertEquals('/bar/asd', $targetNode->getPath());
659
-			$hooksRun++;
660
-		};
661
-
662
-		$postWriteListener = function (Node $targetNode) use (&$hooksRun, $targetTestNode): void {
663
-			$this->assertSame($targetTestNode, $targetNode);
664
-			$hooksRun++;
665
-		};
639
+        $preListener = function (Node $sourceNode, Node $targetNode) use (&$hooksRun, $node): void {
640
+            $this->assertSame($node, $sourceNode);
641
+            $this->assertInstanceOf($this->getNodeClass(), $sourceNode);
642
+            $this->assertInstanceOf($this->getNonExistingNodeClass(), $targetNode);
643
+            $this->assertEquals('/bar/asd', $targetNode->getPath());
644
+            $hooksRun++;
645
+        };
646
+
647
+        $postListener = function (Node $sourceNode, Node $targetNode) use (&$hooksRun, $node, $targetTestNode): void {
648
+            $this->assertSame($node, $sourceNode);
649
+            $this->assertNotSame($node, $targetNode);
650
+            $this->assertSame($targetTestNode, $targetNode);
651
+            $this->assertInstanceOf($this->getNodeClass(), $sourceNode);
652
+            $this->assertInstanceOf($this->getNodeClass(), $targetNode);
653
+            $hooksRun++;
654
+        };
655
+
656
+        $preWriteListener = function (Node $targetNode) use (&$hooksRun): void {
657
+            $this->assertInstanceOf($this->getNonExistingNodeClass(), $targetNode);
658
+            $this->assertEquals('/bar/asd', $targetNode->getPath());
659
+            $hooksRun++;
660
+        };
661
+
662
+        $postWriteListener = function (Node $targetNode) use (&$hooksRun, $targetTestNode): void {
663
+            $this->assertSame($targetTestNode, $targetNode);
664
+            $hooksRun++;
665
+        };
666 666
 
667
-		$root->listen('\OC\Files', $preHookName, $preListener);
668
-		$root->listen('\OC\Files', 'preWrite', $preWriteListener);
669
-		$root->listen('\OC\Files', $postHookName, $postListener);
670
-		$root->listen('\OC\Files', 'postWrite', $postWriteListener);
667
+        $root->listen('\OC\Files', $preHookName, $preListener);
668
+        $root->listen('\OC\Files', 'preWrite', $preWriteListener);
669
+        $root->listen('\OC\Files', $postHookName, $postListener);
670
+        $root->listen('\OC\Files', 'postWrite', $postWriteListener);
671 671
 
672
-		$node->$operationMethod('/bar/asd');
673
-
674
-		$this->assertEquals(4, $hooksRun);
675
-	}
672
+        $node->$operationMethod('/bar/asd');
673
+
674
+        $this->assertEquals(4, $hooksRun);
675
+    }
676 676
 
677 677
 
678
-	public function testMoveNotPermitted(): void {
679
-		$this->expectException(NotPermittedException::class);
678
+    public function testMoveNotPermitted(): void {
679
+        $this->expectException(NotPermittedException::class);
680 680
 
681
-		$this->view->expects($this->any())
682
-			->method('getFileInfo')
683
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_READ]));
681
+        $this->view->expects($this->any())
682
+            ->method('getFileInfo')
683
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_READ]));
684 684
 
685
-		$this->view->expects($this->never())
686
-			->method('rename');
685
+        $this->view->expects($this->never())
686
+            ->method('rename');
687 687
 
688
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
689
-		$parentNode = new Folder($this->root, $this->view, '/bar');
688
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
689
+        $parentNode = new Folder($this->root, $this->view, '/bar');
690 690
 
691
-		$this->root->expects($this->once())
692
-			->method('get')
693
-			->with('/bar')
694
-			->willReturn($parentNode);
691
+        $this->root->expects($this->once())
692
+            ->method('get')
693
+            ->with('/bar')
694
+            ->willReturn($parentNode);
695 695
 
696
-		$node->move('/bar/asd');
697
-	}
696
+        $node->move('/bar/asd');
697
+    }
698 698
 
699 699
 
700
-	public function testMoveNoParent(): void {
701
-		$this->expectException(NotFoundException::class);
700
+    public function testMoveNoParent(): void {
701
+        $this->expectException(NotFoundException::class);
702 702
 
703
-		/**
704
-		 * @var Storage|\PHPUnit\Framework\MockObject\MockObject $storage
705
-		 */
706
-		$storage = $this->createMock('\OC\Files\Storage\Storage');
703
+        /**
704
+         * @var Storage|\PHPUnit\Framework\MockObject\MockObject $storage
705
+         */
706
+        $storage = $this->createMock('\OC\Files\Storage\Storage');
707 707
 
708
-		$storage->expects($this->never())
709
-			->method('rename');
708
+        $storage->expects($this->never())
709
+            ->method('rename');
710 710
 
711
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
711
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
712 712
 
713
-		$this->root->expects($this->once())
714
-			->method('get')
715
-			->with('/bar')
716
-			->willThrowException(new NotFoundException());
713
+        $this->root->expects($this->once())
714
+            ->method('get')
715
+            ->with('/bar')
716
+            ->willThrowException(new NotFoundException());
717 717
 
718
-		$node->move('/bar/asd');
719
-	}
718
+        $node->move('/bar/asd');
719
+    }
720 720
 
721 721
 
722
-	public function testMoveParentIsFile(): void {
723
-		$this->expectException(NotPermittedException::class);
722
+    public function testMoveParentIsFile(): void {
723
+        $this->expectException(NotPermittedException::class);
724 724
 
725
-		$this->view->expects($this->never())
726
-			->method('rename');
725
+        $this->view->expects($this->never())
726
+            ->method('rename');
727 727
 
728
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
729
-		$parentNode = new File($this->root, $this->view, '/bar');
728
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
729
+        $parentNode = new File($this->root, $this->view, '/bar');
730 730
 
731
-		$this->root->expects($this->once())
732
-			->method('get')
733
-			->with('/bar')
734
-			->willReturn($parentNode);
731
+        $this->root->expects($this->once())
732
+            ->method('get')
733
+            ->with('/bar')
734
+            ->willReturn($parentNode);
735 735
 
736
-		$node->move('/bar/asd');
737
-	}
736
+        $node->move('/bar/asd');
737
+    }
738 738
 
739 739
 
740
-	public function testMoveFailed(): void {
741
-		$this->expectException(NotPermittedException::class);
740
+    public function testMoveFailed(): void {
741
+        $this->expectException(NotPermittedException::class);
742 742
 
743
-		$this->view->expects($this->any())
744
-			->method('rename')
745
-			->with('/bar/foo', '/bar/asd')
746
-			->willReturn(false);
743
+        $this->view->expects($this->any())
744
+            ->method('rename')
745
+            ->with('/bar/foo', '/bar/asd')
746
+            ->willReturn(false);
747 747
 
748
-		$this->view->expects($this->any())
749
-			->method('getFileInfo')
750
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL, 'fileid' => 1]));
748
+        $this->view->expects($this->any())
749
+            ->method('getFileInfo')
750
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL, 'fileid' => 1]));
751 751
 
752
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
753
-		$parentNode = new Folder($this->root, $this->view, '/bar');
752
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
753
+        $parentNode = new Folder($this->root, $this->view, '/bar');
754 754
 
755
-		$this->root->expects($this->any())
756
-			->method('get')
757
-			->willReturnMap([['/bar', $parentNode], ['/bar/asd', $node]]);
755
+        $this->root->expects($this->any())
756
+            ->method('get')
757
+            ->willReturnMap([['/bar', $parentNode], ['/bar/asd', $node]]);
758 758
 
759
-		$node->move('/bar/asd');
760
-	}
759
+        $node->move('/bar/asd');
760
+    }
761 761
 
762 762
 
763
-	public function testCopyFailed(): void {
764
-		$this->expectException(NotPermittedException::class);
763
+    public function testCopyFailed(): void {
764
+        $this->expectException(NotPermittedException::class);
765 765
 
766
-		$this->view->expects($this->any())
767
-			->method('copy')
768
-			->with('/bar/foo', '/bar/asd')
769
-			->willReturn(false);
766
+        $this->view->expects($this->any())
767
+            ->method('copy')
768
+            ->with('/bar/foo', '/bar/asd')
769
+            ->willReturn(false);
770 770
 
771
-		$this->view->expects($this->any())
772
-			->method('getFileInfo')
773
-			->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL, 'fileid' => 1]));
771
+        $this->view->expects($this->any())
772
+            ->method('getFileInfo')
773
+            ->willReturn($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL, 'fileid' => 1]));
774 774
 
775
-		$node = $this->createTestNode($this->root, $this->view, '/bar/foo');
776
-		$parentNode = new Folder($this->root, $this->view, '/bar');
775
+        $node = $this->createTestNode($this->root, $this->view, '/bar/foo');
776
+        $parentNode = new Folder($this->root, $this->view, '/bar');
777 777
 
778
-		$this->root->expects($this->any())
779
-			->method('get')
780
-			->willReturnMap([['/bar', $parentNode], ['/bar/asd', $node]]);
778
+        $this->root->expects($this->any())
779
+            ->method('get')
780
+            ->willReturnMap([['/bar', $parentNode], ['/bar/asd', $node]]);
781 781
 
782
-		$node->copy('/bar/asd');
783
-	}
782
+        $node->copy('/bar/asd');
783
+    }
784 784
 }
Please login to merge, or discard this patch.