* @copyright Copyright (c) 2019, Branko Kokanovic * * @author Branko Kokanovic * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ namespace OCA\FaceRecognition\Service; use OCP\IUser; use OCP\IUserManager; use OCA\FaceRecognition\Db\FaceMapper; use OCA\FaceRecognition\Db\ImageMapper; use OCA\FaceRecognition\Db\PersonMapper; use OCA\FaceRecognition\Service\SettingsService; /** * Background service. Both command and cron job are calling this service for long-running background operations. * Background processing for face recognition is comprised of several steps, called tasks. Each task is independent, * idempotent, DI-aware logic unit that yields. Since tasks are non-preemptive, they should yield from time to time, so we son't end up * working for more than given timeout. * * Tasks can be seen as normal sequential functions, but they are easier to work with, * reason about them and test them independently. Other than that, they are really glorified functions. */ class FaceManagementService { /** @var IUserManager */ private $userManager; /** @var FaceMapper */ private $faceMapper; /** @var ImageMapper */ private $imageMapper; /** @var PersonMapper */ private $personMapper; /** @var SettingsService */ private $settingsService; public function __construct(IUserManager $userManager, FaceMapper $faceMapper, ImageMapper $imageMapper, PersonMapper $personMapper, SettingsService $settingsService) { $this->userManager = $userManager; $this->faceMapper = $faceMapper; $this->imageMapper = $imageMapper; $this->personMapper = $personMapper; $this->settingsService = $settingsService; } /** * Check if the current model has data on db * * @param IUser|null $user Optional user to check * @param Int $modelId Optional model to check * * @return bool */ public function hasData(IUser $user = null, int $modelId = -1): bool { if ($modelId === -1) { $modelId = $this->settingsService->getCurrentFaceModel(); } $eligible_users = $this->getEligiblesUserId($user); foreach ($eligible_users as $userId) { if ($this->hasDataForUser($userId, $modelId)) { return true; } } return false; } /** * Check if the current model has data on db for user * * @param string $user ID of user to check * @param Int $modelId model to check * * @return bool */ public function hasDataForUser(string $userId, int $modelId): bool { $facesCount = $this->faceMapper->countFaces($userId, $modelId); return ($facesCount > 0); } /** * Deletes all faces, images and persons found. IF no user is given, resetting is executed for all users. * * @param IUser|null $user Optional user to execute resetting for * * @return void */ public function resetAll(IUser $user = null): void { $eligible_users = $this->getEligiblesUserId($user); foreach($eligible_users as $user) { $this->resetAllForUser($user); } } /** * Deletes all faces, images and persons found for a given user. * * @param string $user ID of user to execute resetting for * * @return void */ public function resetAllForUser(string $userId): void { $this->faceMapper->deleteUserFaces($userId); $this->personMapper->deleteUserPersons($userId); $this->imageMapper->deleteUserImages($userId); $this->settingsService->setUserFullScanDone(false, $userId); } /** * Deletes all faces, images and persons found. If no user is given, resetting is executed for all users. * * @param IUser|null $user Optional user to execute resetting for * @param Int $modelId Optional model to clean * * @return void */ public function resetModel(IUser $user = null, int $modelId = -1): void { if ($modelId === -1) { $modelId = $this->settingsService->getCurrentFaceModel(); } $eligible_users = $this->getEligiblesUserId($user); foreach($eligible_users as $userId) { $this->resetModelForUser($userId, $modelId); } } /** * Deletes all faces, images and persons found for a given user. * * @param string $user ID of user to execute resetting for * @param Int $modelId model to clean * * @return void */ public function resetModelForUser(string $userId, $modelId): void { $this->personMapper->deleteUserModel($userId, $modelId); $this->faceMapper->deleteUserModel($userId, $modelId); $this->imageMapper->deleteUserModel($userId, $modelId); $this->settingsService->setUserFullScanDone(false, $userId); } /** * Reset error in images in order to re-analyze again. * If no user is given, resetting is executed for all users. * * @param IUser|null $user Optional user to execute resetting for * * @return void */ public function resetImageErrors(IUser $user = null): void { $eligible_users = $this->getEligiblesUserId($user); foreach($eligible_users as $userId) { $this->imageMapper->resetErrors($userId); $this->settingsService->setUserFullScanDone(false, $userId); } } /** * Eliminate all faces relations with person. * If no user is given, resetting is executed for all users. * * @param IUser|null $user Optional user to execute resetting for * * @return void */ public function resetClusters(IUser $user = null): void { $eligible_users = $this->getEligiblesUserId($user); foreach($eligible_users as $user) { $this->resetClustersForUser($user); } } /** * Eliminate all faces relations with person. * * @param string $user ID of user to execute resetting for * * @return void */ public function resetClustersForUser(string $userId): void { $model = $this->settingsService->getCurrentFaceModel(); $this->faceMapper->unsetPersonsRelationForUser($userId, $model); $this->personMapper->deleteUserPersons($userId); } /** * Get an array with the eligibles users taking into account the user argument, * or all users. * * @param IUser|null $user Optional user to get specific user. */ private function getEligiblesUserId(IUser $user = null): array { $eligible_users = array(); if (is_null($user)) { $this->userManager->callForAllUsers(function (IUser $user) use (&$eligible_users) { $eligible_users[] = $user->getUID(); }); } else { $eligible_users[] = $user->getUID(); } return $eligible_users; } }