diff --git a/.github/workflows/upgrade.yml b/.github/workflows/upgrade.yml index 812a9b896..734240b70 100644 --- a/.github/workflows/upgrade.yml +++ b/.github/workflows/upgrade.yml @@ -24,10 +24,15 @@ jobs: # do not stop on another job's failure fail-fast: false matrix: - php-versions: ['8.1', '8.2', '8.3', '8.4'] + php-versions: ['8.2', '8.3', '8.4'] databases: ['sqlite', 'mysql', 'pgsql'] - server-versions: ['stable32', 'master'] + server-versions: ['stable32', 'stable33', 'master'] prev-version: ['stable'] + include: + - databases: 'sqlite' + server-versions: 'stable32' + php-versions: '8.1' + prev-version: 'stable' name: Update from ${{ matrix.prev-version }} on ${{ matrix.databases }}-${{ matrix.server-versions }} diff --git a/appinfo/info.xml b/appinfo/info.xml index 0e783daae..b7986913f 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -23,7 +23,7 @@ Requirements: - mbstring: * - when using MySQL, use at least v8.0 ]]> - 16.0.1 + 16.1.0-dev.0 agpl Marcel Klehr Arthur Schiwon @@ -42,7 +42,7 @@ Requirements: pgsql intl mbstring - + OCA\Bookmarks\BackgroundJobs\CrawlJob diff --git a/appinfo/routes.php b/appinfo/routes.php index f14ff69b2..c0e2e2b13 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -45,6 +45,7 @@ ['name' => 'internal_bookmark#import_bookmark', 'url' => '/bookmark/import', 'verb' => 'POST'], ['name' => 'internal_bookmark#count_unavailable', 'url' => '/bookmark/unavailable', 'verb' => 'GET'], ['name' => 'internal_bookmark#count_archived', 'url' => '/bookmark/archived', 'verb' => 'GET'], + ['name' => 'internal_bookmark#count_deleted', 'url' => '/bookmark/deletedCount', 'verb' => 'GET'], ['name' => 'internal_bookmark#count_duplicated', 'url' => '/bookmark/duplicated', 'verb' => 'GET'], ['name' => 'internal_bookmark#get_deleted_bookmarks', 'url' => '/bookmark/deleted', 'verb' => 'GET'], ['name' => 'internal_bookmark#edit_bookmark', 'url' => '/bookmark/{id}', 'verb' => 'PUT'], diff --git a/lib/Controller/BookmarkController.php b/lib/Controller/BookmarkController.php index 569f47dcb..8764a6d59 100644 --- a/lib/Controller/BookmarkController.php +++ b/lib/Controller/BookmarkController.php @@ -170,7 +170,7 @@ private function _returnBookmarkAsArray(Bookmark $bookmark): array { if (!isset($array['tags'])) { $array['tags'] = $this->tagMapper->findByBookmark($bookmark->getId()); } - if ($array['archivedFile'] !== 0 && $array['archivedFile'] !== null) { + if ($array['archivedFile'] !== 0 && $array['archivedFile'] !== null && $this->authorizer->getUserId() === $bookmark->getUserId()) { $result = $this->rootFolder->getFirstNodeById($array['archivedFile']); if ($result !== null) { $array['archivedFilePath'] = $result->getPath(); @@ -744,7 +744,7 @@ public function importBookmark($folder = null): JSONResponse { return new JSONResponse(['status' => 'error', 'data' => ['Could not import all bookmarks: User limit Exceeded']], Http::STATUS_BAD_REQUEST); } catch (AlreadyExistsError $e) { return new JSONResponse(['status' => 'error', 'data' => ['Could not import all bookmarks: Already exists']], Http::STATUS_BAD_REQUEST); - } catch (UnsupportedOperation $e) { + } catch (UnsupportedOperation|\OCP\DB\Exception $e) { return new JSONResponse(['status' => 'error', 'data' => ['Internal server error']], Http::STATUS_INTERNAL_SERVER_ERROR); } if (count($result['errors']) !== 0) { @@ -874,6 +874,25 @@ public function countDuplicated(): JSONResponse { return new JSONResponse(['status' => 'success', 'item' => $count]); } + /** + * @return JSONResponse + * @NoAdminRequired + * @NoCSRFRequired + * @BruteForceProtection + * @PublicPage + * @throws UnauthenticatedError + */ + public function countDeleted(): JSONResponse { + if (!Authorizer::hasPermission(Authorizer::PERM_READ, $this->authorizer->getPermissionsForFolder(-1, $this->request))) { + $res = new JSONResponse(['status' => 'error', 'data' => ['Unauthorized']], Http::STATUS_FORBIDDEN); + $res->throttle(); + return $res; + } + + $count = $this->bookmarkMapper->countDeleted($this->authorizer->getUserId()); + return new JSONResponse(['status' => 'success', 'item' => $count]); + } + /** * @return JSONResponse * @NoAdminRequired diff --git a/lib/Controller/InternalBookmarkController.php b/lib/Controller/InternalBookmarkController.php index 695e955ed..5709d8e0e 100644 --- a/lib/Controller/InternalBookmarkController.php +++ b/lib/Controller/InternalBookmarkController.php @@ -286,4 +286,13 @@ public function countAllClicks(): DataResponse { public function countWithClicks(): DataResponse { return $this->publicController->countWithClicks(); } + + /** + * @return JSONResponse + * @throws \OCA\Bookmarks\Exception\UnauthenticatedError + * @NoAdminRequired + */ + public function countDeleted() { + return $this->publicController->countDeleted(); + } } diff --git a/lib/Controller/WebViewController.php b/lib/Controller/WebViewController.php index fe6ac1184..a44db041a 100644 --- a/lib/Controller/WebViewController.php +++ b/lib/Controller/WebViewController.php @@ -76,6 +76,7 @@ public function index(): AugmentedTemplateResponse { $this->initialState->provideInitialState($this->appName, 'folders', $this->folderController->getFolders()->getData()['data']); $this->initialState->provideInitialState($this->appName, 'deletedFolders', $this->folderController->getDeletedFolders()->getData()['data']); $this->initialState->provideInitialState($this->appName, 'archivedCount', $this->bookmarkController->countArchived()->getData()['item']); + $this->initialState->provideInitialState($this->appName, 'deletedCount', $this->bookmarkController->countDeleted()->getData()['item']); $this->initialState->provideInitialState($this->appName, 'duplicatedCount', $this->bookmarkController->countDuplicated()->getData()['item']); $this->initialState->provideInitialState($this->appName, 'unavailableCount', $this->bookmarkController->countUnavailable()->getData()['item']); $this->initialState->provideInitialState($this->appName, 'allCount', $this->bookmarkController->countBookmarks(-1)->getData()['item']); diff --git a/lib/Db/Bookmark.php b/lib/Db/Bookmark.php index 1f1bd693b..888c26e48 100644 --- a/lib/Db/Bookmark.php +++ b/lib/Db/Bookmark.php @@ -32,6 +32,8 @@ * @method setArchivedFile(int $fileId) * @method getUserId(): string * @method setUserId(string $userId) + * @method setUrlHash(string $urlHash) + * @method getUrlHash():string */ class Bookmark extends Entity { protected $url; @@ -47,9 +49,10 @@ class Bookmark extends Entity { protected $archivedFile; protected $textContent; protected $htmlContent; + protected $urlHash; - public static $columns = ['id', 'url', 'title', 'description', 'lastmodified', 'added', 'clickcount', 'last_preview', 'available', 'archived_file', 'user_id', 'text_content', 'html_content']; - public static $fields = ['id', 'url', 'title', 'description', 'lastmodified', 'added', 'clickcount', 'lastPreview', 'available', 'archivedFile', 'userId', 'textContent','htmlContent']; + public static $columns = ['id', 'url', 'title', 'description', 'lastmodified', 'added', 'clickcount', 'last_preview', 'available', 'archived_file', 'user_id', 'text_content', 'html_content', 'url_hash']; + public static $fields = ['id', 'url', 'title', 'description', 'lastmodified', 'added', 'clickcount', 'lastPreview', 'available', 'archivedFile', 'userId', 'textContent','htmlContent', 'urlHash']; public static function fromArray($props): self { $bookmark = new Bookmark(); @@ -75,6 +78,7 @@ public function __construct() { $this->addType('lastPreview', 'integer'); $this->addType('available', 'boolean'); $this->addType('archivedFile', 'integer'); + $this->addType('urlHash', 'string'); } public function toArray(): array { @@ -89,6 +93,9 @@ public function toArray(): array { $array['target'] = $this->url; continue; } + if ($field === 'urlHash') { + continue; + } $array[$field] = $this->{'get' . $field}(); } return $array; diff --git a/lib/Db/BookmarkMapper.php b/lib/Db/BookmarkMapper.php index 8646ab51b..bf493ed56 100644 --- a/lib/Db/BookmarkMapper.php +++ b/lib/Db/BookmarkMapper.php @@ -109,7 +109,7 @@ protected function getFindByUrlQuery(): IQueryBuilder { ->select('*') ->from('bookmarks') ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id'))) - ->andWhere($qb->expr()->eq('url', $qb->createParameter('url'))); + ->andWhere($qb->expr()->eq('url_hash', $qb->createParameter('url_hash'))); return $qb; } @@ -132,7 +132,7 @@ public function findByUrl($userId, $url): Bookmark { $qb = $this->findByUrlQuery; $qb->setParameters([ 'user_id' => $userId, - 'url' => $url + 'url_hash' => md5($url), ]); return $this->findEntity($qb); } @@ -141,17 +141,19 @@ public function findByUrl($userId, $url): Bookmark { * @param string $userId * @throws DoesNotExistException * @throws MultipleObjectsReturnedException + * @throws Exception */ public function deleteAll(string $userId): void { $qb = $this->db->getQueryBuilder(); $qb->select('b.id') ->from('bookmarks', 'b') ->where($qb->expr()->eq('b.user_id', $qb->createPositionalParameter($userId))); - $orphanedBookmarks = $qb->execute(); - while ($bookmark = $orphanedBookmarks->fetchColumn()) { + $result = $qb->executeQuery(); + while ($bookmark = $result->fetchOne()) { $bm = $this->find($bookmark); $this->delete($bm); } + $result->closeCursor(); } /** @@ -265,8 +267,6 @@ protected function findEntitiesWithRawQuery(string $query, array $params, array protected function getIteratorWithRawQuery(string $query, array $params, array $types): \Generator { $cursor = $this->db->executeQuery($query, $params, $types); - $entities = []; - while ($row = $cursor->fetch()) { yield $this->mapRowToEntity($row); } @@ -401,7 +401,7 @@ private function _sortAndPaginate(IQueryBuilder $qb, QueryParameters $params): v private function _filterUrl(IQueryBuilder $qb, QueryParameters $params): void { if (($url = $params->getUrl()) !== null) { $normalized = $this->urlNormalizer->normalize($url); - $qb->andWhere($qb->expr()->eq('b.url', $qb->createPositionalParameter($normalized))); + $qb->andWhere($qb->expr()->eq('b.url_hash', $qb->createPositionalParameter(md5($normalized)))); } } @@ -528,6 +528,38 @@ private function _filterTags(IQueryBuilder $qb, QueryParameters $params): void { } } + /** + * @param string $userId + * @return int + * @throws Exception + */ + public function countDeleted(string $userId): int { + $qb = $this->db->getQueryBuilder(); + $qb->selectAlias($qb->func()->count('b.id'), 'count'); + $qb + ->from('bookmarks', 'b') + ->innerJoin('b', 'bookmarks_tree', 'tr', 'b.id = tr.id AND tr.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK)) + ->where($qb->expr()->eq('b.user_id', $qb->createPositionalParameter($userId))) + ->andWhere($qb->expr()->isNotNull('tr.soft_deleted_at')); + $result = $qb->executeQuery(); + $userOwnerDeletedCount = $result->fetch(PDO::FETCH_COLUMN); + $result->closeCursor(); + + $qb = $this->db->getQueryBuilder(); + $qb->selectAlias($qb->func()->count('b.id'), 'count'); + $qb + ->from('bookmarks', 'b') + ->innerJoin('b', 'bookmarks_tree', 'tr', 'b.id = tr.id AND tr.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK)) + ->innerJoin('tr', 'bookmarks_shared_folders', 'sf', $qb->expr()->eq('tr.parent_folder', 'sf.folder_id')) + ->where($qb->expr()->eq('sf.user_id', $qb->createPositionalParameter($userId))) + ->andWhere($qb->expr()->isNotNull('tr.soft_deleted_at')); + $result = $qb->executeQuery(); + $foreignDeletedCount = $result->fetch(PDO::FETCH_COLUMN); + $result->closeCursor(); + + return $userOwnerDeletedCount + $foreignDeletedCount; + } + /** * @param string $userId * @return int @@ -535,23 +567,28 @@ private function _filterTags(IQueryBuilder $qb, QueryParameters $params): void { public function countArchived(string $userId): int { $qb = $this->db->getQueryBuilder(); $qb->selectAlias($qb->func()->count('b.id'), 'count'); + $qb + ->from('bookmarks', 'b') + ->innerJoin('b', 'bookmarks_tree', 'tr', 'b.id = tr.id AND tr.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK) . ' AND tr.soft_deleted_at is NULL') + ->where($qb->expr()->eq('b.user_id', $qb->createPositionalParameter($userId))) + ->andWhere($qb->expr()->isNotNull('b.archived_file')); + $result = $qb->executeQuery(); + $userOwnerArchivedCount = $result->fetch(PDO::FETCH_COLUMN); + $result->closeCursor(); + $qb = $this->db->getQueryBuilder(); + $qb->selectAlias($qb->func()->count('b.id'), 'count'); $qb ->from('bookmarks', 'b') - ->leftJoin('b', 'bookmarks_tree', 'tr', 'b.id = tr.id AND tr.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK) . ' AND tr.soft_deleted_at is NULL') - ->leftJoin('tr', 'bookmarks_shared_folders', 'sf', $qb->expr()->eq('tr.parent_folder', 'sf.folder_id')) - ->where( - $qb->expr()->andX( - $qb->expr()->orX( - $qb->expr()->eq('b.user_id', $qb->createPositionalParameter($userId)), - $qb->expr()->eq('sf.user_id', $qb->createPositionalParameter($userId)) - ), - $qb->expr()->in('b.user_id', array_map([$qb, 'createPositionalParameter'], array_merge($this->_findSharersFor($userId), [$userId]))) - ) - ) + ->innerJoin('b', 'bookmarks_tree', 'tr', 'b.id = tr.id AND tr.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK) . ' AND tr.soft_deleted_at is NULL') + ->innerJoin('tr', 'bookmarks_shared_folders', 'sf', $qb->expr()->eq('tr.parent_folder', 'sf.folder_id')) + ->where($qb->expr()->eq('sf.user_id', $qb->createPositionalParameter($userId))) ->andWhere($qb->expr()->isNotNull('b.archived_file')); + $result = $qb->executeQuery(); + $foreignArchivedCount = $result->fetch(PDO::FETCH_COLUMN); + $result->closeCursor(); - return $qb->execute()->fetch(PDO::FETCH_COLUMN); + return $userOwnerArchivedCount + $foreignArchivedCount; } /** @@ -562,22 +599,28 @@ public function countArchived(string $userId): int { public function countAllClicks(string $userId): int { $qb = $this->db->getQueryBuilder(); $qb->selectAlias($qb->func()->sum('b.clickcount'), 'count'); + $qb + ->from('bookmarks', 'b') + ->innerJoin('b', 'bookmarks_tree', 'tr', 'b.id = tr.id AND tr.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK) . ' AND tr.soft_deleted_at is NULL') + ->where($qb->expr()->eq('b.user_id', $qb->createPositionalParameter($userId))) + ->andWhere($qb->expr()->neq('b.clickcount', $qb->createPositionalParameter(0, IQueryBuilder::PARAM_INT))); + $result = $qb->executeQuery(); + $userOwnerClickCount = $result->fetch(PDO::FETCH_COLUMN); + $result->closeCursor(); + $qb = $this->db->getQueryBuilder(); + $qb->selectAlias($qb->func()->sum('b.clickcount'), 'count'); $qb ->from('bookmarks', 'b') - ->leftJoin('b', 'bookmarks_tree', 'tr', 'b.id = tr.id AND tr.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK) . ' AND tr.soft_deleted_at is NULL') - ->leftJoin('tr', 'bookmarks_shared_folders', 'sf', $qb->expr()->eq('tr.parent_folder', 'sf.folder_id')) - ->where( - $qb->expr()->andX( - $qb->expr()->orX( - $qb->expr()->eq('b.user_id', $qb->createPositionalParameter($userId)), - $qb->expr()->eq('sf.user_id', $qb->createPositionalParameter($userId)) - ), - $qb->expr()->in('b.user_id', array_map([$qb, 'createPositionalParameter'], array_merge($this->_findSharersFor($userId), [$userId]))) - ) - ); + ->innerJoin('b', 'bookmarks_tree', 'tr', 'b.id = tr.id AND tr.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK) . ' AND tr.soft_deleted_at is NULL') + ->innerJoin('tr', 'bookmarks_shared_folders', 'sf', $qb->expr()->eq('tr.parent_folder', 'sf.folder_id')) + ->where($qb->expr()->eq('sf.user_id', $qb->createPositionalParameter($userId))) + ->andWhere($qb->expr()->neq('b.clickcount', $qb->createPositionalParameter(0, IQueryBuilder::PARAM_INT))); + $result = $qb->executeQuery(); + $foreignClickCount = $result->fetch(PDO::FETCH_COLUMN); + $result->closeCursor(); - return $qb->execute()->fetch(PDO::FETCH_COLUMN) ?? 0; + return $userOwnerClickCount + $foreignClickCount; } /** @@ -588,23 +631,28 @@ public function countAllClicks(string $userId): int { public function countWithClicks(string $userId): int { $qb = $this->db->getQueryBuilder(); $qb->selectAlias($qb->func()->count('b.id'), 'count'); + $qb + ->from('bookmarks', 'b') + ->innerJoin('b', 'bookmarks_tree', 'tr', 'b.id = tr.id AND tr.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK) . ' AND tr.soft_deleted_at is NULL') + ->where($qb->expr()->eq('b.user_id', $qb->createPositionalParameter($userId))) + ->andWhere($qb->expr()->neq('b.clickcount', $qb->createPositionalParameter(0, IQueryBuilder::PARAM_INT))); + $result = $qb->executeQuery(); + $userOwnerWithClicksCount = $result->fetch(PDO::FETCH_COLUMN); + $result->closeCursor(); + $qb = $this->db->getQueryBuilder(); + $qb->selectAlias($qb->func()->count('b.id'), 'count'); $qb ->from('bookmarks', 'b') - ->leftJoin('b', 'bookmarks_tree', 'tr', 'b.id = tr.id AND tr.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK) . ' AND tr.soft_deleted_at is NULL') - ->leftJoin('tr', 'bookmarks_shared_folders', 'sf', $qb->expr()->eq('tr.parent_folder', 'sf.folder_id')) - ->where( - $qb->expr()->andX( - $qb->expr()->orX( - $qb->expr()->eq('b.user_id', $qb->createPositionalParameter($userId)), - $qb->expr()->eq('sf.user_id', $qb->createPositionalParameter($userId)) - ), - $qb->expr()->in('b.user_id', array_map([$qb, 'createPositionalParameter'], array_merge($this->_findSharersFor($userId), [$userId]))) - ) - ) + ->innerJoin('b', 'bookmarks_tree', 'tr', 'b.id = tr.id AND tr.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK) . ' AND tr.soft_deleted_at is NULL') + ->innerJoin('tr', 'bookmarks_shared_folders', 'sf', $qb->expr()->eq('tr.parent_folder', 'sf.folder_id')) + ->where($qb->expr()->eq('sf.user_id', $qb->createPositionalParameter($userId))) ->andWhere($qb->expr()->neq('b.clickcount', $qb->createPositionalParameter(0, IQueryBuilder::PARAM_INT))); + $result = $qb->executeQuery(); + $foreignWithClicksCount = $result->fetch(PDO::FETCH_COLUMN); + $result->closeCursor(); - return $qb->execute()->fetch(PDO::FETCH_COLUMN); + return $userOwnerWithClicksCount + $foreignWithClicksCount; } /** @@ -615,46 +663,60 @@ public function countWithClicks(string $userId): int { public function countUnavailable(string $userId): int { $qb = $this->db->getQueryBuilder(); $qb->selectAlias($qb->func()->count('b.id'), 'count'); + $qb + ->from('bookmarks', 'b') + ->innerJoin('b', 'bookmarks_tree', 'tr', 'b.id = tr.id AND tr.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK) . ' AND tr.soft_deleted_at is NULL') + ->where($qb->expr()->eq('b.user_id', $qb->createPositionalParameter($userId))) + ->andWhere($qb->expr()->eq('b.available', $qb->createPositionalParameter(false, IQueryBuilder::PARAM_BOOL))); + $result = $qb->executeQuery(); + $userOwnerUnavailableCount = $result->fetch(PDO::FETCH_COLUMN); + $result->closeCursor(); + $qb = $this->db->getQueryBuilder(); + $qb->selectAlias($qb->func()->count('b.id'), 'count'); $qb ->from('bookmarks', 'b') - ->leftJoin('b', 'bookmarks_tree', 'tr', 'b.id = tr.id AND tr.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK) . ' AND tr.soft_deleted_at is NULL') - ->leftJoin('tr', 'bookmarks_shared_folders', 'sf', $qb->expr()->eq('tr.parent_folder', 'sf.folder_id')) - ->where( - $qb->expr()->andX( - $qb->expr()->orX( - $qb->expr()->eq('b.user_id', $qb->createPositionalParameter($userId)), - $qb->expr()->eq('sf.user_id', $qb->createPositionalParameter($userId)) - ), - $qb->expr()->in('b.user_id', array_map([$qb, 'createPositionalParameter'], array_merge($this->_findSharersFor($userId), [$userId]))) - ) - ) + ->innerJoin('b', 'bookmarks_tree', 'tr', 'b.id = tr.id AND tr.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK) . ' AND tr.soft_deleted_at is NULL') + ->innerJoin('tr', 'bookmarks_shared_folders', 'sf', $qb->expr()->eq('tr.parent_folder', 'sf.folder_id')) + ->where($qb->expr()->eq('sf.user_id', $qb->createPositionalParameter($userId))) ->andWhere($qb->expr()->eq('b.available', $qb->createPositionalParameter(false, IQueryBuilder::PARAM_BOOL))); + $result = $qb->executeQuery(); + $foreignUnavailableCount = $result->fetch(PDO::FETCH_COLUMN); + $result->closeCursor(); - return $qb->execute()->fetch(PDO::FETCH_COLUMN); + return $userOwnerUnavailableCount + $foreignUnavailableCount; } /** * @param string $userId * @return int + * @throws Exception */ public function countDuplicated(string $userId): int { $qb = $this->db->getQueryBuilder(); $qb->selectDistinct($qb->func()->count('b.id')); + $qb + ->from('bookmarks', 'b') + ->innerJoin('b', 'bookmarks_tree', 'tr', 'b.id = tr.id AND tr.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK) . ' AND tr.soft_deleted_at is NULL') + ->where($qb->expr()->eq('b.user_id', $qb->createPositionalParameter($userId))); + $subQuery = $this->db->getQueryBuilder(); + $subQuery->select('trdup.parent_folder') + ->from('bookmarks_tree', 'trdup') + ->where($subQuery->expr()->eq('b.id', 'trdup.id')) + ->andWhere($subQuery->expr()->neq('trdup.parent_folder', 'tr.parent_folder')) + ->andWhere($subQuery->expr()->eq('trdup.type', $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK))); + $qb->andWhere($qb->createFunction('EXISTS(' . $subQuery->getSQL() . ')')); + $result = $qb->executeQuery(); + $userOwnerDuplicatesCount = $result->fetch(PDO::FETCH_COLUMN); + $result->closeCursor(); + $qb = $this->db->getQueryBuilder(); + $qb->selectDistinct($qb->func()->count('b.id')); $qb ->from('bookmarks', 'b') - ->leftJoin('b', 'bookmarks_tree', 'tr', 'b.id = tr.id AND tr.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK) . ' AND tr.soft_deleted_at is NULL') - ->leftJoin('tr', 'bookmarks_shared_folders', 'sf', $qb->expr()->eq('tr.parent_folder', 'sf.folder_id')) - ->where( - $qb->expr()->andX( - $qb->expr()->orX( - $qb->expr()->eq('b.user_id', $qb->createPositionalParameter($userId)), - $qb->expr()->eq('sf.user_id', $qb->createPositionalParameter($userId)) - ), - $qb->expr()->in('b.user_id', array_map([$qb, 'createPositionalParameter'], array_merge($this->_findSharersFor($userId), [$userId]))), - ) - ); + ->innerJoin('b', 'bookmarks_tree', 'tr', 'b.id = tr.id AND tr.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK) . ' AND tr.soft_deleted_at is NULL') + ->innerJoin('tr', 'bookmarks_shared_folders', 'sf', $qb->expr()->eq('tr.parent_folder', 'sf.folder_id')) + ->where($qb->expr()->eq('sf.user_id', $qb->createPositionalParameter($userId))); $subQuery = $this->db->getQueryBuilder(); $subQuery->select('trdup.parent_folder') ->from('bookmarks_tree', 'trdup') @@ -662,8 +724,11 @@ public function countDuplicated(string $userId): int { ->andWhere($subQuery->expr()->neq('trdup.parent_folder', 'tr.parent_folder')) ->andWhere($subQuery->expr()->eq('trdup.type', $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK))); $qb->andWhere($qb->createFunction('EXISTS(' . $subQuery->getSQL() . ')')); + $result = $qb->executeQuery(); + $foreignDuplicatesCount = $result->fetch(PDO::FETCH_COLUMN); + $result->closeCursor(); - return $qb->execute()->fetch(PDO::FETCH_COLUMN); + return $userOwnerDuplicatesCount + $foreignDuplicatesCount; } /** @@ -704,7 +769,7 @@ public function findAllInPublicFolder(string $token, QueryParameters $queryParam $qb ->from('*PREFIX*bookmarks', 'b') - ->join('b', 'folder_tree', 'tree', 'tree.item_id = b.id AND tree.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK) . ' AND tree.soft_deleted_at is NULL'); + ->innerJoin('b', 'folder_tree', 'tree', 'tree.item_id = b.id AND tree.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK) . ' AND tree.soft_deleted_at is NULL'); $this->_filterUrl($qb, $queryParams); @@ -773,7 +838,7 @@ public function delete(Entity $entity): Bookmark { $qb = $this->deleteTagsQuery; $qb->setParameter('id', $id); - $qb->execute(); + $qb->executeStatement(); return $returnedEntity; } @@ -813,6 +878,7 @@ public function insert(Entity $entity): Bookmark { if ($entity->isWebLink()) { $entity->setUrl($this->urlNormalizer->normalize($entity->getUrl())); } + $entity->setUrlHash(md5($entity->getUrl())); if ($entity->getAdded() === null) { $entity->setAdded(time()); @@ -822,16 +888,15 @@ public function insert(Entity $entity): Bookmark { $entity->setClickcount(0); try { - $this->findByUrl($entity->getUserId(), $entity->getUrl()); - } catch (DoesNotExistException $e) { parent::insert($entity); $this->eventDispatcher->dispatchTyped(new InsertEvent('bookmark', $entity->getId())); return $entity; - } catch (MultipleObjectsReturnedException $e) { - // noop + } catch (Exception $e) { + if ($e->getReason() === Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) { + throw new AlreadyExistsError('A bookmark with this URL already exists'); + } + throw $e; } - - throw new AlreadyExistsError('A bookmark with this URL already exists'); } /** @@ -846,19 +911,20 @@ public function insertOrUpdate(Entity $entity): Bookmark { try { $newEntity = $this->insert($entity); } catch (AlreadyExistsError $e) { - $bookmark = $this->findByUrl($entity->getUserId(), $entity->getUrl()); - $entity->setId($bookmark->getId()); - $newEntity = $this->update($entity); + try { + $bookmark = $this->findByUrl($entity->getUserId(), $entity->getUrl()); + $entity->setId($bookmark->getId()); + $newEntity = $this->update($entity); + } catch (DoesNotExistException $e) { + $newEntity = $this->insert($entity); + } } return $newEntity; } /** - * @param $userId - * @param string $userId - * - * @return int + * @throws Exception */ public function countBookmarksOfUser(string $userId) : int { $qb = $this->db->getQueryBuilder(); @@ -866,7 +932,13 @@ public function countBookmarksOfUser(string $userId) : int { ->select($qb->func()->count('id')) ->from('bookmarks') ->where($qb->expr()->eq('user_id', $qb->createPositionalParameter($userId))); - return $qb->execute()->fetch(PDO::FETCH_COLUMN); + $result = $qb->executeQuery(); + $count = $result->fetchOne(); + if ($count === false) { + $count = 0; + } + $result->closeCursor(); + return (int)$count; } /** diff --git a/lib/Db/BookmarkWithTagsAndParent.php b/lib/Db/BookmarkWithTagsAndParent.php index 35ae1bed8..edd53b58b 100644 --- a/lib/Db/BookmarkWithTagsAndParent.php +++ b/lib/Db/BookmarkWithTagsAndParent.php @@ -18,8 +18,8 @@ class BookmarkWithTagsAndParent extends Bookmark { protected $tags; protected $folders; - public static $columns = ['id', 'url', 'title', 'description', 'lastmodified', 'added', 'clickcount', 'last_preview', 'available', 'archived_file', 'user_id', 'tags', 'folders', 'text_content', 'html_content']; - public static $fields = ['id', 'url', 'title', 'description', 'lastmodified', 'added', 'clickcount', 'lastPreview', 'available', 'archivedFile', 'userId', 'tags', 'folders', 'textContent', 'htmlContent']; + public static $columns = ['id', 'url', 'title', 'description', 'lastmodified', 'added', 'clickcount', 'last_preview', 'available', 'archived_file', 'user_id', 'tags', 'folders', 'text_content', 'html_content', 'url_hash']; + public static $fields = ['id', 'url', 'title', 'description', 'lastmodified', 'added', 'clickcount', 'lastPreview', 'available', 'archivedFile', 'userId', 'tags', 'folders', 'textContent', 'htmlContent', 'urlHash']; public function toArray(): array { $array = []; @@ -49,6 +49,9 @@ public function toArray(): array { $array['target'] = $this->url; continue; } + if ($field === 'urlHash') { + continue; + } $array[$field] = $this->{$field}; } return $array; diff --git a/lib/Db/FolderMapper.php b/lib/Db/FolderMapper.php index d8d3c67e5..2d2b89d47 100644 --- a/lib/Db/FolderMapper.php +++ b/lib/Db/FolderMapper.php @@ -80,6 +80,7 @@ public function find(int $id): Folder { * @param string $userId * * @return Folder + * @throws Exception */ public function findRootFolder(string $userId): Folder { $qb = $this->db->getQueryBuilder(); @@ -105,7 +106,7 @@ public function findRootFolder(string $userId): Folder { 'user_id' => $qb->createPositionalParameter($userId), 'folder_id' => $qb->createPositionalParameter($rootFolder->getId(), IQueryBuilder::PARAM_INT), ]) - ->execute(); + ->executeStatement(); } catch (MultipleObjectsReturnedException $e) { $rootFolders = $this->findEntities($qb); return $rootFolders[0]; diff --git a/lib/Db/SharedFolderMapper.php b/lib/Db/SharedFolderMapper.php index 118f478eb..2cc976faa 100644 --- a/lib/Db/SharedFolderMapper.php +++ b/lib/Db/SharedFolderMapper.php @@ -228,7 +228,7 @@ public function delete(Entity $entity): SharedFolder { $qb = $this->db->getQueryBuilder(); $qb->delete('bookmarks_shared_to_shares') ->where($qb->expr()->eq('shared_folder_id', $qb->createPositionalParameter($entity->getId(), IQueryBuilder::PARAM_INT))) - ->execute(); + ->executeStatement(); return parent::delete($entity); } @@ -237,7 +237,7 @@ public function mount(int $id, int $share_id): void { $qb->insert('bookmarks_shared_to_shares')->values([ 'shared_folder_id' => $qb->createPositionalParameter($id), 'share_id' => $qb->createPositionalParameter($share_id, IQueryBuilder::PARAM_INT) - ])->execute(); + ])->executeStatement(); $this->eventDispatcher->dispatch(CreateEvent::class, new CreateEvent( TreeMapper::TYPE_SHARE, $id diff --git a/lib/Db/TagMapper.php b/lib/Db/TagMapper.php index 3634be612..6bc9eeb0d 100644 --- a/lib/Db/TagMapper.php +++ b/lib/Db/TagMapper.php @@ -8,6 +8,7 @@ namespace OCA\Bookmarks\Db; +use OCP\DB\Exception; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; use PDO; @@ -35,6 +36,7 @@ public function __construct(IDBConnection $db) { /** * @param $userId * @return array + * @throws Exception */ public function findAllWithCount($userId): array { $qb = $this->db->getQueryBuilder(); @@ -53,12 +55,13 @@ public function findAllWithCount($userId): array { ->groupBy('t.tag') ->orderBy('count', 'DESC'); - return $qb->execute()->fetchAll(); + return $qb->executeQuery()->fetchAll(); } /** * @param $userId * @return array + * @throws Exception */ public function findAll($userId): array { $qb = $this->db->getQueryBuilder(); @@ -74,12 +77,13 @@ public function findAll($userId): array { $qb->expr()->eq('tr.type', $qb->createPositionalParameter(TreeMapper::TYPE_SHARE))) ) ->groupBy('t.tag'); - return $qb->execute()->fetchAll(PDO::FETCH_COLUMN); + return $qb->executeQuery()->fetchAll(PDO::FETCH_COLUMN); } /** * @param int $bookmarkId * @return array + * @throws Exception */ public function findByBookmark(int $bookmarkId): array { $qb = $this->db->getQueryBuilder(); @@ -89,12 +93,13 @@ public function findByBookmark(int $bookmarkId): array { ->from('bookmarks_tags', 't') ->where($qb->expr()->eq('t.bookmark_id', $qb->createPositionalParameter($bookmarkId, IQueryBuilder::PARAM_INT))); - return $qb->execute()->fetchAll(PDO::FETCH_COLUMN); + return $qb->executeQuery()->fetchAll(PDO::FETCH_COLUMN); } /** * @param $userId * @param string $tag + * @throws Exception */ public function delete($userId, string $tag) { $qb = $this->db->getQueryBuilder(); @@ -103,11 +108,12 @@ public function delete($userId, string $tag) { ->innerJoin('tgs', 'bookmarks', 'bm', $qb->expr()->eq('tgs.bookmark_id', 'bm.id')) ->where($qb->expr()->eq('tgs.tag', $qb->createNamedParameter($tag))) ->andWhere($qb->expr()->eq('bm.user_id', $qb->createNamedParameter($userId))); - return $qb->execute(); + return $qb->executeStatement(); } /** * @param $userId + * @throws Exception */ public function deleteAll(int $userId) { $qb = $this->db->getQueryBuilder(); @@ -115,12 +121,13 @@ public function deleteAll(int $userId) { ->delete('bookmarks_tags', 'tgs') ->innerJoin('tgs', 'bookmarks', 'bm', $qb->expr()->eq('tgs.bookmark_id', 'bm.id')) ->where($qb->expr()->eq('bm.user_id', $qb->createNamedParameter($userId))); - return $qb->execute(); + return $qb->executeStatement(); } /** * @param $tags * @param int $bookmarkId + * @throws Exception */ public function addTo(array $tags, int $bookmarkId): void { if (count($tags) === 0) { @@ -144,12 +151,13 @@ public function addTo(array $tags, int $bookmarkId): void { 'tag' => $qb->createNamedParameter($tag), 'bookmark_id' => $qb->createNamedParameter($bookmarkId), ]); - $qb->execute(); + $qb->executeStatement(); } } /** * @param int $bookmarkId + * @throws Exception */ public function removeAllFrom(int $bookmarkId): void { // Remove old tags @@ -157,7 +165,7 @@ public function removeAllFrom(int $bookmarkId): void { $qb ->delete('bookmarks_tags') ->where($qb->expr()->eq('bookmark_id', $qb->createNamedParameter($bookmarkId))); - $qb->execute(); + $qb->executeStatement(); } /** @@ -174,6 +182,7 @@ public function setOn(array $tags, int $bookmarkId): void { * @param int $userId UserId * @param string $old Old Tag Name * @param string $new New Tag Name + * @throws Exception */ public function renameTag($userId, string $old, string $new): void { // Remove about-to-be duplicated tags @@ -186,14 +195,14 @@ public function renameTag($userId, string $old, string $new): void { ->where($qb->expr()->eq('tgs.tag', $qb->createNamedParameter($new))) ->andWhere($qb->expr()->eq('bm.user_id', $qb->createNamedParameter($userId))) ->andWhere($qb->expr()->eq('t.tag', $qb->createNamedParameter($old))); - $duplicates = $qb->execute()->fetchAll(PDO::FETCH_COLUMN); + $duplicates = $qb->executeQuery()->fetchAll(PDO::FETCH_COLUMN); if (count($duplicates) !== 0) { $qb = $this->db->getQueryBuilder(); $qb ->delete('bookmarks_tags') ->where($qb->expr()->in('bookmark_id', array_map([$qb, 'createNamedParameter'], $duplicates))) ->andWhere($qb->expr()->eq('tag', $qb->createNamedParameter($old))); - $qb->execute(); + $qb->executeStatement(); } // Update tags to the new label @@ -204,7 +213,7 @@ public function renameTag($userId, string $old, string $new): void { ->innerJoin('tgs', 'bookmarks', 'bm', $qb->expr()->eq('tgs.bookmark_id', 'bm.id')) ->where($qb->expr()->eq('tgs.tag', $qb->createNamedParameter($old))) ->andWhere($qb->expr()->eq('bm.user_id', $qb->createNamedParameter($userId))); - $bookmarks = $qb->execute()->fetchAll(PDO::FETCH_COLUMN); + $bookmarks = $qb->executeQuery()->fetchAll(PDO::FETCH_COLUMN); if (count($bookmarks) !== 0) { $qb = $this->db->getQueryBuilder(); $qb @@ -212,13 +221,14 @@ public function renameTag($userId, string $old, string $new): void { ->set('tag', $qb->createNamedParameter($new)) ->where($qb->expr()->eq('tag', $qb->createNamedParameter($old))) ->andWhere($qb->expr()->in('bookmark_id', array_map([$qb, 'createNamedParameter'], $bookmarks))); - $qb->execute(); + $qb->executeStatement(); } } /** * @param $userId * @param string $old + * @throws Exception */ public function deleteTag($userId, string $old): void { $qb = $this->db->getQueryBuilder(); @@ -228,14 +238,14 @@ public function deleteTag($userId, string $old): void { ->innerJoin('t', 'bookmarks', 'bm', $qb->expr()->eq('t.bookmark_id', 'bm.id')) ->where($qb->expr()->eq('t.tag', $qb->createNamedParameter($old))) ->andWhere($qb->expr()->eq('bm.user_id', $qb->createNamedParameter($userId))); - $affectedBookmarks = $qb->execute()->fetchAll(PDO::FETCH_COLUMN); + $affectedBookmarks = $qb->executeQuery()->fetchAll(PDO::FETCH_COLUMN); if (count($affectedBookmarks) !== 0) { $qb = $this->db->getQueryBuilder(); $qb ->delete('bookmarks_tags') ->where($qb->expr()->in('bookmark_id', array_map([$qb, 'createNamedParameter'], $affectedBookmarks))) ->andWhere($qb->expr()->eq('tag', $qb->createNamedParameter($old))); - $qb->execute(); + $qb->executeStatement(); } } } diff --git a/lib/Db/TreeMapper.php b/lib/Db/TreeMapper.php index d8296424a..82aad3c90 100644 --- a/lib/Db/TreeMapper.php +++ b/lib/Db/TreeMapper.php @@ -141,7 +141,7 @@ protected function mapRowToEntityWithClass(array $row, string $entityClass): Ent * @psalm-return list */ protected function findEntitiesWithType(IQueryBuilder $query, string $type): array { - $cursor = $query->execute(); + $cursor = $query->executeQuery(); $entities = []; @@ -381,6 +381,7 @@ public function hasDescendant(int $folderId, string $type, int $descendantId): b * @throws DoesNotExistException * @throws MultipleObjectsReturnedException * @throws UnsupportedOperation + * @throws Exception */ public function deleteEntry(string $type, int $id, ?int $folderId = null): void { $this->eventDispatcher->dispatch(BeforeDeleteEvent::class, new BeforeDeleteEvent($type, $id)); @@ -405,7 +406,7 @@ public function deleteEntry(string $type, int $id, ?int $folderId = null): void ->andWhere($qb->expr()->in('parent_folder', $qb->createPositionalParameter(array_map(static function ($folder) { return $folder->getId(); }, $descendantFolders), IQueryBuilder::PARAM_INT_ARRAY))); - $qb->execute(); + $qb->executeStatement(); // remove all folders entries from this subtree foreach ($descendantFolders as $descendantFolder) { @@ -420,12 +421,12 @@ public function deleteEntry(string $type, int $id, ?int $folderId = null): void ->from('bookmarks', 'b') ->leftJoin('b', 'bookmarks_tree', 't', 'b.id = t.id AND t.type = ' . $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK)) ->where($qb->expr()->isNull('t.id')); - $orphanedBookmarks = $qb->execute(); - while ($bookmark = $orphanedBookmarks->fetchColumn()) { + $orphanedBookmarks = $qb->executeQuery(); + while ($bookmark = $orphanedBookmarks->fetchOne()) { $qb = $this->db->getQueryBuilder(); $qb->delete('bookmarks') ->where($qb->expr()->eq('id', $qb->createPositionalParameter($bookmark))) - ->execute(); + ->executeStatement(); } return; @@ -483,7 +484,7 @@ public function softDeleteEntry(string $type, int $id, ?int $folderId = null): v ->andWhere($qb->expr()->in('parent_folder', $qb->createNamedParameter(array_map(static function ($folder) { return $folder->getId(); }, $descendantFoldersPlusThisFolder), IQueryBuilder::PARAM_INT_ARRAY))); - $qb->execute(); + $qb->executeStatement(); // soft delete all folder entries from this subtree foreach ($descendantFoldersPlusThisFolder as $descendantFolder) { @@ -598,7 +599,7 @@ public function remove(string $type, int $itemId): void { ->delete('bookmarks_tree') ->where($qb->expr()->eq('type', $qb->createPositionalParameter($type))) ->andWhere($qb->expr()->eq('id', $qb->createPositionalParameter($itemId, IQueryBuilder::PARAM_INT))); - $qb->execute(); + $qb->executeStatement(); } /** @@ -626,6 +627,7 @@ public function deleteShare(int $shareId): void { * @psalm-param 0|positive-int|null $index * @throws MultipleObjectsReturnedException * @throws UnsupportedOperation + * @throws Exception */ public function move(string $type, int $itemId, int $newParentFolderId, ?int $index = null): void { if ($type === TreeMapper::TYPE_BOOKMARK) { @@ -667,7 +669,7 @@ public function move(string $type, int $itemId, int $newParentFolderId, ?int $in ->set('index', $qb->createPositionalParameter($index ?? $this->countChildren($newParentFolderId), IQueryBuilder::PARAM_INT)) ->where($qb->expr()->eq('id', $qb->createPositionalParameter($itemId, IQueryBuilder::PARAM_INT))) ->andWhere($qb->expr()->eq('type', $qb->createPositionalParameter($type))); - $qb->execute(); + $qb->executeStatement(); } else { // Item currently has no parent => insert into tree. $qb = $this->insertQuery; @@ -677,7 +679,7 @@ public function move(string $type, int $itemId, int $newParentFolderId, ?int $in 'type' => $type, 'index' => $index ?? $this->countChildren($newParentFolderId), ]); - $qb->execute(); + $qb->executeStatement(); } $this->eventDispatcher->dispatch(MoveEvent::class, new MoveEvent( @@ -745,7 +747,7 @@ public function addToFolders(string $type, int $itemId, array $folders, ?int $in 'id' => $itemId, 'index' => $index ?? $this->countChildren($folderId), ]); - $qb->execute(); + $qb->executeStatement(); $this->eventDispatcher->dispatch(MoveEvent::class, new MoveEvent($type, $itemId, null, $folderId)); } @@ -774,7 +776,7 @@ public function removeFromFolders(string $type, int $itemId, array $folders): vo ->where($qb->expr()->eq('parent_folder', $qb->createPositionalParameter($folderId))) ->andWhere($qb->expr()->eq('id', $qb->createPositionalParameter($itemId))) ->andWhere($qb->expr()->eq('type', $qb->createPositionalParameter($type))); - $qb->execute(); + $qb->executeStatement(); $this->eventDispatcher->dispatch(MoveEvent::class, new MoveEvent($type, $itemId, $folderId)); @@ -792,6 +794,7 @@ public function removeFromFolders(string $type, int $itemId, array $folders): vo * @param $newChildrenOrder * @return void * @throws ChildrenOrderValidationError + * @throws Exception */ public function setChildrenOrder(int $folderId, array $newChildrenOrder): void { $existingChildren = $this->getChildrenOrder($folderId); @@ -815,7 +818,7 @@ public function setChildrenOrder(int $folderId, array $newChildrenOrder): void { ->where($qb->expr()->eq('t.parent_folder', $qb->createPositionalParameter($folderId))) ->andWhere($qb->expr()->eq('t.type', $qb->createPositionalParameter(TreeMapper::TYPE_SHARE))) ->orderBy('t.index', 'ASC'); - $childShares = $qb->execute()->fetchAll(); + $childShares = $qb->executeQuery()->fetchAll(); $foldersToShares = array_reduce($childShares, static function ($dict, $shareRec) { $dict[$shareRec['folder_id']] = $shareRec['id']; @@ -839,7 +842,7 @@ public function setChildrenOrder(int $folderId, array $newChildrenOrder): void { ->where($qb->expr()->eq('id', $qb->createPositionalParameter($child['id']))) ->andWhere($qb->expr()->eq('parent_folder', $qb->createPositionalParameter($folderId))) ->andWhere($qb->expr()->eq('type', $qb->createPositionalParameter($child['type']))); - $qb->execute(); + $qb->executeStatement(); } $this->eventDispatcher->dispatch(UpdateEvent::class, new UpdateEvent(TreeMapper::TYPE_FOLDER, $folderId)); @@ -863,12 +866,12 @@ public function getChildrenOrder(int $folderId, int $layers = 0): array { } $qb = $this->getChildrenOrderQuery; $qb->setParameter('parent_folder', $folderId); - $children = $qb->execute()->fetchAll(); + $children = $qb->executeQuery()->fetchAll(); $qb = $this->getChildrenQuery[TreeMapper::TYPE_SHARE]; $this->selectFromType(TreeMapper::TYPE_SHARE, ['t.index'], $qb); $qb->setParameter('parent_folder', $folderId); - $childShares = $qb->execute()->fetchAll(); + $childShares = $qb->executeQuery()->fetchAll(); $children = array_map(function ($child) use ($layers, $childShares) { $item = ['type' => $child['type'], 'id' => (int)$child['id']]; @@ -1009,6 +1012,7 @@ public function getSoftDeletedRootItems(string $userId, string $type): array { * @brief Count the children in the given folder * @param int $folderId * @return int + * @throws Exception */ public function countChildren(int $folderId): int { $qb = $this->db->getQueryBuilder(); @@ -1017,13 +1021,14 @@ public function countChildren(int $folderId): int { ->from('bookmarks_tree') ->where($qb->expr()->eq('parent_folder', $qb->createPositionalParameter($folderId))) ->andWhere($qb->expr()->isNull('soft_deleted_at')); - return $qb->execute()->fetch(PDO::FETCH_COLUMN); + return $qb->executeQuery()->fetch(PDO::FETCH_COLUMN); } /** * @brief Count the descendant bookmarks in the given folder * @param int $folderId * @return int + * @throws Exception */ public function countBookmarksInFolder(int $folderId): int { $count = $this->treeCache->get(TreeCacheManager::CATEGORY_FOLDERCOUNT, TreeMapper::TYPE_FOLDER, $folderId); @@ -1038,7 +1043,7 @@ public function countBookmarksInFolder(int $folderId): int { ->where($qb->expr()->eq('t.parent_folder', $qb->createPositionalParameter($folderId))) ->andWhere($qb->expr()->eq('t.type', $qb->createPositionalParameter(TreeMapper::TYPE_BOOKMARK))) ->andWhere($qb->expr()->isNull('t.soft_deleted_at')); - $countChildren = $qb->execute()->fetch(PDO::FETCH_COLUMN); + $countChildren = $qb->executeQuery()->fetch(PDO::FETCH_COLUMN); $qb = $this->db->getQueryBuilder(); $qb @@ -1049,7 +1054,7 @@ public function countBookmarksInFolder(int $folderId): int { ->andWhere($qb->expr()->eq('t.type', $qb->createPositionalParameter(TreeMapper::TYPE_FOLDER))) ->andWhere($qb->expr()->isNull('t.soft_deleted_at')); ; - $childFolders = $qb->execute()->fetchAll(PDO::FETCH_COLUMN); + $childFolders = $qb->executeQuery()->fetchAll(PDO::FETCH_COLUMN); foreach ($childFolders as $subFolderId) { $countChildren += $this->countBookmarksInFolder($subFolderId); @@ -1075,17 +1080,17 @@ public function getChildren(int $folderId, int $layers = 0): array { $qb = $this->getChildrenQuery[TreeMapper::TYPE_BOOKMARK]; $this->selectFromType(TreeMapper::TYPE_BOOKMARK, ['t.index', 't.type'], $qb); $qb->setParameter('parent_folder', $folderId); - $childBookmarks = $qb->execute()->fetchAll(); + $childBookmarks = $qb->executeQuery()->fetchAll(); $qb = $this->getChildrenQuery[TreeMapper::TYPE_FOLDER]; $this->selectFromType(TreeMapper::TYPE_FOLDER, ['t.index', 't.type'], $qb); $qb->setParameter('parent_folder', $folderId); - $childFolders = $qb->execute()->fetchAll(); + $childFolders = $qb->executeQuery()->fetchAll(); $qb = $this->getChildrenQuery[TreeMapper::TYPE_SHARE]; $this->selectFromType(TreeMapper::TYPE_SHARE, ['t.index', 't.type'], $qb); $qb->setParameter('parent_folder', $folderId); - $childShares = $qb->execute()->fetchAll(); + $childShares = $qb->executeQuery()->fetchAll(); $children = array_merge($childBookmarks, $childFolders, $childShares); $indices = array_column($children, 'index'); diff --git a/lib/Migration/DeduplicateSharedFoldersRepairStep.php b/lib/Migration/DeduplicateSharedFoldersRepairStep.php index 99fdbf820..781ef9988 100644 --- a/lib/Migration/DeduplicateSharedFoldersRepairStep.php +++ b/lib/Migration/DeduplicateSharedFoldersRepairStep.php @@ -42,18 +42,18 @@ public function run(IOutput $output) { ->from('bookmarks_shared_folders', 'p1') ->leftJoin('p1', 'bookmarks_shared_folders', 'p2', 'p1.folder_id = p2.folder_id AND p1.user_id = p2.user_id') ->where($qb->expr()->lt('p2.id', 'p1.id')); - $duplicateSharedFolders = $qb->execute(); + $duplicateSharedFolders = $qb->executeQuery(); $i = 0; - while ($sharedFolder = $duplicateSharedFolders->fetchColumn()) { + while ($sharedFolder = $duplicateSharedFolders->fetch(\PDO::FETCH_COLUMN)) { $qb = $this->db->getQueryBuilder(); $qb->delete('bookmarks_tree') ->where($qb->expr()->eq('id', $qb->createPositionalParameter($sharedFolder))) ->andWhere($qb->expr()->eq('type', $qb->createPositionalParameter('share'))) - ->execute(); + ->executeStatement(); $qb = $this->db->getQueryBuilder(); $qb->delete('bookmarks_shared_folders') ->where($qb->expr()->eq('id', $qb->createPositionalParameter($sharedFolder))) - ->execute(); + ->executeStatement(); $i++; } $output->info("Removed $i duplicate shares"); diff --git a/lib/Migration/GroupSharesUpdateRepairStep.php b/lib/Migration/GroupSharesUpdateRepairStep.php index f8c413651..c9c5ee08a 100644 --- a/lib/Migration/GroupSharesUpdateRepairStep.php +++ b/lib/Migration/GroupSharesUpdateRepairStep.php @@ -88,7 +88,7 @@ public function run(IOutput $output) { $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(); + $groupShares = $qb->executeQuery(); while ($groupShare = $groupShares->fetch()) { // find users in share @@ -97,7 +97,7 @@ public function run(IOutput $output) { ->from('bookmarks_shared_folders', 'sf') ->join('sf', '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); + $usersInShare = $qb->executeQuery()->fetchAll(PDO::FETCH_COLUMN); $group = $this->groupManager->get($groupShare['participant']); if ($group === null) { diff --git a/lib/Migration/OrphanedSharesRepairStep.php b/lib/Migration/OrphanedSharesRepairStep.php index f30457578..889665a39 100644 --- a/lib/Migration/OrphanedSharesRepairStep.php +++ b/lib/Migration/OrphanedSharesRepairStep.php @@ -44,28 +44,28 @@ public function run(IOutput $output) { ->from('bookmarks_shares', 's') ->leftJoin('s', 'bookmarks_folders', 'f', $qb->expr()->eq('f.id', 's.folder_id')) ->where($qb->expr()->isNull('f.id')); - $shares = $qb->execute(); + $shares = $qb->executeQuery(); $i = 0; - while ($share = $shares->fetchColumn()) { + while ($share = $shares->fetch(\PDO::FETCH_COLUMN)) { $qb = $this->db->getQueryBuilder(); $folders = $qb->select('f.id') ->from('bookmarks_shared_folders', 'f') ->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, IQueryBuilder::PARAM_INT))) - ->execute() + ->executeQuery() ->fetchAll(PDO::FETCH_COLUMN); foreach ($folders as $folderId) { $qb = $this->db->getQueryBuilder(); $qb->delete('bookmarks_tree') ->where($qb->expr()->eq('type', $qb->createPositionalParameter('share'))) ->andWhere($qb->expr()->eq('id', $qb->createPositionalParameter($folderId, IQueryBuilder::PARAM_INT))) - ->execute(); + ->executeStatement(); } $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))) - ->execute(); + ->executeStatement(); $i++; } $output->info("Removed $i orphaned shares"); @@ -75,14 +75,14 @@ public function run(IOutput $output) { ->from('bookmarks_folders_public', 'p') ->leftJoin('p', 'bookmarks_folders', 'f', $qb->expr()->eq('f.id', 'p.folder_id')) ->where($qb->expr()->isNull('f.id')) - ->execute() + ->executeQuery() ->fetchAll(PDO::FETCH_COLUMN); $i = 0; foreach ($publics as $publicId) { $qb = $this->db->getQueryBuilder(); $qb->delete('bookmarks_folders_public') ->where($qb->expr()->eq('id', $qb->createPositionalParameter($publicId))) - ->execute(); + ->executeStatement(); $i++; } $output->info("Removed $i orphaned public links"); diff --git a/lib/Migration/OrphanedTreeItemsRepairStep.php b/lib/Migration/OrphanedTreeItemsRepairStep.php index 5cf0d491d..ad230d7dd 100644 --- a/lib/Migration/OrphanedTreeItemsRepairStep.php +++ b/lib/Migration/OrphanedTreeItemsRepairStep.php @@ -44,14 +44,14 @@ public function run(IOutput $output) { ->leftJoin('t', 'bookmarks', 'b', $qb->expr()->eq('b.id', 't.id')) ->where($qb->expr()->isNull('b.id')) ->andWhere($qb->expr()->eq('t.type', $qb->createPositionalParameter('bookmark'))); - $orphanedBookmarks = $qb->execute(); + $orphanedBookmarks = $qb->executeQuery(); $i = 0; - while ($bookmark = $orphanedBookmarks->fetchColumn()) { + while ($bookmark = $orphanedBookmarks->fetch(\PDO::FETCH_COLUMN)) { $qb = $this->db->getQueryBuilder(); $qb->delete('bookmarks_tree') ->where($qb->expr()->eq('id', $qb->createPositionalParameter($bookmark, IQueryBuilder::PARAM_INT))) ->andWhere($qb->expr()->eq('type', $qb->createPositionalParameter('bookmark'))) - ->execute(); + ->executeStatement(); $i++; } $output->info("Removed $i orphaned bookmarks entries"); @@ -64,14 +64,14 @@ public function run(IOutput $output) { ->where($qb->expr()->isNull('f.id')) ->andWhere($qb->expr()->isNull('r.folder_id')) ->andWhere($qb->expr()->eq('t.type', $qb->createPositionalParameter('folder'))); - $orphanedFolders = $qb->execute(); + $orphanedFolders = $qb->executeQuery(); $i = 0; - while ($folder = $orphanedFolders->fetchColumn()) { + while ($folder = $orphanedFolders->fetch(\PDO::FETCH_COLUMN)) { $qb = $this->db->getQueryBuilder(); $qb->delete('bookmarks_tree') ->where($qb->expr()->eq('id', $qb->createPositionalParameter($folder, IQueryBuilder::PARAM_INT))) ->andWhere($qb->expr()->eq('type', $qb->createPositionalParameter('folder'))) - ->execute(); + ->executeStatement(); $i++; } $output->info("Removed $i orphaned folders entries"); @@ -81,7 +81,7 @@ public function run(IOutput $output) { ->from('bookmarks_tree', 't') ->leftJoin('t', 'bookmarks_folders', 'f', $qb->expr()->eq('t.parent_folder', 'f.id')) ->where($qb->expr()->isNull('f.id')); - $orphanedTreeItems = $qb->execute(); + $orphanedTreeItems = $qb->executeQuery(); $i = 0; while ($treeItem = $orphanedTreeItems->fetch()) { if ($treeItem['type'] === 'bookmark') { @@ -89,7 +89,7 @@ public function run(IOutput $output) { $bookmark = $qb->select('user_id') ->from('bookmarks') ->where($qb->expr()->eq('id', $qb->createNamedParameter($treeItem['id']))) - ->execute() + ->executeQuery() ->fetch(); $userId = $bookmark['user_id']; } elseif ($treeItem['type'] === 'folder') { @@ -97,7 +97,7 @@ public function run(IOutput $output) { $folder = $qb->select('user_id') ->from('bookmarks_folders') ->where($qb->expr()->eq('id', $qb->createNamedParameter($treeItem['id']))) - ->execute() + ->executeQuery() ->fetch(); $userId = $folder['user_id']; } elseif ($treeItem['type'] === 'share') { @@ -105,7 +105,7 @@ public function run(IOutput $output) { $folder = $qb->select('user_id') ->from('bookmarks_shared_folders') ->where($qb->expr()->eq('id', $qb->createNamedParameter($treeItem['id']))) - ->execute() + ->executeQuery() ->fetch(); $userId = $folder['user_id']; } @@ -117,7 +117,7 @@ public function run(IOutput $output) { ->set('index', $qb->createNamedParameter($rootFolder['count'])) ->where($qb->expr()->eq('id', $qb->createNamedParameter($treeItem['id'], IQueryBuilder::PARAM_INT))) ->andWhere($qb->expr()->eq('type', $qb->createNamedParameter($treeItem['type']))) - ->execute(); + ->executeStatement(); $i++; } $output->info("Reinserted $i orphaned children entries"); @@ -130,13 +130,13 @@ public function run(IOutput $output) { ->where($qb->expr()->isNull('t.id')) ->andWhere($qb->expr()->isNull('r.folder_id')) ->andWhere($qb->expr()->eq('t.type', $qb->createPositionalParameter('folder'))); - $orphanedFolders = $qb->execute(); + $orphanedFolders = $qb->executeQuery(); $i = 0; - while ($folder = $orphanedFolders->fetchColumn()) { + while ($folder = $orphanedFolders->fetch(\PDO::FETCH_COLUMN)) { $qb = $this->db->getQueryBuilder(); $qb->delete('bookmarks_folders') ->where($qb->expr()->eq('id', $qb->createPositionalParameter($folder, IQueryBuilder::PARAM_INT))) - ->execute(); + ->executeStatement(); $i++; } $output->info("Removed $i orphaned bookmark folders"); @@ -146,7 +146,7 @@ public function run(IOutput $output) { ->from('bookmarks', 'b') ->leftJoin('b', 'bookmarks_tree', 't', 'b.id = t.id AND t.type = ' . $qb->createPositionalParameter('bookmark')) ->where($qb->expr()->isNull('t.id')); - $orphanedBookmarks = $qb->execute(); + $orphanedBookmarks = $qb->executeQuery(); $i = 0; while ($bookmark = $orphanedBookmarks->fetch()) { $rootFolder = $this->ensureRootFolder($bookmark['user_id']); @@ -156,7 +156,7 @@ public function run(IOutput $output) { 'type' => $qb->createPositionalParameter('bookmark'), 'parent_folder' => $qb->createPositionalParameter($rootFolder['folder_id']), 'index' => $qb->createPositionalParameter($rootFolder['count']), - ])->execute(); + ])->executeStatement(); $i++; } $output->info("Reinserted $i orphaned bookmarks"); @@ -170,7 +170,7 @@ private function ensureRootFolder($userId) { ->leftJoin('r', 'bookmarks_tree', 't', 't.parent_folder = r.folder_id') ->where($qb->expr()->eq('r.user_id', $qb->createNamedParameter($userId))) ->groupBy(['r.folder_id']) - ->execute() + ->executeQuery() ->fetch(); if ($rootFolder === null || $rootFolder === false || $rootFolder['folder_id'] === null) { $qb = $this->db->getQueryBuilder(); @@ -179,7 +179,7 @@ private function ensureRootFolder($userId) { 'user_id' => $qb->createNamedParameter($userId), 'title' => $qb->createNamedParameter('') ]) - ->execute(); + ->executeStatement(); $rootFolder = [ 'folder_id' => $qb->getLastInsertId(), 'count' => 0 @@ -188,14 +188,14 @@ private function ensureRootFolder($userId) { $oldRootFolder = $qb->select('folder_id') ->from('bookmarks_root_folders') ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId))) - ->execute() + ->executeQuery() ->fetch(); if ($oldRootFolder) { $qb = $this->db->getQueryBuilder(); $qb->update('bookmarks_root_folders') ->set('folder_id', $qb->createNamedParameter($rootFolder['folder_id'])) ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId))) - ->execute(); + ->executeStatement(); } else { $qb = $this->db->getQueryBuilder(); $qb->insert('bookmarks_root_folders') @@ -203,7 +203,7 @@ private function ensureRootFolder($userId) { 'folder_id' => $qb->createNamedParameter($rootFolder['folder_id']), 'user_id' => $qb->createNamedParameter($userId) ]) - ->execute(); + ->executeStatement(); } } return $rootFolder; diff --git a/lib/Migration/SuperfluousSharedFoldersRepairStep.php b/lib/Migration/SuperfluousSharedFoldersRepairStep.php index e84ea1b8a..e466d2e6b 100644 --- a/lib/Migration/SuperfluousSharedFoldersRepairStep.php +++ b/lib/Migration/SuperfluousSharedFoldersRepairStep.php @@ -45,18 +45,18 @@ public function run(IOutput $output) { ->join('to', 'bookmarks_shares', 's', $qb->expr()->eq('to.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(); + $superfluousSharedFolders = $qb->executeQuery(); $i = 0; - while ($sharedFolder = $superfluousSharedFolders->fetchColumn()) { + while ($sharedFolder = $superfluousSharedFolders->fetch(\PDO::FETCH_COLUMN)) { $qb = $this->db->getQueryBuilder(); $qb->delete('bookmarks_tree') ->where($qb->expr()->eq('id', $qb->createPositionalParameter($sharedFolder))) ->andWhere($qb->expr()->eq('type', $qb->createPositionalParameter('share'))) - ->execute(); + ->executeStatement(); $qb = $this->db->getQueryBuilder(); $qb->delete('bookmarks_shared_folders') ->where($qb->expr()->eq('id', $qb->createPositionalParameter($sharedFolder))) - ->execute(); + ->executeStatement(); $i++; } $output->info("Removed $i superfluous shares"); diff --git a/lib/Migration/Version000014000Date20181002094721.php b/lib/Migration/Version000014000Date20181002094721.php index d4adc90c8..1c0dcadb5 100644 --- a/lib/Migration/Version000014000Date20181002094721.php +++ b/lib/Migration/Version000014000Date20181002094721.php @@ -160,7 +160,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { $query = $this->db->getQueryBuilder(); $query->select('id', 'user_id')->from('bookmarks'); - $bookmarks = $query->execute()->fetchAll(); + $bookmarks = $query->executeQuery()->fetchAll(); foreach ($bookmarks as $i => $bookmark) { $query = $this->db->getQueryBuilder(); $query->select('bookmark_id') @@ -168,7 +168,7 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array ->where( $query->expr()->eq('bookmark_id', $query->createPositionalParameter($bookmark['id'])) ); - if (count($query->execute()->fetchAll()) > 0) { + if (count($query->executeQuery()->fetchAll()) > 0) { continue; } $query = $this->db->getQueryBuilder(); @@ -178,7 +178,7 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array 'folder_id' => $query->createNamedParameter(-1), 'bookmark_id' => $query->createNamedParameter($bookmark['id']), ]); - $query->execute(); + $query->executeStatement(); } } } diff --git a/lib/Migration/Version000014000Date20181029094721.php b/lib/Migration/Version000014000Date20181029094721.php index 7fdfbc92e..6e975c82e 100644 --- a/lib/Migration/Version000014000Date20181029094721.php +++ b/lib/Migration/Version000014000Date20181029094721.php @@ -71,7 +71,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { $query = $this->db->getQueryBuilder(); $query->select('id')->from('bookmarks_folders'); - $folders = $query->execute()->fetchAll(PDO::FETCH_COLUMN); + $folders = $query->executeQuery()->fetchAll(PDO::FETCH_COLUMN); $folders[] = -1; foreach ($folders as $folder) { $qb = $this->db->getQueryBuilder(); @@ -80,14 +80,14 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array ->from('bookmarks_folders') ->where($qb->expr()->eq('parent_folder', $qb->createPositionalParameter($folder, IQueryBuilder::PARAM_INT))) ->orderBy('title', 'DESC'); - $childFolders = $qb->execute()->fetchAll(); + $childFolders = $qb->executeQuery()->fetchAll(); $qb = $this->db->getQueryBuilder(); $qb ->select('bookmark_id') ->from('bookmarks_folders_bookmarks') ->where($qb->expr()->eq('folder_id', $qb->createPositionalParameter($folder, IQueryBuilder::PARAM_INT))); - $childBookmarks = $qb->execute()->fetchAll(); + $childBookmarks = $qb->executeQuery()->fetchAll(); $children = array_merge($childFolders, $childBookmarks); $children = array_map(static function ($child) { @@ -107,7 +107,7 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array ->set('index', $qb->createPositionalParameter($i, IQueryBuilder::PARAM_INT)) ->where($qb->expr()->eq('bookmark_id', $qb->createPositionalParameter($child['id']))) ->andWhere($qb->expr()->eq('folder_id', $qb->createPositionalParameter($folder))); - $qb->execute(); + $qb->executeStatement(); } else { $qb = $this->db->getQueryBuilder(); $qb @@ -115,7 +115,7 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array ->set('index', $qb->createPositionalParameter($i)) ->where($qb->expr()->eq('id', $qb->createPositionalParameter($child['id']))) ->andWhere($qb->expr()->eq('parent_folder', $qb->createPositionalParameter($folder))); - $qb->execute(); + $qb->executeStatement(); } } } diff --git a/lib/Migration/Version003000000Date20191123094721.php b/lib/Migration/Version003000000Date20191123094721.php index 8d8233825..42a901b2a 100644 --- a/lib/Migration/Version003000000Date20191123094721.php +++ b/lib/Migration/Version003000000Date20191123094721.php @@ -190,14 +190,14 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { $qb = $this->db->getQueryBuilder(); $qb->selectDistinct('user_id')->from('bookmarks'); - $usersQuery = $qb->execute(); - while ($user = $usersQuery->fetchColumn()) { + $usersQuery = $qb->executeQuery(); + while ($user = $usersQuery->fetch(\PDO::FETCH_COLUMN)) { $qb = $this->db->getQueryBuilder(); $rootFolderId = $qb->select('folder_id') ->from('bookmarks_root_folders') ->where($qb->expr()->eq('user_id', $qb->createPositionalParameter($user))) - ->execute() - ->fetchColumn(); + ->executeQuery() + ->fetchOne(); if ($rootFolderId === false) { // Create root folders $qb = $this->db->getQueryBuilder(); @@ -205,7 +205,7 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array 'title' => $qb->createPositionalParameter(''), 'user_id' => $qb->createPositionalParameter($user), ]); - $qb->execute(); + $qb->executeStatement(); $rootFolderId = $qb->getLastInsertId(); $qb = $this->db->getQueryBuilder(); @@ -213,14 +213,14 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array 'folder_id' => $qb->createPositionalParameter($rootFolderId, IQueryBuilder::PARAM_INT), 'user_id' => $qb->createPositionalParameter($user), ]); - $qb->execute(); + $qb->executeStatement(); } $qb = $this->db->getQueryBuilder(); $qb->select('id', 'parent_folder', 'index') ->from('bookmarks_folders') ->where($qb->expr()->eq('user_id', $qb->createPositionalParameter($user))); - $foldersQuery = $qb->execute(); + $foldersQuery = $qb->executeQuery(); while ($folder = $foldersQuery->fetch()) { if ((string)$folder['id'] === (string)$rootFolderId || $folder['parent_folder'] === null) { continue; @@ -232,8 +232,8 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $qb->expr()->eq('id', $qb->createPositionalParameter($folder['id'], IQueryBuilder::PARAM_INT)), $qb->expr()->eq('type', $qb->createPositionalParameter('folder')) ) - ->execute() - ->fetchColumn(); + ->executeQuery() + ->fetchOne(); if ($folderId === false) { $qb = $this->db->getQueryBuilder(); $qb->insert('bookmarks_tree') @@ -242,7 +242,7 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array 'type' => $qb->createPositionalParameter('folder'), 'parent_folder' => $qb->createPositionalParameter(($folder['parent_folder'] === '-1' || $folder['parent_folder'] === -1) ? $rootFolderId : $folder['parent_folder'], IQueryBuilder::PARAM_INT), 'index' => $qb->createPositionalParameter($folder['index'], IQueryBuilder::PARAM_INT), - ])->execute(); + ])->executeStatement(); } } $qb = $this->db->getQueryBuilder(); @@ -250,7 +250,7 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array ->from('bookmarks_folders_bookmarks', 'f') ->leftJoin('f', 'bookmarks', 'b', $qb->expr()->eq('b.id', 'f.bookmark_id')) ->where($qb->expr()->eq('b.user_id', $qb->createPositionalParameter($user))); - $bookmarksQuery = $qb->execute(); + $bookmarksQuery = $qb->executeQuery(); while ($bookmark = $bookmarksQuery->fetch()) { $qb = $this->db->getQueryBuilder(); $parentFolder = ($bookmark['folder_id'] === '-1' || $bookmark['folder_id'] === -1) ? $rootFolderId : $bookmark['folder_id']; @@ -261,8 +261,8 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $qb->expr()->eq('type', $qb->createPositionalParameter('bookmark')), $qb->expr()->eq('parent_folder', $qb->createPositionalParameter($parentFolder, IQueryBuilder::PARAM_INT)) ) - ->execute() - ->fetchColumn(); + ->executeQuery() + ->fetchOne(); if ($bookmarkId === false) { $qb = $this->db->getQueryBuilder(); $qb->insert('bookmarks_tree')->values([ @@ -270,7 +270,7 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array 'type' => $qb->createPositionalParameter('bookmark'), 'parent_folder' => $qb->createPositionalParameter($parentFolder, IQueryBuilder::PARAM_INT), 'index' => $qb->createPositionalParameter($bookmark['index']), - ])->execute(); + ])->executeStatement(); } } } diff --git a/lib/Migration/Version003001000Date20200526094721.php b/lib/Migration/Version003001000Date20200526094721.php index 4f5ea3936..bf518ec1f 100644 --- a/lib/Migration/Version003001000Date20200526094721.php +++ b/lib/Migration/Version003001000Date20200526094721.php @@ -85,7 +85,7 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $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(); + ->executeQuery(); 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(); @@ -93,7 +93,7 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array ->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() + ->executeQuery() ->fetch(); if (!$canonicalSharedFolder) { // If there's no canonical shared folder, we make this one it. @@ -101,14 +101,14 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $qb->update('bookmarks_shared_folders') ->set('folder_id', $qb->createPositionalParameter($sharedFolder['folder_id'])) ->where($qb->expr()->eq('id', $qb->createPositionalParameter($sharedFolder['id']))) - ->execute(); + ->executeStatement(); $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(); + ->executeStatement(); } // Insert into pivot table @@ -118,7 +118,7 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array 'shared_folder_id' => $qb->createPositionalParameter($canonicalSharedFolder['id']), 'share_id' => $qb->createPositionalParameter($sharedFolder['share_id']) ]) - ->execute(); + ->executeStatement(); } } } diff --git a/lib/Migration/Version004002000Date20210208124721.php b/lib/Migration/Version004002000Date20210208124721.php index b9b26d398..ce1d6c866 100644 --- a/lib/Migration/Version004002000Date20210208124721.php +++ b/lib/Migration/Version004002000Date20210208124721.php @@ -93,7 +93,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { // Reset last_preview of all bookmarks to trigger re-visiting them $qb = $this->db->getQueryBuilder(); - $qb->update('bookmarks')->set('last_preview', $qb->createPositionalParameter(0, IQueryBuilder::PARAM_INT))->execute(); + $qb->update('bookmarks')->set('last_preview', $qb->createPositionalParameter(0, IQueryBuilder::PARAM_INT))->executeStatement(); } protected function ensureColumnIsNullable(ISchemaWrapper $schema, string $tableName, string $columnName): bool { diff --git a/lib/Migration/Version010002000Date20220319124721.php b/lib/Migration/Version010002000Date20220319124721.php index d696c2271..737396245 100644 --- a/lib/Migration/Version010002000Date20220319124721.php +++ b/lib/Migration/Version010002000Date20220319124721.php @@ -40,7 +40,7 @@ public function __construct(IDBConnection $db) { */ public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { $qb = $this->db->getQueryBuilder(); - $this->rootFolders = $qb->select('user_id', 'locked')->from('bookmarks_root_folders')->execute()->fetchAll(); + $this->rootFolders = $qb->select('user_id', 'locked')->from('bookmarks_root_folders')->executeQuery()->fetchAll(); } /** @@ -80,7 +80,7 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $qb->update('bookmarks_root_folders') ->set('locked_time', $qb->createPositionalParameter(new DateTime(), Types::DATETIME)) ->where($qb->expr()->eq('user_id', $qb->createPositionalParameter($rootFolder['user_id']))) - ->execute(); + ->executeStatement(); } } } diff --git a/lib/Migration/Version016002000Date20260201124723.php b/lib/Migration/Version016002000Date20260201124723.php new file mode 100644 index 000000000..9a70b4634 --- /dev/null +++ b/lib/Migration/Version016002000Date20260201124723.php @@ -0,0 +1,82 @@ +hasTable('bookmarks')) { + $table = $schema->getTable('bookmarks'); + if (!$table->hasColumn('url_hash')) { + $table->addColumn('url_hash', 'string', [ + 'notnull' => false, + 'length' => 32, + ]); + $table->addUniqueIndex(['user_id', 'url_hash'], 'bookmarks_uniq_url'); + } + } + + return $schema; + } + + public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { + $countQb = $this->db->getQueryBuilder(); + $countQb->select($countQb->func()->count('id'))->from('bookmarks')->where($countQb->expr()->isNull('url_hash')); + $result = $countQb->executeQuery(); + $count = $result->fetchOne(); + $output->info('Hashing URLs of n=' . $count . ' bookmarks'); + $output->startProgress($count); + + $qb = $this->db->getQueryBuilder(); + $qb->select('id', 'url')->from('bookmarks')->where($qb->expr()->isNull('url_hash')); + $result = $qb->executeQuery(); + $setQb = $this->db->getQueryBuilder(); + $setQb->update('bookmarks') + ->set('url_hash', $qb->createParameter('url_hash')) + ->where($qb->expr()->eq('id', $qb->createParameter('id'))); + $i = 1; + $this->db->beginTransaction(); + while ($row = $result->fetch()) { + if ($i++ % 1000 === 0) { + $this->db->commit(); + $this->db->beginTransaction(); + } + $setQb->setParameter('url_hash', md5($row['url'])); + $setQb->setParameter('id', $row['id']); + $setQb->executeStatement(); + $output->advance(); + } + $this->db->commit(); + $output->finishProgress(); + $result->closeCursor(); + } + +} diff --git a/lib/Service/BookmarksParser.php b/lib/Service/BookmarksParser.php index 98e61c9e6..9f56573bc 100644 --- a/lib/Service/BookmarksParser.php +++ b/lib/Service/BookmarksParser.php @@ -73,12 +73,7 @@ class BookmarksParser { * @var bool */ private $ignorePersonalToolbarFolder = true; - /** - * If tags should be included - * - * @var bool - */ - private $includeFolderTags = true; + /** * Constructor @@ -105,14 +100,13 @@ public static function isValid($doctype): bool { * * @param string $input A Netscape Bookmark File Format HTML string * @param bool $ignorePersonalToolbarFolder If we should ignore the personal toolbar bookmark folder - * @param bool $includeFolderTags If we should include folter tags * @param bool $useDateTimeObjects If we should return \DateTime objects * * @return mixed A PHP value * * @throws HtmlParseError */ - public function parse($input, $ignorePersonalToolbarFolder = true, $includeFolderTags = true, $useDateTimeObjects = true) { + public function parse($input, $ignorePersonalToolbarFolder = true, $useDateTimeObjects = true) { $document = new DOMDocument(); $document->preserveWhiteSpace = false; if (empty($input)) { @@ -123,7 +117,6 @@ public function parse($input, $ignorePersonalToolbarFolder = true, $includeFolde } $this->xpath = new DOMXPath($document); $this->ignorePersonalToolbarFolder = $ignorePersonalToolbarFolder; - $this->includeFolderTags = $includeFolderTags; $this->useDateTimeObjects = $useDateTimeObjects; // set root folder @@ -134,19 +127,18 @@ public function parse($input, $ignorePersonalToolbarFolder = true, $includeFolde return empty($this->bookmarks) ? null : $this->bookmarks; } - /** - * Traverses a DOMNode - * - * @param DOMNode|null $node - */ private function traverse(?DOMNode $node = null): void { - $query = './*'; - $entries = $this->xpath->query($query, $node ?: null); + if ($node !== null) { + $entries = $node->childNodes; + } else { + $query = './*'; + $entries = $this->xpath->query($query, null); + } if (!$entries) { return; } - for ($i = 0; $i < $entries->length; $i++) { - $entry = $entries->item($i); + + foreach ($entries as $entry) { if ($entry === null) { continue; } @@ -217,12 +209,6 @@ private function addBookmark(DOMNode $node): void { 'tags' => [], ]; $bookmark = array_merge($bookmark, $this->getAttributes($node)); - if ($this->includeFolderTags) { - $tags = $this->getCurrentFolderTags(); - if (!empty($tags)) { - $bookmark['tags'] = $tags; - } - } $this->currentFolder['bookmarks'][] = & $bookmark; $this->bookmarks[] = & $bookmark; } @@ -253,13 +239,8 @@ private function addDescription(DOMNode $node): void { private function getAttributes(DOMNode $node): array { $attributes = []; if ($node->attributes) { - $length = $node->attributes->length; - for ($i = 0; $i < $length; ++$i) { - $item = $node->attributes->item($i); - if ($item === null) { - continue; - } - $attributes[strtolower($item->nodeName)] = $item->nodeValue; + foreach ($node->attributes as $attribute) { + $attributes[strtolower($attribute->nodeName)] = $attribute->nodeValue; } } $lastModified = null; @@ -283,25 +264,30 @@ private function getAttributes(DOMNode $node): array { $modified->setTimestamp($attributes['last_modified'] instanceof DateTime ? $attributes['last_modified']->getTimestamp() : (int)$attributes['last_modified']); $attributes['last_modified'] = $modified; } + } else { + if (isset($attributes['add_date'])) { + if ((int)$attributes['add_date'] > self::THOUSAND_YEARS) { + // Google exports dates in miliseconds. This way we only lose the first year of UNIX Epoch. + // This is invalid once we hit 2970. So, quite a long time. + $attributes['add_date'] = ((int)($attributes['add_date']) / 1000); + } else { + $attributes['add_date'] = (int)$attributes['add_date']; + } + } + if (isset($attributes['last_modified'])) { + $attributes['last_modified'] = $attributes['last_modified'] instanceof DateTime ? $attributes['last_modified']->getTimestamp() : (int)$attributes['last_modified']; + if ((int)$attributes['last_modified'] > self::THOUSAND_YEARS) { + // Google exports dates in miliseconds. This way we only lose the first year of UNIX Epoch. + // This is invalid once we hit 2970. So, quite a long time. + $attributes['last_modified'] = ((int)($attributes['last_modified']) / 1000); + } else { + $attributes['last_modified'] = (int)$attributes['last_modified']; + } + } } if (isset($attributes['tags'])) { $attributes['tags'] = explode(',', $attributes['tags']); } return $attributes; } - - /** - * Get current folder tags - * - * @return array - */ - private function getCurrentFolderTags(): array { - $tags = []; - array_walk_recursive($this->currentFolder, static function ($tag, $key) use (&$tags) { - if ($key === 'name') { - $tags[] = $tag; - } - }); - return $tags; - } } diff --git a/lib/Service/FolderService.php b/lib/Service/FolderService.php index 37ff115e2..b8d005e73 100644 --- a/lib/Service/FolderService.php +++ b/lib/Service/FolderService.php @@ -421,11 +421,13 @@ public function addSharedFolder(Share $share, Folder $folder, string $userId): v * @param $file * @param int $folder * @return array - * @throws DoesNotExistException - * @throws MultipleObjectsReturnedException * @throws AlreadyExistsError + * @throws DoesNotExistException + * @throws Exception * @throws HtmlParseError + * @throws MultipleObjectsReturnedException * @throws UnauthorizedAccessError + * @throws UnsupportedOperation * @throws UserLimitExceededError */ public function importFile(string $userId, $file, $folder): array { diff --git a/lib/Service/HtmlImporter.php b/lib/Service/HtmlImporter.php index 188b11df2..fbd202d4d 100644 --- a/lib/Service/HtmlImporter.php +++ b/lib/Service/HtmlImporter.php @@ -23,6 +23,8 @@ use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\Entity; use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\DB\Exception; +use OCP\IDBConnection; /** * Class HtmlImporter @@ -33,49 +35,18 @@ class HtmlImporter { // Taken from https://stackoverflow.com/questions/33126595/what-is-the-actual-range-of-a-mysql-int-column-in-this-situation public const DB_MAX_INT = 2147483647; - /** - * @var BookmarkMapper - */ - protected $bookmarkMapper; - - /** - * @var FolderMapper - */ - protected $folderMapper; - - /** - * @var TagMapper - */ - protected $tagMapper; + private int $transactionCounter = 0; - /** @var BookmarksParser */ - private $bookmarksParser; - /** - * @var TreeMapper - */ - private $treeMapper; - /** - * @var TreeCacheManager - */ - private $hashManager; - /** - * ImportService constructor. - * - * @param BookmarkMapper $bookmarkMapper - * @param FolderMapper $folderMapper - * @param TagMapper $tagMapper - * @param TreeMapper $treeMapper - * @param BookmarksParser $bookmarksParser - * @param TreeCacheManager $hashManager - */ - public function __construct(BookmarkMapper $bookmarkMapper, FolderMapper $folderMapper, TagMapper $tagMapper, TreeMapper $treeMapper, BookmarksParser $bookmarksParser, \OCA\Bookmarks\Service\TreeCacheManager $hashManager) { - $this->bookmarkMapper = $bookmarkMapper; - $this->folderMapper = $folderMapper; - $this->tagMapper = $tagMapper; - $this->treeMapper = $treeMapper; - $this->bookmarksParser = $bookmarksParser; - $this->hashManager = $hashManager; + public function __construct( + private BookmarkMapper $bookmarkMapper, + private FolderMapper $folderMapper, + private TagMapper $tagMapper, + private TreeMapper $treeMapper, + private BookmarksParser $bookmarksParser, + private \OCA\Bookmarks\Service\TreeCacheManager $hashManager, + private IDBConnection $connection, + ) { } /** @@ -87,12 +58,14 @@ public function __construct(BookmarkMapper $bookmarkMapper, FolderMapper $folder * * @return array * + * @throws AlreadyExistsError * @throws DoesNotExistException + * @throws Exception + * @throws HtmlParseError * @throws MultipleObjectsReturnedException * @throws UnauthorizedAccessError - * @throws AlreadyExistsError + * @throws UnsupportedOperation * @throws UserLimitExceededError - * @throws HtmlParseError */ public function importFile(string $userId, string $file, ?int $rootFolder = null): array { $content = file_get_contents($file); @@ -114,6 +87,7 @@ public function importFile(string $userId, string $file, ?int $rootFolder = null * @throws MultipleObjectsReturnedException * @throws UnauthorizedAccessError * @throws UserLimitExceededError|UnsupportedOperation + * @throws Exception * * @psalm-return array{imported: list, errors: array} */ @@ -130,22 +104,30 @@ public function import(string $userId, string $content, ?int $rootFolderId = nul } } - $this->bookmarksParser->parse($content, false); + $this->bookmarksParser->parse($content, false, useDateTimeObjects: false); // Disable invalidation, since we're going to add a bunch of new data to the tree at a single point $this->hashManager->setInvalidationEnabled(false); - foreach ($this->bookmarksParser->currentFolder['children'] as $folder) { - $imported[] = $this->importFolder($userId, $folder, $rootFolder->getId(), $errors); - } - foreach ($this->bookmarksParser->currentFolder['bookmarks'] as $bookmark) { - try { - $bm = $this->importBookmark($userId, $rootFolder->getId(), $bookmark); - } catch (UrlParseError $e) { - $errors[] = 'Failed to parse URL: ' . $bookmark['href']; - continue; + $this->connection->beginTransaction(); + $this->transactionCounter = 0; + try { + foreach ($this->bookmarksParser->currentFolder['children'] as $folder) { + $imported[] = $this->importFolder($userId, $folder, $rootFolder->getId(), $errors); } - $imported[] = ['type' => 'bookmark', 'id' => $bm->getId(), 'title' => $bookmark['title'], 'url' => $bookmark['href']]; + // Might not start at 0 because this folder already exists + $index = $this->treeMapper->countChildren($rootFolder->getId()); + foreach ($this->bookmarksParser->currentFolder['bookmarks'] as $bookmark) { + try { + $bm = $this->importBookmark($userId, $rootFolder->getId(), $bookmark, $index++); + } catch (UrlParseError $e) { + $errors[] = 'Failed to parse URL: ' . $bookmark['href']; + continue; + } + $imported[] = ['type' => 'bookmark', 'id' => $bm->getId(), 'title' => $bookmark['title'], 'url' => $bookmark['href']]; + } + } finally { + $this->connection->commit(); } $this->hashManager->setInvalidationEnabled(true); @@ -201,7 +183,7 @@ private function importFolder(string $userId, array $folderParams, int $parentId * @param array $bookmark * @param null|int $index * @return Bookmark|Entity - * @throws UrlParseError|AlreadyExistsError|UnsupportedOperation|UserLimitExceededError|MultipleObjectsReturnedException + * @throws UrlParseError|AlreadyExistsError|UnsupportedOperation|UserLimitExceededError|MultipleObjectsReturnedException|Exception */ private function importBookmark(string $userId, int $folderId, array $bookmark, $index = null) { $bm = new Bookmark(); @@ -210,8 +192,8 @@ private function importBookmark(string $userId, int $folderId, array $bookmark, $bm->setTitle($bookmark['title']); $bm->setDescription($bookmark['description']); if (isset($bookmark['add_date'])) { - if ($bookmark['add_date']->getTimestamp() < self::DB_MAX_INT && $bookmark['add_date']->getTimestamp() > -self::DB_MAX_INT) { - $bm->setAdded($bookmark['add_date']->getTimestamp()); + if ($bookmark['add_date'] < self::DB_MAX_INT && $bookmark['add_date'] > -self::DB_MAX_INT) { + $bm->setAdded($bookmark['add_date']); } else { $bm->setAdded(time()); } @@ -224,6 +206,13 @@ private function importBookmark(string $userId, int $folderId, array $bookmark, // add tags $this->tagMapper->addTo($bookmark['tags'], $bm->getId()); + $this->transactionCounter++; + if ($this->transactionCounter >= 10_000) { + $this->transactionCounter = 0; + $this->connection->commit(); + $this->connection->beginTransaction(); + } + return $bm; } } diff --git a/lib/Service/LockManager.php b/lib/Service/LockManager.php index 63e75ccc3..b0c6afcc3 100644 --- a/lib/Service/LockManager.php +++ b/lib/Service/LockManager.php @@ -11,6 +11,7 @@ use OCA\Bookmarks\Db\FolderMapper; use OCA\Bookmarks\Db\Types; use OCP\AppFramework\Utility\ITimeFactory; +use OCP\DB\Exception; use OCP\IDBConnection; class LockManager { @@ -43,12 +44,13 @@ public function setLock(string $userId, bool $locked): void { $qb->update('bookmarks_root_folders') ->set('locked_time', $qb->createNamedParameter($value, Types::DATETIME)) ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId))) - ->execute(); + ->executeStatement(); } /** * @param string $userId * @return bool + * @throws Exception */ public function getLock(string $userId): bool { $this->folderMapper->findRootFolder($userId); @@ -56,7 +58,7 @@ public function getLock(string $userId): bool { $lockedAt = $qb->select('locked_time') ->from('bookmarks_root_folders') ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId))) - ->execute() + ->executeQuery() ->fetch(\PDO::FETCH_COLUMN); if ($lockedAt === null) { return false; diff --git a/package-lock.json b/package-lock.json index 730f671ef..384707372 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,20 +1,12 @@ { "name": "bookmarks", -<<<<<<< HEAD - "version": "15.2.0", -======= - "version": "16.0.0", ->>>>>>> 1493a1ee (enh: Support nextcloud 32) + "version": "16.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "bookmarks", -<<<<<<< HEAD - "version": "15.2.0", -======= - "version": "16.0.0", ->>>>>>> 1493a1ee (enh: Support nextcloud 32) + "version": "16.0.1", "license": "AGPL-3.0-or-later", "dependencies": { "@nextcloud/auth": "^2.1.0", @@ -70,16 +62,16 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" @@ -386,18 +378,18 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -431,27 +423,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.7.tgz", - "integrity": "sha512-8NHiL98vsi0mbPQmYAGWwfcFaOy4j2HY49fXJCfuDcdE7fMIsH9a7GdaeXpIBsbT7307WU8KCMp5pUVDNL4f9A==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.7" + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.7.tgz", - "integrity": "sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "license": "MIT", "dependencies": { - "@babel/types": "^7.26.7" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -1627,16 +1619,16 @@ } }, "node_modules/@babel/template": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", - "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1663,13 +1655,13 @@ } }, "node_modules/@babel/types": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.7.tgz", - "integrity": "sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -1947,19 +1939,6 @@ "version": "0.4.4", "resolved": "https://registry.npmjs.org/@file-type/xml/-/xml-0.4.4.tgz", "integrity": "sha512-NhCyXoHlVZ8TqM476hyzwGJ24+D5IPSaZhmrPj7qXnEVb3q6jrFzA3mM9TBpknKSI9EuQeGTKRg2DXGUwvBBoQ==", -<<<<<<< HEAD - "license": "MIT", - "dependencies": { - "sax": "^1.4.1", - "strtok3": "^10.3.4" - } - }, - "node_modules/@floating-ui/core": { - "version": "1.6.9", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz", - "integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==", -======= ->>>>>>> 1493a1ee (enh: Support nextcloud 32) "license": "MIT", "dependencies": { "sax": "^1.4.1", @@ -1967,21 +1946,21 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", - "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz", + "integrity": "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==", "license": "MIT", "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "node_modules/@floating-ui/dom": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", - "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz", + "integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==", "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.7.3", + "@floating-ui/core": "^1.7.4", "@floating-ui/utils": "^0.2.10" } }, @@ -2141,9 +2120,9 @@ } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", "license": "MIT", "peer": true, "dependencies": { @@ -2298,12 +2277,12 @@ "license": "Apache-2.0" }, "node_modules/@nextcloud/auth": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@nextcloud/auth/-/auth-2.5.2.tgz", - "integrity": "sha512-1dr+Xhvg2QtsFC23KFXJSkU524EVgI/+WFBGTZ8tFa+9hmcZ3CqZIHjtXm3KxUvezwAY5023Ml0n2vpdYkpBXQ==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@nextcloud/auth/-/auth-2.5.3.tgz", + "integrity": "sha512-KIhWLk0BKcP4hvypE4o11YqKOPeFMfEFjRrhUUF+h7Fry+dhTBIEIxuQPVCKXMIpjTDd8791y8V6UdRZ2feKAQ==", "license": "GPL-3.0-or-later", "dependencies": { - "@nextcloud/browser-storage": "^0.4.0", + "@nextcloud/browser-storage": "^0.5.0", "@nextcloud/event-bus": "^3.3.2" }, "engines": { @@ -2311,18 +2290,17 @@ } }, "node_modules/@nextcloud/axios": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@nextcloud/axios/-/axios-2.5.1.tgz", - "integrity": "sha512-AA7BPF/rsOZWAiVxqlobGSdD67AEwjOnymZCKUIwEIBArKxYK7OQEqcILDjQwgj6G0e/Vg9Y8zTVsPZp+mlvwA==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/@nextcloud/axios/-/axios-2.5.2.tgz", + "integrity": "sha512-8frJb77jNMbz00TjsSqs1PymY0nIEbNM4mVmwen2tXY7wNgRai6uXilIlXKOYB9jR/F/HKRj6B4vUwVwZbhdbw==", "license": "GPL-3.0-or-later", "dependencies": { - "@nextcloud/auth": "^2.3.0", + "@nextcloud/auth": "^2.5.1", "@nextcloud/router": "^3.0.1", - "axios": "^1.6.8" + "axios": "^1.12.2" }, "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" } }, "node_modules/@nextcloud/axios/node_modules/@nextcloud/router": { @@ -2355,16 +2333,12 @@ } }, "node_modules/@nextcloud/browser-storage": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@nextcloud/browser-storage/-/browser-storage-0.4.0.tgz", - "integrity": "sha512-D6XxznxCYmJ3oBCC3p0JB6GZJ2RZ9dgbB1UqtTePXrIvHUMBAeF/YkiGKYxLAVZCZb+NSNZXgAYHm/3LnIUbDg==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@nextcloud/browser-storage/-/browser-storage-0.5.0.tgz", + "integrity": "sha512-usYr4GlJQlK3hgZURvklqWb9ivi7sgsSuFqXrs7s4hl1LTS4enzPrnkQumm6nRsQruf0ITS+OBsK+oELEbvYPA==", "license": "GPL-3.0-or-later", - "dependencies": { - "core-js": "3.37.0" - }, "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" + "node": "^24 || ^22 || ^20" } }, "node_modules/@nextcloud/browserslist-config": { @@ -2379,56 +2353,72 @@ } }, "node_modules/@nextcloud/capabilities": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@nextcloud/capabilities/-/capabilities-1.2.0.tgz", - "integrity": "sha512-L1NQtOfHWzkfj0Ple1MEJt6HmOHWAi3y4qs+OnwSWexqJT0DtXTVPyRxi7ADyITwRxS5H9R/HMl6USAj4Nr1nQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@nextcloud/capabilities/-/capabilities-1.2.1.tgz", + "integrity": "sha512-snZ0/910zzwN6PDsIlx2Uvktr1S5x0ClhDUnfPlCj7ntNvECzuVHNY5wzby22LIkc+9ZjaDKtCwuCt2ye+9p/Q==", "license": "GPL-3.0-or-later", "dependencies": { - "@nextcloud/initial-state": "^2.1.0" + "@nextcloud/initial-state": "^3.0.0" }, "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" + } + }, + "node_modules/@nextcloud/capabilities/node_modules/@nextcloud/initial-state": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-3.0.0.tgz", + "integrity": "sha512-cV+HBdkQJGm8FxkBI5rFT/FbMNWNBvpbj6OPrg4Ae4YOOsQ15CL8InPOAw1t4XkOkQK2NEdUGQLVUz/19wXbdQ==", + "license": "GPL-3.0-or-later", + "engines": { + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" } }, "node_modules/@nextcloud/dialogs": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/@nextcloud/dialogs/-/dialogs-6.3.2.tgz", - "integrity": "sha512-ioZ483wmKdNX1HdSJ1EG7ewTSyQAqlmbBALkhT4guZdR9JG8VIdnijX15qwKgAWITG2y36PWoi9Rimb3dDf+7A==", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@nextcloud/dialogs/-/dialogs-6.4.2.tgz", + "integrity": "sha512-xj6fyUdb56StWt1DWeDHYnqK0Ck7EWQLUEyWtXHnneknoOV3x/Y0HPRL5L2PTJaDuVQB8TcVW53JjR38JG9W6Q==", "license": "AGPL-3.0-or-later", "dependencies": { "@mdi/js": "^7.4.47", - "@nextcloud/auth": "^2.5.1", - "@nextcloud/axios": "^2.5.1", - "@nextcloud/browser-storage": "^0.4.0", - "@nextcloud/event-bus": "^3.3.2", - "@nextcloud/files": "^3.10.2", - "@nextcloud/initial-state": "^2.2.0", - "@nextcloud/l10n": "^3.3.0", - "@nextcloud/router": "^3.0.1", - "@nextcloud/sharing": "^0.2.4", - "@nextcloud/typings": "^1.9.1", + "@nextcloud/auth": "^2.5.3", + "@nextcloud/axios": "^2.5.2", + "@nextcloud/browser-storage": "^0.5.0", + "@nextcloud/event-bus": "^3.3.3", + "@nextcloud/files": "^3.12.2", + "@nextcloud/initial-state": "^3.0.0", + "@nextcloud/l10n": "^3.4.1", + "@nextcloud/paths": "^3.0.0", + "@nextcloud/router": "^3.1.0", + "@nextcloud/sharing": "^0.3.0", "@types/toastify-js": "^1.12.4", "@vueuse/core": "^11.3.0", "cancelable-promise": "^4.3.1", - "p-queue": "^8.1.0", + "p-queue": "^9.0.1", "toastify-js": "^1.12.0", "vue-frag": "^1.4.3", "webdav": "^5.8.0" }, "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0", - "npm": "^10.5.1" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" }, "peerDependencies": { "@nextcloud/vue": "^8.24.0", "vue": "^2.7.16" } }, + "node_modules/@nextcloud/dialogs/node_modules/@nextcloud/initial-state": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-3.0.0.tgz", + "integrity": "sha512-cV+HBdkQJGm8FxkBI5rFT/FbMNWNBvpbj6OPrg4Ae4YOOsQ15CL8InPOAw1t4XkOkQK2NEdUGQLVUz/19wXbdQ==", + "license": "GPL-3.0-or-later", + "engines": { + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" + } + }, "node_modules/@nextcloud/dialogs/node_modules/@nextcloud/l10n": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-3.4.0.tgz", - "integrity": "sha512-K4UBSl0Ou6sXXLxyjuhktRf2FyTCjyvHxJyBLmS2z3YEYcRkpf8ib3XneRwEQIEpzBPQjul2/ZdFlt7umd8Gaw==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-3.4.1.tgz", + "integrity": "sha512-aTFinTcKiK2gEXwLgutXekpZZ8/v/4QiC8C3QCLH5m0o+WtxsBC+fqV142ebC/rfDnzCLhY4ZtswSu8bFbZocg==", "license": "GPL-3.0-or-later", "dependencies": { "@nextcloud/router": "^3.0.1", @@ -2442,16 +2432,43 @@ } }, "node_modules/@nextcloud/dialogs/node_modules/@nextcloud/router": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-3.0.1.tgz", - "integrity": "sha512-Ci/uD3x8OKHdxSqXL6gRJ+mGJOEXjeiHjj7hqsZqVTsT7kOrCjDf0/J8z5RyLlokKZ0IpSe+hGxgi3YB7Gpw3Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-3.1.0.tgz", + "integrity": "sha512-e4dkIaxRSwdZJlZFpn9x03QgBn/Sa2hN1hp/BA7+AbzykmSAlKuWfdmX8j/8ewrLpQwYmZR23IZO9XwpJXq2Uw==", "license": "GPL-3.0-or-later", "dependencies": { - "@nextcloud/typings": "^1.7.0" + "@nextcloud/typings": "^1.10.0" }, "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" + } + }, + "node_modules/@nextcloud/dialogs/node_modules/p-queue": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.1.0.tgz", + "integrity": "sha512-O/ZPaXuQV29uSLbxWBGGZO1mCQXV2BLIwUr59JUU9SoH76mnYvtms7aafH/isNSNGwuEfP6W/4xD0/TJXxrizw==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.1", + "p-timeout": "^7.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@nextcloud/dialogs/node_modules/p-timeout": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.1.tgz", + "integrity": "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@nextcloud/eslint-config": { @@ -2516,23 +2533,22 @@ } }, "node_modules/@nextcloud/event-bus": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/@nextcloud/event-bus/-/event-bus-3.3.2.tgz", - "integrity": "sha512-1Qfs6i7Tz2qd1A33NpBQOt810ydHIRjhyXMFwSEkYX2yUI80lAk/sWO8HIB2Fqp+iffhyviPPcQYoytMDRyDNw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@nextcloud/event-bus/-/event-bus-3.3.3.tgz", + "integrity": "sha512-zIfvKmUGkXpVzRKoXrcO9hkoiKDm65fqNxy/XIbIxrQhZByPq3gDkjBpnu3V5Gs8JdYwa73R8DjzV9oH8HYhIg==", "license": "GPL-3.0-or-later", "dependencies": { - "@types/semver": "^7.5.8", - "semver": "^7.6.3" + "@types/semver": "^7.7.0", + "semver": "^7.7.2" }, "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" + "node": "^20 || ^22 || ^24" } }, "node_modules/@nextcloud/event-bus/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -2542,20 +2558,20 @@ } }, "node_modules/@nextcloud/files": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/@nextcloud/files/-/files-3.12.0.tgz", - "integrity": "sha512-LVZklgooZzBj2jkbPRZO4jnnvW5+RvOn7wN5weyOZltF6i2wVMbg1Y/Czl2pi/UNMjUm5ENqc0j7FgxMBo8bwA==", + "version": "3.12.2", + "resolved": "https://registry.npmjs.org/@nextcloud/files/-/files-3.12.2.tgz", + "integrity": "sha512-vBo8tf3Xh6efiF8CrEo3pKj9AtvAF6RdDGO1XKL65IxV8+UUd9Uxl2lUExHlzoDRRczCqfGfaWfRRaFhYqce5Q==", "license": "AGPL-3.0-or-later", "dependencies": { - "@nextcloud/auth": "^2.5.1", - "@nextcloud/capabilities": "^1.2.0", - "@nextcloud/l10n": "^3.3.0", - "@nextcloud/logger": "^3.0.2", - "@nextcloud/paths": "^2.2.1", - "@nextcloud/router": "^3.0.1", - "@nextcloud/sharing": "^0.2.4", + "@nextcloud/auth": "^2.5.3", + "@nextcloud/capabilities": "^1.2.1", + "@nextcloud/l10n": "^3.4.1", + "@nextcloud/logger": "^3.0.3", + "@nextcloud/paths": "^3.0.0", + "@nextcloud/router": "^3.1.0", + "@nextcloud/sharing": "^0.3.0", "cancelable-promise": "^4.3.1", - "is-svg": "^6.0.0", + "is-svg": "^6.1.0", "typescript-event-target": "^1.1.1", "webdav": "^5.8.0" }, @@ -2564,9 +2580,9 @@ } }, "node_modules/@nextcloud/files/node_modules/@nextcloud/l10n": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-3.4.0.tgz", - "integrity": "sha512-K4UBSl0Ou6sXXLxyjuhktRf2FyTCjyvHxJyBLmS2z3YEYcRkpf8ib3XneRwEQIEpzBPQjul2/ZdFlt7umd8Gaw==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-3.4.1.tgz", + "integrity": "sha512-aTFinTcKiK2gEXwLgutXekpZZ8/v/4QiC8C3QCLH5m0o+WtxsBC+fqV142ebC/rfDnzCLhY4ZtswSu8bFbZocg==", "license": "GPL-3.0-or-later", "dependencies": { "@nextcloud/router": "^3.0.1", @@ -2580,16 +2596,15 @@ } }, "node_modules/@nextcloud/files/node_modules/@nextcloud/router": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-3.0.1.tgz", - "integrity": "sha512-Ci/uD3x8OKHdxSqXL6gRJ+mGJOEXjeiHjj7hqsZqVTsT7kOrCjDf0/J8z5RyLlokKZ0IpSe+hGxgi3YB7Gpw3Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-3.1.0.tgz", + "integrity": "sha512-e4dkIaxRSwdZJlZFpn9x03QgBn/Sa2hN1hp/BA7+AbzykmSAlKuWfdmX8j/8ewrLpQwYmZR23IZO9XwpJXq2Uw==", "license": "GPL-3.0-or-later", "dependencies": { - "@nextcloud/typings": "^1.7.0" + "@nextcloud/typings": "^1.10.0" }, "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" } }, "node_modules/@nextcloud/files/node_modules/is-svg": { @@ -2635,26 +2650,24 @@ } }, "node_modules/@nextcloud/logger": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@nextcloud/logger/-/logger-3.0.2.tgz", - "integrity": "sha512-wByt0R0/6QC44RBpaJr1MWghjjOxk/pRbACHo/ZWWKht1qYbJRHB4GtEi+35KEIHY07ZpqxiDk6dIRuN7sXYWQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@nextcloud/logger/-/logger-3.0.3.tgz", + "integrity": "sha512-TcbVRL4/O5ffI1RXFmQAFD3gwwT15AAdr1770x+RNqVvfBdoGVyhzOwCIyA5Vfc3fA1iJXFa+rE6buJZSoqlcw==", "license": "GPL-3.0-or-later", "dependencies": { - "@nextcloud/auth": "^2.3.0" + "@nextcloud/auth": "^2.5.3" }, "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" } }, "node_modules/@nextcloud/paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@nextcloud/paths/-/paths-2.2.1.tgz", - "integrity": "sha512-M3ShLjrxR7B48eKThLMoqbxTqTKyQXcwf9TgeXQGbCIhiHoXU6as5j8l5qNv/uZlANokVdowpuWHBi3b2+YNNA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@nextcloud/paths/-/paths-3.0.0.tgz", + "integrity": "sha512-+sTfTkIbVUa2Ue3bkz3R7F1mhddvHPOWUxkSNg7Q5dAsimVFBaTRgiBAJmsAag3JPsxyuS8kUgeb0zdEssRdTA==", "license": "GPL-3.0-or-later", "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" } }, "node_modules/@nextcloud/router": { @@ -2672,16 +2685,43 @@ } }, "node_modules/@nextcloud/sharing": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@nextcloud/sharing/-/sharing-0.2.4.tgz", - "integrity": "sha512-kOLAr0w4NDUGPF42L22i9iSs6Z3ylTsE0RudAGDBzw/pnxGY8PEwZI2j0IMAFRfQ7XFNcpV/EVHI5YCMxtxGMQ==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@nextcloud/sharing/-/sharing-0.3.0.tgz", + "integrity": "sha512-kV7qeUZvd1fTKeFyH+W5Qq5rNOqG9rLATZM3U9MBxWXHJs3OxMqYQb8UQ3NYONzsX3zDGJmdQECIGHm1ei2sCA==", "license": "GPL-3.0-or-later", "dependencies": { - "@nextcloud/initial-state": "^2.2.0" + "@nextcloud/initial-state": "^3.0.0", + "is-svg": "^6.1.0" }, "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" + }, + "optionalDependencies": { + "@nextcloud/files": "^3.12.0" + } + }, + "node_modules/@nextcloud/sharing/node_modules/@nextcloud/initial-state": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-3.0.0.tgz", + "integrity": "sha512-cV+HBdkQJGm8FxkBI5rFT/FbMNWNBvpbj6OPrg4Ae4YOOsQ15CL8InPOAw1t4XkOkQK2NEdUGQLVUz/19wXbdQ==", + "license": "GPL-3.0-or-later", + "engines": { + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" + } + }, + "node_modules/@nextcloud/sharing/node_modules/is-svg": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-6.1.0.tgz", + "integrity": "sha512-i7YPdvYuSCYcaLQrKwt8cvKTlwHcdA6Hp8N9SO3Q5jIzo8x6kH3N47W0BvPP7NdxVBmIHx7X9DK36czYYW7lHg==", + "license": "MIT", + "dependencies": { + "@file-type/xml": "^0.4.3" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@nextcloud/stylelint-config": { @@ -2700,61 +2740,47 @@ "stylelint-config-recommended-vue": "^1.1.0" } }, - "node_modules/@nextcloud/timezones": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@nextcloud/timezones/-/timezones-0.2.0.tgz", - "integrity": "sha512-1mwQ+asTFOgv9rxPoAMEbDF8JfnenIa2EGNS+8MATCyi6WXxYh0Lhkaq1d3l2+xNbUPHgMnk4cRYsvIo319lkA==", - "license": "AGPL-3.0-or-later", - "dependencies": { - "ical.js": "^2.1.0" - }, - "engines": { - "node": "^20 || ^22" - } - }, "node_modules/@nextcloud/typings": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@nextcloud/typings/-/typings-1.9.1.tgz", - "integrity": "sha512-i0l/L5gKW8EACbXHVxXM6wn3sUhY2qmnL2OijppzU4dENC7/hqySMQDer7/+cJbNSNG7uHF/Z+9JmHtDfRfuGg==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@nextcloud/typings/-/typings-1.10.0.tgz", + "integrity": "sha512-SMC42rDjOH3SspPTLMZRv76ZliHpj2JJkF8pGLP8l1QrVTZxE47Qz5qeKmbj2VL+dRv2e/NgixlAFmzVnxkhqg==", "license": "GPL-3.0-or-later", "dependencies": { "@types/jquery": "3.5.16" }, "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" } }, "node_modules/@nextcloud/vue": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-8.31.0.tgz", - "integrity": "sha512-P5m3Odfw4m0siu7qs88WJutu2C8mEknqMS1ijlqYtQvc8qZwmpQshgCV5GhyyBTTK9Baicthm+ULglIf/Eq/sg==", + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-8.36.0.tgz", + "integrity": "sha512-x1MEh4nvCrD1zoJ3ybhtbSDox+1wyHRP7st95Uu14Wm630quRrfXGaQ1bxqaZ7en/wqaihR0NPyQKfmjrPmseg==", "license": "AGPL-3.0-or-later", "dependencies": { - "@floating-ui/dom": "^1.7.4", + "@floating-ui/dom": "^1.7.5", "@linusborg/vue-simple-portal": "^0.1.5", - "@nextcloud/auth": "^2.5.2", - "@nextcloud/axios": "^2.5.0", - "@nextcloud/browser-storage": "^0.4.0", - "@nextcloud/capabilities": "^1.2.0", - "@nextcloud/event-bus": "^3.3.2", + "@nextcloud/auth": "^2.5.3", + "@nextcloud/axios": "^2.5.2", + "@nextcloud/browser-storage": "^0.5.0", + "@nextcloud/capabilities": "^1.2.1", + "@nextcloud/event-bus": "^3.3.3", "@nextcloud/initial-state": "^2.2.0", - "@nextcloud/l10n": "^3.4.0", - "@nextcloud/logger": "^3.0.2", - "@nextcloud/router": "^3.0.1", + "@nextcloud/l10n": "^3.4.1", + "@nextcloud/logger": "^3.0.3", + "@nextcloud/router": "^3.1.0", "@nextcloud/sharing": "^0.3.0", - "@nextcloud/timezones": "^0.2.0", "@nextcloud/vue-select": "^3.26.0", "@vueuse/components": "^11.0.0", "@vueuse/core": "^11.0.0", "blurhash": "^2.0.5", "clone": "^2.1.2", "debounce": "^2.2.0", - "dompurify": "^3.2.4", + "dompurify": "^3.3.1", "emoji-mart-vue-fast": "^15.0.5", "escape-html": "^1.0.3", "floating-vue": "^1.0.0-beta.19", - "focus-trap": "^7.4.3", + "focus-trap": "^7.8.0", "linkify-string": "^4.3.2", "md5": "^2.3.0", "p-queue": "^8.1.1", @@ -2768,11 +2794,11 @@ "splitpanes": "^2.4.1", "string-length": "^5.0.1", "striptags": "^3.2.0", - "tabbable": "^6.2.0", + "tabbable": "^6.4.0", "tributejs": "^5.1.3", "unified": "^11.0.1", "unist-builder": "^4.0.0", - "unist-util-visit": "^5.0.0", + "unist-util-visit": "^5.1.0", "vue": "^2.7.16", "vue-color": "^2.8.1", "vue-frag": "^1.4.3", @@ -2796,9 +2822,9 @@ } }, "node_modules/@nextcloud/vue/node_modules/@nextcloud/l10n": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-3.4.0.tgz", - "integrity": "sha512-K4UBSl0Ou6sXXLxyjuhktRf2FyTCjyvHxJyBLmS2z3YEYcRkpf8ib3XneRwEQIEpzBPQjul2/ZdFlt7umd8Gaw==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-3.4.1.tgz", + "integrity": "sha512-aTFinTcKiK2gEXwLgutXekpZZ8/v/4QiC8C3QCLH5m0o+WtxsBC+fqV142ebC/rfDnzCLhY4ZtswSu8bFbZocg==", "license": "GPL-3.0-or-later", "dependencies": { "@nextcloud/router": "^3.0.1", @@ -2812,56 +2838,15 @@ } }, "node_modules/@nextcloud/vue/node_modules/@nextcloud/router": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-3.0.1.tgz", - "integrity": "sha512-Ci/uD3x8OKHdxSqXL6gRJ+mGJOEXjeiHjj7hqsZqVTsT7kOrCjDf0/J8z5RyLlokKZ0IpSe+hGxgi3YB7Gpw3Q==", - "license": "GPL-3.0-or-later", - "dependencies": { - "@nextcloud/typings": "^1.7.0" - }, - "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" - } - }, - "node_modules/@nextcloud/vue/node_modules/@nextcloud/sharing": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@nextcloud/sharing/-/sharing-0.3.0.tgz", - "integrity": "sha512-kV7qeUZvd1fTKeFyH+W5Qq5rNOqG9rLATZM3U9MBxWXHJs3OxMqYQb8UQ3NYONzsX3zDGJmdQECIGHm1ei2sCA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-3.1.0.tgz", + "integrity": "sha512-e4dkIaxRSwdZJlZFpn9x03QgBn/Sa2hN1hp/BA7+AbzykmSAlKuWfdmX8j/8ewrLpQwYmZR23IZO9XwpJXq2Uw==", "license": "GPL-3.0-or-later", "dependencies": { - "@nextcloud/initial-state": "^3.0.0", - "is-svg": "^6.1.0" + "@nextcloud/typings": "^1.10.0" }, "engines": { "node": "^20.0.0 || ^22.0.0 || ^24.0.0" - }, - "optionalDependencies": { - "@nextcloud/files": "^3.12.0" - } - }, - "node_modules/@nextcloud/vue/node_modules/@nextcloud/sharing/node_modules/@nextcloud/initial-state": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-3.0.0.tgz", - "integrity": "sha512-cV+HBdkQJGm8FxkBI5rFT/FbMNWNBvpbj6OPrg4Ae4YOOsQ15CL8InPOAw1t4XkOkQK2NEdUGQLVUz/19wXbdQ==", - "license": "GPL-3.0-or-later", - "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0" - } - }, - "node_modules/@nextcloud/vue/node_modules/is-svg": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-6.1.0.tgz", - "integrity": "sha512-i7YPdvYuSCYcaLQrKwt8cvKTlwHcdA6Hp8N9SO3Q5jIzo8x6kH3N47W0BvPP7NdxVBmIHx7X9DK36czYYW7lHg==", - "license": "MIT", - "dependencies": { - "@file-type/xml": "^0.4.3" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@nextcloud/webpack-vue-config": { @@ -3423,9 +3408,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "license": "MIT", "peer": true }, @@ -4489,9 +4474,9 @@ } }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", "peer": true, "bin": { @@ -4501,6 +4486,19 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -4516,6 +4514,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -4571,16 +4570,6 @@ "license": "MIT", "peer": true }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, "node_modules/ansi-html-community": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", @@ -5006,6 +4995,16 @@ ], "license": "MIT" }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -5054,31 +5053,31 @@ "license": "MIT" }, "node_modules/bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", "license": "MIT" }, "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "bytes": "3.1.2", + "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", "type-is": "~1.6.18", - "unpipe": "1.0.0" + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8", @@ -5096,6 +5095,28 @@ "ms": "2.0.0" } }, + "node_modules/body-parser/node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -5104,21 +5125,15 @@ "license": "MIT", "peer": true }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "node_modules/body-parser/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "peer": true, - "dependencies": { - "side-channel": "^1.0.6" - }, "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.8" } }, "node_modules/bonjour-service": { @@ -5222,24 +5237,23 @@ } }, "node_modules/browserify-sign": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", - "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", + "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", "license": "ISC", "dependencies": { - "bn.js": "^5.2.1", - "browserify-rsa": "^4.1.0", + "bn.js": "^5.2.2", + "browserify-rsa": "^4.1.1", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "elliptic": "^6.5.5", - "hash-base": "~3.0", + "elliptic": "^6.6.1", "inherits": "^2.0.4", - "parse-asn1": "^5.1.7", + "parse-asn1": "^5.1.9", "readable-stream": "^2.3.8", "safe-buffer": "^5.2.1" }, "engines": { - "node": ">= 0.12" + "node": ">= 0.10" } }, "node_modules/browserify-sign/node_modules/isarray": { @@ -5294,9 +5308,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "funding": [ { "type": "opencollective", @@ -5314,10 +5328,11 @@ "license": "MIT", "peer": true, "dependencies": { - "caniuse-lite": "^1.0.30001688", - "electron-to-chromium": "^1.5.73", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -5555,9 +5570,9 @@ "license": "MIT" }, "node_modules/caniuse-lite": { - "version": "1.0.30001695", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001695.tgz", - "integrity": "sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==", + "version": "1.0.30001769", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz", + "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==", "funding": [ { "type": "opencollective", @@ -5792,9 +5807,9 @@ } }, "node_modules/compression": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.5.tgz", - "integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", "dev": true, "license": "MIT", "peer": true, @@ -5803,7 +5818,7 @@ "compressible": "~2.0.18", "debug": "2.6.9", "negotiator": "~0.6.4", - "on-headers": "~1.0.2", + "on-headers": "~1.1.0", "safe-buffer": "5.2.1", "vary": "~1.1.2" }, @@ -6575,9 +6590,9 @@ } }, "node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz", + "integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==", "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -6705,9 +6720,9 @@ } }, "node_modules/dompurify": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.6.tgz", - "integrity": "sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz", + "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" @@ -6805,9 +6820,9 @@ "peer": true }, "node_modules/electron-to-chromium": { - "version": "1.5.88", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.88.tgz", - "integrity": "sha512-K3C2qf1o+bGzbilTDCTBhTQcMS9KW60yTAaTeeXsfvQuTDDwlokLam/AdqlqcSy9u4UainDgsHV23ksXAOgamw==", + "version": "1.5.286", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", + "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", "license": "ISC", "peer": true }, @@ -6875,14 +6890,14 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.0.tgz", - "integrity": "sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", "license": "MIT", "peer": true, "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "tapable": "^2.3.0" }, "engines": { "node": ">=10.13.0" @@ -7011,9 +7026,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", - "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", "license": "MIT", "peer": true }, @@ -7936,41 +7951,41 @@ } }, "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", "dev": true, "license": "MIT", "peer": true, "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", + "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.13.0", + "qs": "~6.14.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", + "send": "~0.19.0", + "serve-static": "~1.16.2", "setprototypeof": "1.2.0", - "statuses": "2.0.1", + "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -8002,23 +8017,6 @@ "license": "MIT", "peer": true }, - "node_modules/express/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -8081,6 +8079,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, "license": "MIT", "peer": true }, @@ -8366,12 +8365,12 @@ } }, "node_modules/focus-trap": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.4.tgz", - "integrity": "sha512-xx560wGBk7seZ6y933idtjJQc1l+ck+pI3sKvhKozdBV1dRZoKhkW5xoCaFv9tQiX5RH1xfSxjuNu6g+lmN/gw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.8.0.tgz", + "integrity": "sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==", "license": "MIT", "dependencies": { - "tabbable": "^6.2.0" + "tabbable": "^6.4.0" } }, "node_modules/follow-redirects": { @@ -8624,9 +8623,10 @@ } }, "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -9292,12 +9292,6 @@ "node": ">=10.18" } }, - "node_modules/ical.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ical.js/-/ical.js-2.2.0.tgz", - "integrity": "sha512-P8gjWkTEd5M/SEEvBVPPO/KC+V+HRNRZh3xfCDTVWmUTEfVbL8JaK5GTWS2MJ55aLMhfXhbh7kYzd0nrBARjsA==", - "license": "MPL-2.0" - }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -10349,9 +10343,9 @@ "peer": true }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "peer": true, @@ -10406,6 +10400,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, "license": "MIT", "peer": true }, @@ -10535,13 +10530,17 @@ "peer": true }, "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", + "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", "license": "MIT", "peer": true, "engines": { "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/loader-utils": { @@ -10592,15 +10591,15 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "license": "MIT" }, "node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", "license": "MIT" }, "node_modules/lodash.debounce": { @@ -10882,9 +10881,9 @@ } }, "node_modules/mdast-util-to-hast": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", - "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -12947,9 +12946,9 @@ } }, "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz", + "integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==", "dev": true, "license": "(BSD-3-Clause OR GPL-2.0)", "peer": true, @@ -12958,9 +12957,9 @@ } }, "node_modules/node-gettext": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/node-gettext/-/node-gettext-3.0.0.tgz", - "integrity": "sha512-/VRYibXmVoN6tnSAY2JWhNRhWYJ8Cd844jrZU/DwLVoI4vBI6ceYbd8i42sYZ9uOgDH3S7vslIKOWV/ZrT2YBA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/node-gettext/-/node-gettext-3.0.1.tgz", + "integrity": "sha512-foI20qQAV22OlCeFIUZiXZutPbe23nGuDp7hLvK6PanhOYlUJIgLAUZa4MB5pX0J62dubOM/MYVhQ2aYTUPbhA==", "dependencies": { "lodash.get": "^4.4.2" } @@ -13006,9 +13005,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "license": "MIT", "peer": true }, @@ -13220,9 +13219,9 @@ } }, "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", "dev": true, "license": "MIT", "peer": true, @@ -13425,16 +13424,15 @@ } }, "node_modules/parse-asn1": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", - "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", + "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", "license": "ISC", "dependencies": { "asn1.js": "^4.10.1", "browserify-aes": "^1.2.0", "evp_bytestokey": "^1.0.3", - "hash-base": "~3.0", - "pbkdf2": "^3.1.2", + "pbkdf2": "^3.1.5", "safe-buffer": "^5.2.1" }, "engines": { @@ -13574,51 +13572,20 @@ } }, "node_modules/pbkdf2": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.3.tgz", - "integrity": "sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", + "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", "license": "MIT", "dependencies": { - "create-hash": "~1.1.3", + "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "ripemd160": "=2.0.1", + "ripemd160": "^2.0.3", "safe-buffer": "^5.2.1", - "sha.js": "^2.4.11", - "to-buffer": "^1.2.0" + "sha.js": "^2.4.12", + "to-buffer": "^1.2.1" }, "engines": { - "node": ">=0.12" - } - }, - "node_modules/pbkdf2/node_modules/create-hash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", - "integrity": "sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA==", - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "sha.js": "^2.4.0" - } - }, - "node_modules/pbkdf2/node_modules/hash-base": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", - "integrity": "sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1" - } - }, - "node_modules/pbkdf2/node_modules/ripemd160": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", - "integrity": "sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w==", - "license": "MIT", - "dependencies": { - "hash-base": "^2.0.0", - "inherits": "^2.0.1" + "node": ">= 0.10" } }, "node_modules/picocolors": { @@ -14140,9 +14107,9 @@ } }, "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -14235,22 +14202,55 @@ } }, "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" } }, + "node_modules/raw-body/node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/raw-body/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/read-pkg": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-6.0.0.tgz", @@ -14939,15 +14939,75 @@ } }, "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", "license": "MIT", "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" + "hash-base": "^3.1.2", + "inherits": "^2.0.4" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ripemd160/node_modules/hash-base": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ripemd160/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/ripemd160/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/ripemd160/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/ripemd160/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" } }, + "node_modules/ripemd160/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/run-applescript": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", @@ -15177,9 +15237,9 @@ "license": "ISC" }, "node_modules/schema-utils": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", - "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "license": "MIT", "peer": true, "dependencies": { @@ -16540,9 +16600,9 @@ "peer": true }, "node_modules/tabbable": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", - "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz", + "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==", "license": "MIT" }, "node_modules/table": { @@ -16614,24 +16674,28 @@ } }, "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", "license": "MIT", "peer": true, "engines": { "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/terser": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz", - "integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==", + "version": "5.46.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", + "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", "license": "BSD-2-Clause", "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", + "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -16643,9 +16707,9 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.11", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.11.tgz", - "integrity": "sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==", + "version": "5.3.16", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", + "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", "license": "MIT", "peer": true, "dependencies": { @@ -17260,9 +17324,9 @@ } }, "node_modules/unist-util-visit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -17300,9 +17364,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", - "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "funding": [ { "type": "opencollective", @@ -17334,6 +17398,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, "license": "BSD-2-Clause", "peer": true, "dependencies": { @@ -17770,9 +17835,9 @@ } }, "node_modules/watchpack": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", - "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", "license": "MIT", "peer": true, "dependencies": { @@ -17814,16 +17879,16 @@ } }, "node_modules/webdav": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webdav/-/webdav-5.8.0.tgz", - "integrity": "sha512-iuFG7NamJ41Oshg4930iQgfIpRrUiatPWIekeznYgEf2EOraTRcDPTjy7gIOMtkdpKTaqPk1E68NO5PAGtJahA==", + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/webdav/-/webdav-5.9.0.tgz", + "integrity": "sha512-OMJ6wtK1WvCO++aOLoQgE96S8KT4e5aaClWHmHXfFU369r4eyELN569B7EqT4OOUb99mmO58GkyuiCv/Ag6J0Q==", "license": "MIT", "dependencies": { "@buttercup/fetch": "^0.2.1", "base-64": "^1.0.0", "byte-length": "^1.0.2", - "entities": "^6.0.0", - "fast-xml-parser": "^4.5.1", + "entities": "^6.0.1", + "fast-xml-parser": "^5.3.4", "hot-patcher": "^2.0.1", "layerr": "^3.0.0", "md5": "^2.3.0", @@ -17850,36 +17915,68 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/webdav/node_modules/fast-xml-parser": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.4.tgz", + "integrity": "sha512-EFd6afGmXlCx8H8WTZHhAoDaWaGyuIBoZJ2mknrNxug+aZKjkp0a0dlars9Izl+jF+7Gu1/5f/2h68cQpe0IiA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^2.1.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/webdav/node_modules/strnum": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz", + "integrity": "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, "node_modules/webpack": { - "version": "5.97.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz", - "integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==", + "version": "5.105.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz", + "integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==", "license": "MIT", "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.6", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.14.0", - "browserslist": "^4.24.0", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", - "es-module-lexer": "^1.2.1", + "enhanced-resolve": "^5.19.0", + "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", + "loader-runner": "^4.3.1", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.16", + "watchpack": "^2.5.1", + "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" @@ -18119,34 +18216,15 @@ } }, "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", + "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", "license": "MIT", "peer": true, "engines": { "node": ">=10.13.0" } }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", diff --git a/psalm-baseline.xml b/psalm-baseline.xml index bc42557f2..df3c115ec 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,5 +1,5 @@ - + @@ -20,58 +20,13 @@ bookmarkController->countArchived()->getData()]]> bookmarkController->countBookmarks(-1)->getData()]]> + bookmarkController->countDeleted()->getData()]]> bookmarkController->countDuplicated()->getData()]]> bookmarkController->countUnavailable()->getData()]]> folderController->getFolders()->getData()]]> - - - createPositionalParameter($folderId, IQueryBuilder::PARAM_INT)]]> - createPositionalParameter($folderId, IQueryBuilder::PARAM_INT)]]> - createPositionalParameter(TreeMapper::TYPE_FOLDER)]]> - createPositionalParameter(TreeMapper::TYPE_FOLDER)]]> - createFunction($qb->getColumnName($col))]]> - createPositionalParameter(TreeMapper::TYPE_BOOKMARK)]]> - createPositionalParameter(TreeMapper::TYPE_BOOKMARK)]]> - createPositionalParameter(TreeMapper::TYPE_BOOKMARK)]]> - createPositionalParameter(TreeMapper::TYPE_BOOKMARK)]]> - createPositionalParameter(TreeMapper::TYPE_BOOKMARK)]]> - createPositionalParameter(TreeMapper::TYPE_BOOKMARK)]]> - createPositionalParameter(TreeMapper::TYPE_BOOKMARK)]]> - createPositionalParameter(TreeMapper::TYPE_BOOKMARK)]]> - createPositionalParameter(TreeMapper::TYPE_BOOKMARK)]]> - createPositionalParameter(TreeMapper::TYPE_FOLDER)]]> - createPositionalParameter(TreeMapper::TYPE_FOLDER)]]> - createPositionalParameter(TreeMapper::TYPE_SHARE)]]> - createPositionalParameter(TreeMapper::TYPE_FOLDER)]]> - - - - - - - - - - - - - - getId()]]> - getId()]]> - - - - - createPositionalParameter(TreeMapper::TYPE_BOOKMARK)]]> - createPositionalParameter(TreeMapper::TYPE_BOOKMARK)]]> - - - - createPositionalParameter(TreeMapper::TYPE_BOOKMARK)]]> - bookmarkMapper->findAll($userId, $params)]]> @@ -133,19 +88,6 @@ - - - createPositionalParameter('bookmark')]]> - - - - - server]]> - - - - - @@ -161,11 +103,6 @@ - - - - - @@ -182,11 +119,6 @@ - - - - - getId()]]> @@ -206,9 +138,4 @@ - - - - - diff --git a/psalm.xml b/psalm.xml index c6ff140cd..8778c7014 100644 --- a/psalm.xml +++ b/psalm.xml @@ -5,7 +5,7 @@ ~ This file is licensed under the Affero General Public License version 3 or later. See the COPYING file. --> - - + + diff --git a/src/components/Controls.vue b/src/components/Controls.vue index d0df29f4e..112b8f2f8 100644 --- a/src/components/Controls.vue +++ b/src/components/Controls.vue @@ -20,7 +20,7 @@