Passed
Push — cleanup-after-deleted-users ( 9407f3...2c4c8c )
by Branko
02:10
created

Watcher::postUserDelete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, Roeland Jago Douma <[email protected]>
4
 * @copyright Copyright (c) 2017, Matias De lellis <[email protected]>
5
 *
6
 * @author Roeland Jago Douma <[email protected]>
7
 * @author Matias De lellis <[email protected]>
8
 *
9
 * @license GNU AGPL version 3 or any later version
10
 *
11
 * This program is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU Affero General Public License as
13
 * published by the Free Software Foundation, either version 3 of the
14
 * License, or (at your option) any later version.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23
 *
24
 */
25
namespace OCA\FaceRecognition;
26
27
use OCP\Files\Folder;
28
use OCP\Files\IHomeStorage;
29
use OCP\Files\Node;
30
use OCP\IConfig;
31
use OCP\IDBConnection;
32
use OCP\ILogger;
33
use OCP\IUserManager;
34
35
use OCA\FaceRecognition\FaceManagementService;
36
37
use OCA\FaceRecognition\BackgroundJob\Tasks\AddMissingImagesTask;
38
use OCA\FaceRecognition\BackgroundJob\Tasks\StaleImagesRemovalTask;
39
use OCA\FaceRecognition\Db\Face;
40
use OCA\FaceRecognition\Db\Image;
41
use OCA\FaceRecognition\Db\FaceMapper;
42
use OCA\FaceRecognition\Db\ImageMapper;
43
use OCA\FaceRecognition\Db\PersonMapper;
44
use OCA\FaceRecognition\Helper\Requirements;
45
use OCA\FaceRecognition\Migration\AddDefaultFaceModel;
46
47
class Watcher {
48
49
	/** @var IConfig Config */
50
	private $config;
51
52
	/** @var ILogger Logger */
53
	private $logger;
54
55
	/** @var IDBConnection */
56
	private $connection;
57
58
	/** @var IUserManager */
59
	private $userManager;
60
61
	/** @var FaceMapper */
62
	private $faceMapper;
63
64
	/** @var ImageMapper */
65
	private $imageMapper;
66
67
	/** @var PersonMapper */
68
	private $personMapper;
69
70
	/** @var FaceManagementService */
71
	private $faceManagementService;
72
73
	/**
74
	 * Watcher constructor.
75
	 *
76
	 * @param IConfig $config
77
	 * @param ILogger $logger
78
	 * @param IDBConnection $connection
79 8
	 * @param IUserManager $userManager
80
	 * @param FaceMapper $faceMapper
81
	 * @param ImageMapper $imageMapper
82
	 * @param PersonMapper $personMapper
83
	 * @param FaceManagementService $faceManagementService
84
	 */
85
	public function __construct(
86
								IConfig               $config,
87 8
								ILogger               $logger,
88 8
								IDBConnection         $connection,
89 8
								IUserManager          $userManager,
90 8
								FaceMapper            $faceMapper,
91 8
								ImageMapper           $imageMapper,
92 8
								PersonMapper          $personMapper,
93 8
								FaceManagementService $faceManagementService)
94 8
	{
95
		$this->config = $config;
96
		$this->logger = $logger;
97
		$this->connection = $connection;
98
		$this->userManager = $userManager;
99
		$this->faceMapper = $faceMapper;
100
		$this->imageMapper = $imageMapper;
101
		$this->personMapper = $personMapper;
102 8
		$this->faceManagementService = $faceManagementService;
103 8
	}
104
105
	/**
106 8
	 * A node has been updated. We just store the file id
107 8
	 * with the current user in the DB
108
	 *
109
	 * @param Node $node
110 8
	 */
111 8
	public function postWrite(Node $node) {
112
		$model = intval($this->config->getAppValue('facerecognition', 'model', AddDefaultFaceModel::DEFAULT_FACE_MODEL_ID));
113
114
		// todo: should we also care about this too: instanceOfStorage(ISharedStorage::class);
115
		if ($node->getStorage()->instanceOfStorage(IHomeStorage::class) === false) {
116
			return;
117
		}
118
119
		if ($node instanceof Folder) {
120
			return;
121
		}
122
123
		$owner = $node->getOwner()->getUid();
124
125
		if ($node->getName() === '.nomedia') {
126
			// If user added this file, it means all images in this and all child directories should be removed.
127
			// Instead of doing that here, it's better to just add flag that image removal should be done.
128
			$this->config->setUserValue($owner, 'facerecognition', StaleImagesRemovalTask::STALE_IMAGES_REMOVAL_NEEDED_KEY, 'true');
129
			return;
130
		}
131
132
		if (!Requirements::isImageTypeSupported($node->getMimeType())) {
133
			return;
134
		}
135
136
		if (!$this->userManager->userExists($owner)) {
137
			$this->logger->debug(
138
				"Skipping inserting image " . $node->getName() . " because it seems that user  " . $owner . " doesn't exist");
139
			return;
140
		}
141
142
		// If we detect .nomedia file anywhere on the path to root folder (id===null), bail out
143
		$parentNode = $node->getParent();
144
		while (($parentNode instanceof Folder) && ($parentNode->getId() !== null)) {
145
			if ($parentNode->nodeExists('.nomedia')) {
146
				$this->logger->debug(
147
					"Skipping inserting image " . $node->getName() . " because directory " . $parentNode->getName() . " contains .nomedia file");
148
				return;
149
			}
150
151
			$parentNode = $parentNode->getParent();
152
		}
153
154
		$this->logger->debug("Inserting/updating image " . $node->getName() . " for face recognition");
155
156
		$image = new Image();
157
		$image->setUser($owner);
158
		$image->setFile($node->getId());
159
		$image->setModel($model);
160
161
		$imageId = $this->imageMapper->imageExists($image);
162
		if ($imageId === null) {
163
			// todo: can we have larger transaction with bulk insert?
164
			$this->imageMapper->insert($image);
165
		} else {
166
			$this->imageMapper->resetImage($image);
167
			// note that invalidatePersons depends on existence of faces for a given image,
168
			// and we must invalidate before we delete faces!
169
			$this->personMapper->invalidatePersons($imageId);
170
			$this->faceMapper->removeFaces($imageId);
171
		}
172
	}
173
174
	/**
175
	 * A node has been deleted. Remove faces with file id
176
	 * with the current user in the DB
177
	 *
178
	 * @param Node $node
179
	 */
180
	public function postDelete(Node $node) {
181
		$model = intval($this->config->getAppValue('facerecognition', 'model', AddDefaultFaceModel::DEFAULT_FACE_MODEL_ID));
182
183
		// todo: should we also care about this too: instanceOfStorage(ISharedStorage::class);
184
		if ($node->getStorage()->instanceOfStorage(IHomeStorage::class) === false) {
185
			return;
186
		}
187
188
		if ($node instanceof Folder) {
189
			return;
190
		}
191
192
		$owner = $node->getOwner()->getUid();
193
194
		if ($node->getName() === '.nomedia') {
195
			// If user deleted file named .nomedia, that means all images in this and all child directories should be added.
196
			// But, instead of doing that here, better option seem to be to just reset flag that image scan is not done.
197
			// This will trigger another round of image crawling in AddMissingImagesTask for this user and those images will be added.
198
			$this->config->setUserValue($owner, 'facerecognition', AddMissingImagesTask::FULL_IMAGE_SCAN_DONE_KEY, 'false');
199
			return;
200
		}
201
202
		if (!Requirements::isImageTypeSupported($node->getMimeType())) {
203
			return;
204
		}
205
206
		$this->logger->debug("Deleting image " . $node->getName() . " from face recognition");
207
208
		$image = new Image();
209
		$image->setUser($owner);
210
		$image->setFile($node->getId());
211
		$image->setModel($model);
212
213
		$imageId = $this->imageMapper->imageExists($image);
214
		if ($imageId !== null) {
215
			// note that invalidatePersons depends on existence of faces for a given image,
216
			// and we must invalidate before we delete faces!
217
			$this->personMapper->invalidatePersons($imageId);
218
			$this->faceMapper->removeFaces($imageId);
219
220
			$image->setId($imageId);
221
			$this->imageMapper->delete($image);
222
		}
223
	}
224
225
	/**
226
	 * A user has been deleted. Cleanup everything from this user.
227
	 *
228
	 * @param \OC\User\User $user Deleted user
229
	 */
230
	public function postUserDelete(\OC\User\User $user) {
0 ignored issues
show
Bug introduced by
The type OC\User\User was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
231
		$userId = $user->getUid();
232
		$this->faceManagementService->resetAllForUser($userId);
233
		$this->logger->info("Removed all face recognition data for deleted user " . $userId);
234
	}
235
}
236