Passed
Push — php8 ( 3e2147...190cd5 )
by Matias
10:58 queued 08:41
created

FileHooks::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 8
dl 0
loc 17
ccs 0
cts 9
cp 0
crap 2
rs 10
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
declare(strict_types=1);
3
/**
4
 * @copyright Copyright (c) 2016, Roeland Jago Douma <[email protected]>
5
 * @copyright Copyright (c) 2017-2021 Matias De lellis <[email protected]>
6
 *
7
 * @author Roeland Jago Douma <[email protected]>
8
 * @author Matias De lellis <[email protected]>
9
 *
10
 * @license GNU AGPL version 3 or any later version
11
 *
12
 * This program is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License as
14
 * published by the Free Software Foundation, either version 3 of the
15
 * License, or (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
 *
25
 */
26
27
namespace OCA\FaceRecognition\Hooks;
28
29
use OCP\Files\IRootFolder;
30
use OCP\Files\Folder;
31
use OCP\Files\Node;
32
use OCP\ILogger;
33
use OCP\IUserManager;
34
35
use OCA\FaceRecognition\Service\FileService;
36
use OCA\FaceRecognition\Service\SettingsService;
37
38
use OCA\FaceRecognition\Db\Face;
39
use OCA\FaceRecognition\Db\Image;
40
41
use OCA\FaceRecognition\Db\FaceMapper;
42
use OCA\FaceRecognition\Db\ImageMapper;
43
use OCA\FaceRecognition\Db\PersonMapper;
44
45
class FileHooks {
46
47
	/** @var IRootFolder */
48
	private $root;
49
50
	/** @var ILogger Logger */
51
	private $logger;
52
53
	/** @var IUserManager */
54
	private $userManager;
55
56
	/** @var FaceMapper */
57
	private $faceMapper;
58
59
	/** @var ImageMapper */
60
	private $imageMapper;
61
62
	/** @var PersonMapper */
63
	private $personMapper;
64
65
	/** @var SettingsService */
66
	private $settingsService;
67
68
	/** @var FileService */
69
	private $fileService;
70
71
	/**
72
	 * Watcher constructor.
73
	 *
74
	 * @param IRootFolder $root
75
	 * @param ILogger $logger
76
	 * @param IUserManager $userManager
77
	 * @param FaceMapper $faceMapper
78
	 * @param ImageMapper $imageMapper
79
	 * @param PersonMapper $personMapper
80
	 * @param SettingsService $settingsService
81
	 * @param FileService $fileService
82
	 */
83
	public function __construct(IRootFolder           $root,
84
	                            ILogger               $logger,
85
	                            IUserManager          $userManager,
86
	                            FaceMapper            $faceMapper,
87
	                            ImageMapper           $imageMapper,
88
	                            PersonMapper          $personMapper,
89
	                            SettingsService       $settingsService,
90
	                            FileService           $fileService)
91
	{
92
		$this->root                  = $root;
93
		$this->logger                = $logger;
94
		$this->userManager           = $userManager;
95
		$this->faceMapper            = $faceMapper;
96
		$this->imageMapper           = $imageMapper;
97
		$this->personMapper          = $personMapper;
98
		$this->settingsService       = $settingsService;
99
		$this->fileService           = $fileService;
100
	}
101
102 28
	public function register() {
103
		// Watch on postWrite to handle new and changes files
104
		$this->root->listen('\OC\Files', 'postWrite', function (Node $node) {
105 28
			$this->postWrite($node);
106 28
		});
107
108
		// We want to react on postDelete and not preDelete as in preDelete we don't know if
109
		// file actually got deleted (locked, other errors...)
110
		$this->root->listen('\OC\Files', 'postDelete', function (Node $node) {
111 28
			$this->postDelete($node);
112 28
		});
113
	}
114
115
	/**
116
	 * A node has been updated. We just store the file id
117
	 * with the current user in the DB
118
	 *
119
	 * @param Node $node
120
	 */
121 28
	public function postWrite(Node $node) {
122 28
		if (!$this->fileService->isAllowedNode($node)) {
123
			// Nextcloud sends the Hooks when create thumbnails for example.
124 28
			return;
125
		}
126
127 28
		if ($node instanceof Folder) {
128 28
			return;
129
		}
130
131
		$modelId = $this->settingsService->getCurrentFaceModel();
132
		if ($modelId === SettingsService::FALLBACK_CURRENT_MODEL) {
133
			$this->logger->debug("Skipping inserting file since there are no configured model");
0 ignored issues
show
Deprecated Code introduced by
The function OCP\ILogger::debug() has been deprecated: 20.0.0 use \Psr\Log\LoggerInterface::debug ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

133
			/** @scrutinizer ignore-deprecated */ $this->logger->debug("Skipping inserting file since there are no configured model");

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
134
			return;
135
		}
136
137
		$owner = null;
138
		if ($this->fileService->isUserFile($node)) {
139
			$owner = $node->getOwner()->getUid();
140
		} else {
141
			if (!\OC::$server->getUserSession()->isLoggedIn()) {
142
				$this->logger->debug('Skipping interting file ' . $node->getName() . ' since we cannot determine the owner.');
0 ignored issues
show
Deprecated Code introduced by
The function OCP\ILogger::debug() has been deprecated: 20.0.0 use \Psr\Log\LoggerInterface::debug ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

142
				/** @scrutinizer ignore-deprecated */ $this->logger->debug('Skipping interting file ' . $node->getName() . ' since we cannot determine the owner.');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
143
				return;
144
			}
145
			$owner = \OC::$server->getUserSession()->getUser()->getUID();
146
		}
147
148
		if (!$this->userManager->userExists($owner)) {
149
			$this->logger->debug(
0 ignored issues
show
Deprecated Code introduced by
The function OCP\ILogger::debug() has been deprecated: 20.0.0 use \Psr\Log\LoggerInterface::debug ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

149
			/** @scrutinizer ignore-deprecated */ $this->logger->debug(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
150
				"Skipping inserting file " . $node->getName() . " because it seems that user  " . $owner . " doesn't exist");
151
			return;
152
		}
153
154
		$enabled = $this->settingsService->getUserEnabled($owner);
155
		if (!$enabled) {
156
			$this->logger->debug('The user ' . $owner . ' not have the analysis enabled. Skipping');
0 ignored issues
show
Deprecated Code introduced by
The function OCP\ILogger::debug() has been deprecated: 20.0.0 use \Psr\Log\LoggerInterface::debug ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

156
			/** @scrutinizer ignore-deprecated */ $this->logger->debug('The user ' . $owner . ' not have the analysis enabled. Skipping');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
157
			return;
158
		}
159
160
		if ($node->getName() === FileService::NOMEDIA_FILE ||
161
		    $node->getName() === FileService::NOIMAGE_FILE) {
162
			// If user added this file, it means all images in this and all child directories should be removed.
163
			// Instead of doing that here, it's better to just add flag that image removal should be done.
164
			$this->settingsService->setNeedRemoveStaleImages(true, $owner);
165
			return;
166
		}
167
168
		if ($node->getName() === FileService::FACERECOGNITION_SETTINGS_FILE) {
169
			// This file can enable or disable the analysis, so I have to look for new files and forget others.
170
			$this->settingsService->setNeedRemoveStaleImages(true, $owner);
171
			$this->settingsService->setUserFullScanDone(false, $owner);
172
			return;
173
		}
174
175
		if (!$this->settingsService->isAllowedMimetype($node->getMimeType())) {
176
			// The file is not an image or the model does not support it
177
			return;
178
		}
179
180
		if ($this->fileService->isUnderNoDetection($node)) {
181
			$this->logger->debug(
0 ignored issues
show
Deprecated Code introduced by
The function OCP\ILogger::debug() has been deprecated: 20.0.0 use \Psr\Log\LoggerInterface::debug ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

181
			/** @scrutinizer ignore-deprecated */ $this->logger->debug(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
182
				"Skipping inserting image " . $node->getName() . " because is inside an folder that contains a .nomedia file");
183
			return;
184
		}
185
186
		$this->logger->debug("Inserting/updating image " . $node->getName() . " for face recognition");
0 ignored issues
show
Deprecated Code introduced by
The function OCP\ILogger::debug() has been deprecated: 20.0.0 use \Psr\Log\LoggerInterface::debug ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

186
		/** @scrutinizer ignore-deprecated */ $this->logger->debug("Inserting/updating image " . $node->getName() . " for face recognition");

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
187
188
		$image = new Image();
189
		$image->setUser($owner);
190
		$image->setFile($node->getId());
191
		$image->setModel($modelId);
192
193
		$imageId = $this->imageMapper->imageExists($image);
194
		if ($imageId === null) {
195
			// todo: can we have larger transaction with bulk insert?
196
			$this->imageMapper->insert($image);
197
		} else {
198
			$this->imageMapper->resetImage($image);
199
			// note that invalidatePersons depends on existence of faces for a given image,
200
			// and we must invalidate before we delete faces!
201
			$this->personMapper->invalidatePersons($imageId);
202
203
			// Fetch all faces to be deleted before deleting them, and then delete them
204
			$facesToRemove = $this->faceMapper->findByImage($imageId);
205
			$this->faceMapper->removeFromImage($imageId);
206
207
			// If any person is now without faces, remove those (empty) persons
208
			foreach ($facesToRemove as $faceToRemove) {
209
				if ($faceToRemove->getPerson() !== null) {
210
					$this->personMapper->removeIfEmpty($faceToRemove->getPerson());
211
				}
212
			}
213
		}
214
	}
215
216
	/**
217
	 * A node has been deleted. Remove faces with file id
218
	 * with the current user in the DB
219
	 *
220
	 * @param Node $node
221
	 */
222 28
	public function postDelete(Node $node) {
223 28
		if (!$this->fileService->isAllowedNode($node)) {
224
			// Nextcloud sends the Hooks when create thumbnails for example.
225 28
			return;
226
		}
227
228
		if ($node instanceof Folder) {
229
			return;
230
		}
231
232
		$modelId = $this->settingsService->getCurrentFaceModel();
233
		if ($modelId === SettingsService::FALLBACK_CURRENT_MODEL) {
234
			$this->logger->debug("Skipping deleting file since there are no configured model");
0 ignored issues
show
Deprecated Code introduced by
The function OCP\ILogger::debug() has been deprecated: 20.0.0 use \Psr\Log\LoggerInterface::debug ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

234
			/** @scrutinizer ignore-deprecated */ $this->logger->debug("Skipping deleting file since there are no configured model");

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
235
			return;
236
		}
237
238
		$owner = null;
239
		if ($this->fileService->isUserFile($node)) {
240
			$owner = $node->getOwner()->getUid();
241
		} else {
242
			if (!\OC::$server->getUserSession()->isLoggedIn()) {
243
				$this->logger->debug('Skipping deleting the file ' . $node->getName() .  ' since we cannot determine the owner');
0 ignored issues
show
Deprecated Code introduced by
The function OCP\ILogger::debug() has been deprecated: 20.0.0 use \Psr\Log\LoggerInterface::debug ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

243
				/** @scrutinizer ignore-deprecated */ $this->logger->debug('Skipping deleting the file ' . $node->getName() .  ' since we cannot determine the owner');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
244
				return;
245
			}
246
			$owner = \OC::$server->getUserSession()->getUser()->getUID();
247
		}
248
249
		$enabled = $this->settingsService->getUserEnabled($owner);
250
		if (!$enabled) {
251
			$this->logger->debug('The user ' . $owner . ' not have the analysis enabled. Skipping');
0 ignored issues
show
Deprecated Code introduced by
The function OCP\ILogger::debug() has been deprecated: 20.0.0 use \Psr\Log\LoggerInterface::debug ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

251
			/** @scrutinizer ignore-deprecated */ $this->logger->debug('The user ' . $owner . ' not have the analysis enabled. Skipping');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
252
			return;
253
		}
254
255
		if ($node->getName() === FileService::NOMEDIA_FILE ||
256
		    $node->getName() === FileService::NOIMAGE_FILE) {
257
			// If user deleted file named .nomedia, that means all images in this and all child directories should be added.
258
			// But, instead of doing that here, better option seem to be to just reset flag that image scan is not done.
259
			// This will trigger another round of image crawling in AddMissingImagesTask for this user and those images will be added.
260
			$this->settingsService->setUserFullScanDone(false, $owner);
261
			return;
262
		}
263
264
		if ($node->getName() === FileService::FACERECOGNITION_SETTINGS_FILE) {
265
			// This file can enable or disable the analysis, so I have to look for new files and forget others.
266
			$this->settingsService->setNeedRemoveStaleImages(true, $owner);
267
			$this->settingsService->setUserFullScanDone(false, $owner);
268
			return;
269
		}
270
271
		if (!$this->settingsService->isAllowedMimetype($node->getMimeType())) {
272
			// The file is not an image or the model does not support it
273
			return;
274
		}
275
276
		$this->logger->debug("Deleting image " . $node->getName() . " from face recognition");
0 ignored issues
show
Deprecated Code introduced by
The function OCP\ILogger::debug() has been deprecated: 20.0.0 use \Psr\Log\LoggerInterface::debug ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

276
		/** @scrutinizer ignore-deprecated */ $this->logger->debug("Deleting image " . $node->getName() . " from face recognition");

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
277
278
		$image = new Image();
279
		$image->setUser($owner);
280
		$image->setFile($node->getId());
281
		$image->setModel($modelId);
282
283
		$imageId = $this->imageMapper->imageExists($image);
284
		if ($imageId !== null) {
285
			// note that invalidatePersons depends on existence of faces for a given image,
286
			// and we must invalidate before we delete faces!
287
			$this->personMapper->invalidatePersons($imageId);
288
289
			// Fetch all faces to be deleted before deleting them, and then delete them
290
			$facesToRemove = $this->faceMapper->findByImage($imageId);
291
			$this->faceMapper->removeFromImage($imageId);
292
293
			$image->setId($imageId);
294
			$this->imageMapper->delete($image);
295
296
			// If any person is now without faces, remove those (empty) persons
297
			foreach ($facesToRemove as $faceToRemove) {
298
				if ($faceToRemove->getPerson() !== null) {
299
					$this->personMapper->removeIfEmpty($faceToRemove->getPerson());
300
				}
301
			}
302
		}
303
	}
304
}
305