firstOrCreate([ 'folder_id' => $folder->id, 'assignable_type' => $assignable->getMorphClass(), 'assignable_id' => $assignable->getKey(), ]); $this->activity->log(Action::FolderShared, subject: $folder, context: ['target' => $targetName]); $recipients = $this->recipients($assignable); $this->notifier->send('file_shared', $recipients, subject: $folder, data: ['itemName' => $folder->name]); // The master switch and each recipient's own preference are the // digester's job now — every caller was repeating them. $this->digester->queue('file_shared', $recipients, $folder->name, ['is_folder' => true]); } /** * @return bool whether an assignment was actually removed */ public function unassign(Folder $folder, User|Group $assignable, string $targetName): bool { $deleted = FolderAssignment::query() ->where('folder_id', $folder->id) ->where('assignable_type', $assignable->getMorphClass()) ->where('assignable_id', $assignable->getKey()) ->delete(); if ($deleted > 0) { $this->activity->log(Action::FolderUnshared, subject: $folder, context: ['target' => $targetName]); } return $deleted > 0; } /** * Notifier performs no authorization of its own — see its SECURITY * CONTRACT docblock — so the recipient list is resolved here, from the * assignment itself. * * @return iterable */ private function recipients(User|Group $assignable): iterable { return $assignable instanceof Group ? $assignable->members : [$assignable]; } }