3838use OCP \Files \Node ;
3939use OCP \Files \NotFoundException ;
4040use OCP \IGroupManager ;
41- use OCP \Share \Events \ShareAcceptedEvent ;
41+ use OCP \Share \Events \ShareCreatedEvent ;
4242use OCP \Share \Events \ShareDeletedEvent ;
4343use OCP \Share \IManager ;
4444use Psr \Log \LoggerInterface ;
@@ -53,6 +53,9 @@ final class FileListener implements IEventListener {
5353 private array $ sourceUserIds ;
5454 private ?Node $ source = null ;
5555
56+ /** @var array<string, bool> */
57+ private array $ addedMounts = [];
58+
5659 public function __construct (
5760 private FaceDetectionMapper $ faceDetectionMapper ,
5861 private LoggerInterface $ logger ,
@@ -71,14 +74,14 @@ public function __construct(
7174 }
7275
7376 /**
74- * @param Node $node
77+ * @param int $nodeId
7578 * @return list<string>
7679 * @throws InvalidPathException
7780 * @throws NotFoundException
7881 */
79- private function getUsersWithFileAccess (Node $ node ): array {
82+ private function getUsersWithFileAccess (int $ nodeId ): array {
8083 $ this ->userMountCache ->clear ();
81- $ mountInfos = $ this ->userMountCache ->getMountsForFileId ($ node -> getId () );
84+ $ mountInfos = $ this ->userMountCache ->getMountsForFileId ($ nodeId );
8285 $ userIds = array_map (static function (ICachedMountInfo $ mountInfo ) {
8386 return $ mountInfo ->getUser ()->getUID ();
8487 }, $ mountInfos );
@@ -88,11 +91,31 @@ private function getUsersWithFileAccess(Node $node): array {
8891
8992 public function handle (Event $ event ): void {
9093 try {
91- if ($ event instanceof ShareAcceptedEvent) {
94+ if ($ event instanceof \OCP \Files \Config \Event \UserMountAddedEvent) {
95+ $ rootId = $ event ->mountPoint ->getRootId ();
96+ // Asynchronous, because we potentially recurse and this event needs to be handled fast
97+ $ this ->onAccessUpdate ($ event ->mountPoint ->getStorageId (), $ rootId );
98+ // Remember that this mount was added in the current process (see UserMountRemovedEvent below)
99+ $ this ->addedMounts [$ event ->mountPoint ->getUser ()->getUID () . '- ' . $ rootId ] = true ;
100+ }
101+
102+ if ($ event instanceof \OCP \Files \Config \Event \UserMountRemovedEvent) {
103+ // If we just added this mount, ignore the removal, as the 'removal' event is always fired after
104+ // the 'added' event in server
105+ $ rootId = $ event ->mountPoint ->getRootId ();
106+ $ mountKey = $ event ->mountPoint ->getUser ()->getUID () . '- ' . $ rootId ;
107+ if (array_key_exists ($ mountKey , $ this ->addedMounts ) && $ this ->addedMounts [$ mountKey ] === true ) {
108+ return ;
109+ }
110+ // Asynchronous, because we potentially recurse and this event needs to be handled fast
111+ $ this ->onAccessUpdate ($ event ->mountPoint ->getStorageId (), $ rootId );
112+ }
113+
114+ if ($ event instanceof ShareCreatedEvent) {
92115 $ share = $ event ->getShare ();
93116 $ ownerId = $ share ->getShareOwner ();
94117 $ node = $ share ->getNode ();
95- $ userIds = $ this ->getUsersWithFileAccess ($ node );
118+ $ userIds = $ this ->getUsersWithFileAccess ($ node-> getId () );
96119
97120 if ($ node ->getType () === FileInfo::TYPE_FOLDER ) {
98121 $ mount = $ node ->getMountPoint ();
@@ -126,7 +149,7 @@ public function handle(Event $event): void {
126149 if ($ event instanceof ShareDeletedEvent) {
127150 $ share = $ event ->getShare ();
128151 $ node = $ share ->getNode ();
129- $ userIds = $ this ->getUsersWithFileAccess ($ node );
152+ $ userIds = $ this ->getUsersWithFileAccess ($ node-> getId () );
130153
131154 if ($ node ->getType () === FileInfo::TYPE_FOLDER ) {
132155 $ mount = $ node ->getMountPoint ();
@@ -159,7 +182,7 @@ public function handle(Event $event): void {
159182 } else {
160183 $ this ->movingDirFromIgnoredTerritory = $ this ->getDirIgnores ($ event ->getSource ());
161184 }
162- $ this ->sourceUserIds = $ this ->getUsersWithFileAccess ($ event ->getSource ());
185+ $ this ->sourceUserIds = $ this ->getUsersWithFileAccess ($ event ->getSource ()-> getId () );
163186 $ this ->source = $ event ->getSource ();
164187 return ;
165188 }
@@ -390,7 +413,7 @@ public function postInsert(Node $node, bool $recurse = true, ?array $mimeTypes =
390413 * @throws Exception
391414 */
392415 public function postRename (Node $ source , Node $ target ): void {
393- $ targetUserIds = $ this ->getUsersWithFileAccess ($ target );
416+ $ targetUserIds = $ this ->getUsersWithFileAccess ($ target-> getId () );
394417
395418 $ usersToAdd = array_values (array_diff ($ targetUserIds , $ this ->sourceUserIds ));
396419 $ existingUsers = array_diff ($ targetUserIds , $ usersToAdd );
@@ -412,11 +435,11 @@ public function postRename(Node $source, Node $target): void {
412435 private function copyFaceDetectionsForNode (string $ ownerId , array $ usersToAdd , array $ targetUserIds , Node $ node ): void {
413436 if ($ node instanceof Folder) {
414437 try {
415- foreach ($ node ->getDirectoryListing () as $ node ) {
416- if (!in_array ($ node ->getMimetype (), Constants::IMAGE_FORMATS )) {
438+ foreach ($ node ->getDirectoryListing () as $ n ) {
439+ if (!in_array ($ n ->getMimetype (), Constants::IMAGE_FORMATS )) {
417440 continue ;
418441 }
419- $ this ->copyFaceDetectionsForNode ($ ownerId , $ usersToAdd , $ targetUserIds , $ node );
442+ $ this ->copyFaceDetectionsForNode ($ ownerId , $ usersToAdd , $ targetUserIds , $ n );
420443 }
421444 } catch (NotFoundException |Exception |InvalidPathException $ e ) {
422445 $ this ->logger ->warning ('Error in recognize file listener ' , ['exception ' => $ e ]);
@@ -512,4 +535,41 @@ private function resetIgnoreCache(Node $node) : void {
512535 }
513536 $ this ->ignoreService ->clearCacheForStorage ($ storageId );
514537 }
538+
539+ /**
540+ * @throws NotFoundException
541+ * @throws InvalidPathException
542+ * @throws Exception
543+ */
544+ private function onAccessUpdate (int $ storageId , int $ rootId ): void {
545+ $ userIds = $ this ->getUsersWithFileAccess ($ rootId );
546+ $ files = $ this ->storageService ->getFilesInMount ($ storageId , $ rootId , [ClusteringFaceClassifier::MODEL_NAME ], 0 , 0 );
547+ $ userIdsToScheduleClustering = [];
548+ foreach ($ files as $ fileInfo ) {
549+ $ node = current ($ this ->rootFolder ->getById ($ fileInfo ['fileid ' ])) ?: null ;
550+ $ ownerId = $ node ?->getOwner()?->getUID();
551+ if ($ ownerId === null ) {
552+ continue ;
553+ }
554+ $ detectionsForFile = $ this ->faceDetectionMapper ->findByFileId ($ fileInfo ['fileid ' ]);
555+ $ userHasDetectionForFile = [];
556+ foreach ($ detectionsForFile as $ detection ) {
557+ $ userHasDetectionForFile [$ detection ->getUserId ()] = true ;
558+ }
559+ foreach ($ userIds as $ userId ) {
560+ if ($ userId === $ ownerId ) {
561+ continue ;
562+ }
563+ if ($ userHasDetectionForFile [$ userId ] ?? false ) {
564+ continue ;
565+ }
566+ $ this ->faceDetectionMapper ->copyDetectionsForFileFromUserToUser ($ fileInfo ['fileid ' ], $ ownerId , $ userId );
567+ $ userIdsToScheduleClustering [$ userId ] = true ;
568+ }
569+ $ this ->faceDetectionMapper ->removeDetectionsForFileFromUsersNotInList ($ fileInfo ['fileid ' ], $ userIds );
570+ }
571+ foreach (array_keys ($ userIdsToScheduleClustering ) as $ userId ) {
572+ $ this ->jobList ->add (ClusterFacesJob::class, ['userId ' => $ userId ]);
573+ }
574+ }
515575}
0 commit comments