OldGroupMembershipShares.php 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. namespace OC\Repair;
  8. use OCP\IDBConnection;
  9. use OCP\IGroupManager;
  10. use OCP\Migration\IOutput;
  11. use OCP\Migration\IRepairStep;
  12. use OCP\Share\IShare;
  13. class OldGroupMembershipShares implements IRepairStep {
  14. /** @var \OCP\IDBConnection */
  15. protected $connection;
  16. /** @var \OCP\IGroupManager */
  17. protected $groupManager;
  18. /**
  19. * @var array [gid => [uid => (bool)]]
  20. */
  21. protected $memberships;
  22. /**
  23. * @param IDBConnection $connection
  24. * @param IGroupManager $groupManager
  25. */
  26. public function __construct(IDBConnection $connection, IGroupManager $groupManager) {
  27. $this->connection = $connection;
  28. $this->groupManager = $groupManager;
  29. }
  30. /**
  31. * Returns the step's name
  32. *
  33. * @return string
  34. */
  35. public function getName() {
  36. return 'Remove shares of old group memberships';
  37. }
  38. /**
  39. * Run repair step.
  40. * Must throw exception on error.
  41. *
  42. * @throws \Exception in case of failure
  43. */
  44. public function run(IOutput $output) {
  45. $deletedEntries = 0;
  46. $query = $this->connection->getQueryBuilder();
  47. $query->select('s1.id')->selectAlias('s1.share_with', 'user')->selectAlias('s2.share_with', 'group')
  48. ->from('share', 's1')
  49. ->where($query->expr()->isNotNull('s1.parent'))
  50. // \OC\Share\Constant::$shareTypeGroupUserUnique === 2
  51. ->andWhere($query->expr()->eq('s1.share_type', $query->expr()->literal(2)))
  52. ->andWhere($query->expr()->isNotNull('s2.id'))
  53. ->andWhere($query->expr()->eq('s2.share_type', $query->expr()->literal(IShare::TYPE_GROUP)))
  54. ->leftJoin('s1', 'share', 's2', $query->expr()->eq('s1.parent', 's2.id'));
  55. $deleteQuery = $this->connection->getQueryBuilder();
  56. $deleteQuery->delete('share')
  57. ->where($query->expr()->eq('id', $deleteQuery->createParameter('share')));
  58. $result = $query->execute();
  59. while ($row = $result->fetch()) {
  60. if (!$this->isMember($row['group'], $row['user'])) {
  61. $deletedEntries += $deleteQuery->setParameter('share', (int) $row['id'])
  62. ->execute();
  63. }
  64. }
  65. $result->closeCursor();
  66. if ($deletedEntries) {
  67. $output->info('Removed ' . $deletedEntries . ' shares where user is not a member of the group anymore');
  68. }
  69. }
  70. /**
  71. * @param string $gid
  72. * @param string $uid
  73. * @return bool
  74. */
  75. protected function isMember($gid, $uid) {
  76. if (isset($this->memberships[$gid][$uid])) {
  77. return $this->memberships[$gid][$uid];
  78. }
  79. $isMember = $this->groupManager->isInGroup($uid, $gid);
  80. if (!isset($this->memberships[$gid])) {
  81. $this->memberships[$gid] = [];
  82. }
  83. $this->memberships[$gid][$uid] = $isMember;
  84. return $isMember;
  85. }
  86. }