Completed
Pull Request — master (#49)
by Matias
02:08
created

ImageMapper::resetImage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 0
cts 11
cp 0
rs 9.9
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
1
<?php
2
/**
3
 * @copyright Copyright (c) 2017, Matias De lellis <[email protected]>
4
 * @copyright Copyright (c) 2018, Branko Kokanovic <[email protected]>
5
 *
6
 * @author Branko Kokanovic <[email protected]>
7
 *
8
 * @license GNU AGPL version 3 or any later version
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License as
12
 * published by the Free Software Foundation, either version 3 of the
13
 * License, or (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU Affero General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Affero General Public License
21
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 *
23
 */
24
namespace OCA\FaceRecognition\Db;
25
26
use OCP\IDBConnection;
27
use OCP\IUser;
28
29
use OCP\AppFramework\Db\Mapper;
30
use OCP\AppFramework\Db\DoesNotExistException;
31
use OCP\DB\QueryBuilder\IQueryBuilder;
32
33
class ImageMapper extends Mapper {
34
35
	public function __construct(IDBConnection $db) {
36
		parent::__construct($db, 'face_recognition_images', '\OCA\FaceRecognition\Db\Image');
37
	}
38
39 View Code Duplication
	public function find (string $userId, int $imageId): Image {
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
40
		$qb = $this->db->getQueryBuilder();
41
		$qb->select('id', 'file')
42
			->from('face_recognition_images', 'i')
43
			->where($qb->expr()->eq('user', $qb->createParameter('user_id')))
44
			->andWhere($qb->expr()->eq('id', $qb->createParameter('image_id')));
45
		$params = array();
46
		$params['user_id'] = $userId;
47
		$params['image_id'] = $imageId;
48
		$image = $this->findEntity($qb->getSQL(), $params);
49
		return $image;
50
	}
51
52
	public function imageExists(Image $image) {
53
		$qb = $this->db->getQueryBuilder();
54
		$query = $qb
55
			->select(['id'])
56
			->from('face_recognition_images')
57
			->where($qb->expr()->eq('user', $qb->createParameter('user')))
58
			->andWhere($qb->expr()->eq('file', $qb->createParameter('file')))
59
			->andWhere($qb->expr()->eq('model', $qb->createParameter('model')))
60
			->setParameter('user', $image->getUser())
61
			->setParameter('file', $image->getFile())
62
			->setParameter('model', $image->getModel());
63
		$resultStatement = $query->execute();
64
		$row = $resultStatement->fetch();
65
		$resultStatement->closeCursor();
66
		return $row ? (int)$row['id'] : null;
67
	}
68
69
	public function countUserImages(string $userId, $model): int {
70
		$qb = $this->db->getQueryBuilder();
71
		$query = $qb
72
			->select($qb->createFunction('COUNT(' . $qb->getColumnName('id') . ')'))
73
			->from('face_recognition_images')
74
			->where($qb->expr()->eq('user', $qb->createParameter('user')))
75
			->andWhere($qb->expr()->eq('model', $qb->createParameter('model')))
76
			->setParameter('user', $userId)
77
			->setParameter('model', $model);
78
		$resultStatement = $query->execute();
79
		$data = $resultStatement->fetch(\PDO::FETCH_NUM);
80
		$resultStatement->closeCursor();
81
82
		return (int)$data[0];
83
	}
84
85
	public function countUserProcessedImages(string $userId, $model): int {
86
		$qb = $this->db->getQueryBuilder();
87
		$query = $qb
88
			->select($qb->createFunction('COUNT(' . $qb->getColumnName('id') . ')'))
89
			->from('face_recognition_images')
90
			->where($qb->expr()->eq('user', $qb->createParameter('user')))
91
			->andWhere($qb->expr()->eq('model', $qb->createParameter('model')))
92
			->andWhere($qb->expr()->eq('is_processed', $qb->createParameter('is_processed')))
93
			->setParameter('user', $userId)
94
			->setParameter('model', $model)
95
			->setParameter('is_processed', True);
96
		$resultStatement = $query->execute();
97
		$data = $resultStatement->fetch(\PDO::FETCH_NUM);
98
		$resultStatement->closeCursor();
99
100
		return (int)$data[0];
101
	}
102
103
	/**
104
	 * @param IUser|null $user User for which to get images for. If not given, all images from instance are returned.
105
	 */
106
	public function findImagesWithoutFaces(IUser $user = null) {
107
		$qb = $this->db->getQueryBuilder();
108
		$params = array();
109
110
		$query = $qb
111
			->select(['id', 'user', 'file', 'model'])
112
			->from('face_recognition_images')
113
			->where($qb->expr()->eq('is_processed',  $qb->createParameter('is_processed')));
114
			$params['is_processed'] = False;
115
		if (!is_null($user)) {
116
			$query->andWhere($qb->expr()->eq('user', $qb->createParameter('user')));
117
			$params['user'] = $user->getUID();
118
		}
119
120
		$images = $this->findEntities($qb->getSQL(), $params);
121
		return $images;
122
	}
123
124
125
	public function findImagesFromPerson(string $userId, string $name, int $model): array {
126
		$qb = $this->db->getQueryBuilder();
127
		$qb->select('i.id', 'i.file')
128
			->from('face_recognition_images', 'i')
129
			->innerJoin('i', 'face_recognition_faces', 'f', $qb->expr()->eq('f.image', 'i.id'))
130
			->innerJoin('i', 'face_recognition_persons', 'p', $qb->expr()->eq('f.person', 'p.id'))
131
			->where($qb->expr()->eq('p.user', $qb->createParameter('user')))
132
			->andWhere($qb->expr()->eq('model', $qb->createParameter('model')))
133
			->andWhere($qb->expr()->eq('is_processed', $qb->createParameter('is_processed')))
134
			->andWhere($qb->expr()->like($qb->func()->lower('p.name'), $qb->createParameter('query')));
135
136
		$params = array();
137
		$params['user'] = $userId;
138
		$params['model'] = $model;
139
		$params['is_processed'] = True;
140
		$params['query'] = '%' . $this->db->escapeLikeParameter(strtolower($name)) . '%';
141
		$images = $this->findEntities($qb->getSQL(), $params);
142
		return $images;
143
	}
144
145
	/**
146
	 * Writes to DB that image has been processed. Previously found faces are deleted and new ones are inserted.
147
	 * If there is exception, its stack trace is also updated.
148
	 *
149
	 * @param Image $image Image to be updated
150
	 * @param FaceNew[] $faces Faces to insert
151
	 * @param int $duration Processing time, in milliseconds
152
	 * @param \Exception|null $e Any exception that happened during image processing
153
	 */
154
	public function imageProcessed(Image $image, array $faces, int $duration, \Exception $e = null) {
155
		$this->db->beginTransaction();
156
		try {
157
			// Update image itself
158
			//
159
			$error = null;
160
			if ($e != null) {
161
				$error = substr($e->getMessage(), 0, 1024);
162
			}
163
164
			$qb = $this->db->getQueryBuilder();
165
			$qb->update('face_recognition_images')
166
				->set("is_processed", $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL))
167
				->set("error", $qb->createNamedParameter($error))
168
				->set("last_processed_time", $qb->createNamedParameter($currentDateTime, IQueryBuilder::PARAM_DATE))
0 ignored issues
show
Bug introduced by
The variable $currentDateTime does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
169
				->set("processing_duration", $qb->createNamedParameter($duration))
170
				->where($qb->expr()->eq('id', $qb->createNamedParameter($image->id)))
171
				->execute();
172
173
			// Delete all previous faces
174
			//
175
			$qb = $this->db->getQueryBuilder();
176
			$qb->delete('face_recognition_faces')
177
				->where($qb->expr()->eq('image', $qb->createNamedParameter($image->id)))
178
				->execute();
179
180
			// Insert all faces
181
			//
182
			foreach ($faces as $face) {
183
				// Simple INSERT will close cursor and we want to be in transaction, so use hard way
184
				// todo: should we move this to FaceNewMapper (don't forget to hand over connection though)
185
				$qb = $this->db->getQueryBuilder();
186
				$qb->insert('face_recognition_faces')
187
					->values([
188
						'image' => $qb->createNamedParameter($image->id),
189
						'person' => $qb->createNamedParameter(null),
190
						'left' => $qb->createNamedParameter($face->left),
191
						'right' => $qb->createNamedParameter($face->right),
192
						'top' => $qb->createNamedParameter($face->top),
193
						'bottom' => $qb->createNamedParameter($face->bottom),
194
						'descriptor' => $qb->createNamedParameter(json_encode($face->descriptor)),
195
						'creation_time' => $qb->createNamedParameter($face->creation_time, IQueryBuilder::PARAM_DATE),
196
					])
197
					->execute();
198
			}
199
200
			$this->db->commit();
201
		} catch (\Exception $e) {
202
			$this->db->rollBack();
203
			throw $e;
204
		}
205
	}
206
207
	/**
208
	 * Resets image by deleting all associated faces and prepares it to be processed again
209
	 *
210
	 * @param Image $image Image to reset
211
	 */
212
	public function resetImage(Image $image) {
213
		$qb = $this->db->getQueryBuilder();
214
		$qb->update($this->getTableName())
215
			->set("is_processed", $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL))
216
			->set("error", $qb->createNamedParameter(null))
217
			->set("last_processed_time", $qb->createNamedParameter(null))
218
			->where($qb->expr()->eq('user', $qb->createNamedParameter($image->getUser())))
219
			->andWhere($qb->expr()->eq('file', $qb->createNamedParameter($image->getFile())))
220
			->andWhere($qb->expr()->eq('model', $qb->createNamedParameter($image->getModel())))
221
			->execute();
222
	}
223
}
224