Passed
Push — drop-old-code ( a3823a...bf8145 )
by Matias
02:15
created

Watcher   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 162
Duplicated Lines 0 %

Test Coverage

Coverage 23.44%

Importance

Changes 0
Metric Value
eloc 68
dl 0
loc 162
ccs 15
cts 64
cp 0.2344
rs 10
c 0
b 0
f 0
wmc 16

3 Methods

Rating   Name   Duplication   Size   Complexity  
B postWrite() 0 55 9
A __construct() 0 14 1
B postDelete() 0 42 6
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\BackgroundJob\Tasks\AddMissingImagesTask;
36
use OCA\FaceRecognition\Db\FaceNew;
37
use OCA\FaceRecognition\Db\Image;
38
use OCA\FaceRecognition\Db\FaceNewMapper;
39
use OCA\FaceRecognition\Db\ImageMapper;
40
use OCA\FaceRecognition\Db\PersonMapper;
41
use OCA\FaceRecognition\Helper\Requirements;
42
use OCA\FaceRecognition\Migration\AddDefaultFaceModel;
43
44
class Watcher {
45
46
	/** @var IConfig Config */
47
	private $config;
48
49
	/** @var ILogger Logger */
50
	private $logger;
51
52
	/** @var IDBConnection */
53
	private $connection;
54
55
	/** @var IUserManager */
56
	private $userManager;
57
58
	/** @var FaceNewMapper */
59
	private $faceNewMapper;
60
61
	/** @var ImageMapper */
62
	private $imageMapper;
63
64
	/** @var PersonMapper */
65
	private $personMapper;
66
67
	/**
68
	 * Watcher constructor.
69
	 *
70
	 * @param IConfig $config
71
	 * @param ILogger $logger
72
	 * @param IDBConnection $connection
73
	 * @param IUserManager $userManager
74
	 * @param FaceNewMapper $faceNewMapper
75
	 * @param ImageMapper $imageMapper
76
	 * @param PersonMapper $personMapper
77
	 */
78 4
	public function __construct(IConfig       $config,
79
								ILogger       $logger,
80
								IDBConnection $connection,
81
								IUserManager  $userManager,
82
								FaceNewMapper $faceNewMapper,
83
								ImageMapper   $imageMapper,
84
								PersonMapper  $personMapper) {
85 4
		$this->config = $config;
86 4
		$this->logger = $logger;
87 4
		$this->connection = $connection;
88 4
		$this->userManager = $userManager;
89 4
		$this->faceNewMapper = $faceNewMapper;
90 4
		$this->imageMapper = $imageMapper;
91 4
		$this->personMapper = $personMapper;
92 4
	}
93
94
	/**
95
	 * A node has been updated. We just store the file id
96
	 * with the current user in the DB
97
	 *
98
	 * @param Node $node
99
	 */
100 4
	public function postWrite(Node $node) {
101 4
		$model = intval($this->config->getAppValue('facerecognition', 'model', AddDefaultFaceModel::DEFAULT_FACE_MODEL_ID));
102
103
		// todo: should we also care about this too: instanceOfStorage(ISharedStorage::class);
104 4
		if ($node->getStorage()->instanceOfStorage(IHomeStorage::class) == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
105 4
			return;
106
		}
107
108 2
		if ($node instanceof Folder) {
109 2
			return;
110
		}
111
112
		// todo: issue #37 - if we detect .nomedia written, reset some global flag such that RemoveMissingImagesTask is triggered.
113
114
		if (!Requirements::isImageTypeSupported($node->getMimeType())) {
115
			return;
116
		}
117
118
		// If we detect .nomedia file anywhere on the path to root folder (id==null), bail out
119
		$parentNode = $node->getParent();
120
		while (($parentNode instanceof Folder) && ($parentNode->getId() != null)) {
121
			if ($parentNode->nodeExists('.nomedia')) {
122
				$this->logger->debug(
123
					"Skipping inserting image " . $node->getName() . " because directory " . $parentNode->getName() . " contains .nomedia file");
124
				return;
125
			}
126
127
			$parentNode = $parentNode->getParent();
128
		}
129
130
		$owner = $node->getOwner()->getUid();
131
132
		if (!$this->userManager->userExists($owner)) {
133
			$this->logger->debug(
134
				"Skipping inserting image " . $node->getName() . " because it seems that user  " . $owner . " doesn't exist");
135
			return;
136
		}
137
138
		$this->logger->debug("Inserting/updating image " . $node->getName() . " for face recognition");
139
140
		$image = new Image();
141
		$image->setUser($owner);
142
		$image->setFile($node->getId());
143
		$image->setModel($model);
144
145
		$imageId = $this->imageMapper->imageExists($image);
146
		if ($imageId === null) {
147
			// todo: can we have larger transaction with bulk insert?
148
			$this->imageMapper->insert($image);
149
		} else {
150
			$this->imageMapper->resetImage($image);
151
			// note that invalidatePersons depends on existence of faces for a given image,
152
			// and we must invalidate before we delete faces!
153
			$this->personMapper->invalidatePersons($imageId);
154
			$this->faceNewMapper->removeFaces($imageId);
155
		}
156
	}
157
158
	/**
159
	 * A node has been delete. Remove faces with file id
160
	 * with the current user in the DB
161
	 *
162
	 * @param Node $node
163
	 */
164
	public function postDelete(Node $node) {
165
		$model = intval($this->config->getAppValue('facerecognition', 'model', AddDefaultFaceModel::DEFAULT_FACE_MODEL_ID));
166
167
		// todo: should we also care about this too: instanceOfStorage(ISharedStorage::class);
168
		if ($node->getStorage()->instanceOfStorage(IHomeStorage::class) == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
169
			return;
170
		}
171
172
		if ($node instanceof Folder) {
173
			return;
174
		}
175
176
		if ($node->getName() == '.nomedia') {
177
			// If user deleted file named .nomedia, that means all images in this and all child directories should be added.
178
			// But, instead of doing that here, better option seem to be to just reset global flag that image scan is not done.
179
			// This will trigger another round of image crawling in AddMissingImagesTask and those images will be added.
180
			$this->config->setAppValue('facerecognition', AddMissingImagesTask::FULL_IMAGE_SCAN_DONE_KEY, 'false');
181
			return;
182
		}
183
184
		if (!Requirements::isImageTypeSupported($node->getMimeType())) {
185
			return;
186
		}
187
188
		$owner = $node->getOwner()->getUid();
189
190
		$this->logger->debug("Deleting image " . $node->getName() . " from face recognition");
191
192
		$image = new Image();
193
		$image->setUser($owner);
194
		$image->setFile($node->getId());
195
		$image->setModel($model);
196
197
		$imageId = $this->imageMapper->imageExists($image);
198
		if ($imageId !== null) {
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
			$this->faceNewMapper->removeFaces($imageId);
203
204
			$image->setId($imageId);
205
			$this->imageMapper->delete($image);
206
		}
207
	}
208
}
209