diff --git a/lib/Controller/Api1Controller.php b/lib/Controller/Api1Controller.php index 6ce68a54c..2fbed4948 100644 --- a/lib/Controller/Api1Controller.php +++ b/lib/Controller/Api1Controller.php @@ -728,7 +728,7 @@ public function indexViewColumns(int $viewId): DataResponse { * @param string|null $selectionOptions Options for a selection (json array{id: int, label: string}) * @param string|null $selectionDefault Default option IDs for a selection (json int[]) * @param string|null $datetimeDefault Default value, if column is datetime - * @param string|null $usergroupDefault Default value, if column is usergroup (json array{id: string, icon: string, isUser: bool, displayName: string}) + * @param string|null $usergroupDefault Default value, if column is usergroup (json array{id: string, type: int}) * @param bool|null $usergroupMultipleItems Can select multiple users or/and groups, if column is usergroup * @param bool|null $usergroupSelectUsers Can select users, if column type is usergroup * @param bool|null $usergroupSelectGroups Can select groups, if column type is usergroup diff --git a/lib/Controller/ApiColumnsController.php b/lib/Controller/ApiColumnsController.php index 9d6583672..163cf869b 100644 --- a/lib/Controller/ApiColumnsController.php +++ b/lib/Controller/ApiColumnsController.php @@ -334,7 +334,7 @@ public function createDatetimeColumn(int $baseNodeId, string $title, ?string $da * * @param int $baseNodeId Context of the column creation * @param string $title Title - * @param string|null $usergroupDefault Json array{id: string, isUser: bool, displayName: string}, eg [{"id": "admin", "isUser": true, "displayName": "admin"}, {"id": "user1", "isUser": true, "displayName": "user1"}] + * @param string|null $usergroupDefault Json array{id: string, type: int}, eg [{"id": "admin", "type": 0}, {"id": "user1", "type": 0}] * @param boolean $usergroupMultipleItems Whether you can select multiple users or/and groups * @param boolean $usergroupSelectUsers Whether you can select users * @param boolean $usergroupSelectGroups Whether you can select groups diff --git a/lib/Db/ColumnTypes/UsergroupColumnQB.php b/lib/Db/ColumnTypes/UsergroupColumnQB.php index 1453fa527..ccada8a50 100644 --- a/lib/Db/ColumnTypes/UsergroupColumnQB.php +++ b/lib/Db/ColumnTypes/UsergroupColumnQB.php @@ -6,10 +6,7 @@ class UsergroupColumnQB extends SuperColumnQB implements IColumnTypeQB { public function passSearchValue(IQueryBuilder $qb, string $unformattedSearchValue, string $operator, string $searchValuePlaceHolder): void { - if(substr($unformattedSearchValue, 0, 1) === '@') { - // TODO - } else { - $qb->setParameter($searchValuePlaceHolder, $unformattedSearchValue, IQueryBuilder::PARAM_STR); - } + // TODO how to handle searching for multiple users/groups? + $qb->setParameter($searchValuePlaceHolder, $unformattedSearchValue, IQueryBuilder::PARAM_STR); } } diff --git a/lib/Db/Row2Mapper.php b/lib/Db/Row2Mapper.php index 06deb17cf..b0988c781 100644 --- a/lib/Db/Row2Mapper.php +++ b/lib/Db/Row2Mapper.php @@ -58,7 +58,7 @@ public function delete(Row2 $row): Row2 { /** @var RowCellMapperSuper $cellMapper */ try { $cellMapper = Server::get($cellMapperClassName); - } catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) { + } catch (NotFoundExceptionInterface | ContainerExceptionInterface $e) { $this->logger->error($e->getMessage(), ['exception' => $e]); throw new Exception(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage()); } @@ -69,7 +69,7 @@ public function delete(Row2 $row): Row2 { } catch (Throwable $e) { $this->db->rollBack(); $this->logger->error($e->getMessage(), ['exception' => $e]); - throw new Exception(get_class($this) . ' - ' . __FUNCTION__ . ': '.$e->getMessage()); + throw new Exception(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage()); } return $row; @@ -91,11 +91,11 @@ public function find(int $id, array $columns): Row2 { } elseif (count($rows) === 0) { $e = new Exception('Wanted row not found.'); $this->logger->error($e->getMessage(), ['exception' => $e]); - throw new NotFoundError(get_class($this) . ' - ' . __FUNCTION__ . ': '.$e->getMessage()); + throw new NotFoundError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage()); } else { $e = new Exception('Too many results for one wanted row.'); $this->logger->error($e->getMessage(), ['exception' => $e]); - throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': '.$e->getMessage()); + throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage()); } } @@ -105,9 +105,9 @@ public function find(int $id, array $columns): Row2 { public function findNextId(int $offsetId = -1): ?int { try { $rowSleeve = $this->rowSleeveMapper->findNext($offsetId); - } catch (MultipleObjectsReturnedException|Exception $e) { + } catch (MultipleObjectsReturnedException | Exception $e) { $this->logger->error($e->getMessage(), ['exception' => $e]); - throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': '.$e->getMessage()); + throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage()); } catch (DoesNotExistException $e) { return null; } @@ -139,7 +139,7 @@ private function getWantedRowIds(string $userId, int $tableId, ?array $filter = $qb->select('id') ->from('tables_row_sleeves', 'sleeves') ->where($qb->expr()->eq('table_id', $qb->createNamedParameter($tableId, IQueryBuilder::PARAM_INT))); - if($filter) { + if ($filter) { $this->addFilterToQuery($qb, $filter, $userId); } if ($limit !== null) { @@ -195,7 +195,7 @@ private function getRows(array $rowIds, array $columnIds): array { $qbTmp = $this->db->getQueryBuilder(); $qbTmp->select('row_id', 'column_id', 'last_edit_at', 'last_edit_by') ->selectAlias($qb->expr()->castColumn('value', IQueryBuilder::PARAM_STR), 'value') - ->from('tables_row_cells_'.$columnType) + ->from('tables_row_cells_' . $columnType) ->where($qb->expr()->in('column_id', $qb->createNamedParameter($columnIds, IQueryBuilder::PARAM_INT_ARRAY, ':columnIds'))) ->andWhere($qb->expr()->in('row_id', $qb->createNamedParameter($rowIds, IQueryBuilder::PARAM_INT_ARRAY, ':rowsIds'))); @@ -222,7 +222,7 @@ private function getRows(array $rowIds, array $columnIds): array { $sleeves = $this->rowSleeveMapper->findMultiple($rowIds); } catch (Exception $e) { $this->logger->error($e->getMessage(), ['exception' => $e]); - throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': '.$e->getMessage()); + throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage()); } return $this->parseEntities($result, $sleeves); @@ -247,7 +247,7 @@ private function addFilterToQuery(IQueryBuilder &$qb, array $filters, string $us private function replacePlaceholderValues(array &$filters, string $userId): void { foreach ($filters as &$filterGroup) { foreach ($filterGroup as &$filter) { - if(substr($filter['value'], 0, 1) === '@') { + if (substr($filter['value'], 0, 1) === '@') { $filter['value'] = $this->resolveSearchValue($filter['value'], $userId); } } @@ -297,7 +297,7 @@ private function getFilter(IQueryBuilder &$qb, array $filterGroup): array { } else { $e = new Exception("Needed column (" . $columnId . ") not found."); $this->logger->error($e->getMessage(), ['exception' => $e]); - throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': '.$e->getMessage()); + throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage()); } $filterExpressions[] = $sql; } @@ -341,20 +341,20 @@ private function getFilterExpression(IQueryBuilder $qb, Column $column, string $ if ($column->getType() === 'selection' && $column->getSubtype() === 'multi') { $value = str_replace(['"', '\''], '', $value); $filterExpression = $qb2->expr()->orX( - $qb->expr()->like('value', $qb->createNamedParameter('['.$this->db->escapeLikeParameter($value).']')), - $qb->expr()->like('value', $qb->createNamedParameter('['.$this->db->escapeLikeParameter($value).',%')), - $qb->expr()->like('value', $qb->createNamedParameter('%,'.$this->db->escapeLikeParameter($value).']%')), - $qb->expr()->like('value', $qb->createNamedParameter('%,'.$this->db->escapeLikeParameter($value).',%')) + $qb->expr()->like('value', $qb->createNamedParameter('[' . $this->db->escapeLikeParameter($value) . ']')), + $qb->expr()->like('value', $qb->createNamedParameter('[' . $this->db->escapeLikeParameter($value) . ',%')), + $qb->expr()->like('value', $qb->createNamedParameter('%,' . $this->db->escapeLikeParameter($value) . ']%')), + $qb->expr()->like('value', $qb->createNamedParameter('%,' . $this->db->escapeLikeParameter($value) . ',%')) ); break; } - $filterExpression = $qb->expr()->like('value', $qb->createNamedParameter('%'.$this->db->escapeLikeParameter($value).'%', $paramType)); + $filterExpression = $qb->expr()->like('value', $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%', $paramType)); break; case 'is-equal': $includeDefault = $defaultValue === $value; if ($column->getType() === 'selection' && $column->getSubtype() === 'multi') { $value = str_replace(['"', '\''], '', $value); - $filterExpression = $qb->expr()->eq('value', $qb->createNamedParameter('['.$this->db->escapeLikeParameter($value).']', $paramType)); + $filterExpression = $qb->expr()->eq('value', $qb->createNamedParameter('[' . $this->db->escapeLikeParameter($value) . ']', $paramType)); break; } $filterExpression = $qb->expr()->eq('value', $qb->createNamedParameter($value, $paramType)); @@ -380,7 +380,7 @@ private function getFilterExpression(IQueryBuilder $qb, Column $column, string $ $filterExpression = $qb->expr()->isNull('value'); break; default: - throw new InternalError('Operator '.$operator.' is not supported.'); + throw new InternalError('Operator ' . $operator . ' is not supported.'); } return $qb2->andWhere( @@ -435,11 +435,11 @@ private function getMetaFilterExpression(IQueryBuilder $qb, int $columnId, strin private function getSqlOperator(string $operator, IQueryBuilder $qb, string $columnName, $value, $paramType): string { switch ($operator) { case 'begins-with': - return $qb->expr()->like($columnName, $qb->createNamedParameter('%'.$this->db->escapeLikeParameter($value), $paramType)); + return $qb->expr()->like($columnName, $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value), $paramType)); case 'ends-with': - return $qb->expr()->like($columnName, $qb->createNamedParameter($this->db->escapeLikeParameter($value).'%', $paramType)); + return $qb->expr()->like($columnName, $qb->createNamedParameter($this->db->escapeLikeParameter($value) . '%', $paramType)); case 'contains': - return $qb->expr()->like($columnName, $qb->createNamedParameter('%'.$this->db->escapeLikeParameter($value).'%', $paramType)); + return $qb->expr()->like($columnName, $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%', $paramType)); case 'is-equal': return $qb->expr()->eq($columnName, $qb->createNamedParameter($value, $paramType)); case 'is-greater-than': @@ -453,7 +453,7 @@ private function getSqlOperator(string $operator, IQueryBuilder $qb, string $col case 'is-empty': return $qb->expr()->isNull($columnName); default: - throw new InternalError('Operator '.$operator.' is not supported.'); + throw new InternalError('Operator ' . $operator . ' is not supported.'); } } @@ -540,7 +540,7 @@ public function isRowInViewPresent(int $rowId, View $view, string $userId): bool public function insert(Row2 $row, array $columns): Row2 { $this->setColumns($columns); - if($row->getId()) { + if ($row->getId()) { // if row has an id from migration or import etc. $rowSleeve = $this->createRowSleeveFromExistingData($row->getId(), $row->getTableId(), $row->getCreatedAt(), $row->getCreatedBy(), $row->getLastEditBy(), $row->getLastEditAt()); } else { @@ -564,7 +564,7 @@ public function insert(Row2 $row, array $columns): Row2 { * @throws InternalError */ public function update(Row2 $row, array $columns): Row2 { - if(!$columns) { + if (!$columns) { throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': columns are missing'); } $this->setColumns($columns); @@ -579,9 +579,9 @@ public function update(Row2 $row, array $columns): Row2 { $sleeve = $this->rowSleeveMapper->find($row->getId()); $this->updateMetaData($sleeve); $this->rowSleeveMapper->update($sleeve); - } catch (DoesNotExistException|MultipleObjectsReturnedException|Exception $e) { + } catch (DoesNotExistException | MultipleObjectsReturnedException | Exception $e) { $this->logger->error($e->getMessage(), ['exception' => $e]); - throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': '.$e->getMessage()); + throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage()); } // write all changed cells to its db-table @@ -648,32 +648,50 @@ private function insertCell(int $rowId, int $columnId, $value, ?string $lastEdit throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': '.$e->getMessage()); } - $cellClassName = 'OCA\Tables\Db\RowCell'.ucfirst($this->columns[$columnId]->getType()); - /** @var RowCellSuper $cell */ - $cell = new $cellClassName(); - - $cell->setRowIdWrapper($rowId); - $cell->setColumnIdWrapper($columnId); - $this->updateMetaData($cell, false, $lastEditAt, $lastEditBy); + $cellClassName = 'OCA\Tables\Db\RowCell' . ucfirst($this->columns[$columnId]->getType()); // insert new cell - $cellMapperClassName = 'OCA\Tables\Db\RowCell'.ucfirst($this->columns[$columnId]->getType()).'Mapper'; + $cellMapperClassName = 'OCA\Tables\Db\RowCell' . ucfirst($this->columns[$columnId]->getType()) . 'Mapper'; /** @var QBMapper $cellMapper */ try { $cellMapper = Server::get($cellMapperClassName); - } catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) { + } catch (NotFoundExceptionInterface | ContainerExceptionInterface $e) { $this->logger->error($e->getMessage(), ['exception' => $e]); - throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': '.$e->getMessage()); + throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage()); } $v = $this->formatValue($this->columns[$columnId], $value, 'in'); - $cell->setValueWrapper($v); - try { - $cellMapper->insert($cell); - } catch (Exception $e) { - $this->logger->error($e->getMessage(), ['exception' => $e]); - throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': '.$e->getMessage()); + if ($this->columns[$columnId]->getType() == 'usergroup') { + foreach ($v as $val) { + /** @var RowCellSuper $cell */ + $cell = new $cellClassName(); + $cell->setRowIdWrapper($rowId); + $cell->setColumnIdWrapper($columnId); + $this->updateMetaData($cell, false, $lastEditAt, $lastEditBy); + $cell->setValueWrapper((string)$val['id']); + $cell->setValueTypeWrapper((int)$val['type']); + try { + $cellMapper->insert($cell); + } catch (Exception $e) { + $this->logger->error($e->getMessage(), ['exception' => $e]); + throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage()); + } + } + } else { + /** @var RowCellSuper $cell */ + $cell = new $cellClassName(); + $cell->setRowIdWrapper($rowId); + $cell->setColumnIdWrapper($columnId); + $this->updateMetaData($cell, false, $lastEditAt, $lastEditBy); + $cell->setValueWrapper($v); + + try { + $cellMapper->insert($cell); + } catch (Exception $e) { + $this->logger->error($e->getMessage(), ['exception' => $e]); + throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage()); + } } } @@ -695,7 +713,8 @@ private function updateCell(RowCellSuper $cell, RowCellMapperSuper $mapper, $val * @throws InternalError */ private function insertOrUpdateCell(int $rowId, int $columnId, $value): void { - $cellMapperClassName = 'OCA\Tables\Db\RowCell'.ucfirst($this->columns[$columnId]->getType()).'Mapper'; + $columnType = $this->columns[$columnId]->getType(); + $cellMapperClassName = 'OCA\Tables\Db\RowCell'.ucfirst($columnType).'Mapper'; /** @var RowCellMapperSuper $cellMapper */ try { $cellMapper = Server::get($cellMapperClassName); @@ -703,14 +722,25 @@ private function insertOrUpdateCell(int $rowId, int $columnId, $value): void { $this->logger->error($e->getMessage(), ['exception' => $e]); throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': '.$e->getMessage()); } - try { - $cell = $cellMapper->findByRowAndColumn($rowId, $columnId); - $this->updateCell($cell, $cellMapper, $value, $this->columns[$columnId]); - } catch (DoesNotExistException $e) { - $this->insertCell($rowId, $columnId, $value); - } catch (MultipleObjectsReturnedException|Exception $e) { - $this->logger->error($e->getMessage(), ['exception' => $e]); - throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': '.$e->getMessage()); + if ($columnType == 'usergroup') { + try { + // TODO Maybe these should be a transaction? + $cellMapper->deleteAllForRow($row->getId()); + $this->insertCell($rowId, $columnId, $value); + } catch (Exception $e) { + $this->logger->error($e->getMessage(), ['exception' => $e]); + throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': '.$e->getMessage()); + } + } else { + try { + $cell = $cellMapper->findByRowAndColumn($rowId, $columnId); + $this->updateCell($cell, $cellMapper, $value, $this->columns[$columnId]); + } catch (DoesNotExistException $e) { + $this->insertCell($rowId, $columnId, $value); + } catch (MultipleObjectsReturnedException|Exception $e) { + $this->logger->error($e->getMessage(), ['exception' => $e]); + throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': '.$e->getMessage()); + } } } @@ -783,7 +813,7 @@ public function deleteDataForColumn(Column $column): void { $cellMapper->deleteAllForColumn($column->getId()); } catch (Exception $e) { $this->logger->error($e->getMessage(), ['exception' => $e]); - throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': '.$e->getMessage()); + throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage()); } } @@ -845,8 +875,10 @@ private function getFormattedDefaultValue(Column $column) { case Column::TYPE_TEXT: $defaultValue = $this->formatValue($column, $column->getTextDefault(), 'in'); break; + case Column::TYPE_USERGROUP: + $defaultValue = $this->formatValue($column, $column->getUsergroupDefault(), 'in'); + break; } return $defaultValue; } - } diff --git a/lib/Db/RowCellDatetime.php b/lib/Db/RowCellDatetime.php index 5ee46201b..fa4c0deaf 100644 --- a/lib/Db/RowCellDatetime.php +++ b/lib/Db/RowCellDatetime.php @@ -5,8 +5,9 @@ /** @template-extends RowCellSuper */ class RowCellDatetime extends RowCellSuper { protected ?string $value = null; + protected ?int $valueType = null; public function jsonSerialize(): array { - return parent::jsonSerializePreparation($this->value); + return parent::jsonSerializePreparation($this->value, $this->valueType); } } diff --git a/lib/Db/RowCellMapperSuper.php b/lib/Db/RowCellMapperSuper.php index 86f76509e..35f557a36 100644 --- a/lib/Db/RowCellMapperSuper.php +++ b/lib/Db/RowCellMapperSuper.php @@ -86,6 +86,21 @@ public function findByRowAndColumn(int $rowId, int $columnId): RowCellSuper { return $this->findEntity($qb); } + // /** + // * @throws MultipleObjectsReturnedException + // * @throws DoesNotExistException + // * @throws Exception + // */ + // public function findMultByRowAndColumn(int $rowId, int $columnId): array{ + // $qb = $this->db->getQueryBuilder(); + // $qb->select('*') + // ->from($this->tableName) + // ->where($qb->expr()->eq('row_id', $qb->createNamedParameter($rowId, IQueryBuilder::PARAM_INT))) + // ->andWhere($qb->expr()->eq('column_id', $qb->createNamedParameter($columnId, IQueryBuilder::PARAM_INT))); + // return $this->findEntities($qb); + // } + + /** * @throws MultipleObjectsReturnedException * @throws DoesNotExistException diff --git a/lib/Db/RowCellNumber.php b/lib/Db/RowCellNumber.php index c1d33f7a6..45e0f1c96 100644 --- a/lib/Db/RowCellNumber.php +++ b/lib/Db/RowCellNumber.php @@ -5,8 +5,9 @@ /** @template-extends RowCellSuper */ class RowCellNumber extends RowCellSuper { protected ?float $value = null; + protected ?int $valueType = null; public function jsonSerialize(): array { - return parent::jsonSerializePreparation($this->value); + return parent::jsonSerializePreparation($this->value, $this->valueType); } } diff --git a/lib/Db/RowCellSelection.php b/lib/Db/RowCellSelection.php index 42cc14202..9219944f3 100644 --- a/lib/Db/RowCellSelection.php +++ b/lib/Db/RowCellSelection.php @@ -5,8 +5,9 @@ /** @template-extends RowCellSuper */ class RowCellSelection extends RowCellSuper { protected ?string $value = null; + protected ?int $valueType = null; public function jsonSerialize(): array { - return parent::jsonSerializePreparation($this->value); + return parent::jsonSerializePreparation($this->value, $this->valueType); } } diff --git a/lib/Db/RowCellSuper.php b/lib/Db/RowCellSuper.php index e2d5962ec..9a0d7a287 100644 --- a/lib/Db/RowCellSuper.php +++ b/lib/Db/RowCellSuper.php @@ -15,6 +15,8 @@ * @method setRowId(int $rowId) * @method getValue(): string * @method setValue(string $value) + * @method getValueType(): int + * @method setValueType(int $valueType) * @method getCreatedBy(): string * @method setCreatedBy(string $createdBy) * @method getCreatedAt(): string @@ -38,15 +40,17 @@ public function __construct() { /** * @param float|null|string $value + * @param int $value_type */ - public function jsonSerializePreparation(string|float|null $value): array { + public function jsonSerializePreparation(string|float|null $value, int $valueType): array { return [ 'id' => $this->id, 'columnId' => $this->columnId, 'rowId' => $this->rowId, 'lastEditBy' => $this->lastEditBy, 'lastEditAt' => $this->lastEditAt, - 'value' => $value + 'value' => $value, + 'valueType' => $valueType ]; } @@ -61,4 +65,8 @@ public function setColumnIdWrapper(int $columnId) { public function setValueWrapper($value) { $this->setValue($value); } + + public function setValueTypeWrapper($valueType) { + $this->setValueType($valueType); + } } diff --git a/lib/Db/RowCellText.php b/lib/Db/RowCellText.php index 0650d7d8f..c64126f48 100644 --- a/lib/Db/RowCellText.php +++ b/lib/Db/RowCellText.php @@ -5,8 +5,9 @@ /** @template-extends RowCellSuper */ class RowCellText extends RowCellSuper { protected ?string $value = null; + protected ?int $valueType = null; public function jsonSerialize(): array { - return parent::jsonSerializePreparation($this->value); + return parent::jsonSerializePreparation($this->value, $this->valueType); } } diff --git a/lib/Db/RowCellUsergroup.php b/lib/Db/RowCellUsergroup.php index 73f85e4e9..3321070e5 100644 --- a/lib/Db/RowCellUsergroup.php +++ b/lib/Db/RowCellUsergroup.php @@ -5,8 +5,9 @@ /** @template-extends RowCellSuper */ class RowCellUsergroup extends RowCellSuper { protected ?string $value = null; + protected ?int $valueType = null; public function jsonSerialize(): array { - return parent::jsonSerializePreparation($this->value); + return parent::jsonSerializePreparation($this->value, $this->valueType); } } diff --git a/lib/Db/RowCellUsergroupMapper.php b/lib/Db/RowCellUsergroupMapper.php index 84ab446e1..792d16194 100644 --- a/lib/Db/RowCellUsergroupMapper.php +++ b/lib/Db/RowCellUsergroupMapper.php @@ -15,10 +15,9 @@ public function __construct(IDBConnection $db) { /** * @inheritDoc */ - public function parseValueIncoming(Column $column, $value): string { - // need to convert from array to string before saving - // TODO figure out whether to handle these conversions in the BE or FE; confusing to have both - return json_encode($value); + public function parseValueIncoming(Column $column, $value): array { + return json_decode(json_encode($value), true); + //return json_encode($value); } /** diff --git a/lib/Migration/Version000400Date20230406000000.php b/lib/Migration/Version000400Date20230406000000.php index 9cb722b25..d4dfda99f 100644 --- a/lib/Migration/Version000400Date20230406000000.php +++ b/lib/Migration/Version000400Date20230406000000.php @@ -39,6 +39,9 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt $column->setLength(65535); $column->setType(Type::getType('text')); + $column = $table->getColumn('usergroup_default'); + $column->setLength(65535); + $column = $table->getColumn('text_default'); $column->setLength(65535); $column->setType(Type::getType('text')); diff --git a/lib/Migration/Version000700Date20230916000000.php b/lib/Migration/Version000700Date20230916000000.php index ccd6ed084..b0c8544bb 100644 --- a/lib/Migration/Version000700Date20230916000000.php +++ b/lib/Migration/Version000700Date20230916000000.php @@ -76,6 +76,7 @@ private function createRowValueTable(ISchemaWrapper $schema, string $name, strin $table->addColumn('column_id', Types::INTEGER, ['notnull' => true]); $table->addColumn('row_id', Types::INTEGER, ['notnull' => true]); $table->addColumn('value', $type, ['notnull' => false]); + $table->addColumn('value_type', Types::INTEGER, ['notnull' => false]); // we will write this data to use it one day to extract versions of rows based on the timestamp $table->addColumn('last_edit_at', Types::DATETIME, ['notnull' => true]); $table->addColumn('last_edit_by', Types::STRING, ['notnull' => true, 'length' => 64]); diff --git a/lib/Service/ColumnTypes/UsergroupBusiness.php b/lib/Service/ColumnTypes/UsergroupBusiness.php index 62d351aa1..bd390f9e1 100644 --- a/lib/Service/ColumnTypes/UsergroupBusiness.php +++ b/lib/Service/ColumnTypes/UsergroupBusiness.php @@ -25,7 +25,7 @@ public function parseValue($value, ?Column $column = null): string { } /** - * @param mixed $value array{id: string, isUser: bool, displayName: string} + * @param mixed $value array{id: string, type: int} * @param Column|null $column * @return bool */ @@ -41,7 +41,7 @@ public function canBeParsed($value, ?Column $column = null): bool { foreach ($value as $v) { // TODO: maybe check if key exists first - if(!is_string($v['id']) && !is_string($v['displayName']) && !is_bool($v['isUser'])) { + if((array_key_exists('id', $v) && !is_string($v['id'])) && (array_key_exists('type', $v) && !is_int($v['type']))) { return false; } } diff --git a/openapi.json b/openapi.json index 20c5828f7..2f7da1097 100644 --- a/openapi.json +++ b/openapi.json @@ -3388,7 +3388,7 @@ { "name": "usergroupDefault", "in": "query", - "description": "Default value, if column is usergroup (json array{id: string, icon: string, isUser: bool, displayName: string})", + "description": "Default value, if column is usergroup (json array{id: string, type: int})", "schema": { "type": "string", "nullable": true, @@ -7788,7 +7788,7 @@ { "name": "usergroupDefault", "in": "query", - "description": "Json array{id: string, isUser: bool, displayName: string}, eg [{\"id\": \"admin\", \"isUser\": true, \"displayName\": \"admin\"}, {\"id\": \"user1\", \"isUser\": true, \"displayName\": \"user1\"}]", + "description": "Json array{id: string, type: int}, eg [{\"id\": \"admin\", \"type\": 0}, {\"id\": \"user1\", \"type\": 0}]", "schema": { "type": "string", "nullable": true diff --git a/src/types/openapi/openapi.ts b/src/types/openapi/openapi.ts index b66ada532..f40ab776e 100644 --- a/src/types/openapi/openapi.ts +++ b/src/types/openapi/openapi.ts @@ -1635,7 +1635,7 @@ export type operations = { selectionDefault?: string | null; /** @description Default value, if column is datetime */ datetimeDefault?: string | null; - /** @description Default value, if column is usergroup (json array{id: string, icon: string, isUser: bool, displayName: string}) */ + /** @description Default value, if column is usergroup (json array{id: string, type: int}) */ usergroupDefault?: string | null; /** @description Can select multiple users or/and groups, if column is usergroup */ usergroupMultipleItems?: 0 | 1 | null; @@ -3410,7 +3410,7 @@ export type operations = { baseNodeId: number; /** @description Title */ title: string; - /** @description Json array{id: string, isUser: bool, displayName: string}, eg [{"id": "admin", "isUser": true, "displayName": "admin"}, {"id": "user1", "isUser": true, "displayName": "user1"}] */ + /** @description Json array{id: string, type: int}, eg [{"id": "admin", "type": 0}, {"id": "user1", "type": 0}] */ usergroupDefault?: string | null; /** @description Whether you can select multiple users or/and groups */ usergroupMultipleItems?: 0 | 1; diff --git a/tests/integration/features/APIv2.feature b/tests/integration/features/APIv2.feature index bc17ce833..56e218729 100644 --- a/tests/integration/features/APIv2.feature +++ b/tests/integration/features/APIv2.feature @@ -98,7 +98,7 @@ Feature: APIv2 Given table "Table 5" with emoji "👋" exists for user "participant1-v2" as "t5" via v2 Then column from main type "usergroup" for node type "table" and node name "t5" exists with name "ug-c1" and following properties via v2 | title | ug column | - | usergroupDefault | [{"id": "admin", "displayName": "admin", "isUser": true}] | + | usergroupDefault | [{"id": "admin", "type": 0}] | Then node with node type "table" and node name "t5" has the following columns via v2 | ug column | Then print register