Passed
Push — find-similar ( 493fd2 )
by Matias
04:37
created

PersonController::updateName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 5
c 2
b 0
f 0
nc 1
nop 2
dl 0
loc 7
ccs 0
cts 6
cp 0
crap 2
rs 10
1
<?php
2
/**
3
 * @copyright Copyright (c) 2018-2020 Matias De lellis <[email protected]>
4
 *
5
 * @author Matias De lellis <[email protected]>
6
 *
7
 * @license GNU AGPL version 3 or any later version
8
 *
9
 * This program is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License as
11
 * published by the Free Software Foundation, either version 3 of the
12
 * License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 *
22
 */
23
24
namespace OCA\FaceRecognition\Controller;
25
26
use OCP\IRequest;
27
use OCP\Files\IRootFolder;
28
use OCP\Files\File;
29
use OCP\IUserSession;
30
use OCP\IURLGenerator;
31
32
use OCP\AppFramework\Http;
33
use OCP\AppFramework\Http\DataResponse;
34
use OCP\AppFramework\Http\JSONResponse;
35
use OCP\AppFramework\Http\DataDisplayResponse;
36
use OCP\AppFramework\Controller;
37
38
use OCA\FaceRecognition\Db\Face;
39
use OCA\FaceRecognition\Db\FaceMapper;
40
41
use OCA\FaceRecognition\Db\Image;
42
use OCA\FaceRecognition\Db\ImageMapper;
43
44
use OCA\FaceRecognition\Db\Person;
45
use OCA\FaceRecognition\Db\PersonMapper;
46
47
use OCA\FaceRecognition\Service\SettingsService;
48
49
class PersonController extends Controller {
50
51
	/** @var IRootFolder */
52
	private $rootFolder;
53
54
	/** @var IUserSession */
55
	private $userSession;
56
57
	/** @var IURLGenerator */
58
	private $urlGenerator;
59
60
	/** @var FaceMapper */
61
	private $faceMapper;
62
63
	/** @var ImageMapper */
64
	private $imageMapper;
65
66
	/** @var PersonMapper */
67
	private $personMapper;
68
69
	/** @var SettingsService */
70
	private $settingsService;
71
72
	/** @var string */
73
	private $userId;
74
75
	public function __construct($AppName,
76
	                            IRequest        $request,
77
	                            IRootFolder     $rootFolder,
78
	                            IUserSession    $userSession,
79
	                            IURLGenerator   $urlGenerator,
80
	                            FaceMapper      $faceMapper,
81
	                            ImageMapper     $imageMapper,
82
	                            PersonMapper    $personmapper,
83
	                            SettingsService $settingsService,
84
	                            $UserId)
85
	{
86
		parent::__construct($AppName, $request);
87
88
		$this->rootFolder      = $rootFolder;
89
		$this->userSession     = $userSession;
90
		$this->urlGenerator    = $urlGenerator;
91
		$this->faceMapper      = $faceMapper;
92
		$this->imageMapper     = $imageMapper;
93
		$this->personMapper    = $personmapper;
94
		$this->settingsService = $settingsService;
95
		$this->userId          = $UserId;
96
	}
97
98
	/**
99
	 * @NoAdminRequired
100
	 */
101
	public function index() {
102
		$notGrouped = $this->settingsService->getShowNotGrouped();
103
		$userEnabled = $this->settingsService->getUserEnabled($this->userId);
104
105
		$resp = array();
106
		$resp['enabled'] = $userEnabled;
107
		$resp['clusters'] = array();
108
109
		if (!$userEnabled)
110
			return new DataResponse($resp);
111
112
		$modelId = $this->settingsService->getCurrentFaceModel();
113
114
		$persons = $this->personMapper->findAll($this->userId, $modelId);
115
		foreach ($persons as $person) {
116
			$personFaces = $this->faceMapper->findFacesFromPerson($this->userId, $person->getId(), $modelId);
117
			if ($notGrouped === false && count($personFaces) <= 1)
118
				continue;
119
120
			$limit = 14;
121
			$faces = [];
122
			foreach ($personFaces as $personFace) {
123
				$image = $this->imageMapper->find($this->userId, $personFace->getImage());
124
				$fileUrl = $this->getRedirectToFileUrl($image->getFile());
0 ignored issues
show
Bug introduced by
It seems like $image->getFile() can also be of type null; however, parameter $fileId of OCA\FaceRecognition\Cont...:getRedirectToFileUrl() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

124
				$fileUrl = $this->getRedirectToFileUrl(/** @scrutinizer ignore-type */ $image->getFile());
Loading history...
125
				if (NULL === $fileUrl)
126
					continue;
127
128
				$face = [];
129
				$face['thumb-url'] = $this->getThumbUrl($personFace->getId());
130
				$face['file-url'] = $fileUrl;
131
				$faces[] = $face;
132
133
				if (--$limit === 0)
134
					break;
135
			}
136
137
			$cluster = [];
138
			$cluster['name'] = $person->getName();
139
			$cluster['count'] = count($personFaces);
140
			$cluster['id'] = $person->getId();
141
			$cluster['faces'] = $faces;
142
143
			$resp['clusters'][] = $cluster;
144
		}
145
		return new DataResponse($resp);
146
	}
147
148
	/**
149
	 * @NoAdminRequired
150
	 */
151
	public function find(int $id) {
152
		$person = $this->personMapper->find($this->userId, $id);
153
154
		$resp = [];
155
		$faces = [];
156
		$personFaces = $this->faceMapper->findFacesFromPerson($this->userId, $person->getId(), $this->settingsService->getCurrentFaceModel());
157
		foreach ($personFaces as $personFace) {
158
			$image = $this->imageMapper->find($this->userId, $personFace->getImage());
159
			$fileUrl = $this->getRedirectToFileUrl($image->getFile());
0 ignored issues
show
Bug introduced by
It seems like $image->getFile() can also be of type null; however, parameter $fileId of OCA\FaceRecognition\Cont...:getRedirectToFileUrl() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

159
			$fileUrl = $this->getRedirectToFileUrl(/** @scrutinizer ignore-type */ $image->getFile());
Loading history...
160
			if (NULL === $fileUrl)
161
				continue;
162
			$face = [];
163
			$face['thumb-url'] = $this->getThumbUrl($personFace->getId());
164
			$face['file-url'] = $fileUrl;
165
			$faces[] = $face;
166
		}
167
		$resp['name'] = $person->getName();
168
		$resp['id'] = $person->getId();
169
		$resp['faces'] = $faces;
170
171
		return new DataResponse($resp);
172
	}
173
174
	/**
175
	 * @NoAdminRequired
176
	 */
177
	public function findSimilar(int $id) {
178
		if (!version_compare(phpversion('pdlib'), '1.0.2', '>=')) {
179
			return new DataResponse(array());
180
		}
181
		$sensitivity = $this->settingsService->getSensitivity();
182
		$modelId = $this->settingsService->getCurrentFaceModel();
183
184
		$mainPerson = $this->personMapper->find($this->userId, $id);
185
		$mainFace = $this->faceMapper->findRepresentativeFromPerson($this->userId, $id, $sensitivity, $modelId);
186
187
		$resp = array();
188
		$persons = $this->personMapper->findAll($this->userId, $modelId);
189
		foreach ($persons as $cmpPerson) {
190
			if ($mainPerson->getName() === $cmpPerson->getName())
191
				continue;
192
193
			$cmpFace = $this->faceMapper->findRepresentativeFromPerson($this->userId, $cmpPerson->getId(), $sensitivity, $modelId);
194
			$distance = dlib_vector_length($mainFace->descriptor, $cmpFace->descriptor);
0 ignored issues
show
Bug introduced by
The function dlib_vector_length was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

194
			$distance = /** @scrutinizer ignore-call */ dlib_vector_length($mainFace->descriptor, $cmpFace->descriptor);
Loading history...
195
			if ($distance < ($sensitivity + 0.1)) {
196
				$similar = array();
197
				$similar['id'] = $cmpPerson->getId();
198
				$similar['name'] = $cmpPerson->getName();
199
				$similar['thumb-url'] = $this->getThumbUrl($cmpFace->getId());
200
				$resp[] = $similar;
201
			}
202
		}
203
204
		return new DataResponse($resp);
205
	}
206
207
	/**
208
	 * @NoAdminRequired
209
	 */
210
	public function findByName(string $personName) {
211
		$userEnabled = $this->settingsService->getUserEnabled($this->userId);
212
213
		$resp = array();
214
		$resp['enabled'] = $userEnabled;
215
		$resp['clusters'] = array();
216
217
		if (!$userEnabled)
218
			return new DataResponse($resp);
219
220
		$modelId = $this->settingsService->getCurrentFaceModel();
221
222
		$persons = $this->personMapper->findByName($this->userId, $modelId, $personName);
223
		foreach ($persons as $person) {
224
			$personFaces = $this->faceMapper->findFacesFromPerson($this->userId, $person->getId(), $modelId);
225
226
			$faces = [];
227
			foreach ($personFaces as $personFace) {
228
				$image = $this->imageMapper->find($this->userId, $personFace->getImage());
229
				$fileUrl = $this->getRedirectToFileUrl($image->getFile());
0 ignored issues
show
Bug introduced by
It seems like $image->getFile() can also be of type null; however, parameter $fileId of OCA\FaceRecognition\Cont...:getRedirectToFileUrl() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

229
				$fileUrl = $this->getRedirectToFileUrl(/** @scrutinizer ignore-type */ $image->getFile());
Loading history...
230
				if (NULL === $fileUrl)
231
					continue;
232
233
				$face = [];
234
				$face['thumb-url'] = $this->getThumbUrl($personFace->getId());
235
				$face['file-url'] = $fileUrl;
236
				$faces[] = $face;
237
			}
238
239
			$cluster = [];
240
			$cluster['name'] = $person->getName();
241
			$cluster['count'] = count($personFaces);
242
			$cluster['id'] = $person->getId();
243
			$cluster['faces'] = $faces;
244
			$resp['clusters'][] = $cluster;
245
		}
246
247
		return new DataResponse($resp);
248
	}
249
250
	/**
251
	 * @NoAdminRequired
252
	 *
253
	 * @param int $id
254
	 * @param string $name
255
	 */
256
	public function updateName($id, $name) {
257
		$person = $this->personMapper->find ($this->userId, $id);
258
		$person->setName($name);
259
		$this->personMapper->update($person);
260
261
		$newPerson = $this->personMapper->find($this->userId, $id);
262
		return new DataResponse($newPerson);
263
	}
264
265
	/**
266
	 * Url to thumb face
267
	 *
268
	 * @param string $faceId face id to show
269
	 */
270
	private function getThumbUrl($faceId) {
271
		$params = [];
272
		$params['id'] = $faceId;
273
		$params['size'] = 50;
274
		return $this->urlGenerator->linkToRoute('facerecognition.face.getThumb', $params);
275
	}
276
277
	/**
278
	 * Redirects to the file list and highlight the given file id
279
	 *
280
	 * @param int $fileId file id to show
281
	 */
282
	private function getRedirectToFileUrl(int $fileId) {
283
		$uid        = $this->userSession->getUser()->getUID();
284
		$baseFolder = $this->rootFolder->getUserFolder($uid);
285
		$files      = $baseFolder->getById($fileId);
286
		$file       = current($files);
287
288
		if(!($file instanceof File)) {
289
			// If we cannot find a file probably it was deleted out of our control and we must clean our tables.
290
			$this->settingsService->setNeedRemoveStaleImages(true, $this->userId);
291
			return NULL;
292
		}
293
294
		$params = [];
295
		$params['dir'] = $baseFolder->getRelativePath($file->getParent()->getPath());
296
		$params['scrollto'] = $file->getName();
297
298
		return $this->urlGenerator->linkToRoute('files.view.index', $params);
299
	}
300
301
}
302