diff --git a/appinfo/routes.php b/appinfo/routes.php index 488a0f849..f0b22403a 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -79,6 +79,7 @@ ['name' => 'view#create', 'url' => '/view', 'verb' => 'POST'], ['name' => 'view#update', 'url' => '/view/{id}', 'verb' => 'PUT'], ['name' => 'view#destroy', 'url' => '/view/{id}', 'verb' => 'DELETE'], + ['name' => 'view#createTemporaryView', 'url' => '/view/{tableId}/temporary-view', 'verb' => 'POST'], // columns ['name' => 'column#indexTableByView', 'url' => '/column/table/{tableId}/view/{viewId}', 'verb' => 'GET'], diff --git a/lib/Controller/ViewController.php b/lib/Controller/ViewController.php index 5587297dd..c72377ad5 100644 --- a/lib/Controller/ViewController.php +++ b/lib/Controller/ViewController.php @@ -95,6 +95,15 @@ public function update(int $id, array $data): DataResponse { }); } + /** + * @NoAdminRequired + */ + public function createTemporaryView(int $tableId, array $data): DataResponse { + return $this->handleError(function () use ($tableId, $data) { + return $this->service->createTemporaryView($tableId, $data, $this->userId); + }); + } + /** * @NoAdminRequired */ diff --git a/lib/Db/View.php b/lib/Db/View.php index 744ba9441..1376d3768 100644 --- a/lib/Db/View.php +++ b/lib/Db/View.php @@ -53,6 +53,10 @@ * @method setSort(string $sort) * @method getOwnerDisplayName(): string * @method setOwnerDisplayName(string $ownerDisplayName) + * @method getRows(): string + * @method setRows(string $rows) + * @method getColumnValues(): string + * @method setColumnValues(string $columnValues) */ class View extends Entity implements JsonSerializable { protected ?string $title = null; @@ -73,6 +77,8 @@ class View extends Entity implements JsonSerializable { protected ?int $rowsCount = 0; protected ?string $ownership = null; protected ?string $ownerDisplayName = null; + protected ?string $rows = null; + protected ?string $columnValues = null; public function __construct() { $this->addType('id', 'integer'); @@ -87,6 +93,16 @@ public function getColumnsArray(): array { return $this->getArray($this->getColumns()); } + + public function getRowsArray(): array { + return $this->getArray($this->getRows()); + } + + public function getColumnValuesArray(): array { + return $this->getArray($this->getColumnValues()); + } + + /** * @psalm-suppress MismatchingDocblockReturnType * @return list @@ -125,6 +141,14 @@ public function setColumnsArray(array $array):void { $this->setColumns(\json_encode($array)); } + public function setRowsArray(array $array):void { + $this->setRows(\json_encode($array)); + } + + public function setColumnValuesArray(array $array):void { + $this->setColumnValues(\json_encode($array)); + } + public function setSortArray(array $array):void { $this->setSort(\json_encode($array)); } @@ -168,6 +192,8 @@ public function jsonSerialize(): array { 'hasShares' => !!$this->hasShares, 'rowsCount' => $this->rowsCount ?: 0, 'ownerDisplayName' => $this->ownerDisplayName, + 'rows' => $this->getRowsArray(), + 'columnValues' => $this->getColumnValuesArray(), ]; $serialisedJson['filter'] = $this->getFilterArray(); diff --git a/lib/Service/ViewService.php b/lib/Service/ViewService.php index bd7e98bc0..61b95fb1a 100644 --- a/lib/Service/ViewService.php +++ b/lib/Service/ViewService.php @@ -17,6 +17,9 @@ use OCA\Tables\Db\Table; use OCA\Tables\Db\View; use OCA\Tables\Db\ViewMapper; +use OCA\Tables\Db\ColumnMapper; +use OCA\Tables\Db\Row2; +use OCA\Tables\Db\Row2Mapper; use OCA\Tables\Errors\InternalError; use OCA\Tables\Errors\NotFoundError; use OCA\Tables\Errors\PermissionError; @@ -40,6 +43,9 @@ class ViewService extends SuperService { private RowService $rowService; + private ColumnMapper $columnMapper; + private Row2Mapper $row2Mapper; + protected UserHelper $userHelper; protected FavoritesService $favoritesService; @@ -54,6 +60,8 @@ public function __construct( LoggerInterface $logger, ?string $userId, ViewMapper $mapper, + ColumnMapper $columnMapper, + Row2Mapper $row2Mapper, ShareService $shareService, RowService $rowService, UserHelper $userHelper, @@ -67,6 +75,8 @@ public function __construct( $this->mapper = $mapper; $this->shareService = $shareService; $this->rowService = $rowService; + $this->columnMapper = $columnMapper; + $this->row2Mapper = $row2Mapper; $this->userHelper = $userHelper; $this->favoritesService = $favoritesService; $this->eventDispatcher = $eventDispatcher; @@ -550,4 +560,123 @@ public function search(string $term, int $limit = 100, int $offset = 0, ?string return []; } } + + /** + * @param int $tableId + * @param array $data + * @param string|null $userId + * @return View + * @throws InternalError + * @throws PermissionError + * @throws InvalidArgumentException + */ + public function createTemporaryView(int $tableId, array $data, ?string $userId = null): View { + $userId = $this->permissionsService->preCheckUserId($userId); + + try { + // $table = $this->tableService->find($tableId); + + // // security + // if (!$this->permissionsService->canReadTable($table, $userId)) { + // throw new PermissionError('PermissionError: can not read table with id ' . $tableId); + // } + $this->logger->warning((string)$tableId.' , '.$userId); + + $view = new View(); + $view->setTableId($tableId); + $view->setOwnership($userId); + + $updatableParameter = ['title', 'emoji', 'description', 'columns', 'sort', 'filter']; + + foreach ($data as $key => $value) { + if (!in_array($key, $updatableParameter)) { + throw new InvalidArgumentException('Invalid parameter: ' . $key); + } + + switch ($key) { + case 'title': + $view->setTitle($value); + break; + case 'emoji': + $view->setEmoji($value); + break; + case 'description': + $view->setDescription($value); + break; + case 'columns': + $view->setColumnsArray($value); + break; + case 'sort': + $view->setSortArray($value); + break; + case 'filter': + $view->setFilterArray($value); + break; + } + } + $rows = $this->findRowsByView($tableId, $userId, $view); + $view->setRowsArray($rows); + $columnValues = $this->findColumnsByView($tableId, $view, $userId); + $view->setColumnValuesArray($columnValues); + + // $this->enhanceTemporaryView($view, $userId); + + return $view; + } catch (NotFoundError $e) { + $this->logger->error($e->getMessage(), ['exception' => $e]); + throw new InternalError('Table not found: ' . $tableId); + } catch (PermissionError $e) { + $this->logger->debug('permission error during creating temporary view', ['exception' => $e]); + throw $e; + } catch (Exception $e) { + $this->logger->error($e->getMessage(), ['exception' => $e]); + throw new InternalError($e->getMessage()); + } + } + + /** + * @param int $tableId + * @param string $userId + * @param View view + * @param int|null $limit + * @param int|null $offset + * @return Row2[] + * @throws DoesNotExistException + * @throws InternalError + * @throws MultipleObjectsReturnedException + * @throws PermissionError + */ + public function findRowsByView(int $tableId, string $userId, View $view, ?int $limit = null, ?int $offset = null): array { + try { + if ($this->permissionsService->canReadRowsByElementId($tableId, 'table', $userId)) { + $columnsArray = $view->getColumnsArray(); + $filterColumns = $this->columnMapper->findAll($columnsArray); + $tableColumns = $this->columnMapper->findAllByTable($view->getTableId()); + + return $this->row2Mapper->findAll($tableColumns, $filterColumns, $view->getTableId(), $limit, $offset, $view->getFilterArray(), $view->getSortArray(), $userId); + } else { + throw new PermissionError('no read access to table id = '.$tableId); + } + } catch (Exception $e) { + $this->logger->error($e->getMessage()); + throw new InternalError($e->getMessage()); + } + } + + + /** + * @param int $tableId + * @param View view + * @param string|null $userId + * @return array + * @throws NotFoundError + * @throws PermissionError + * @throws InternalError + */ + public function findColumnsByView(int $tableId, View $view, ?string $userId = null): array { + $viewColumnIds = $view->getColumnsArray(); + $viewColumns = $this->columnMapper->findAll($viewColumnIds); + return $viewColumns; + } + } diff --git a/src/modules/main/sections/Temp.vue b/src/modules/main/sections/Temp.vue new file mode 100644 index 000000000..50c92f66f --- /dev/null +++ b/src/modules/main/sections/Temp.vue @@ -0,0 +1,69 @@ + + + + diff --git a/src/pages/TemporaryView.vue b/src/pages/TemporaryView.vue new file mode 100644 index 000000000..6aa0013f5 --- /dev/null +++ b/src/pages/TemporaryView.vue @@ -0,0 +1,124 @@ + + + + + diff --git a/src/router.js b/src/router.js index 45ce7bd4c..210882b5a 100644 --- a/src/router.js +++ b/src/router.js @@ -9,6 +9,7 @@ import MainViewWrapper from './pages/View.vue' import MainDashboardWrapper from './pages/Table.vue' import Startpage from './pages/Startpage.vue' import Context from './pages/Context.vue' +import TemporaryView from './pages/TemporaryView.vue' Vue.use(Router) @@ -50,6 +51,11 @@ export default new Router({ component: MainViewWrapper, name: 'view', }, + { + path: '/tempview', + component: TemporaryView, + name: 'temporaryView', + }, { path: '/view/:viewId/content', component: MainViewWrapper, diff --git a/src/store/store.js b/src/store/store.js index 03d6ed4b4..0a01bb99d 100644 --- a/src/store/store.js +++ b/src/store/store.js @@ -221,6 +221,18 @@ export default new Vuex.Store({ return res.data.id }, + + async createTemporaryView({ commit, state }, { tableId, data }) { + let res = null + try { + res = await axios.post(generateUrl('/apps/tables/view/' + tableId + '/temporary-view'), { data }) + } catch (e) { + displayError(e, t('tables', 'Could not create temporary view.')) + return false + } + return res.data + }, + async updateView({ state, commit, dispatch }, { id, data }) { let res = null