SetupManager.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright Copyright (c) 2022 Robin Appelman <robin@icewind.nl>
  5. *
  6. * @license GNU AGPL version 3 or any later version
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Affero General Public License as
  10. * published by the Free Software Foundation, either version 3 of the
  11. * License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Affero General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. namespace OC\Files;
  23. use OC\Files\Config\MountProviderCollection;
  24. use OC\Files\Mount\HomeMountPoint;
  25. use OC\Files\Mount\MountPoint;
  26. use OC\Files\Storage\Common;
  27. use OC\Files\Storage\Home;
  28. use OC\Files\Storage\Storage;
  29. use OC\Files\Storage\Wrapper\Availability;
  30. use OC\Files\Storage\Wrapper\Encoding;
  31. use OC\Files\Storage\Wrapper\PermissionsMask;
  32. use OC\Files\Storage\Wrapper\Quota;
  33. use OC\Lockdown\Filesystem\NullStorage;
  34. use OC\Share\Share;
  35. use OC\Share20\ShareDisableChecker;
  36. use OC_App;
  37. use OC_Hook;
  38. use OC_Util;
  39. use OCA\Files_External\Config\ConfigAdapter;
  40. use OCA\Files_Sharing\External\Mount;
  41. use OCA\Files_Sharing\ISharedMountPoint;
  42. use OCA\Files_Sharing\SharedMount;
  43. use OCP\Constants;
  44. use OCP\Diagnostics\IEventLogger;
  45. use OCP\EventDispatcher\IEventDispatcher;
  46. use OCP\Files\Config\ICachedMountInfo;
  47. use OCP\Files\Config\IHomeMountProvider;
  48. use OCP\Files\Config\IMountProvider;
  49. use OCP\Files\Config\IUserMountCache;
  50. use OCP\Files\Events\InvalidateMountCacheEvent;
  51. use OCP\Files\Events\Node\FilesystemTornDownEvent;
  52. use OCP\Files\Mount\IMountManager;
  53. use OCP\Files\Mount\IMountPoint;
  54. use OCP\Files\NotFoundException;
  55. use OCP\Files\Storage\IStorage;
  56. use OCP\Group\Events\UserAddedEvent;
  57. use OCP\Group\Events\UserRemovedEvent;
  58. use OCP\ICache;
  59. use OCP\ICacheFactory;
  60. use OCP\IConfig;
  61. use OCP\IUser;
  62. use OCP\IUserManager;
  63. use OCP\IUserSession;
  64. use OCP\Lockdown\ILockdownManager;
  65. use OCP\Share\Events\ShareCreatedEvent;
  66. use Psr\Log\LoggerInterface;
  67. class SetupManager {
  68. private bool $rootSetup = false;
  69. // List of users for which at least one mount is setup
  70. private array $setupUsers = [];
  71. // List of users for which all mounts are setup
  72. private array $setupUsersComplete = [];
  73. /** @var array<string, string[]> */
  74. private array $setupUserMountProviders = [];
  75. private ICache $cache;
  76. private bool $listeningForProviders;
  77. private array $fullSetupRequired = [];
  78. private bool $setupBuiltinWrappersDone = false;
  79. private bool $forceFullSetup = false;
  80. public function __construct(
  81. private IEventLogger $eventLogger,
  82. private MountProviderCollection $mountProviderCollection,
  83. private IMountManager $mountManager,
  84. private IUserManager $userManager,
  85. private IEventDispatcher $eventDispatcher,
  86. private IUserMountCache $userMountCache,
  87. private ILockdownManager $lockdownManager,
  88. private IUserSession $userSession,
  89. ICacheFactory $cacheFactory,
  90. private LoggerInterface $logger,
  91. private IConfig $config,
  92. private ShareDisableChecker $shareDisableChecker,
  93. ) {
  94. $this->cache = $cacheFactory->createDistributed('setupmanager::');
  95. $this->listeningForProviders = false;
  96. $this->forceFullSetup = $this->config->getSystemValueBool('debug.force-full-fs-setup');
  97. $this->setupListeners();
  98. }
  99. private function isSetupStarted(IUser $user): bool {
  100. return in_array($user->getUID(), $this->setupUsers, true);
  101. }
  102. public function isSetupComplete(IUser $user): bool {
  103. return in_array($user->getUID(), $this->setupUsersComplete, true);
  104. }
  105. private function setupBuiltinWrappers() {
  106. if ($this->setupBuiltinWrappersDone) {
  107. return;
  108. }
  109. $this->setupBuiltinWrappersDone = true;
  110. // load all filesystem apps before, so no setup-hook gets lost
  111. OC_App::loadApps(['filesystem']);
  112. $prevLogging = Filesystem::logWarningWhenAddingStorageWrapper(false);
  113. Filesystem::addStorageWrapper('mount_options', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
  114. if ($mount->getOptions() && $storage->instanceOfStorage(Common::class)) {
  115. $storage->setMountOptions($mount->getOptions());
  116. }
  117. return $storage;
  118. });
  119. $reSharingEnabled = Share::isResharingAllowed();
  120. $user = $this->userSession->getUser();
  121. $sharingEnabledForUser = $user ? !$this->shareDisableChecker->sharingDisabledForUser($user->getUID()) : true;
  122. Filesystem::addStorageWrapper(
  123. 'sharing_mask',
  124. function ($mountPoint, IStorage $storage, IMountPoint $mount) use ($reSharingEnabled, $sharingEnabledForUser) {
  125. $sharingEnabledForMount = $mount->getOption('enable_sharing', true);
  126. $isShared = $mount instanceof ISharedMountPoint;
  127. if (!$sharingEnabledForMount || !$sharingEnabledForUser || (!$reSharingEnabled && $isShared)) {
  128. return new PermissionsMask([
  129. 'storage' => $storage,
  130. 'mask' => Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE,
  131. ]);
  132. }
  133. return $storage;
  134. }
  135. );
  136. // install storage availability wrapper, before most other wrappers
  137. Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
  138. $externalMount = $mount instanceof ConfigAdapter || $mount instanceof Mount;
  139. if ($externalMount && !$storage->isLocal()) {
  140. return new Availability(['storage' => $storage]);
  141. }
  142. return $storage;
  143. });
  144. Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
  145. if ($mount->getOption('encoding_compatibility', false) && !$mount instanceof SharedMount) {
  146. return new Encoding(['storage' => $storage]);
  147. }
  148. return $storage;
  149. });
  150. $quotaIncludeExternal = $this->config->getSystemValue('quota_include_external_storage', false);
  151. Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage, IMountPoint $mount) use ($quotaIncludeExternal) {
  152. // set up quota for home storages, even for other users
  153. // which can happen when using sharing
  154. if ($mount instanceof HomeMountPoint) {
  155. $user = $mount->getUser();
  156. return new Quota(['storage' => $storage, 'quotaCallback' => function () use ($user) {
  157. return OC_Util::getUserQuota($user);
  158. }, 'root' => 'files', 'include_external_storage' => $quotaIncludeExternal]);
  159. }
  160. return $storage;
  161. });
  162. Filesystem::addStorageWrapper('readonly', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
  163. /*
  164. * Do not allow any operations that modify the storage
  165. */
  166. if ($mount->getOption('readonly', false)) {
  167. return new PermissionsMask([
  168. 'storage' => $storage,
  169. 'mask' => Constants::PERMISSION_ALL & ~(
  170. Constants::PERMISSION_UPDATE |
  171. Constants::PERMISSION_CREATE |
  172. Constants::PERMISSION_DELETE
  173. ),
  174. ]);
  175. }
  176. return $storage;
  177. });
  178. Filesystem::logWarningWhenAddingStorageWrapper($prevLogging);
  179. }
  180. /**
  181. * Setup the full filesystem for the specified user
  182. */
  183. public function setupForUser(IUser $user): void {
  184. if ($this->isSetupComplete($user)) {
  185. return;
  186. }
  187. $this->setupUsersComplete[] = $user->getUID();
  188. $this->eventLogger->start('fs:setup:user:full', 'Setup full filesystem for user');
  189. if (!isset($this->setupUserMountProviders[$user->getUID()])) {
  190. $this->setupUserMountProviders[$user->getUID()] = [];
  191. }
  192. $previouslySetupProviders = $this->setupUserMountProviders[$user->getUID()];
  193. $this->setupForUserWith($user, function () use ($user) {
  194. $this->mountProviderCollection->addMountForUser($user, $this->mountManager, function (
  195. IMountProvider $provider
  196. ) use ($user) {
  197. return !in_array(get_class($provider), $this->setupUserMountProviders[$user->getUID()]);
  198. });
  199. });
  200. $this->afterUserFullySetup($user, $previouslySetupProviders);
  201. $this->eventLogger->end('fs:setup:user:full');
  202. }
  203. /**
  204. * part of the user setup that is run only once per user
  205. */
  206. private function oneTimeUserSetup(IUser $user) {
  207. if ($this->isSetupStarted($user)) {
  208. return;
  209. }
  210. $this->setupUsers[] = $user->getUID();
  211. $this->setupRoot();
  212. $this->eventLogger->start('fs:setup:user:onetime', 'Onetime filesystem for user');
  213. $this->setupBuiltinWrappers();
  214. $prevLogging = Filesystem::logWarningWhenAddingStorageWrapper(false);
  215. OC_Hook::emit('OC_Filesystem', 'preSetup', ['user' => $user->getUID()]);
  216. Filesystem::logWarningWhenAddingStorageWrapper($prevLogging);
  217. $userDir = '/' . $user->getUID() . '/files';
  218. Filesystem::initInternal($userDir);
  219. if ($this->lockdownManager->canAccessFilesystem()) {
  220. $this->eventLogger->start('fs:setup:user:home', 'Setup home filesystem for user');
  221. // home mounts are handled separate since we need to ensure this is mounted before we call the other mount providers
  222. $homeMount = $this->mountProviderCollection->getHomeMountForUser($user);
  223. $this->mountManager->addMount($homeMount);
  224. if ($homeMount->getStorageRootId() === -1) {
  225. $this->eventLogger->start('fs:setup:user:home:scan', 'Scan home filesystem for user');
  226. $homeMount->getStorage()->mkdir('');
  227. $homeMount->getStorage()->getScanner()->scan('');
  228. $this->eventLogger->end('fs:setup:user:home:scan');
  229. }
  230. $this->eventLogger->end('fs:setup:user:home');
  231. } else {
  232. $this->mountManager->addMount(new MountPoint(
  233. new NullStorage([]),
  234. '/' . $user->getUID()
  235. ));
  236. $this->mountManager->addMount(new MountPoint(
  237. new NullStorage([]),
  238. '/' . $user->getUID() . '/files'
  239. ));
  240. $this->setupUsersComplete[] = $user->getUID();
  241. }
  242. $this->listenForNewMountProviders();
  243. $this->eventLogger->end('fs:setup:user:onetime');
  244. }
  245. /**
  246. * Final housekeeping after a user has been fully setup
  247. */
  248. private function afterUserFullySetup(IUser $user, array $previouslySetupProviders): void {
  249. $this->eventLogger->start('fs:setup:user:full:post', 'Housekeeping after user is setup');
  250. $userRoot = '/' . $user->getUID() . '/';
  251. $mounts = $this->mountManager->getAll();
  252. $mounts = array_filter($mounts, function (IMountPoint $mount) use ($userRoot) {
  253. return str_starts_with($mount->getMountPoint(), $userRoot);
  254. });
  255. $allProviders = array_map(function (IMountProvider $provider) {
  256. return get_class($provider);
  257. }, $this->mountProviderCollection->getProviders());
  258. $newProviders = array_diff($allProviders, $previouslySetupProviders);
  259. $mounts = array_filter($mounts, function (IMountPoint $mount) use ($previouslySetupProviders) {
  260. return !in_array($mount->getMountProvider(), $previouslySetupProviders);
  261. });
  262. $this->userMountCache->registerMounts($user, $mounts, $newProviders);
  263. $cacheDuration = $this->config->getSystemValueInt('fs_mount_cache_duration', 5 * 60);
  264. if ($cacheDuration > 0) {
  265. $this->cache->set($user->getUID(), true, $cacheDuration);
  266. $this->fullSetupRequired[$user->getUID()] = false;
  267. }
  268. $this->eventLogger->end('fs:setup:user:full:post');
  269. }
  270. /**
  271. * @param IUser $user
  272. * @param IMountPoint $mounts
  273. * @return void
  274. * @throws \OCP\HintException
  275. * @throws \OC\ServerNotAvailableException
  276. */
  277. private function setupForUserWith(IUser $user, callable $mountCallback): void {
  278. $this->oneTimeUserSetup($user);
  279. if ($this->lockdownManager->canAccessFilesystem()) {
  280. $mountCallback();
  281. }
  282. $this->eventLogger->start('fs:setup:user:post-init-mountpoint', 'post_initMountPoints legacy hook');
  283. \OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', ['user' => $user->getUID()]);
  284. $this->eventLogger->end('fs:setup:user:post-init-mountpoint');
  285. $userDir = '/' . $user->getUID() . '/files';
  286. $this->eventLogger->start('fs:setup:user:setup-hook', 'setup legacy hook');
  287. OC_Hook::emit('OC_Filesystem', 'setup', ['user' => $user->getUID(), 'user_dir' => $userDir]);
  288. $this->eventLogger->end('fs:setup:user:setup-hook');
  289. }
  290. /**
  291. * Set up the root filesystem
  292. */
  293. public function setupRoot(): void {
  294. //setting up the filesystem twice can only lead to trouble
  295. if ($this->rootSetup) {
  296. return;
  297. }
  298. $this->setupBuiltinWrappers();
  299. $this->rootSetup = true;
  300. $this->eventLogger->start('fs:setup:root', 'Setup root filesystem');
  301. $rootMounts = $this->mountProviderCollection->getRootMounts();
  302. foreach ($rootMounts as $rootMountProvider) {
  303. $this->mountManager->addMount($rootMountProvider);
  304. }
  305. $this->eventLogger->end('fs:setup:root');
  306. }
  307. /**
  308. * Get the user to setup for a path or `null` if the root needs to be setup
  309. *
  310. * @param string $path
  311. * @return IUser|null
  312. */
  313. private function getUserForPath(string $path) {
  314. if (str_starts_with($path, '/__groupfolders')) {
  315. return null;
  316. } elseif (substr_count($path, '/') < 2) {
  317. if ($user = $this->userSession->getUser()) {
  318. return $user;
  319. } else {
  320. return null;
  321. }
  322. } elseif (str_starts_with($path, '/appdata_' . \OC_Util::getInstanceId()) || str_starts_with($path, '/files_external/')) {
  323. return null;
  324. } else {
  325. [, $userId] = explode('/', $path);
  326. }
  327. return $this->userManager->get($userId);
  328. }
  329. /**
  330. * Set up the filesystem for the specified path
  331. */
  332. public function setupForPath(string $path, bool $includeChildren = false): void {
  333. $user = $this->getUserForPath($path);
  334. if (!$user) {
  335. $this->setupRoot();
  336. return;
  337. }
  338. if ($this->isSetupComplete($user)) {
  339. return;
  340. }
  341. if ($this->fullSetupRequired($user)) {
  342. $this->setupForUser($user);
  343. return;
  344. }
  345. // for the user's home folder, and includes children we need everything always
  346. if (rtrim($path) === "/" . $user->getUID() . "/files" && $includeChildren) {
  347. $this->setupForUser($user);
  348. return;
  349. }
  350. if (!isset($this->setupUserMountProviders[$user->getUID()])) {
  351. $this->setupUserMountProviders[$user->getUID()] = [];
  352. }
  353. $setupProviders = &$this->setupUserMountProviders[$user->getUID()];
  354. $currentProviders = [];
  355. try {
  356. $cachedMount = $this->userMountCache->getMountForPath($user, $path);
  357. } catch (NotFoundException $e) {
  358. $this->setupForUser($user);
  359. return;
  360. }
  361. $this->oneTimeUserSetup($user);
  362. $this->eventLogger->start('fs:setup:user:path', "Setup $path filesystem for user");
  363. $this->eventLogger->start('fs:setup:user:path:find', "Find mountpoint for $path");
  364. $mounts = [];
  365. if (!in_array($cachedMount->getMountProvider(), $setupProviders)) {
  366. $currentProviders[] = $cachedMount->getMountProvider();
  367. if ($cachedMount->getMountProvider()) {
  368. $setupProviders[] = $cachedMount->getMountProvider();
  369. $mounts = $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$cachedMount->getMountProvider()]);
  370. } else {
  371. $this->logger->debug("mount at " . $cachedMount->getMountPoint() . " has no provider set, performing full setup");
  372. $this->eventLogger->end('fs:setup:user:path:find');
  373. $this->setupForUser($user);
  374. $this->eventLogger->end('fs:setup:user:path');
  375. return;
  376. }
  377. }
  378. if ($includeChildren) {
  379. $subCachedMounts = $this->userMountCache->getMountsInPath($user, $path);
  380. $this->eventLogger->end('fs:setup:user:path:find');
  381. $needsFullSetup = array_reduce($subCachedMounts, function (bool $needsFullSetup, ICachedMountInfo $cachedMountInfo) {
  382. return $needsFullSetup || $cachedMountInfo->getMountProvider() === '';
  383. }, false);
  384. if ($needsFullSetup) {
  385. $this->logger->debug("mount has no provider set, performing full setup");
  386. $this->setupForUser($user);
  387. $this->eventLogger->end('fs:setup:user:path');
  388. return;
  389. } else {
  390. foreach ($subCachedMounts as $cachedMount) {
  391. if (!in_array($cachedMount->getMountProvider(), $setupProviders)) {
  392. $currentProviders[] = $cachedMount->getMountProvider();
  393. $setupProviders[] = $cachedMount->getMountProvider();
  394. $mounts = array_merge($mounts, $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$cachedMount->getMountProvider()]));
  395. }
  396. }
  397. }
  398. } else {
  399. $this->eventLogger->end('fs:setup:user:path:find');
  400. }
  401. if (count($mounts)) {
  402. $this->userMountCache->registerMounts($user, $mounts, $currentProviders);
  403. $this->setupForUserWith($user, function () use ($mounts) {
  404. array_walk($mounts, [$this->mountManager, 'addMount']);
  405. });
  406. } elseif (!$this->isSetupStarted($user)) {
  407. $this->oneTimeUserSetup($user);
  408. }
  409. $this->eventLogger->end('fs:setup:user:path');
  410. }
  411. private function fullSetupRequired(IUser $user): bool {
  412. if ($this->forceFullSetup) {
  413. return true;
  414. }
  415. // we perform a "cached" setup only after having done the full setup recently
  416. // this is also used to trigger a full setup after handling events that are likely
  417. // to change the available mounts
  418. if (!isset($this->fullSetupRequired[$user->getUID()])) {
  419. $this->fullSetupRequired[$user->getUID()] = !$this->cache->get($user->getUID());
  420. }
  421. return $this->fullSetupRequired[$user->getUID()];
  422. }
  423. /**
  424. * @param string $path
  425. * @param string[] $providers
  426. */
  427. public function setupForProvider(string $path, array $providers): void {
  428. $user = $this->getUserForPath($path);
  429. if (!$user) {
  430. $this->setupRoot();
  431. return;
  432. }
  433. if ($this->isSetupComplete($user)) {
  434. return;
  435. }
  436. if ($this->fullSetupRequired($user)) {
  437. $this->setupForUser($user);
  438. return;
  439. }
  440. $this->eventLogger->start('fs:setup:user:providers', "Setup filesystem for " . implode(', ', $providers));
  441. $this->oneTimeUserSetup($user);
  442. // home providers are always used
  443. $providers = array_filter($providers, function (string $provider) {
  444. return !is_subclass_of($provider, IHomeMountProvider::class);
  445. });
  446. if (in_array('', $providers)) {
  447. $this->setupForUser($user);
  448. return;
  449. }
  450. $setupProviders = $this->setupUserMountProviders[$user->getUID()] ?? [];
  451. $providers = array_diff($providers, $setupProviders);
  452. if (count($providers) === 0) {
  453. if (!$this->isSetupStarted($user)) {
  454. $this->oneTimeUserSetup($user);
  455. }
  456. $this->eventLogger->end('fs:setup:user:providers');
  457. return;
  458. } else {
  459. $this->setupUserMountProviders[$user->getUID()] = array_merge($setupProviders, $providers);
  460. $mounts = $this->mountProviderCollection->getUserMountsForProviderClasses($user, $providers);
  461. }
  462. $this->userMountCache->registerMounts($user, $mounts, $providers);
  463. $this->setupForUserWith($user, function () use ($mounts) {
  464. array_walk($mounts, [$this->mountManager, 'addMount']);
  465. });
  466. $this->eventLogger->end('fs:setup:user:providers');
  467. }
  468. public function tearDown() {
  469. $this->setupUsers = [];
  470. $this->setupUsersComplete = [];
  471. $this->setupUserMountProviders = [];
  472. $this->fullSetupRequired = [];
  473. $this->rootSetup = false;
  474. $this->mountManager->clear();
  475. $this->eventDispatcher->dispatchTyped(new FilesystemTornDownEvent());
  476. }
  477. /**
  478. * Get mounts from mount providers that are registered after setup
  479. */
  480. private function listenForNewMountProviders() {
  481. if (!$this->listeningForProviders) {
  482. $this->listeningForProviders = true;
  483. $this->mountProviderCollection->listen('\OC\Files\Config', 'registerMountProvider', function (
  484. IMountProvider $provider
  485. ) {
  486. foreach ($this->setupUsers as $userId) {
  487. $user = $this->userManager->get($userId);
  488. if ($user) {
  489. $mounts = $provider->getMountsForUser($user, Filesystem::getLoader());
  490. array_walk($mounts, [$this->mountManager, 'addMount']);
  491. }
  492. }
  493. });
  494. }
  495. }
  496. private function setupListeners() {
  497. // note that this event handling is intentionally pessimistic
  498. // clearing the cache to often is better than not enough
  499. $this->eventDispatcher->addListener(UserAddedEvent::class, function (UserAddedEvent $event) {
  500. $this->cache->remove($event->getUser()->getUID());
  501. });
  502. $this->eventDispatcher->addListener(UserRemovedEvent::class, function (UserRemovedEvent $event) {
  503. $this->cache->remove($event->getUser()->getUID());
  504. });
  505. $this->eventDispatcher->addListener(ShareCreatedEvent::class, function (ShareCreatedEvent $event) {
  506. $this->cache->remove($event->getShare()->getSharedWith());
  507. });
  508. $this->eventDispatcher->addListener(InvalidateMountCacheEvent::class, function (InvalidateMountCacheEvent $event
  509. ) {
  510. if ($user = $event->getUser()) {
  511. $this->cache->remove($user->getUID());
  512. } else {
  513. $this->cache->clear();
  514. }
  515. });
  516. $genericEvents = [
  517. 'OCA\Circles\Events\CreatingCircleEvent',
  518. 'OCA\Circles\Events\DestroyingCircleEvent',
  519. 'OCA\Circles\Events\AddingCircleMemberEvent',
  520. 'OCA\Circles\Events\RemovingCircleMemberEvent',
  521. ];
  522. foreach ($genericEvents as $genericEvent) {
  523. $this->eventDispatcher->addListener($genericEvent, function ($event) {
  524. $this->cache->clear();
  525. });
  526. }
  527. }
  528. }