Fix shares

- adjust db schema
- listen to group changes
- Add repair steps
This commit is contained in:
Marcel Klehr 2020-05-26 18:09:51 +02:00
parent e7eb042d7c
commit d17c7cb96d
15 changed files with 534 additions and 51 deletions

View File

@ -18,11 +18,16 @@ use OCA\Bookmarks\Events\BeforeDeleteEvent;
use OCA\Bookmarks\Events\CreateEvent;
use OCA\Bookmarks\Events\MoveEvent;
use OCA\Bookmarks\Events\UpdateEvent;
use OCA\Bookmarks\Hooks\UserGroupListener;
use OCA\Bookmarks\Hooks\UserHooks;
use OCA\Bookmarks\Service\HashManager;
use OCP\AppFramework\App;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Group\Events\UserAddedEvent;
use OCP\Group\Events\UserRemovedEvent;
use OCP\IContainer;
use OCP\IUser;
use OCP\User\Events\BeforeUserDeletedEvent;
class Application extends App {
public function __construct(array $urlParams = []) {
@ -46,5 +51,8 @@ class Application extends App {
$dispatcher->addServiceListener(UpdateEvent::class, HashManager::class);
$dispatcher->addServiceListener(BeforeDeleteEvent::class, HashManager::class);
$dispatcher->addServiceListener(MoveEvent::class, HashManager::class);
$dispatcher->addServiceListener(BeforeUserDeletedEvent::class, UserGroupListener::class);
$dispatcher->addServiceListener(UserAddedEvent::class, UserGroupListener::class);
$dispatcher->addServiceListener(UserRemovedEvent::class, UserGroupListener::class);
}
}

View File

@ -11,11 +11,27 @@ use OCP\IConfig;
use OCP\IUserManager;
class PreviewsJob extends TimedJob {
/**
* @var BookmarkPreviewer
*/
private $bookmarkPreviewer;
/**
* @var FaviconPreviewer
*/
private $faviconPreviewer;
/**
* @var BookmarkMapper
*/
private $bookmarkMapper;
/**
* @var IConfig
*/
private $settings;
public function __construct(
IConfig $settings, IUserManager $userManager, BookmarkMapper $bookmarkMapper, BookmarkPreviewer $bookmarkPreviewer, FaviconPreviewer $faviconPreviewer
IConfig $settings, BookmarkMapper $bookmarkMapper, BookmarkPreviewer $bookmarkPreviewer, FaviconPreviewer $faviconPreviewer
) {
$this->settings = $settings;
$this->userManager = $userManager;
$this->bookmarkMapper = $bookmarkMapper;
$this->bookmarkPreviewer = $bookmarkPreviewer;
$this->faviconPreviewer = $faviconPreviewer;

View File

@ -81,7 +81,7 @@ class BookmarkMapper extends QBMapper {
public function find(int $id): Entity {
$qb = $this->db->getQueryBuilder();
$qb
->select('*')
->select(Bookmark::$columns)
->from('bookmarks')
->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
@ -128,9 +128,10 @@ class BookmarkMapper extends QBMapper {
->leftJoin('b', 'bookmarks_tags', 't', $qb->expr()->eq('t.bookmark_id', 'b.id'))
->leftJoin('b', 'bookmarks_tree', 'tr', $qb->expr()->eq('tr.id', 'b.id'))
->leftJoin('tr', 'bookmarks_shares', 's', $qb->expr()->eq('tr.parent_folder', 's.folder_id'))
->leftJoin('s', 'bookmarks_shared_folders', 'p', $qb->expr()->eq('s.id', 'p.share_id'))
->leftJoin('s', 'bookmarks_shared_to_shares', 't', $qb->expr()->eq('s.id', 't.share_id'))
->leftJoin('t', 'bookmarks_shared_folders', 'sf', $qb->expr()->eq('t.shred_folder_id', 'sf.id'))
->where($qb->expr()->eq('b.user_id', $qb->createPositionalParameter($userId)))
->orWhere($qb->expr()->eq('p.user_id', $qb->createPositionalParameter($userId)));
->orWhere($qb->expr()->eq('sf.user_id', $qb->createPositionalParameter($userId)));
$this->_findBookmarksBuildFilter($qb, $filters, $params);
@ -398,7 +399,7 @@ class BookmarkMapper extends QBMapper {
*/
public function findPendingPreviews(int $limit, int $stalePeriod): array {
$qb = $this->db->getQueryBuilder();
$qb->select('*');
$qb->select(Bookmark::$columns);
$qb->from('bookmarks', 'b');
$qb->where($qb->expr()->lt('last_preview', $qb->createPositionalParameter(time() - $stalePeriod)));
$qb->orWhere($qb->expr()->isNull('last_preview'));

View File

@ -115,9 +115,10 @@ class ShareMapper extends QBMapper {
return 's.' . $c;
}, Share::$columns))
->from('bookmarks_shares', 's')
->leftJoin('s', 'bookmarks_shared_folders', 'p', 's.id = p.share_id')
->leftJoin('s', 'bookmarks_shared_to_shares', 't', 's.id = t.share_id')
->leftJoin('t', 'bookmarks_shared_folders', 'sf', 'sf.id = t.shared_folder_id')
->where($qb->expr()->eq('s.folder_id', $qb->createPositionalParameter($folderId)))
->andWhere($qb->expr()->eq('p.user_id', $qb->createPositionalParameter($userId)));
->andWhere($qb->expr()->eq('sf.user_id', $qb->createPositionalParameter($userId)));
return $this->findEntity($qb);
}
@ -132,9 +133,10 @@ class ShareMapper extends QBMapper {
return 's.' . $c;
}, Share::$columns))
->from('bookmarks_shares', 's')
->leftJoin('s', 'bookmarks_shared_folders', 'p', 's.id = p.share_id')
->leftJoin('s', 'bookmarks_shared_to_shares', 't', 's.id = t.share_id')
->leftJoin('t', 'bookmarks_shared_folders', 'sf', 's.shared_folder_id = sf.id')
->where($qb->expr()->eq('s.owner', $qb->createPositionalParameter($owner)))
->andWhere($qb->expr()->eq('p.user_id', $qb->createPositionalParameter($userId)));
->andWhere($qb->expr()->eq('sf.user_id', $qb->createPositionalParameter($userId)));
return $this->findEntities($qb);
}

View File

@ -22,17 +22,16 @@ class SharedFolder extends Entity {
protected $title;
protected $index;
public static $columns = ['id', 'share_id', 'user_id', 'title'];
public static $columns = ['id', 'user_id', 'title'];
public function __construct() {
// add types in constructor
$this->addType('id', 'integer');
$this->addType('shareId', 'integer');
$this->addType('userId', 'string');
$this->addType('title', 'string');
}
public function toArray() {
return ['title' => $this->title, 'userId' => $this->userId, 'shareId' => $this->shareId];
return ['title' => $this->title, 'userId' => $this->userId];
}
}

View File

@ -37,8 +37,9 @@ class SharedFolderMapper extends QBMapper {
public function findByShare(int $shareId): array {
$qb = $this->db->getQueryBuilder();
$qb->select(SharedFolder::$columns)
->from('bookmarks_shared_folders')
->where($qb->expr()->eq('share_id', $qb->createPositionalParameter($shareId)));
->from('bookmarks_shared_folders', 'sf')
->join('sf', 'bookmarks_shared_to_shares', 't', $qb->expr()->eq('sf.id', 't.shared_folder_id'))
->where($qb->expr()->eq('t.share_id', $qb->createPositionalParameter($shareId)));
return $this->findEntities($qb);
}
@ -49,11 +50,10 @@ class SharedFolderMapper extends QBMapper {
public function findByFolder(int $folderId): array {
$qb = $this->db->getQueryBuilder();
$qb->select(array_map(static function ($c) {
return 'p.' . $c;
return 'sf.' . $c;
}, SharedFolder::$columns))
->from('bookmarks_shared_folders', 'p')
->leftJoin('p', 'bookmarks_shares', 's', 'p.share_id = s.id')
->where($qb->expr()->eq('s.folder_id', $qb->createPositionalParameter($folderId)));
->from('bookmarks_shared_folders', 'sf')
->where($qb->expr()->eq('sf.folder_id', $qb->createPositionalParameter($folderId)));
return $this->findEntities($qb);
}
@ -67,7 +67,8 @@ class SharedFolderMapper extends QBMapper {
return 'p.' . $c;
}, SharedFolder::$columns))
->from('bookmarks_shared_folders', 'p')
->leftJoin('p', 'bookmarks_shares', 's', 'p.share_id = s.id')
->leftJoin('p', 'bookmarks_shared_to_shares', 't', 't.shared_folder_id = p.id')
->leftJoin('t', 'bookmarks_shares', 's', 't.share_id = s.id')
->where($qb->expr()->eq('s.owner', $qb->createPositionalParameter($userId)));
return $this->findEntities($qb);
}
@ -83,7 +84,8 @@ class SharedFolderMapper extends QBMapper {
return 'p.' . $c;
}, SharedFolder::$columns))
->from('bookmarks_shared_folders', 'p')
->leftJoin('p', 'bookmarks_shares', 's', 'p.share_id = s.id')
->leftJoin('p', 'bookmarks_shared_to_shares', 't', 'p.id = t.shared_folder_id')
->leftJoin('t', 'bookmarks_shares', 's', 't.share_id = s.id')
->where($qb->expr()->eq('s.participant', $qb->createPositionalParameter($participant)))
->andWhere($qb->expr()->eq('s.type', $qb->createPositionalParameter($type)));
return $this->findEntities($qb);
@ -103,8 +105,9 @@ class SharedFolderMapper extends QBMapper {
return 'p.' . $c;
}, SharedFolder::$columns))
->from('bookmarks_shared_folders', 'p')
->leftJoin('p', 'bookmarks_shares', 's', 'p.share_id = s.id')
->where($qb->expr()->eq('folder_id', $qb->createPositionalParameter($folderId)))
->leftJoin('p', 'bookmarks_shared_to_shares', 't', 't.shared_folder_id = p.id')
->leftJoin('t', 'bookmarks_shares', 's', 't.share_id = s.id')
->where($qb->expr()->eq('p.folder_id', $qb->createPositionalParameter($folderId)))
->andWhere($qb->expr()->eq('participant', $qb->createPositionalParameter($participant)))
->andWhere($qb->expr()->eq('type', $qb->createPositionalParameter($type)));
return $this->findEntity($qb);
@ -123,8 +126,7 @@ class SharedFolderMapper extends QBMapper {
return 'p.' . $c;
}, SharedFolder::$columns))
->from('bookmarks_shared_folders', 'p')
->leftJoin('p', 'bookmarks_shares', 's', 'p.share_id = s.id')
->where($qb->expr()->eq('s.folder_id', $qb->createPositionalParameter($folderId)))
->where($qb->expr()->eq('p.folder_id', $qb->createPositionalParameter($folderId)))
->andWhere($qb->expr()->eq('p.user_id', $qb->createPositionalParameter($userId)));
return $this->findEntity($qb);
}
@ -140,7 +142,8 @@ class SharedFolderMapper extends QBMapper {
return 'p.' . $c;
}, SharedFolder::$columns))
->from('bookmarks_shared_folders', 'p')
->leftJoin('p', 'bookmarks_shares', 's', 'p.share_id = s.id')
->leftJoin('p', 'bookmarks_shared_to_shares', 't', 'p.id = t.shared_folder_id')
->leftJoin('t', 'bookmarks_shares', 's', 't.share_id = s.id')
->where($qb->expr()->eq('s.owner', $qb->createPositionalParameter($owner)))
->andWhere($qb->expr()->eq('p.user_id', $qb->createPositionalParameter($userId)));
return $this->findEntities($qb);
@ -159,9 +162,23 @@ class SharedFolderMapper extends QBMapper {
return 'p.' . $c;
}, SharedFolder::$columns))
->from('bookmarks_shared_folder', 'p')
->leftJoin('p', 'bookmarks_shares', 's', 'p.share_id = s.id')
->where($qb->expr()->eq('s.share_id', $qb->createPositionalParameter($shareId)))
->leftJoin('p', 'bookmarks_shared_to_shares', 't', 't.shared_folder_id = p.id')
->where($qb->expr()->eq('t.share_id', $qb->createPositionalParameter($shareId)))
->andWhere($qb->expr()->eq('p.user_id', $qb->createPositionalParameter($userId)));
return $this->findEntity($qb);
}
public function findByParticipantAndUser(int $type, string $participant, string $userId) {
$qb = $this->db->getQueryBuilder();
$qb->select(array_map(static function ($c) {
return 'p.' . $c;
}, SharedFolder::$columns))
->from('bookmarks_shared_folders', 'p')
->leftJoin('p', 'bookmarks_shared_to_shares', 't', 't.shared_folder_id = p.id')
->leftJoin('t', 'bookmarks_shares', 's', 't.share_id = s.id')
->where($qb->expr()->eq('s.participant', $qb->createPositionalParameter($participant)))
->andWhere($qb->expr()->eq('s.type', $qb->createPositionalParameter($type)))
->andWhere($qb->expr()->eq('p.user_id', $qb->createPositionalParameter($userId)));
return $this->findEntities($qb);
}
}

View File

@ -479,17 +479,16 @@ class TreeMapper extends QBMapper {
$qb = $this->db->getQueryBuilder();
$qb
->select('folder_id', 'f.id')
->from('bookmarks_shares', 's')
->innerJoin('s', 'bookmarks_shared_folders', 'f', $qb->expr()->eq('f.share_id', 's.id'))
->innerJoin('f', 'bookmarks_tree', 't', $qb->expr()->eq('t.id', 'f.id'))
->select('folder_id', 'id')
->from('bookmarks_shared_folder', 's')
->innerJoin('s', 'bookmarks_tree', 't', $qb->expr()->eq('t.id', 's.id'))
->where($qb->expr()->eq('t.parent_folder', $qb->createPositionalParameter($folderId)))
->andWhere($qb->expr()->eq('t.type', $qb->createPositionalParameter(self::TYPE_SHARE)))
->orderBy('t.index', 'ASC');
$childShares = $qb->execute()->fetchAll();
$foldersToShares = array_reduce($childShares, static function ($dict, $shareRec) {
$dict[$shareRec['folder_id']] = $shareRec['f.id'];
$dict[$shareRec['folder_id']] = $shareRec['id'];
return $dict;
}, []);
@ -534,9 +533,8 @@ class TreeMapper extends QBMapper {
$qb = $this->db->getQueryBuilder();
$qb
->select('folder_id', 'index')
->from('bookmarks_shares', 's')
->innerJoin('s', 'bookmarks_shared_folders', 'f', $qb->expr()->eq('f.share_id', 's.id'))
->innerJoin('f', 'bookmarks_tree', 't', $qb->expr()->eq('t.id', 'f.id'))
->from('bookmarks_shared_folders', 'sf')
->innerJoin('f', 'bookmarks_tree', 't', $qb->expr()->eq('t.id', 'sf.id'))
->where($qb->expr()->eq('t.parent_folder', $qb->createPositionalParameter($folderId)))
->andWhere($qb->expr()->eq('t.type', $qb->createPositionalParameter(self::TYPE_SHARE)))
->orderBy('t.index', 'ASC');
@ -659,10 +657,9 @@ class TreeMapper extends QBMapper {
$qb = $this->db->getQueryBuilder();
$qb
->select('folder_id', 'f.title', 'user_id', 'index', 't.type')
->from('bookmarks_shares', 's')
->innerJoin('s', 'bookmarks_shared_folders', 'f', $qb->expr()->eq('f.share_id', 's.id'))
->innerJoin('f', 'bookmarks_tree', 't', $qb->expr()->eq('t.id', 'f.id'))
->select('folder_id', 's.title', 'user_id', 'index', 't.type')
->from('bookmarks_shared_folders', 's')
->innerJoin('f', 'bookmarks_tree', 't', $qb->expr()->eq('t.id', 's.id'))
->where($qb->expr()->eq('t.parent_folder', $qb->createPositionalParameter($folderId)))
->andWhere($qb->expr()->eq('t.type', $qb->createPositionalParameter(self::TYPE_SHARE)))
->orderBy('t.index', 'ASC');

View File

@ -0,0 +1,144 @@
<?php
namespace OCA\Bookmarks\Hooks;
use OCA\Bookmarks\Db\Folder;
use OCA\Bookmarks\Db\FolderMapper;
use OCA\Bookmarks\Db\Share;
use OCA\Bookmarks\Db\SharedFolderMapper;
use OCA\Bookmarks\Db\ShareMapper;
use OCA\Bookmarks\Db\TreeMapper;
use OCA\Bookmarks\Service\BookmarkService;
use OCA\Bookmarks\Service\FolderService;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Group\Events\BeforeGroupDeletedEvent;
use OCP\Group\Events\UserAddedEvent;
use OCP\Group\Events\UserRemovedEvent;
use OCP\IGroup;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Share\IShare;
use OCP\User\Events\BeforeUserDeletedEvent;
class UserGroupListener implements IEventListener {
private $userManager;
/**
* @var ShareMapper
*/
private $shareMapper;
/**
* @var SharedFolderMapper
*/
private $sharedFolderMapper;
/**
* @var FolderService
*/
private $folders;
/**
* @var FolderMapper
*/
private $folderMapper;
/**
* @var TreeMapper
*/
private $treeMapper;
/**
* @var BookmarkService
*/
private $bookmarks;
public function __construct(ShareMapper $shareMapper, SharedFolderMapper $sharedFolderMapper, FolderService $folders, FolderMapper $folderMapper, TreeMapper $treeMapper, BookmarkService $bookmarks) {
$this->shareMapper = $shareMapper;
$this->sharedFolderMapper = $sharedFolderMapper;
$this->folders = $folders;
$this->folderMapper = $folderMapper;
$this->treeMapper = $treeMapper;
$this->bookmarks = $bookmarks;
}
/**
* @param Event $event
* @throws \OCA\Bookmarks\Exception\UnsupportedOperation
* @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
*/
public function handle(Event $event): void {
if ($event instanceof BeforeUserDeletedEvent) {
$this->preDeleteUser($event->getUser());
}
if ($event instanceof UserAddedEvent) {
$this->postAddUser($event->getGroup(), $event->getUser());
}
if ($event instanceof UserRemovedEvent) {
$this->preRemoveUser($event->getGroup(), $event->getUser());
}
if ($event instanceof BeforeGroupDeletedEvent) {
$this->preDeleteGroup($event->getGroup());
}
}
/**
* @param IUser $user
* @throws \OCA\Bookmarks\Exception\UnsupportedOperation
* @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
*/
public function preDeleteUser(IUser $user): void {
$this->bookmarks->deleteAll($user->getUID());
// delete dangling shares
$sharesToDelete = $this->shareMapper->findByParticipant(IShare::TYPE_USER, $user->getUID());
foreach ($sharesToDelete as $share) {
$this->shareMapper->delete($share);
}
}
/**
* @param IGroup $group
*/
public function preDeleteGroup(IGroup $group): void {
$sharesToDelete = $this->shareMapper->findByParticipant(IShare::TYPE_GROUP, $group->getGID());
foreach ($sharesToDelete as $share) {
$this->shareMapper->delete($share);
}
}
/**
* @param IGroup $group
* @param IUser $user
* @throws \OCA\Bookmarks\Exception\UnsupportedOperation
* @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
*/
public function preRemoveUser(IGroup $group, IUser $user): void {
$sharedFoldersToDelete = $this->sharedFolderMapper->findByParticipantAndUser(IShare::TYPE_GROUP, $group->getGID(), $user->getUID());
foreach ($sharedFoldersToDelete as $sharedFolder) {
$this->treeMapper->deleteEntry(TreeMapper::TYPE_SHARE, $sharedFolder->getId());
}
}
/**
* @param IGroup $group
* @param IUser $user
* @throws \OCA\Bookmarks\Exception\UnsupportedOperation
* @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
*/
public function postAddUser(IGroup $group, IUser $user): void {
/**
* @var Share[] $shares
*/
$shares = $this->shareMapper->findByParticipant(IShare::TYPE_GROUP, $group->getGID());
foreach ($shares as $share) {
if ($share->getOwner() === $user->getUID()) {
continue;
}
/**
* @var Folder $folder
*/
$folder = $this->folderMapper->find($share->getFolderId());
$this->folders->addSharedFolder($share, $folder, $user->getUID());
}
}
}

View File

@ -0,0 +1,132 @@
<?php
namespace OCA\Bookmarks\Migration;
use OCA\Bookmarks\Db\Folder;
use OCA\Bookmarks\Db\FolderMapper;
use OCA\Bookmarks\Db\Share;
use OCA\Bookmarks\Db\SharedFolder;
use OCA\Bookmarks\Db\SharedFolderMapper;
use OCA\Bookmarks\Db\ShareMapper;
use OCA\Bookmarks\Db\TreeMapper;
use OCA\Bookmarks\Service\FolderService;
use OCP\IDBConnection;
use OCP\IUser;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
use OCP\Share\IShare;
class GroupSharesUpdateRepairStep implements IRepairStep {
/**
* @var IDBConnection
*/
private $db;
/**
* @var \OCP\IGroupManager
*/
private $groupManager;
/**
* @var FolderService
*/
private $folders;
/**
* @var ShareMapper
*/
private $shareMapper;
/**
* @var FolderMapper
*/
private $folderMapper;
/**
* @var SharedFolderMapper
*/
private $sharedFolderMapper;
public function __construct(IDBConnection $db, \OCP\IGroupManager $groupManager, FolderService $folders, ShareMapper $shareMapper, FolderMapper $folderMapper, SharedFolderMapper $sharedFolderMapper) {
$this->db = $db;
$this->groupManager = $groupManager;
$this->folders = $folders;
$this->shareMapper = $shareMapper;
$this->folderMapper = $folderMapper;
$this->sharedFolderMapper = $sharedFolderMapper;
}
/**
* Returns the step's name
*/
public function getName() {
return 'Update bookmark group shares';
}
/**
* @param IOutput $output
* @throws \OCA\Bookmarks\Exception\UnsupportedOperation
* @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
*/
public function run(IOutput $output) {
$deleted = 0;
$added = 0;
$groups = 0;
$deletedShares = 0;
// find group shares
$qb = $this->db->getQueryBuilder();
$qb->select('s.id', 's.participant', 's.folder_id', 's.owner')
->from('bookmarks_shares', 's')
->where($qb->expr()->eq('s.type', $qb->createPositionalParameter(IShare::TYPE_GROUP)));
$groupShares = $qb->execute();
while ($groupShare = $groupShares->fetch()) {
// find users in share
$qb = $this->db->getQueryBuilder();
$qb->select('sf.user_id')
->from('bookmarks_shared_folders', 'sf')
->join('bookmarks_shared_to_shares', 't', $qb->expr()->eq('t.shared_folder_id', 'sf.id'))
->where($qb->expr()->eq('t.share_id', $qb->createPositionalParameter($groupShare['id'])));
$usersInShare = $qb->execute()->fetchAll(\PDO::FETCH_COLUMN);
$group = $this->groupManager->get($groupShare['participant']);
if ($group === null) {
$this->folders->deleteShare($groupShare['id']);
$deletedShares++;
continue;
}
$usersInGroup = array_filter(array_map(static function ($user) {
return $user->getUID();
}, $group->getUsers()), static function ($userId) use ($groupShare) {
return $userId !== $groupShare['owner'];
});
$notInShareUsers = array_diff($usersInGroup, $usersInShare);
$notInGroupUsers = array_diff($usersInShare, $usersInGroup);
foreach ($notInGroupUsers as $userId) {
$this->folders->deleteSharedFolderOrFolder($userId, $groupShare['folder_id']);
$sharedFolder = $this->sharedFolderMapper->findByFolderAndUser($groupShare['folder_id'], $userId);
$this->sharedFolderMapper->delete($sharedFolder);
$deleted++;
}
foreach ($notInShareUsers as $userId) {
/**
* @var Share $share
*/
$share = $this->shareMapper->find($groupShare['id']);
/**
* @var Folder $folder
*/
$folder = $this->folderMapper->find($groupShare['folder_id']);
$this->folders->addSharedFolder($share, $folder, $userId);
$added++;
}
$groups++;
}
$output->info("Removed $deleted users and added $added users to $groups groups");
$output->info("Removed $deletedShares shares");
}
}

View File

@ -39,7 +39,8 @@ class OrphanedSharesRepairStep implements IRepairStep {
$qb = $this->db->getQueryBuilder();
$folders = $qb->select('f.id')
->from('bookmarks_shared_folders', 'f')
->where($qb->expr()->eq('f.share_id', $qb->createPositionalParameter($share)))
->join('f', 'bookmarks_shared_to_shares', 't', $qb->expr()->eq('f.id', 't.shared_folder_id'))
->where($qb->expr()->eq('t.share_id', $qb->createPositionalParameter($share)))
->execute()
->fetchAll(\PDO::FETCH_COLUMN);
foreach ($folders as $folderId) {
@ -50,9 +51,7 @@ class OrphanedSharesRepairStep implements IRepairStep {
->execute();
}
$qb = $this->db->getQueryBuilder();
$qb->delete('bookmarks_shared_folders')
->where($qb->expr()->eq('share_id', $qb->createPositionalParameter($share)))
->execute();
$this->db->executeQuery('DELETE sf FROM *PREFIX*bookmarks_shared_folders sf JOIN *PREFIX*bookmarks_shared_to_shares t ON sf.id = t.shared_folder_id WHERE t.share_id = ?', [$share]);
$qb = $this->db->getQueryBuilder();
$qb->delete('bookmarks_shares')
->where($qb->expr()->eq('id', $qb->createPositionalParameter($share)))

View File

@ -22,7 +22,7 @@ class OrphanedTreeItemsRepairStep implements IRepairStep {
* Returns the step's name
*/
public function getName() {
return 'Remove orphaned tree items';
return 'Remove orphaned bookmark tree items';
}
/**

View File

@ -22,7 +22,7 @@ class SuperfluousSharedFoldersRepairStep implements IRepairStep {
* Returns the step's name
*/
public function getName() {
return 'Remove superfluous shared folders';
return 'Remove superfluous shared bookmark folders';
}
/**
@ -33,7 +33,8 @@ class SuperfluousSharedFoldersRepairStep implements IRepairStep {
$qb->select('t.id')
->from('bookmarks_tree', 't')
->join('t', 'bookmarks_shared_folders', 'sf', $qb->expr()->eq('t.id', 'sf.id'))
->join('sf', 'bookmarks_shares', 's', $qb->expr()->eq('sf.share_id', 's.id'))
->join('sf', 'bookmarks_shared_to_shares', 't', $qb->expr()->eq('sf.id', 't.shared_folder_id'))
->join('t', 'bookmarks_shares', 's', $qb->expr()->eq('t.share_id', 's.id'))
->where($qb->expr()->eq('t.type', $qb->createPositionalParameter('share')))
->andWhere($qb->expr()->eq('s.owner', 'sf.user_id'));
$superfluousSharedFolders = $qb->execute();

View File

@ -0,0 +1,113 @@
<?php
namespace OCA\Bookmarks\Migration;
use Doctrine\DBAL\Types\BigIntType;
use Doctrine\DBAL\Types\Type;
use OCP\DB\ISchemaWrapper;
use OCP\IDBConnection;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;
/**
* Auto-generated migration step: Please modify to your needs!
*/
class Version003001000Date20200526094721 extends SimpleMigrationStep {
private $db;
public function __construct(IDBConnection $db) {
$this->db = $db;
}
/**
* @param IOutput $output
* @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
*/
public function preSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) {
}
/**
* @param IOutput $output
* @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
* @return null|ISchemaWrapper
* @throws \Doctrine\DBAL\Schema\SchemaException
*/
public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
if (!$schema->hasTable('bookmarks_shared_to_shares')) {
$table = $schema->createTable('bookmarks_shared_to_shares');
$table->addColumn('shared_folder_id', 'bigint', [
'notnull' => true,
'length' => 64,
]);
$table->addColumn('share_id', 'bigint', [
'notnull' => true,
'length' => 64,
]);
$table->setPrimaryKey(['shared_folder_id', 'share_id']);
$table->addIndex(['shared_folder_id'], 'bookmarks_shares_to_shares');
$table->addIndex(['share_id'], 'bookmarks_share_to_shared');
}
$table = $schema->getTable('bookmarks_shared_folders');
if (!$table->hasColumn('folder_id')) {
$table->addColumn('folder_id', 'bigint', [
'notnull' => true,
'length' => 64,
'default' => 0
]);
$table->addIndex(['folder_id'], 'bookmarks_shared_folder');
}
return $schema;
}
/**
* @param IOutput $output
* @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
*/
public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) {
$qb = $this->db->getQueryBuilder();
// Find all shared folders
$sharedFolders = $qb->select('sf.share_id', 'sf.id', 's.folder_id', 'sf.user_id')
->from('bookmarks_shared_folders', 'sf')
->leftJoin('sf', 'bookmarks_shares', 's', $qb->expr()->eq('sf.share_id', 's.id'))
->execute();
while($sharedFolder = $sharedFolders->fetch()) {
// Find a shared folder with folder_id already set. This is gonna be the only one we will have for this folder from now on.
$qb = $this->db->getQueryBuilder();
$canonicalSharedFolder = $qb->select('sf.id', 'sf.folder_id')
->from('bookmarks_shared_folders', 'sf')
->where($qb->expr()->eq('sf.folder_id', $qb->createPositionalParameter($sharedFolder['folder_id'])))
->andWhere($qb->expr()->eq('sf.user_id', $qb->createPositionalParameter($sharedFolder['user_id'])))
->execute()
->fetch();
if (!$canonicalSharedFolder) {
// If there's no canonical shared folder, we make this one it.
$qb = $this->db->getQueryBuilder();
$qb->update('bookmarks_shared_folders')
->set('folder_id', $qb->createPositionalParameter($sharedFolder['folder_id']))
->where($qb->expr()->eq('id', $qb->createPositionalParameter($sharedFolder['id'])))
->execute();
$canonicalSharedFolder = $sharedFolder;
}else{
// ...otherwise delete this shared folder.
$qb = $this->db->getQueryBuilder();
$qb->delete('bookmarks_shared_folders')
->where($qb->expr()->eq('id', $qb->createPositionalParameter($sharedFolder['id'])))
->execute();
}
// Insert into pivot table
$qb = $this->db->getQueryBuilder();
$qb->insert('bookmarks_shared_to_shares')
->values([
'shared_folder_id' => $qb->createPositionalParameter($canonicalSharedFolder['id']),
'share_id' => $qb->createPositionalParameter($sharedFolder['share_id'])
])
->execute();
}
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace OCA\Bookmarks\Migration;
use Doctrine\DBAL\Types\BigIntType;
use Doctrine\DBAL\Types\Type;
use OCP\DB\ISchemaWrapper;
use OCP\IDBConnection;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;
/**
* Auto-generated migration step: Please modify to your needs!
*/
class Version003001000Date20200526124721 extends SimpleMigrationStep {
private $db;
public function __construct(IDBConnection $db) {
$this->db = $db;
}
/**
* @param IOutput $output
* @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
*/
public function preSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) {
}
/**
* @param IOutput $output
* @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
* @return null|ISchemaWrapper
* @throws \Doctrine\DBAL\Schema\SchemaException
*/
public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
if ($schema->hasTable('bookmarks_shared_folders')) {
$table = $schema->getTable('bookmarks_shared_folders');
$table->dropColumn('share_id');
}
return $schema;
}
/**
* @param IOutput $output
* @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
*/
public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) {
}
}

View File

@ -183,7 +183,7 @@ class FolderService {
* @var $sharedFolder SharedFolder
*/
$sharedFolder = $this->sharedFolderMapper->findByFolderAndUser($folder->getId(), $userId);
$this->sharedFolderMapper->delete($sharedFolder);
$this->treeMapper->deleteEntry(TreeMapper::TYPE_SHARE, $sharedFolder->getId());
return;
} catch (DoesNotExistException $e) {
// noop
@ -300,7 +300,7 @@ class FolderService {
if ($participant === $folder->getUserId()) {
throw new UnsupportedOperation('Cannot share with oneself');
}
$this->_addSharedFolder($share, $folder, $participant);
$this->addSharedFolder($share, $folder, $participant);
} else if ($type === IShare::TYPE_GROUP) {
$group = $this->groupManager->get($participant);
if ($group === null) {
@ -320,7 +320,7 @@ class FolderService {
// do nothing
}
$this->_addSharedFolder($share, $folder, $user->getUID());
$this->addSharedFolder($share, $folder, $user->getUID());
}
}
return $share;
@ -333,7 +333,7 @@ class FolderService {
* @throws MultipleObjectsReturnedException
* @throws UnsupportedOperation
*/
private function _addSharedFolder(Share $share, Folder $folder, string $userId): void {
public function addSharedFolder(Share $share, Folder $folder, string $userId): void {
$sharedFolder = new SharedFolder();
$sharedFolder->setShareId($share->getId());
$sharedFolder->setTitle($folder->getTitle());