Passed
Push — master ( 873501...d2df81 )
by Maxence
14:59 queued 12s
created
apps/settings/lib/Controller/ChangePasswordController.php 2 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -229,7 +229,7 @@
 block discarded – undo
229 229
 						'message' => $this->l->t('Please provide an admin recovery password; otherwise, all user data will be lost.'),
230 230
 					]
231 231
 				]);
232
-			} elseif ($recoveryEnabledForUser && ! $validRecoveryPassword) {
232
+			} elseif ($recoveryEnabledForUser && !$validRecoveryPassword) {
233 233
 				return new JSONResponse([
234 234
 					'status' => 'error',
235 235
 					'data' => [
Please login to merge, or discard this patch.
Indentation   +217 added lines, -217 removed lines patch added patch discarded remove patch
@@ -49,235 +49,235 @@
 block discarded – undo
49 49
 use OCP\IUserSession;
50 50
 
51 51
 class ChangePasswordController extends Controller {
52
-	private ?string $userId;
53
-	private IUserManager $userManager;
54
-	private IL10N $l;
55
-	private GroupManager $groupManager;
56
-	private Session $userSession;
57
-	private IAppManager $appManager;
52
+    private ?string $userId;
53
+    private IUserManager $userManager;
54
+    private IL10N $l;
55
+    private GroupManager $groupManager;
56
+    private Session $userSession;
57
+    private IAppManager $appManager;
58 58
 
59
-	public function __construct(string $appName,
60
-								IRequest $request,
61
-								?string $userId,
62
-								IUserManager $userManager,
63
-								IUserSession $userSession,
64
-								IGroupManager $groupManager,
65
-								IAppManager $appManager,
66
-								IL10N $l) {
67
-		parent::__construct($appName, $request);
59
+    public function __construct(string $appName,
60
+                                IRequest $request,
61
+                                ?string $userId,
62
+                                IUserManager $userManager,
63
+                                IUserSession $userSession,
64
+                                IGroupManager $groupManager,
65
+                                IAppManager $appManager,
66
+                                IL10N $l) {
67
+        parent::__construct($appName, $request);
68 68
 
69
-		$this->userId = $userId;
70
-		$this->userManager = $userManager;
71
-		$this->userSession = $userSession;
72
-		$this->groupManager = $groupManager;
73
-		$this->appManager = $appManager;
74
-		$this->l = $l;
75
-	}
69
+        $this->userId = $userId;
70
+        $this->userManager = $userManager;
71
+        $this->userSession = $userSession;
72
+        $this->groupManager = $groupManager;
73
+        $this->appManager = $appManager;
74
+        $this->l = $l;
75
+    }
76 76
 
77
-	/**
78
-	 * @NoAdminRequired
79
-	 * @NoSubAdminRequired
80
-	 * @BruteForceProtection(action=changePersonalPassword)
81
-	 */
82
-	public function changePersonalPassword(string $oldpassword = '', string $newpassword = null): JSONResponse {
83
-		$loginName = $this->userSession->getLoginName();
84
-		/** @var IUser $user */
85
-		$user = $this->userManager->checkPassword($loginName, $oldpassword);
86
-		if ($user === false) {
87
-			$response = new JSONResponse([
88
-				'status' => 'error',
89
-				'data' => [
90
-					'message' => $this->l->t('Wrong password'),
91
-				],
92
-			]);
93
-			$response->throttle();
94
-			return $response;
95
-		}
77
+    /**
78
+     * @NoAdminRequired
79
+     * @NoSubAdminRequired
80
+     * @BruteForceProtection(action=changePersonalPassword)
81
+     */
82
+    public function changePersonalPassword(string $oldpassword = '', string $newpassword = null): JSONResponse {
83
+        $loginName = $this->userSession->getLoginName();
84
+        /** @var IUser $user */
85
+        $user = $this->userManager->checkPassword($loginName, $oldpassword);
86
+        if ($user === false) {
87
+            $response = new JSONResponse([
88
+                'status' => 'error',
89
+                'data' => [
90
+                    'message' => $this->l->t('Wrong password'),
91
+                ],
92
+            ]);
93
+            $response->throttle();
94
+            return $response;
95
+        }
96 96
 
97
-		try {
98
-			if ($newpassword === null || strlen($newpassword) > IUserManager::MAX_PASSWORD_LENGTH || $user->setPassword($newpassword) === false) {
99
-				return new JSONResponse([
100
-					'status' => 'error',
101
-					'data' => [
102
-						'message' => $this->l->t('Unable to change personal password'),
103
-					],
104
-				]);
105
-			}
106
-			// password policy app throws exception
107
-		} catch (HintException $e) {
108
-			return new JSONResponse([
109
-				'status' => 'error',
110
-				'data' => [
111
-					'message' => $e->getHint(),
112
-				],
113
-			]);
114
-		}
97
+        try {
98
+            if ($newpassword === null || strlen($newpassword) > IUserManager::MAX_PASSWORD_LENGTH || $user->setPassword($newpassword) === false) {
99
+                return new JSONResponse([
100
+                    'status' => 'error',
101
+                    'data' => [
102
+                        'message' => $this->l->t('Unable to change personal password'),
103
+                    ],
104
+                ]);
105
+            }
106
+            // password policy app throws exception
107
+        } catch (HintException $e) {
108
+            return new JSONResponse([
109
+                'status' => 'error',
110
+                'data' => [
111
+                    'message' => $e->getHint(),
112
+                ],
113
+            ]);
114
+        }
115 115
 
116
-		$this->userSession->updateSessionTokenPassword($newpassword);
116
+        $this->userSession->updateSessionTokenPassword($newpassword);
117 117
 
118
-		return new JSONResponse([
119
-			'status' => 'success',
120
-			'data' => [
121
-				'message' => $this->l->t('Saved'),
122
-			],
123
-		]);
124
-	}
118
+        return new JSONResponse([
119
+            'status' => 'success',
120
+            'data' => [
121
+                'message' => $this->l->t('Saved'),
122
+            ],
123
+        ]);
124
+    }
125 125
 
126
-	/**
127
-	 * @NoAdminRequired
128
-	 * @PasswordConfirmationRequired
129
-	 */
130
-	public function changeUserPassword(string $username = null, string $password = null, string $recoveryPassword = null): JSONResponse {
131
-		if ($username === null) {
132
-			return new JSONResponse([
133
-				'status' => 'error',
134
-				'data' => [
135
-					'message' => $this->l->t('No user supplied'),
136
-				],
137
-			]);
138
-		}
126
+    /**
127
+     * @NoAdminRequired
128
+     * @PasswordConfirmationRequired
129
+     */
130
+    public function changeUserPassword(string $username = null, string $password = null, string $recoveryPassword = null): JSONResponse {
131
+        if ($username === null) {
132
+            return new JSONResponse([
133
+                'status' => 'error',
134
+                'data' => [
135
+                    'message' => $this->l->t('No user supplied'),
136
+                ],
137
+            ]);
138
+        }
139 139
 
140
-		if ($password === null) {
141
-			return new JSONResponse([
142
-				'status' => 'error',
143
-				'data' => [
144
-					'message' => $this->l->t('Unable to change password'),
145
-				],
146
-			]);
147
-		}
140
+        if ($password === null) {
141
+            return new JSONResponse([
142
+                'status' => 'error',
143
+                'data' => [
144
+                    'message' => $this->l->t('Unable to change password'),
145
+                ],
146
+            ]);
147
+        }
148 148
 
149
-		if (strlen($password) > IUserManager::MAX_PASSWORD_LENGTH) {
150
-			return new JSONResponse([
151
-				'status' => 'error',
152
-				'data' => [
153
-					'message' => $this->l->t('Unable to change password. Password too long.'),
154
-				],
155
-			]);
156
-		}
149
+        if (strlen($password) > IUserManager::MAX_PASSWORD_LENGTH) {
150
+            return new JSONResponse([
151
+                'status' => 'error',
152
+                'data' => [
153
+                    'message' => $this->l->t('Unable to change password. Password too long.'),
154
+                ],
155
+            ]);
156
+        }
157 157
 
158
-		$currentUser = $this->userSession->getUser();
159
-		$targetUser = $this->userManager->get($username);
160
-		if ($currentUser === null || $targetUser === null ||
161
-			!($this->groupManager->isAdmin($this->userId) ||
162
-			 $this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $targetUser))
163
-		) {
164
-			return new JSONResponse([
165
-				'status' => 'error',
166
-				'data' => [
167
-					'message' => $this->l->t('Authentication error'),
168
-				],
169
-			]);
170
-		}
158
+        $currentUser = $this->userSession->getUser();
159
+        $targetUser = $this->userManager->get($username);
160
+        if ($currentUser === null || $targetUser === null ||
161
+            !($this->groupManager->isAdmin($this->userId) ||
162
+             $this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $targetUser))
163
+        ) {
164
+            return new JSONResponse([
165
+                'status' => 'error',
166
+                'data' => [
167
+                    'message' => $this->l->t('Authentication error'),
168
+                ],
169
+            ]);
170
+        }
171 171
 
172
-		if ($this->appManager->isEnabledForUser('encryption')) {
173
-			//handle the recovery case
174
-			$crypt = new \OCA\Encryption\Crypto\Crypt(
175
-				\OC::$server->getLogger(),
176
-				\OC::$server->getUserSession(),
177
-				\OC::$server->getConfig(),
178
-				\OC::$server->getL10N('encryption'));
179
-			$keyStorage = \OC::$server->getEncryptionKeyStorage();
180
-			$util = new \OCA\Encryption\Util(
181
-				new \OC\Files\View(),
182
-				$crypt,
183
-				\OC::$server->getLogger(),
184
-				\OC::$server->getUserSession(),
185
-				\OC::$server->getConfig(),
186
-				\OC::$server->getUserManager());
187
-			$keyManager = new \OCA\Encryption\KeyManager(
188
-				$keyStorage,
189
-				$crypt,
190
-				\OC::$server->getConfig(),
191
-				\OC::$server->getUserSession(),
192
-				new \OCA\Encryption\Session(\OC::$server->getSession()),
193
-				\OC::$server->getLogger(),
194
-				$util,
195
-				\OC::$server->getLockingProvider()
196
-			);
197
-			$recovery = new \OCA\Encryption\Recovery(
198
-				\OC::$server->getUserSession(),
199
-				$crypt,
200
-				$keyManager,
201
-				\OC::$server->getConfig(),
202
-				\OC::$server->getEncryptionFilesHelper(),
203
-				new \OC\Files\View());
204
-			$recoveryAdminEnabled = $recovery->isRecoveryKeyEnabled();
172
+        if ($this->appManager->isEnabledForUser('encryption')) {
173
+            //handle the recovery case
174
+            $crypt = new \OCA\Encryption\Crypto\Crypt(
175
+                \OC::$server->getLogger(),
176
+                \OC::$server->getUserSession(),
177
+                \OC::$server->getConfig(),
178
+                \OC::$server->getL10N('encryption'));
179
+            $keyStorage = \OC::$server->getEncryptionKeyStorage();
180
+            $util = new \OCA\Encryption\Util(
181
+                new \OC\Files\View(),
182
+                $crypt,
183
+                \OC::$server->getLogger(),
184
+                \OC::$server->getUserSession(),
185
+                \OC::$server->getConfig(),
186
+                \OC::$server->getUserManager());
187
+            $keyManager = new \OCA\Encryption\KeyManager(
188
+                $keyStorage,
189
+                $crypt,
190
+                \OC::$server->getConfig(),
191
+                \OC::$server->getUserSession(),
192
+                new \OCA\Encryption\Session(\OC::$server->getSession()),
193
+                \OC::$server->getLogger(),
194
+                $util,
195
+                \OC::$server->getLockingProvider()
196
+            );
197
+            $recovery = new \OCA\Encryption\Recovery(
198
+                \OC::$server->getUserSession(),
199
+                $crypt,
200
+                $keyManager,
201
+                \OC::$server->getConfig(),
202
+                \OC::$server->getEncryptionFilesHelper(),
203
+                new \OC\Files\View());
204
+            $recoveryAdminEnabled = $recovery->isRecoveryKeyEnabled();
205 205
 
206
-			$validRecoveryPassword = false;
207
-			$recoveryEnabledForUser = false;
208
-			if ($recoveryAdminEnabled) {
209
-				$validRecoveryPassword = $keyManager->checkRecoveryPassword($recoveryPassword);
210
-				$recoveryEnabledForUser = $recovery->isRecoveryEnabledForUser($username);
211
-			}
206
+            $validRecoveryPassword = false;
207
+            $recoveryEnabledForUser = false;
208
+            if ($recoveryAdminEnabled) {
209
+                $validRecoveryPassword = $keyManager->checkRecoveryPassword($recoveryPassword);
210
+                $recoveryEnabledForUser = $recovery->isRecoveryEnabledForUser($username);
211
+            }
212 212
 
213
-			if ($recoveryEnabledForUser && $recoveryPassword === '') {
214
-				return new JSONResponse([
215
-					'status' => 'error',
216
-					'data' => [
217
-						'message' => $this->l->t('Please provide an admin recovery password; otherwise, all user data will be lost.'),
218
-					]
219
-				]);
220
-			} elseif ($recoveryEnabledForUser && ! $validRecoveryPassword) {
221
-				return new JSONResponse([
222
-					'status' => 'error',
223
-					'data' => [
224
-						'message' => $this->l->t('Wrong admin recovery password. Please check the password and try again.'),
225
-					]
226
-				]);
227
-			} else { // now we know that everything is fine regarding the recovery password, let's try to change the password
228
-				try {
229
-					$result = $targetUser->setPassword($password, $recoveryPassword);
230
-					// password policy app throws exception
231
-				} catch (HintException $e) {
232
-					return new JSONResponse([
233
-						'status' => 'error',
234
-						'data' => [
235
-							'message' => $e->getHint(),
236
-						],
237
-					]);
238
-				}
239
-				if (!$result && $recoveryEnabledForUser) {
240
-					return new JSONResponse([
241
-						'status' => 'error',
242
-						'data' => [
243
-							'message' => $this->l->t('Backend does not support password change, but the user\'s encryption key was updated.'),
244
-						]
245
-					]);
246
-				} elseif (!$result && !$recoveryEnabledForUser) {
247
-					return new JSONResponse([
248
-						'status' => 'error',
249
-						'data' => [
250
-							'message' => $this->l->t('Unable to change password'),
251
-						]
252
-					]);
253
-				}
254
-			}
255
-		} else {
256
-			try {
257
-				if ($targetUser->setPassword($password) === false) {
258
-					return new JSONResponse([
259
-						'status' => 'error',
260
-						'data' => [
261
-							'message' => $this->l->t('Unable to change password'),
262
-						],
263
-					]);
264
-				}
265
-				// password policy app throws exception
266
-			} catch (HintException $e) {
267
-				return new JSONResponse([
268
-					'status' => 'error',
269
-					'data' => [
270
-						'message' => $e->getHint(),
271
-					],
272
-				]);
273
-			}
274
-		}
213
+            if ($recoveryEnabledForUser && $recoveryPassword === '') {
214
+                return new JSONResponse([
215
+                    'status' => 'error',
216
+                    'data' => [
217
+                        'message' => $this->l->t('Please provide an admin recovery password; otherwise, all user data will be lost.'),
218
+                    ]
219
+                ]);
220
+            } elseif ($recoveryEnabledForUser && ! $validRecoveryPassword) {
221
+                return new JSONResponse([
222
+                    'status' => 'error',
223
+                    'data' => [
224
+                        'message' => $this->l->t('Wrong admin recovery password. Please check the password and try again.'),
225
+                    ]
226
+                ]);
227
+            } else { // now we know that everything is fine regarding the recovery password, let's try to change the password
228
+                try {
229
+                    $result = $targetUser->setPassword($password, $recoveryPassword);
230
+                    // password policy app throws exception
231
+                } catch (HintException $e) {
232
+                    return new JSONResponse([
233
+                        'status' => 'error',
234
+                        'data' => [
235
+                            'message' => $e->getHint(),
236
+                        ],
237
+                    ]);
238
+                }
239
+                if (!$result && $recoveryEnabledForUser) {
240
+                    return new JSONResponse([
241
+                        'status' => 'error',
242
+                        'data' => [
243
+                            'message' => $this->l->t('Backend does not support password change, but the user\'s encryption key was updated.'),
244
+                        ]
245
+                    ]);
246
+                } elseif (!$result && !$recoveryEnabledForUser) {
247
+                    return new JSONResponse([
248
+                        'status' => 'error',
249
+                        'data' => [
250
+                            'message' => $this->l->t('Unable to change password'),
251
+                        ]
252
+                    ]);
253
+                }
254
+            }
255
+        } else {
256
+            try {
257
+                if ($targetUser->setPassword($password) === false) {
258
+                    return new JSONResponse([
259
+                        'status' => 'error',
260
+                        'data' => [
261
+                            'message' => $this->l->t('Unable to change password'),
262
+                        ],
263
+                    ]);
264
+                }
265
+                // password policy app throws exception
266
+            } catch (HintException $e) {
267
+                return new JSONResponse([
268
+                    'status' => 'error',
269
+                    'data' => [
270
+                        'message' => $e->getHint(),
271
+                    ],
272
+                ]);
273
+            }
274
+        }
275 275
 
276
-		return new JSONResponse([
277
-			'status' => 'success',
278
-			'data' => [
279
-				'username' => $username,
280
-			],
281
-		]);
282
-	}
276
+        return new JSONResponse([
277
+            'status' => 'success',
278
+            'data' => [
279
+                'username' => $username,
280
+            ],
281
+        ]);
282
+    }
283 283
 }
Please login to merge, or discard this patch.
apps/settings/templates/settings/admin/overview.php 3 patches
Indentation   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -46,9 +46,9 @@
 block discarded – undo
46 46
 	</div>
47 47
 
48 48
 	<div id="postsetupchecks" data-check-wellknown="<?php if ($_['checkForWorkingWellKnownSetup']) {
49
-	p('true');
49
+    p('true');
50 50
 } else {
51
-	p('false');
51
+    p('false');
52 52
 } ?>">
53 53
 		<ul class="errors hidden"></ul>
54 54
 		<ul class="warnings hidden"></ul>
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -28,21 +28,21 @@  discard block
 block discarded – undo
28 28
 ?>
29 29
 
30 30
 <div id="security-warning" class="section">
31
-	<h2 class="inlineblock"><?php p($l->t('Security & setup warnings'));?></h2>
32
-	<a target="_blank" rel="noreferrer" class="icon-info" title="<?php p($l->t('Open documentation'));?>" href="<?php p(link_to_docs('admin-warnings')); ?>"></a>
33
-	<p class="settings-hint"><?php p($l->t('It\'s important for the security and performance of your instance that everything is configured correctly. To help you with that we are doing some automatic checks. Please see the linked documentation for more information.'));?></p>
31
+	<h2 class="inlineblock"><?php p($l->t('Security & setup warnings')); ?></h2>
32
+	<a target="_blank" rel="noreferrer" class="icon-info" title="<?php p($l->t('Open documentation')); ?>" href="<?php p(link_to_docs('admin-warnings')); ?>"></a>
33
+	<p class="settings-hint"><?php p($l->t('It\'s important for the security and performance of your instance that everything is configured correctly. To help you with that we are doing some automatic checks. Please see the linked documentation for more information.')); ?></p>
34 34
 
35 35
 	<div id="security-warning-state-ok" class="hidden">
36
-		<span class="icon icon-checkmark-white"></span><span class="message"><?php p($l->t('All checks passed.'));?></span>
36
+		<span class="icon icon-checkmark-white"></span><span class="message"><?php p($l->t('All checks passed.')); ?></span>
37 37
 	</div>
38 38
 	<div id="security-warning-state-failure" class="hidden">
39
-		<span class="icon icon-close-white"></span><span class="message"><?php p($l->t('There are some errors regarding your setup.'));?></span>
39
+		<span class="icon icon-close-white"></span><span class="message"><?php p($l->t('There are some errors regarding your setup.')); ?></span>
40 40
 	</div>
41 41
 	<div id="security-warning-state-warning" class="hidden">
42
-		<span class="icon icon-error-white"></span><span class="message"><?php p($l->t('There are some warnings regarding your setup.'));?></span>
42
+		<span class="icon icon-error-white"></span><span class="message"><?php p($l->t('There are some warnings regarding your setup.')); ?></span>
43 43
 	</div>
44 44
 	<div id="security-warning-state-loading">
45
-		<span class="icon loading"></span><span class="message"><?php p($l->t('Checking for system and security issues.'));?></span>
45
+		<span class="icon loading"></span><span class="message"><?php p($l->t('Checking for system and security issues.')); ?></span>
46 46
 	</div>
47 47
 
48 48
 	<div id="postsetupchecks" data-check-wellknown="<?php if ($_['checkForWorkingWellKnownSetup']) {
@@ -59,14 +59,14 @@  discard block
 block discarded – undo
59 59
 	</p>
60 60
 
61 61
 	<p class="extra-top-margin">
62
-		<?php print_unescaped($l->t('Check the security of your Nextcloud over <a target="_blank" rel="noreferrer noopener" href="%s">our security scan ↗</a>.', ['https://scan.nextcloud.com']));?>
62
+		<?php print_unescaped($l->t('Check the security of your Nextcloud over <a target="_blank" rel="noreferrer noopener" href="%s">our security scan ↗</a>.', ['https://scan.nextcloud.com'])); ?>
63 63
 	</p>
64 64
 
65 65
 </div>
66 66
 
67 67
 <div id="version" class="section">
68 68
 	<!-- should be the last part, so Updater can follow if enabled (it has no heading therefore). -->
69
-	<h2><?php p($l->t('Version'));?></h2>
69
+	<h2><?php p($l->t('Version')); ?></h2>
70 70
 	<?php if ($theme->getTitle() === 'Nextcloud'): ?>
71 71
 	<p><strong><a href="<?php print_unescaped($theme->getBaseUrl()); ?>" rel="noreferrer noopener" target="_blank">Nextcloud Hub 3</a> (<?php p(OC_Util::getHumanVersion()) ?>)</strong></p>
72 72
 	<?php else: ?>
Please login to merge, or discard this patch.
Braces   +5 added lines, -2 removed lines patch added patch discarded remove patch
@@ -69,7 +69,10 @@
 block discarded – undo
69 69
 	<h2><?php p($l->t('Version'));?></h2>
70 70
 	<?php if ($theme->getTitle() === 'Nextcloud'): ?>
71 71
 	<p><strong><a href="<?php print_unescaped($theme->getBaseUrl()); ?>" rel="noreferrer noopener" target="_blank">Nextcloud Hub 3</a> (<?php p(OC_Util::getHumanVersion()) ?>)</strong></p>
72
-	<?php else: ?>
73
-	<p><strong><a href="<?php print_unescaped($theme->getBaseUrl()); ?>" rel="noreferrer noopener" target="_blank"><?php p($theme->getTitle()); ?></a> <?php p(OC_Util::getHumanVersion()) ?></strong></p>
72
+	<?php else {
73
+    : ?>
74
+	<p><strong><a href="<?php print_unescaped($theme->getBaseUrl());
75
+}
76
+?>" rel="noreferrer noopener" target="_blank"><?php p($theme->getTitle()); ?></a> <?php p(OC_Util::getHumanVersion()) ?></strong></p>
74 77
 	<?php endif; ?>
75 78
 </div>
Please login to merge, or discard this patch.
apps/settings/templates/settings/additional.php 2 patches
Indentation   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -27,7 +27,7 @@
 block discarded – undo
27 27
 ?>
28 28
 
29 29
 <?php foreach ($_['forms'] as $form) {
30
-	if (isset($form['form'])) {?>
30
+    if (isset($form['form'])) {?>
31 31
 		<div id="<?php isset($form['anchor']) ? p($form['anchor']) : p('');?>"><?php print_unescaped($form['form']);?></div>
32 32
 	<?php }
33 33
 } ?>
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -28,6 +28,6 @@
 block discarded – undo
28 28
 
29 29
 <?php foreach ($_['forms'] as $form) {
30 30
 	if (isset($form['form'])) {?>
31
-		<div id="<?php isset($form['anchor']) ? p($form['anchor']) : p('');?>"><?php print_unescaped($form['form']);?></div>
31
+		<div id="<?php isset($form['anchor']) ? p($form['anchor']) : p(''); ?>"><?php print_unescaped($form['form']); ?></div>
32 32
 	<?php }
33 33
 } ?>
Please login to merge, or discard this patch.
apps/settings/templates/settings-vue.php 1 patch
Indentation   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -26,7 +26,7 @@
 block discarded – undo
26 26
 
27 27
 // Do we have some data to inject ?
28 28
 if (is_array($_['serverData'])) {
29
-	?>
29
+    ?>
30 30
 <span id="serverData" data-server="<?php p(json_encode($_['serverData'])); ?>"></span>
31 31
 <?php
32 32
 } ?>
Please login to merge, or discard this patch.
apps/files/lib/Settings/PersonalSettings.php 1 patch
Indentation   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -31,15 +31,15 @@
 block discarded – undo
31 31
 use OCP\Settings\ISettings;
32 32
 
33 33
 class PersonalSettings implements ISettings {
34
-	public function getForm(): TemplateResponse {
35
-		return new TemplateResponse(Application::APP_ID, 'settings-personal');
36
-	}
34
+    public function getForm(): TemplateResponse {
35
+        return new TemplateResponse(Application::APP_ID, 'settings-personal');
36
+    }
37 37
 
38
-	public function getSection(): string {
39
-		return 'sharing';
40
-	}
38
+    public function getSection(): string {
39
+        return 'sharing';
40
+    }
41 41
 
42
-	public function getPriority(): int {
43
-		return 90;
44
-	}
42
+    public function getPriority(): int {
43
+        return 90;
44
+    }
45 45
 }
Please login to merge, or discard this patch.
apps/files/lib/Collaboration/Resources/ResourceProvider.php 1 patch
Indentation   +96 added lines, -96 removed lines patch added patch discarded remove patch
@@ -37,100 +37,100 @@
 block discarded – undo
37 37
 use OCP\IUser;
38 38
 
39 39
 class ResourceProvider implements IProvider {
40
-	public const RESOURCE_TYPE = 'file';
41
-
42
-	/** @var IRootFolder */
43
-	protected $rootFolder;
44
-	/** @var IPreview */
45
-	private $preview;
46
-	/** @var IURLGenerator */
47
-	private $urlGenerator;
48
-
49
-	/** @var array */
50
-	protected $nodes = [];
51
-
52
-	public function __construct(IRootFolder $rootFolder,
53
-								IPreview $preview,
54
-								IURLGenerator $urlGenerator) {
55
-		$this->rootFolder = $rootFolder;
56
-		$this->preview = $preview;
57
-		$this->urlGenerator = $urlGenerator;
58
-	}
59
-
60
-	private function getNode(IResource $resource): ?Node {
61
-		if (isset($this->nodes[(int) $resource->getId()])) {
62
-			return $this->nodes[(int) $resource->getId()];
63
-		}
64
-		$nodes = $this->rootFolder->getById((int) $resource->getId());
65
-		if (!empty($nodes)) {
66
-			$this->nodes[(int) $resource->getId()] = array_shift($nodes);
67
-			return $this->nodes[(int) $resource->getId()];
68
-		}
69
-		return null;
70
-	}
71
-
72
-	/**
73
-	 * @param IResource $resource
74
-	 * @return array
75
-	 * @since 16.0.0
76
-	 */
77
-	public function getResourceRichObject(IResource $resource): array {
78
-		if (isset($this->nodes[(int) $resource->getId()])) {
79
-			$node = $this->nodes[(int) $resource->getId()]->getPath();
80
-		} else {
81
-			$node = $this->getNode($resource);
82
-		}
83
-
84
-		if ($node instanceof Node) {
85
-			$link = $this->urlGenerator->linkToRouteAbsolute(
86
-				'files.viewcontroller.showFile',
87
-				['fileid' => $resource->getId()]
88
-			);
89
-			return [
90
-				'type' => 'file',
91
-				'id' => $resource->getId(),
92
-				'name' => $node->getName(),
93
-				'path' => $node->getInternalPath(),
94
-				'link' => $link,
95
-				'mimetype' => $node->getMimetype(),
96
-				'preview-available' => $this->preview->isAvailable($node),
97
-			];
98
-		}
99
-
100
-		throw new ResourceException('File not found');
101
-	}
102
-
103
-	/**
104
-	 * Can a user/guest access the collection
105
-	 *
106
-	 * @param IResource $resource
107
-	 * @param IUser $user
108
-	 * @return bool
109
-	 * @since 16.0.0
110
-	 */
111
-	public function canAccessResource(IResource $resource, IUser $user = null): bool {
112
-		if (!$user instanceof IUser) {
113
-			return false;
114
-		}
115
-
116
-		$userFolder = $this->rootFolder->getUserFolder($user->getUID());
117
-		$nodes = $userFolder->getById((int) $resource->getId());
118
-
119
-		if (!empty($nodes)) {
120
-			$this->nodes[(int) $resource->getId()] = array_shift($nodes);
121
-			return true;
122
-		}
123
-
124
-		return false;
125
-	}
126
-
127
-	/**
128
-	 * Get the resource type of the provider
129
-	 *
130
-	 * @return string
131
-	 * @since 16.0.0
132
-	 */
133
-	public function getType(): string {
134
-		return self::RESOURCE_TYPE;
135
-	}
40
+    public const RESOURCE_TYPE = 'file';
41
+
42
+    /** @var IRootFolder */
43
+    protected $rootFolder;
44
+    /** @var IPreview */
45
+    private $preview;
46
+    /** @var IURLGenerator */
47
+    private $urlGenerator;
48
+
49
+    /** @var array */
50
+    protected $nodes = [];
51
+
52
+    public function __construct(IRootFolder $rootFolder,
53
+                                IPreview $preview,
54
+                                IURLGenerator $urlGenerator) {
55
+        $this->rootFolder = $rootFolder;
56
+        $this->preview = $preview;
57
+        $this->urlGenerator = $urlGenerator;
58
+    }
59
+
60
+    private function getNode(IResource $resource): ?Node {
61
+        if (isset($this->nodes[(int) $resource->getId()])) {
62
+            return $this->nodes[(int) $resource->getId()];
63
+        }
64
+        $nodes = $this->rootFolder->getById((int) $resource->getId());
65
+        if (!empty($nodes)) {
66
+            $this->nodes[(int) $resource->getId()] = array_shift($nodes);
67
+            return $this->nodes[(int) $resource->getId()];
68
+        }
69
+        return null;
70
+    }
71
+
72
+    /**
73
+     * @param IResource $resource
74
+     * @return array
75
+     * @since 16.0.0
76
+     */
77
+    public function getResourceRichObject(IResource $resource): array {
78
+        if (isset($this->nodes[(int) $resource->getId()])) {
79
+            $node = $this->nodes[(int) $resource->getId()]->getPath();
80
+        } else {
81
+            $node = $this->getNode($resource);
82
+        }
83
+
84
+        if ($node instanceof Node) {
85
+            $link = $this->urlGenerator->linkToRouteAbsolute(
86
+                'files.viewcontroller.showFile',
87
+                ['fileid' => $resource->getId()]
88
+            );
89
+            return [
90
+                'type' => 'file',
91
+                'id' => $resource->getId(),
92
+                'name' => $node->getName(),
93
+                'path' => $node->getInternalPath(),
94
+                'link' => $link,
95
+                'mimetype' => $node->getMimetype(),
96
+                'preview-available' => $this->preview->isAvailable($node),
97
+            ];
98
+        }
99
+
100
+        throw new ResourceException('File not found');
101
+    }
102
+
103
+    /**
104
+     * Can a user/guest access the collection
105
+     *
106
+     * @param IResource $resource
107
+     * @param IUser $user
108
+     * @return bool
109
+     * @since 16.0.0
110
+     */
111
+    public function canAccessResource(IResource $resource, IUser $user = null): bool {
112
+        if (!$user instanceof IUser) {
113
+            return false;
114
+        }
115
+
116
+        $userFolder = $this->rootFolder->getUserFolder($user->getUID());
117
+        $nodes = $userFolder->getById((int) $resource->getId());
118
+
119
+        if (!empty($nodes)) {
120
+            $this->nodes[(int) $resource->getId()] = array_shift($nodes);
121
+            return true;
122
+        }
123
+
124
+        return false;
125
+    }
126
+
127
+    /**
128
+     * Get the resource type of the provider
129
+     *
130
+     * @return string
131
+     * @since 16.0.0
132
+     */
133
+    public function getType(): string {
134
+        return self::RESOURCE_TYPE;
135
+    }
136 136
 }
Please login to merge, or discard this patch.
apps/dav/lib/Connector/Sabre/Exception/InvalidPath.php 2 patches
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -49,17 +49,17 @@
 block discarded – undo
49 49
 	 * @param \DOMElement $errorNode
50 50
 	 * @return void
51 51
 	 */
52
-	public function serialize(\Sabre\DAV\Server $server,\DOMElement $errorNode) {
52
+	public function serialize(\Sabre\DAV\Server $server, \DOMElement $errorNode) {
53 53
 
54 54
 		// set ownCloud namespace
55 55
 		$errorNode->setAttribute('xmlns:o', self::NS_OWNCLOUD);
56 56
 
57 57
 		// adding the retry node
58
-		$error = $errorNode->ownerDocument->createElementNS('o:','o:retry', var_export($this->retry, true));
58
+		$error = $errorNode->ownerDocument->createElementNS('o:', 'o:retry', var_export($this->retry, true));
59 59
 		$errorNode->appendChild($error);
60 60
 
61 61
 		// adding the message node
62
-		$error = $errorNode->ownerDocument->createElementNS('o:','o:reason', $this->getMessage());
62
+		$error = $errorNode->ownerDocument->createElementNS('o:', 'o:reason', $this->getMessage());
63 63
 		$errorNode->appendChild($error);
64 64
 	}
65 65
 }
Please login to merge, or discard this patch.
Indentation   +40 added lines, -40 removed lines patch added patch discarded remove patch
@@ -26,51 +26,51 @@
 block discarded – undo
26 26
 use Sabre\DAV\Exception;
27 27
 
28 28
 class InvalidPath extends Exception {
29
-	public const NS_OWNCLOUD = 'http://owncloud.org/ns';
29
+    public const NS_OWNCLOUD = 'http://owncloud.org/ns';
30 30
 
31
-	/**
32
-	 * @var bool
33
-	 */
34
-	private $retry;
31
+    /**
32
+     * @var bool
33
+     */
34
+    private $retry;
35 35
 
36
-	/**
37
-	 * @param string $message
38
-	 * @param bool $retry
39
-	 * @param \Exception|null $previous
40
-	 */
41
-	public function __construct($message, $retry = false, \Exception $previous = null) {
42
-		parent::__construct($message, 0, $previous);
43
-		$this->retry = $retry;
44
-	}
36
+    /**
37
+     * @param string $message
38
+     * @param bool $retry
39
+     * @param \Exception|null $previous
40
+     */
41
+    public function __construct($message, $retry = false, \Exception $previous = null) {
42
+        parent::__construct($message, 0, $previous);
43
+        $this->retry = $retry;
44
+    }
45 45
 
46
-	/**
47
-	 * Returns the HTTP status code for this exception
48
-	 *
49
-	 * @return int
50
-	 */
51
-	public function getHTTPCode() {
52
-		return 400;
53
-	}
46
+    /**
47
+     * Returns the HTTP status code for this exception
48
+     *
49
+     * @return int
50
+     */
51
+    public function getHTTPCode() {
52
+        return 400;
53
+    }
54 54
 
55
-	/**
56
-	 * This method allows the exception to include additional information
57
-	 * into the WebDAV error response
58
-	 *
59
-	 * @param \Sabre\DAV\Server $server
60
-	 * @param \DOMElement $errorNode
61
-	 * @return void
62
-	 */
63
-	public function serialize(\Sabre\DAV\Server $server,\DOMElement $errorNode) {
55
+    /**
56
+     * This method allows the exception to include additional information
57
+     * into the WebDAV error response
58
+     *
59
+     * @param \Sabre\DAV\Server $server
60
+     * @param \DOMElement $errorNode
61
+     * @return void
62
+     */
63
+    public function serialize(\Sabre\DAV\Server $server,\DOMElement $errorNode) {
64 64
 
65
-		// set ownCloud namespace
66
-		$errorNode->setAttribute('xmlns:o', self::NS_OWNCLOUD);
65
+        // set ownCloud namespace
66
+        $errorNode->setAttribute('xmlns:o', self::NS_OWNCLOUD);
67 67
 
68
-		// adding the retry node
69
-		$error = $errorNode->ownerDocument->createElementNS('o:','o:retry', var_export($this->retry, true));
70
-		$errorNode->appendChild($error);
68
+        // adding the retry node
69
+        $error = $errorNode->ownerDocument->createElementNS('o:','o:retry', var_export($this->retry, true));
70
+        $errorNode->appendChild($error);
71 71
 
72
-		// adding the message node
73
-		$error = $errorNode->ownerDocument->createElementNS('o:','o:reason', $this->getMessage());
74
-		$errorNode->appendChild($error);
75
-	}
72
+        // adding the message node
73
+        $error = $errorNode->ownerDocument->createElementNS('o:','o:reason', $this->getMessage());
74
+        $errorNode->appendChild($error);
75
+    }
76 76
 }
Please login to merge, or discard this patch.
apps/dav/lib/Connector/Sabre/QuotaPlugin.php 2 patches
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -92,7 +92,7 @@  discard block
 block discarded – undo
92 92
 			return;
93 93
 		}
94 94
 
95
-		return $this->checkQuota($parent->getPath() . '/' . basename($uri));
95
+		return $this->checkQuota($parent->getPath().'/'.basename($uri));
96 96
 	}
97 97
 
98 98
 	/**
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
 				// there is still enough space for the remaining chunks
164 164
 				$length -= $chunkHandler->getCurrentSize();
165 165
 				// use target file name for free space check in case of shared files
166
-				$path = rtrim($parentPath, '/') . '/' . $info['name'];
166
+				$path = rtrim($parentPath, '/').'/'.$info['name'];
167 167
 			}
168 168
 			$freeSpace = $this->getFreeSpace($path);
169 169
 			if ($freeSpace >= 0 && $length > $freeSpace) {
Please login to merge, or discard this patch.
Indentation   +203 added lines, -203 removed lines patch added patch discarded remove patch
@@ -44,207 +44,207 @@
 block discarded – undo
44 44
  * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
45 45
  */
46 46
 class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
47
-	/** @var \OC\Files\View */
48
-	private $view;
49
-
50
-	/**
51
-	 * Reference to main server object
52
-	 *
53
-	 * @var \Sabre\DAV\Server
54
-	 */
55
-	private $server;
56
-
57
-	/**
58
-	 * @param \OC\Files\View $view
59
-	 */
60
-	public function __construct($view) {
61
-		$this->view = $view;
62
-	}
63
-
64
-	/**
65
-	 * This initializes the plugin.
66
-	 *
67
-	 * This function is called by \Sabre\DAV\Server, after
68
-	 * addPlugin is called.
69
-	 *
70
-	 * This method should set up the requires event subscriptions.
71
-	 *
72
-	 * @param \Sabre\DAV\Server $server
73
-	 * @return void
74
-	 */
75
-	public function initialize(\Sabre\DAV\Server $server) {
76
-		$this->server = $server;
77
-
78
-		$server->on('beforeWriteContent', [$this, 'beforeWriteContent'], 10);
79
-		$server->on('beforeCreateFile', [$this, 'beforeCreateFile'], 10);
80
-		$server->on('beforeMove', [$this, 'beforeMove'], 10);
81
-		$server->on('beforeCopy', [$this, 'beforeCopy'], 10);
82
-	}
83
-
84
-	/**
85
-	 * Check quota before creating file
86
-	 *
87
-	 * @param string $uri target file URI
88
-	 * @param resource $data data
89
-	 * @param INode $parent Sabre Node
90
-	 * @param bool $modified modified
91
-	 */
92
-	public function beforeCreateFile($uri, $data, INode $parent, $modified) {
93
-		if (!$parent instanceof Node) {
94
-			return;
95
-		}
96
-
97
-		return $this->checkQuota($parent->getPath() . '/' . basename($uri));
98
-	}
99
-
100
-	/**
101
-	 * Check quota before writing content
102
-	 *
103
-	 * @param string $uri target file URI
104
-	 * @param INode $node Sabre Node
105
-	 * @param resource $data data
106
-	 * @param bool $modified modified
107
-	 */
108
-	public function beforeWriteContent($uri, INode $node, $data, $modified) {
109
-		if (!$node instanceof Node) {
110
-			return;
111
-		}
112
-
113
-		return $this->checkQuota($node->getPath());
114
-	}
115
-
116
-	/**
117
-	 * Check if we're moving a Futurefile in which case we need to check
118
-	 * the quota on the target destination.
119
-	 *
120
-	 * @param string $source source path
121
-	 * @param string $destination destination path
122
-	 */
123
-	public function beforeMove($source, $destination) {
124
-		$sourceNode = $this->server->tree->getNodeForPath($source);
125
-		if (!$sourceNode instanceof FutureFile) {
126
-			return;
127
-		}
128
-
129
-		// get target node for proper path conversion
130
-		if ($this->server->tree->nodeExists($destination)) {
131
-			$destinationNode = $this->server->tree->getNodeForPath($destination);
132
-			$path = $destinationNode->getPath();
133
-		} else {
134
-			$parent = dirname($destination);
135
-			if ($parent === '.') {
136
-				$parent = '';
137
-			}
138
-			$parentNode = $this->server->tree->getNodeForPath($parent);
139
-			$path = $parentNode->getPath();
140
-		}
141
-
142
-		return $this->checkQuota($path, $sourceNode->getSize());
143
-	}
144
-
145
-	/**
146
-	 * Check quota on the target destination before a copy.
147
-	 */
148
-	public function beforeCopy(string $sourcePath, string $destinationPath): bool {
149
-		$sourceNode = $this->server->tree->getNodeForPath($sourcePath);
150
-		if (!$sourceNode instanceof Node) {
151
-			return true;
152
-		}
153
-
154
-		// get target node for proper path conversion
155
-		if ($this->server->tree->nodeExists($destinationPath)) {
156
-			$destinationNode = $this->server->tree->getNodeForPath($destinationPath);
157
-			if (!$destinationNode instanceof Node) {
158
-				return true;
159
-			}
160
-			$path = $destinationNode->getPath();
161
-		} else {
162
-			$parent = dirname($destinationPath);
163
-			if ($parent === '.') {
164
-				$parent = '';
165
-			}
166
-			$parentNode = $this->server->tree->getNodeForPath($parent);
167
-			if (!$parentNode instanceof Node) {
168
-				return true;
169
-			}
170
-			$path = $parentNode->getPath();
171
-		}
172
-
173
-		return $this->checkQuota($path, $sourceNode->getSize());
174
-	}
175
-
176
-
177
-	/**
178
-	 * This method is called before any HTTP method and validates there is enough free space to store the file
179
-	 *
180
-	 * @param string $path relative to the users home
181
-	 * @param int $length
182
-	 * @throws InsufficientStorage
183
-	 * @return bool
184
-	 */
185
-	public function checkQuota($path, $length = null) {
186
-		if ($length === null) {
187
-			$length = $this->getLength();
188
-		}
189
-
190
-		if ($length) {
191
-			[$parentPath, $newName] = \Sabre\Uri\split($path);
192
-			if (is_null($parentPath)) {
193
-				$parentPath = '';
194
-			}
195
-			$req = $this->server->httpRequest;
196
-			if ($req->getHeader('OC-Chunked')) {
197
-				$info = \OC_FileChunking::decodeName($newName);
198
-				$chunkHandler = $this->getFileChunking($info);
199
-				// subtract the already uploaded size to see whether
200
-				// there is still enough space for the remaining chunks
201
-				$length -= $chunkHandler->getCurrentSize();
202
-				// use target file name for free space check in case of shared files
203
-				$path = rtrim($parentPath, '/') . '/' . $info['name'];
204
-			}
205
-			$freeSpace = $this->getFreeSpace($path);
206
-			if ($freeSpace >= 0 && $length > $freeSpace) {
207
-				if (isset($chunkHandler)) {
208
-					$chunkHandler->cleanup();
209
-				}
210
-				throw new InsufficientStorage("Insufficient space in $path, $length required, $freeSpace available");
211
-			}
212
-		}
213
-		return true;
214
-	}
215
-
216
-	public function getFileChunking($info) {
217
-		// FIXME: need a factory for better mocking support
218
-		return new \OC_FileChunking($info);
219
-	}
220
-
221
-	public function getLength() {
222
-		$req = $this->server->httpRequest;
223
-		$length = $req->getHeader('X-Expected-Entity-Length');
224
-		if (!is_numeric($length)) {
225
-			$length = $req->getHeader('Content-Length');
226
-			$length = is_numeric($length) ? $length : null;
227
-		}
228
-
229
-		$ocLength = $req->getHeader('OC-Total-Length');
230
-		if (is_numeric($length) && is_numeric($ocLength)) {
231
-			return max($length, $ocLength);
232
-		}
233
-
234
-		return $length;
235
-	}
236
-
237
-	/**
238
-	 * @param string $uri
239
-	 * @return mixed
240
-	 * @throws ServiceUnavailable
241
-	 */
242
-	public function getFreeSpace($uri) {
243
-		try {
244
-			$freeSpace = $this->view->free_space(ltrim($uri, '/'));
245
-			return $freeSpace;
246
-		} catch (StorageNotAvailableException $e) {
247
-			throw new ServiceUnavailable($e->getMessage());
248
-		}
249
-	}
47
+    /** @var \OC\Files\View */
48
+    private $view;
49
+
50
+    /**
51
+     * Reference to main server object
52
+     *
53
+     * @var \Sabre\DAV\Server
54
+     */
55
+    private $server;
56
+
57
+    /**
58
+     * @param \OC\Files\View $view
59
+     */
60
+    public function __construct($view) {
61
+        $this->view = $view;
62
+    }
63
+
64
+    /**
65
+     * This initializes the plugin.
66
+     *
67
+     * This function is called by \Sabre\DAV\Server, after
68
+     * addPlugin is called.
69
+     *
70
+     * This method should set up the requires event subscriptions.
71
+     *
72
+     * @param \Sabre\DAV\Server $server
73
+     * @return void
74
+     */
75
+    public function initialize(\Sabre\DAV\Server $server) {
76
+        $this->server = $server;
77
+
78
+        $server->on('beforeWriteContent', [$this, 'beforeWriteContent'], 10);
79
+        $server->on('beforeCreateFile', [$this, 'beforeCreateFile'], 10);
80
+        $server->on('beforeMove', [$this, 'beforeMove'], 10);
81
+        $server->on('beforeCopy', [$this, 'beforeCopy'], 10);
82
+    }
83
+
84
+    /**
85
+     * Check quota before creating file
86
+     *
87
+     * @param string $uri target file URI
88
+     * @param resource $data data
89
+     * @param INode $parent Sabre Node
90
+     * @param bool $modified modified
91
+     */
92
+    public function beforeCreateFile($uri, $data, INode $parent, $modified) {
93
+        if (!$parent instanceof Node) {
94
+            return;
95
+        }
96
+
97
+        return $this->checkQuota($parent->getPath() . '/' . basename($uri));
98
+    }
99
+
100
+    /**
101
+     * Check quota before writing content
102
+     *
103
+     * @param string $uri target file URI
104
+     * @param INode $node Sabre Node
105
+     * @param resource $data data
106
+     * @param bool $modified modified
107
+     */
108
+    public function beforeWriteContent($uri, INode $node, $data, $modified) {
109
+        if (!$node instanceof Node) {
110
+            return;
111
+        }
112
+
113
+        return $this->checkQuota($node->getPath());
114
+    }
115
+
116
+    /**
117
+     * Check if we're moving a Futurefile in which case we need to check
118
+     * the quota on the target destination.
119
+     *
120
+     * @param string $source source path
121
+     * @param string $destination destination path
122
+     */
123
+    public function beforeMove($source, $destination) {
124
+        $sourceNode = $this->server->tree->getNodeForPath($source);
125
+        if (!$sourceNode instanceof FutureFile) {
126
+            return;
127
+        }
128
+
129
+        // get target node for proper path conversion
130
+        if ($this->server->tree->nodeExists($destination)) {
131
+            $destinationNode = $this->server->tree->getNodeForPath($destination);
132
+            $path = $destinationNode->getPath();
133
+        } else {
134
+            $parent = dirname($destination);
135
+            if ($parent === '.') {
136
+                $parent = '';
137
+            }
138
+            $parentNode = $this->server->tree->getNodeForPath($parent);
139
+            $path = $parentNode->getPath();
140
+        }
141
+
142
+        return $this->checkQuota($path, $sourceNode->getSize());
143
+    }
144
+
145
+    /**
146
+     * Check quota on the target destination before a copy.
147
+     */
148
+    public function beforeCopy(string $sourcePath, string $destinationPath): bool {
149
+        $sourceNode = $this->server->tree->getNodeForPath($sourcePath);
150
+        if (!$sourceNode instanceof Node) {
151
+            return true;
152
+        }
153
+
154
+        // get target node for proper path conversion
155
+        if ($this->server->tree->nodeExists($destinationPath)) {
156
+            $destinationNode = $this->server->tree->getNodeForPath($destinationPath);
157
+            if (!$destinationNode instanceof Node) {
158
+                return true;
159
+            }
160
+            $path = $destinationNode->getPath();
161
+        } else {
162
+            $parent = dirname($destinationPath);
163
+            if ($parent === '.') {
164
+                $parent = '';
165
+            }
166
+            $parentNode = $this->server->tree->getNodeForPath($parent);
167
+            if (!$parentNode instanceof Node) {
168
+                return true;
169
+            }
170
+            $path = $parentNode->getPath();
171
+        }
172
+
173
+        return $this->checkQuota($path, $sourceNode->getSize());
174
+    }
175
+
176
+
177
+    /**
178
+     * This method is called before any HTTP method and validates there is enough free space to store the file
179
+     *
180
+     * @param string $path relative to the users home
181
+     * @param int $length
182
+     * @throws InsufficientStorage
183
+     * @return bool
184
+     */
185
+    public function checkQuota($path, $length = null) {
186
+        if ($length === null) {
187
+            $length = $this->getLength();
188
+        }
189
+
190
+        if ($length) {
191
+            [$parentPath, $newName] = \Sabre\Uri\split($path);
192
+            if (is_null($parentPath)) {
193
+                $parentPath = '';
194
+            }
195
+            $req = $this->server->httpRequest;
196
+            if ($req->getHeader('OC-Chunked')) {
197
+                $info = \OC_FileChunking::decodeName($newName);
198
+                $chunkHandler = $this->getFileChunking($info);
199
+                // subtract the already uploaded size to see whether
200
+                // there is still enough space for the remaining chunks
201
+                $length -= $chunkHandler->getCurrentSize();
202
+                // use target file name for free space check in case of shared files
203
+                $path = rtrim($parentPath, '/') . '/' . $info['name'];
204
+            }
205
+            $freeSpace = $this->getFreeSpace($path);
206
+            if ($freeSpace >= 0 && $length > $freeSpace) {
207
+                if (isset($chunkHandler)) {
208
+                    $chunkHandler->cleanup();
209
+                }
210
+                throw new InsufficientStorage("Insufficient space in $path, $length required, $freeSpace available");
211
+            }
212
+        }
213
+        return true;
214
+    }
215
+
216
+    public function getFileChunking($info) {
217
+        // FIXME: need a factory for better mocking support
218
+        return new \OC_FileChunking($info);
219
+    }
220
+
221
+    public function getLength() {
222
+        $req = $this->server->httpRequest;
223
+        $length = $req->getHeader('X-Expected-Entity-Length');
224
+        if (!is_numeric($length)) {
225
+            $length = $req->getHeader('Content-Length');
226
+            $length = is_numeric($length) ? $length : null;
227
+        }
228
+
229
+        $ocLength = $req->getHeader('OC-Total-Length');
230
+        if (is_numeric($length) && is_numeric($ocLength)) {
231
+            return max($length, $ocLength);
232
+        }
233
+
234
+        return $length;
235
+    }
236
+
237
+    /**
238
+     * @param string $uri
239
+     * @return mixed
240
+     * @throws ServiceUnavailable
241
+     */
242
+    public function getFreeSpace($uri) {
243
+        try {
244
+            $freeSpace = $this->view->free_space(ltrim($uri, '/'));
245
+            return $freeSpace;
246
+        } catch (StorageNotAvailableException $e) {
247
+            throw new ServiceUnavailable($e->getMessage());
248
+        }
249
+    }
250 250
 }
Please login to merge, or discard this patch.
apps/dav/lib/Connector/Sabre/FilesReportPlugin.php 2 patches
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -186,14 +186,14 @@  discard block
 block discarded – undo
186 186
 			return;
187 187
 		}
188 188
 
189
-		$ns = '{' . $this::NS_OWNCLOUD . '}';
189
+		$ns = '{'.$this::NS_OWNCLOUD.'}';
190 190
 		$requestedProps = [];
191 191
 		$filterRules = [];
192 192
 
193 193
 		// parse report properties and gather filter info
194 194
 		foreach ($report as $reportProps) {
195 195
 			$name = $reportProps['name'];
196
-			if ($name === $ns . 'filter-rules') {
196
+			if ($name === $ns.'filter-rules') {
197 197
 				$filterRules = $reportProps['value'];
198 198
 			} elseif ($name === '{DAV:}prop') {
199 199
 				// propfind properties
@@ -254,7 +254,7 @@  discard block
 block discarded – undo
254 254
 		if (empty($filesUri)) {
255 255
 			return '';
256 256
 		}
257
-		return '/' . $filesUri;
257
+		return '/'.$filesUri;
258 258
 	}
259 259
 
260 260
 	/**
@@ -266,19 +266,19 @@  discard block
 block discarded – undo
266 266
 	 * @throws TagNotFoundException whenever a tag was not found
267 267
 	 */
268 268
 	protected function processFilterRules($filterRules) {
269
-		$ns = '{' . $this::NS_OWNCLOUD . '}';
269
+		$ns = '{'.$this::NS_OWNCLOUD.'}';
270 270
 		$resultFileIds = null;
271 271
 		$systemTagIds = [];
272 272
 		$circlesIds = [];
273 273
 		$favoriteFilter = null;
274 274
 		foreach ($filterRules as $filterRule) {
275
-			if ($filterRule['name'] === $ns . 'systemtag') {
275
+			if ($filterRule['name'] === $ns.'systemtag') {
276 276
 				$systemTagIds[] = $filterRule['value'];
277 277
 			}
278 278
 			if ($filterRule['name'] === self::CIRCLE_PROPERTYNAME) {
279 279
 				$circlesIds[] = $filterRule['value'];
280 280
 			}
281
-			if ($filterRule['name'] === $ns . 'favorite') {
281
+			if ($filterRule['name'] === $ns.'favorite') {
282 282
 				$favoriteFilter = true;
283 283
 			}
284 284
 		}
@@ -326,7 +326,7 @@  discard block
 block discarded – undo
326 326
 			}
327 327
 
328 328
 			if (!empty($unknownTagIds)) {
329
-				throw new TagNotFoundException('Tag with ids ' . implode(', ', $unknownTagIds) . ' not found');
329
+				throw new TagNotFoundException('Tag with ids '.implode(', ', $unknownTagIds).' not found');
330 330
 			}
331 331
 		}
332 332
 
@@ -379,7 +379,7 @@  discard block
 block discarded – undo
379 379
 	public function prepareResponses($filesUri, $requestedProps, $nodes) {
380 380
 		$responses = [];
381 381
 		foreach ($nodes as $node) {
382
-			$propFind = new PropFind($filesUri . $node->getPath(), $requestedProps);
382
+			$propFind = new PropFind($filesUri.$node->getPath(), $requestedProps);
383 383
 
384 384
 			$this->server->getPropertiesByNode($propFind, $node);
385 385
 			// copied from Sabre Server's getPropertiesForPath
@@ -392,7 +392,7 @@  discard block
 block discarded – undo
392 392
 			}
393 393
 
394 394
 			$responses[] = new Response(
395
-				rtrim($this->server->getBaseUri(), '/') . $filesUri . $node->getPath(),
395
+				rtrim($this->server->getBaseUri(), '/').$filesUri.$node->getPath(),
396 396
 				$result,
397 397
 				200
398 398
 			);
Please login to merge, or discard this patch.
Indentation   +392 added lines, -392 removed lines patch added patch discarded remove patch
@@ -46,396 +46,396 @@
 block discarded – undo
46 46
 
47 47
 class FilesReportPlugin extends ServerPlugin {
48 48
 
49
-	// namespace
50
-	public const NS_OWNCLOUD = 'http://owncloud.org/ns';
51
-	public const REPORT_NAME = '{http://owncloud.org/ns}filter-files';
52
-	public const SYSTEMTAG_PROPERTYNAME = '{http://owncloud.org/ns}systemtag';
53
-	public const CIRCLE_PROPERTYNAME = '{http://owncloud.org/ns}circle';
54
-
55
-	/**
56
-	 * Reference to main server object
57
-	 *
58
-	 * @var \Sabre\DAV\Server
59
-	 */
60
-	private $server;
61
-
62
-	/**
63
-	 * @var Tree
64
-	 */
65
-	private $tree;
66
-
67
-	/**
68
-	 * @var View
69
-	 */
70
-	private $fileView;
71
-
72
-	/**
73
-	 * @var ISystemTagManager
74
-	 */
75
-	private $tagManager;
76
-
77
-	/**
78
-	 * @var ISystemTagObjectMapper
79
-	 */
80
-	private $tagMapper;
81
-
82
-	/**
83
-	 * Manager for private tags
84
-	 *
85
-	 * @var ITagManager
86
-	 */
87
-	private $fileTagger;
88
-
89
-	/**
90
-	 * @var IUserSession
91
-	 */
92
-	private $userSession;
93
-
94
-	/**
95
-	 * @var IGroupManager
96
-	 */
97
-	private $groupManager;
98
-
99
-	/**
100
-	 * @var Folder
101
-	 */
102
-	private $userFolder;
103
-
104
-	/**
105
-	 * @var IAppManager
106
-	 */
107
-	private $appManager;
108
-
109
-	/**
110
-	 * @param Tree $tree
111
-	 * @param View $view
112
-	 * @param ISystemTagManager $tagManager
113
-	 * @param ISystemTagObjectMapper $tagMapper
114
-	 * @param ITagManager $fileTagger manager for private tags
115
-	 * @param IUserSession $userSession
116
-	 * @param IGroupManager $groupManager
117
-	 * @param Folder $userFolder
118
-	 * @param IAppManager $appManager
119
-	 */
120
-	public function __construct(Tree $tree,
121
-								View $view,
122
-								ISystemTagManager $tagManager,
123
-								ISystemTagObjectMapper $tagMapper,
124
-								ITagManager $fileTagger,
125
-								IUserSession $userSession,
126
-								IGroupManager $groupManager,
127
-								Folder $userFolder,
128
-								IAppManager $appManager
129
-	) {
130
-		$this->tree = $tree;
131
-		$this->fileView = $view;
132
-		$this->tagManager = $tagManager;
133
-		$this->tagMapper = $tagMapper;
134
-		$this->fileTagger = $fileTagger;
135
-		$this->userSession = $userSession;
136
-		$this->groupManager = $groupManager;
137
-		$this->userFolder = $userFolder;
138
-		$this->appManager = $appManager;
139
-	}
140
-
141
-	/**
142
-	 * This initializes the plugin.
143
-	 *
144
-	 * This function is called by \Sabre\DAV\Server, after
145
-	 * addPlugin is called.
146
-	 *
147
-	 * This method should set up the required event subscriptions.
148
-	 *
149
-	 * @param \Sabre\DAV\Server $server
150
-	 * @return void
151
-	 */
152
-	public function initialize(\Sabre\DAV\Server $server) {
153
-		$server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc';
154
-
155
-		$this->server = $server;
156
-		$this->server->on('report', [$this, 'onReport']);
157
-	}
158
-
159
-	/**
160
-	 * Returns a list of reports this plugin supports.
161
-	 *
162
-	 * This will be used in the {DAV:}supported-report-set property.
163
-	 *
164
-	 * @param string $uri
165
-	 * @return array
166
-	 */
167
-	public function getSupportedReportSet($uri) {
168
-		return [self::REPORT_NAME];
169
-	}
170
-
171
-	/**
172
-	 * REPORT operations to look for files
173
-	 *
174
-	 * @param string $reportName
175
-	 * @param $report
176
-	 * @param string $uri
177
-	 * @return bool
178
-	 * @throws BadRequest
179
-	 * @throws PreconditionFailed
180
-	 * @internal param $ [] $report
181
-	 */
182
-	public function onReport($reportName, $report, $uri) {
183
-		$reportTargetNode = $this->server->tree->getNodeForPath($uri);
184
-		if (!$reportTargetNode instanceof Directory || $reportName !== self::REPORT_NAME) {
185
-			return;
186
-		}
187
-
188
-		$ns = '{' . $this::NS_OWNCLOUD . '}';
189
-		$requestedProps = [];
190
-		$filterRules = [];
191
-
192
-		// parse report properties and gather filter info
193
-		foreach ($report as $reportProps) {
194
-			$name = $reportProps['name'];
195
-			if ($name === $ns . 'filter-rules') {
196
-				$filterRules = $reportProps['value'];
197
-			} elseif ($name === '{DAV:}prop') {
198
-				// propfind properties
199
-				foreach ($reportProps['value'] as $propVal) {
200
-					$requestedProps[] = $propVal['name'];
201
-				}
202
-			}
203
-		}
204
-
205
-		if (empty($filterRules)) {
206
-			// an empty filter would return all existing files which would be slow
207
-			throw new BadRequest('Missing filter-rule block in request');
208
-		}
209
-
210
-		// gather all file ids matching filter
211
-		try {
212
-			$resultFileIds = $this->processFilterRules($filterRules);
213
-		} catch (TagNotFoundException $e) {
214
-			throw new PreconditionFailed('Cannot filter by non-existing tag', 0, $e);
215
-		}
216
-
217
-		// find sabre nodes by file id, restricted to the root node path
218
-		$results = $this->findNodesByFileIds($reportTargetNode, $resultFileIds);
219
-
220
-		$filesUri = $this->getFilesBaseUri($uri, $reportTargetNode->getPath());
221
-		$responses = $this->prepareResponses($filesUri, $requestedProps, $results);
222
-
223
-		$xml = $this->server->xml->write(
224
-			'{DAV:}multistatus',
225
-			new MultiStatus($responses)
226
-		);
227
-
228
-		$this->server->httpResponse->setStatus(207);
229
-		$this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
230
-		$this->server->httpResponse->setBody($xml);
231
-
232
-		return false;
233
-	}
234
-
235
-	/**
236
-	 * Returns the base uri of the files root by removing
237
-	 * the subpath from the URI
238
-	 *
239
-	 * @param string $uri URI from this request
240
-	 * @param string $subPath subpath to remove from the URI
241
-	 *
242
-	 * @return string files base uri
243
-	 */
244
-	private function getFilesBaseUri(string $uri, string $subPath): string {
245
-		$uri = trim($uri, '/');
246
-		$subPath = trim($subPath, '/');
247
-		if (empty($subPath)) {
248
-			$filesUri = $uri;
249
-		} else {
250
-			$filesUri = substr($uri, 0, strlen($uri) - strlen($subPath));
251
-		}
252
-		$filesUri = trim($filesUri, '/');
253
-		if (empty($filesUri)) {
254
-			return '';
255
-		}
256
-		return '/' . $filesUri;
257
-	}
258
-
259
-	/**
260
-	 * Find file ids matching the given filter rules
261
-	 *
262
-	 * @param array $filterRules
263
-	 * @return array array of unique file id results
264
-	 *
265
-	 * @throws TagNotFoundException whenever a tag was not found
266
-	 */
267
-	protected function processFilterRules($filterRules) {
268
-		$ns = '{' . $this::NS_OWNCLOUD . '}';
269
-		$resultFileIds = null;
270
-		$systemTagIds = [];
271
-		$circlesIds = [];
272
-		$favoriteFilter = null;
273
-		foreach ($filterRules as $filterRule) {
274
-			if ($filterRule['name'] === $ns . 'systemtag') {
275
-				$systemTagIds[] = $filterRule['value'];
276
-			}
277
-			if ($filterRule['name'] === self::CIRCLE_PROPERTYNAME) {
278
-				$circlesIds[] = $filterRule['value'];
279
-			}
280
-			if ($filterRule['name'] === $ns . 'favorite') {
281
-				$favoriteFilter = true;
282
-			}
283
-		}
284
-
285
-		if ($favoriteFilter !== null) {
286
-			$resultFileIds = $this->fileTagger->load('files')->getFavorites();
287
-			if (empty($resultFileIds)) {
288
-				return [];
289
-			}
290
-		}
291
-
292
-		if (!empty($systemTagIds)) {
293
-			$fileIds = $this->getSystemTagFileIds($systemTagIds);
294
-			if (empty($resultFileIds)) {
295
-				$resultFileIds = $fileIds;
296
-			} else {
297
-				$resultFileIds = array_intersect($fileIds, $resultFileIds);
298
-			}
299
-		}
300
-
301
-		if (!empty($circlesIds)) {
302
-			$fileIds = $this->getCirclesFileIds($circlesIds);
303
-			if (empty($resultFileIds)) {
304
-				$resultFileIds = $fileIds;
305
-			} else {
306
-				$resultFileIds = array_intersect($fileIds, $resultFileIds);
307
-			}
308
-		}
309
-
310
-		return $resultFileIds;
311
-	}
312
-
313
-	private function getSystemTagFileIds($systemTagIds) {
314
-		$resultFileIds = null;
315
-
316
-		// check user permissions, if applicable
317
-		if (!$this->isAdmin()) {
318
-			// check visibility/permission
319
-			$tags = $this->tagManager->getTagsByIds($systemTagIds);
320
-			$unknownTagIds = [];
321
-			foreach ($tags as $tag) {
322
-				if (!$tag->isUserVisible()) {
323
-					$unknownTagIds[] = $tag->getId();
324
-				}
325
-			}
326
-
327
-			if (!empty($unknownTagIds)) {
328
-				throw new TagNotFoundException('Tag with ids ' . implode(', ', $unknownTagIds) . ' not found');
329
-			}
330
-		}
331
-
332
-		// fetch all file ids and intersect them
333
-		foreach ($systemTagIds as $systemTagId) {
334
-			$fileIds = $this->tagMapper->getObjectIdsForTags($systemTagId, 'files');
335
-
336
-			if (empty($fileIds)) {
337
-				// This tag has no files, nothing can ever show up
338
-				return [];
339
-			}
340
-
341
-			// first run ?
342
-			if ($resultFileIds === null) {
343
-				$resultFileIds = $fileIds;
344
-			} else {
345
-				$resultFileIds = array_intersect($resultFileIds, $fileIds);
346
-			}
347
-
348
-			if (empty($resultFileIds)) {
349
-				// Empty intersection, nothing can show up anymore
350
-				return [];
351
-			}
352
-		}
353
-		return $resultFileIds;
354
-	}
355
-
356
-	/**
357
-	 * @suppress PhanUndeclaredClassMethod
358
-	 * @param array $circlesIds
359
-	 * @return array
360
-	 */
361
-	private function getCirclesFileIds(array $circlesIds) {
362
-		if (!$this->appManager->isEnabledForUser('circles') || !class_exists('\OCA\Circles\Api\v1\Circles')) {
363
-			return [];
364
-		}
365
-		return \OCA\Circles\Api\v1\Circles::getFilesForCircles($circlesIds);
366
-	}
367
-
368
-
369
-	/**
370
-	 * Prepare propfind response for the given nodes
371
-	 *
372
-	 * @param string $filesUri $filesUri URI leading to root of the files URI,
373
-	 * with a leading slash but no trailing slash
374
-	 * @param string[] $requestedProps requested properties
375
-	 * @param Node[] nodes nodes for which to fetch and prepare responses
376
-	 * @return Response[]
377
-	 */
378
-	public function prepareResponses($filesUri, $requestedProps, $nodes) {
379
-		$responses = [];
380
-		foreach ($nodes as $node) {
381
-			$propFind = new PropFind($filesUri . $node->getPath(), $requestedProps);
382
-
383
-			$this->server->getPropertiesByNode($propFind, $node);
384
-			// copied from Sabre Server's getPropertiesForPath
385
-			$result = $propFind->getResultForMultiStatus();
386
-			$result['href'] = $propFind->getPath();
387
-
388
-			$resourceType = $this->server->getResourceTypeForNode($node);
389
-			if (in_array('{DAV:}collection', $resourceType) || in_array('{DAV:}principal', $resourceType)) {
390
-				$result['href'] .= '/';
391
-			}
392
-
393
-			$responses[] = new Response(
394
-				rtrim($this->server->getBaseUri(), '/') . $filesUri . $node->getPath(),
395
-				$result,
396
-				200
397
-			);
398
-		}
399
-		return $responses;
400
-	}
401
-
402
-	/**
403
-	 * Find Sabre nodes by file ids
404
-	 *
405
-	 * @param Node $rootNode root node for search
406
-	 * @param array $fileIds file ids
407
-	 * @return Node[] array of Sabre nodes
408
-	 */
409
-	public function findNodesByFileIds($rootNode, $fileIds) {
410
-		$folder = $this->userFolder;
411
-		if (trim($rootNode->getPath(), '/') !== '') {
412
-			$folder = $folder->get($rootNode->getPath());
413
-		}
414
-
415
-		$results = [];
416
-		foreach ($fileIds as $fileId) {
417
-			$entry = $folder->getById($fileId);
418
-			if ($entry) {
419
-				$entry = current($entry);
420
-				if ($entry instanceof \OCP\Files\File) {
421
-					$results[] = new File($this->fileView, $entry);
422
-				} elseif ($entry instanceof \OCP\Files\Folder) {
423
-					$results[] = new Directory($this->fileView, $entry);
424
-				}
425
-			}
426
-		}
427
-
428
-		return $results;
429
-	}
430
-
431
-	/**
432
-	 * Returns whether the currently logged in user is an administrator
433
-	 */
434
-	private function isAdmin() {
435
-		$user = $this->userSession->getUser();
436
-		if ($user !== null) {
437
-			return $this->groupManager->isAdmin($user->getUID());
438
-		}
439
-		return false;
440
-	}
49
+    // namespace
50
+    public const NS_OWNCLOUD = 'http://owncloud.org/ns';
51
+    public const REPORT_NAME = '{http://owncloud.org/ns}filter-files';
52
+    public const SYSTEMTAG_PROPERTYNAME = '{http://owncloud.org/ns}systemtag';
53
+    public const CIRCLE_PROPERTYNAME = '{http://owncloud.org/ns}circle';
54
+
55
+    /**
56
+     * Reference to main server object
57
+     *
58
+     * @var \Sabre\DAV\Server
59
+     */
60
+    private $server;
61
+
62
+    /**
63
+     * @var Tree
64
+     */
65
+    private $tree;
66
+
67
+    /**
68
+     * @var View
69
+     */
70
+    private $fileView;
71
+
72
+    /**
73
+     * @var ISystemTagManager
74
+     */
75
+    private $tagManager;
76
+
77
+    /**
78
+     * @var ISystemTagObjectMapper
79
+     */
80
+    private $tagMapper;
81
+
82
+    /**
83
+     * Manager for private tags
84
+     *
85
+     * @var ITagManager
86
+     */
87
+    private $fileTagger;
88
+
89
+    /**
90
+     * @var IUserSession
91
+     */
92
+    private $userSession;
93
+
94
+    /**
95
+     * @var IGroupManager
96
+     */
97
+    private $groupManager;
98
+
99
+    /**
100
+     * @var Folder
101
+     */
102
+    private $userFolder;
103
+
104
+    /**
105
+     * @var IAppManager
106
+     */
107
+    private $appManager;
108
+
109
+    /**
110
+     * @param Tree $tree
111
+     * @param View $view
112
+     * @param ISystemTagManager $tagManager
113
+     * @param ISystemTagObjectMapper $tagMapper
114
+     * @param ITagManager $fileTagger manager for private tags
115
+     * @param IUserSession $userSession
116
+     * @param IGroupManager $groupManager
117
+     * @param Folder $userFolder
118
+     * @param IAppManager $appManager
119
+     */
120
+    public function __construct(Tree $tree,
121
+                                View $view,
122
+                                ISystemTagManager $tagManager,
123
+                                ISystemTagObjectMapper $tagMapper,
124
+                                ITagManager $fileTagger,
125
+                                IUserSession $userSession,
126
+                                IGroupManager $groupManager,
127
+                                Folder $userFolder,
128
+                                IAppManager $appManager
129
+    ) {
130
+        $this->tree = $tree;
131
+        $this->fileView = $view;
132
+        $this->tagManager = $tagManager;
133
+        $this->tagMapper = $tagMapper;
134
+        $this->fileTagger = $fileTagger;
135
+        $this->userSession = $userSession;
136
+        $this->groupManager = $groupManager;
137
+        $this->userFolder = $userFolder;
138
+        $this->appManager = $appManager;
139
+    }
140
+
141
+    /**
142
+     * This initializes the plugin.
143
+     *
144
+     * This function is called by \Sabre\DAV\Server, after
145
+     * addPlugin is called.
146
+     *
147
+     * This method should set up the required event subscriptions.
148
+     *
149
+     * @param \Sabre\DAV\Server $server
150
+     * @return void
151
+     */
152
+    public function initialize(\Sabre\DAV\Server $server) {
153
+        $server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc';
154
+
155
+        $this->server = $server;
156
+        $this->server->on('report', [$this, 'onReport']);
157
+    }
158
+
159
+    /**
160
+     * Returns a list of reports this plugin supports.
161
+     *
162
+     * This will be used in the {DAV:}supported-report-set property.
163
+     *
164
+     * @param string $uri
165
+     * @return array
166
+     */
167
+    public function getSupportedReportSet($uri) {
168
+        return [self::REPORT_NAME];
169
+    }
170
+
171
+    /**
172
+     * REPORT operations to look for files
173
+     *
174
+     * @param string $reportName
175
+     * @param $report
176
+     * @param string $uri
177
+     * @return bool
178
+     * @throws BadRequest
179
+     * @throws PreconditionFailed
180
+     * @internal param $ [] $report
181
+     */
182
+    public function onReport($reportName, $report, $uri) {
183
+        $reportTargetNode = $this->server->tree->getNodeForPath($uri);
184
+        if (!$reportTargetNode instanceof Directory || $reportName !== self::REPORT_NAME) {
185
+            return;
186
+        }
187
+
188
+        $ns = '{' . $this::NS_OWNCLOUD . '}';
189
+        $requestedProps = [];
190
+        $filterRules = [];
191
+
192
+        // parse report properties and gather filter info
193
+        foreach ($report as $reportProps) {
194
+            $name = $reportProps['name'];
195
+            if ($name === $ns . 'filter-rules') {
196
+                $filterRules = $reportProps['value'];
197
+            } elseif ($name === '{DAV:}prop') {
198
+                // propfind properties
199
+                foreach ($reportProps['value'] as $propVal) {
200
+                    $requestedProps[] = $propVal['name'];
201
+                }
202
+            }
203
+        }
204
+
205
+        if (empty($filterRules)) {
206
+            // an empty filter would return all existing files which would be slow
207
+            throw new BadRequest('Missing filter-rule block in request');
208
+        }
209
+
210
+        // gather all file ids matching filter
211
+        try {
212
+            $resultFileIds = $this->processFilterRules($filterRules);
213
+        } catch (TagNotFoundException $e) {
214
+            throw new PreconditionFailed('Cannot filter by non-existing tag', 0, $e);
215
+        }
216
+
217
+        // find sabre nodes by file id, restricted to the root node path
218
+        $results = $this->findNodesByFileIds($reportTargetNode, $resultFileIds);
219
+
220
+        $filesUri = $this->getFilesBaseUri($uri, $reportTargetNode->getPath());
221
+        $responses = $this->prepareResponses($filesUri, $requestedProps, $results);
222
+
223
+        $xml = $this->server->xml->write(
224
+            '{DAV:}multistatus',
225
+            new MultiStatus($responses)
226
+        );
227
+
228
+        $this->server->httpResponse->setStatus(207);
229
+        $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
230
+        $this->server->httpResponse->setBody($xml);
231
+
232
+        return false;
233
+    }
234
+
235
+    /**
236
+     * Returns the base uri of the files root by removing
237
+     * the subpath from the URI
238
+     *
239
+     * @param string $uri URI from this request
240
+     * @param string $subPath subpath to remove from the URI
241
+     *
242
+     * @return string files base uri
243
+     */
244
+    private function getFilesBaseUri(string $uri, string $subPath): string {
245
+        $uri = trim($uri, '/');
246
+        $subPath = trim($subPath, '/');
247
+        if (empty($subPath)) {
248
+            $filesUri = $uri;
249
+        } else {
250
+            $filesUri = substr($uri, 0, strlen($uri) - strlen($subPath));
251
+        }
252
+        $filesUri = trim($filesUri, '/');
253
+        if (empty($filesUri)) {
254
+            return '';
255
+        }
256
+        return '/' . $filesUri;
257
+    }
258
+
259
+    /**
260
+     * Find file ids matching the given filter rules
261
+     *
262
+     * @param array $filterRules
263
+     * @return array array of unique file id results
264
+     *
265
+     * @throws TagNotFoundException whenever a tag was not found
266
+     */
267
+    protected function processFilterRules($filterRules) {
268
+        $ns = '{' . $this::NS_OWNCLOUD . '}';
269
+        $resultFileIds = null;
270
+        $systemTagIds = [];
271
+        $circlesIds = [];
272
+        $favoriteFilter = null;
273
+        foreach ($filterRules as $filterRule) {
274
+            if ($filterRule['name'] === $ns . 'systemtag') {
275
+                $systemTagIds[] = $filterRule['value'];
276
+            }
277
+            if ($filterRule['name'] === self::CIRCLE_PROPERTYNAME) {
278
+                $circlesIds[] = $filterRule['value'];
279
+            }
280
+            if ($filterRule['name'] === $ns . 'favorite') {
281
+                $favoriteFilter = true;
282
+            }
283
+        }
284
+
285
+        if ($favoriteFilter !== null) {
286
+            $resultFileIds = $this->fileTagger->load('files')->getFavorites();
287
+            if (empty($resultFileIds)) {
288
+                return [];
289
+            }
290
+        }
291
+
292
+        if (!empty($systemTagIds)) {
293
+            $fileIds = $this->getSystemTagFileIds($systemTagIds);
294
+            if (empty($resultFileIds)) {
295
+                $resultFileIds = $fileIds;
296
+            } else {
297
+                $resultFileIds = array_intersect($fileIds, $resultFileIds);
298
+            }
299
+        }
300
+
301
+        if (!empty($circlesIds)) {
302
+            $fileIds = $this->getCirclesFileIds($circlesIds);
303
+            if (empty($resultFileIds)) {
304
+                $resultFileIds = $fileIds;
305
+            } else {
306
+                $resultFileIds = array_intersect($fileIds, $resultFileIds);
307
+            }
308
+        }
309
+
310
+        return $resultFileIds;
311
+    }
312
+
313
+    private function getSystemTagFileIds($systemTagIds) {
314
+        $resultFileIds = null;
315
+
316
+        // check user permissions, if applicable
317
+        if (!$this->isAdmin()) {
318
+            // check visibility/permission
319
+            $tags = $this->tagManager->getTagsByIds($systemTagIds);
320
+            $unknownTagIds = [];
321
+            foreach ($tags as $tag) {
322
+                if (!$tag->isUserVisible()) {
323
+                    $unknownTagIds[] = $tag->getId();
324
+                }
325
+            }
326
+
327
+            if (!empty($unknownTagIds)) {
328
+                throw new TagNotFoundException('Tag with ids ' . implode(', ', $unknownTagIds) . ' not found');
329
+            }
330
+        }
331
+
332
+        // fetch all file ids and intersect them
333
+        foreach ($systemTagIds as $systemTagId) {
334
+            $fileIds = $this->tagMapper->getObjectIdsForTags($systemTagId, 'files');
335
+
336
+            if (empty($fileIds)) {
337
+                // This tag has no files, nothing can ever show up
338
+                return [];
339
+            }
340
+
341
+            // first run ?
342
+            if ($resultFileIds === null) {
343
+                $resultFileIds = $fileIds;
344
+            } else {
345
+                $resultFileIds = array_intersect($resultFileIds, $fileIds);
346
+            }
347
+
348
+            if (empty($resultFileIds)) {
349
+                // Empty intersection, nothing can show up anymore
350
+                return [];
351
+            }
352
+        }
353
+        return $resultFileIds;
354
+    }
355
+
356
+    /**
357
+     * @suppress PhanUndeclaredClassMethod
358
+     * @param array $circlesIds
359
+     * @return array
360
+     */
361
+    private function getCirclesFileIds(array $circlesIds) {
362
+        if (!$this->appManager->isEnabledForUser('circles') || !class_exists('\OCA\Circles\Api\v1\Circles')) {
363
+            return [];
364
+        }
365
+        return \OCA\Circles\Api\v1\Circles::getFilesForCircles($circlesIds);
366
+    }
367
+
368
+
369
+    /**
370
+     * Prepare propfind response for the given nodes
371
+     *
372
+     * @param string $filesUri $filesUri URI leading to root of the files URI,
373
+     * with a leading slash but no trailing slash
374
+     * @param string[] $requestedProps requested properties
375
+     * @param Node[] nodes nodes for which to fetch and prepare responses
376
+     * @return Response[]
377
+     */
378
+    public function prepareResponses($filesUri, $requestedProps, $nodes) {
379
+        $responses = [];
380
+        foreach ($nodes as $node) {
381
+            $propFind = new PropFind($filesUri . $node->getPath(), $requestedProps);
382
+
383
+            $this->server->getPropertiesByNode($propFind, $node);
384
+            // copied from Sabre Server's getPropertiesForPath
385
+            $result = $propFind->getResultForMultiStatus();
386
+            $result['href'] = $propFind->getPath();
387
+
388
+            $resourceType = $this->server->getResourceTypeForNode($node);
389
+            if (in_array('{DAV:}collection', $resourceType) || in_array('{DAV:}principal', $resourceType)) {
390
+                $result['href'] .= '/';
391
+            }
392
+
393
+            $responses[] = new Response(
394
+                rtrim($this->server->getBaseUri(), '/') . $filesUri . $node->getPath(),
395
+                $result,
396
+                200
397
+            );
398
+        }
399
+        return $responses;
400
+    }
401
+
402
+    /**
403
+     * Find Sabre nodes by file ids
404
+     *
405
+     * @param Node $rootNode root node for search
406
+     * @param array $fileIds file ids
407
+     * @return Node[] array of Sabre nodes
408
+     */
409
+    public function findNodesByFileIds($rootNode, $fileIds) {
410
+        $folder = $this->userFolder;
411
+        if (trim($rootNode->getPath(), '/') !== '') {
412
+            $folder = $folder->get($rootNode->getPath());
413
+        }
414
+
415
+        $results = [];
416
+        foreach ($fileIds as $fileId) {
417
+            $entry = $folder->getById($fileId);
418
+            if ($entry) {
419
+                $entry = current($entry);
420
+                if ($entry instanceof \OCP\Files\File) {
421
+                    $results[] = new File($this->fileView, $entry);
422
+                } elseif ($entry instanceof \OCP\Files\Folder) {
423
+                    $results[] = new Directory($this->fileView, $entry);
424
+                }
425
+            }
426
+        }
427
+
428
+        return $results;
429
+    }
430
+
431
+    /**
432
+     * Returns whether the currently logged in user is an administrator
433
+     */
434
+    private function isAdmin() {
435
+        $user = $this->userSession->getUser();
436
+        if ($user !== null) {
437
+            return $this->groupManager->isAdmin($user->getUID());
438
+        }
439
+        return false;
440
+    }
441 441
 }
Please login to merge, or discard this patch.