Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 3 additions & 10 deletions lib/Analytics/AnalyticsDatasource.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,9 @@ public function getTemplate(): array {
// get all tables and subsequent views
foreach ($tables as $table) {
$tableString = $tableString . $table->getId() . '-' . $table->getTitle() . '/';
// get all views per table
try {
$views = $this->viewService->findAll($this->tableService->find($table->getId()), $this->userId);
foreach ($views as $view) {
// concatenate the option-string. The format is tableId:viewId-title
$tableString = $tableString . $table->getId() . ':' . $view->getId() . '-' . $view->getTitle() . '/';
}
} catch (PermissionError) {
// this is a shared table without shared views;
continue;
foreach ($table->getViews() ?? [] as $view) {
// concatenate the option-string. The format is tableId:viewId-title
$tableString = $tableString . $table->getId() . ':' . $view->getId() . '-' . $view->getTitle() . '/';
}
}

Expand Down
5 changes: 3 additions & 2 deletions lib/Controller/Api1Controller.php

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a downstream effect of the findAllSharesForNode change above, the list all shares" endpoint now returns only shares created by the current user. An owner will no longer see shares created by co-managers on their own table or view, so they cannot review or revoke them here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same for sharecontroller.php

Original file line number Diff line number Diff line change
Expand Up @@ -296,11 +296,12 @@ public function deleteTable(int $tableId): DataResponse {
#[NoAdminRequired]
#[NoCSRFRequired]
#[CORS]
#[RequirePermission(permission: Application::PERMISSION_READ, type: Application::NODE_TYPE_TABLE, idParam: 'tableId')]
#[RequirePermission(permission: Application::PERMISSION_MANAGE, type: Application::NODE_TYPE_TABLE, idParam: 'tableId')]
#[OpenAPI(scope: OpenAPI::SCOPE_DEFAULT)]
public function indexViews(int $tableId): DataResponse {
try {
return new DataResponse($this->viewService->formatViews($this->viewService->findAll($this->tableService->find($tableId))));
$table = $this->tableService->find($tableId);
return new DataResponse($this->viewService->formatViews($table->getViews() ?? []));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initially, we return 403 for read-only users . Now, read-only user gets 200 with an empty list, since enhanceTables only loads views for owned or managed tables. So we need to mofify the annotation?

} catch (PermissionError $e) {
$this->logger->warning('A permission error occurred: ' . $e->getMessage(), ['exception' => $e]);
$message = ['message' => $e->getMessage()];
Expand Down
36 changes: 21 additions & 15 deletions lib/Db/ColumnMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,24 +166,30 @@ public function getColumnTypes(array $neededColumnIds): array {
}

/**
* @param int $tableId
* @return int
* @param int[] $tableIds
* @return array<int, int>
*/
public function countColumns(int $tableId): int {
$qb = $this->db->getQueryBuilder();
$qb->select($qb->func()->count('*', 'counter'));
$qb->from($this->table);
$qb->where(
$qb->expr()->eq('table_id', $qb->createNamedParameter($tableId))
);
public function countColumnsForTables(array $tableIds): array {
if (empty($tableIds)) {
return [];
}

try {
$result = $this->findOneQuery($qb);
return (int)$result['counter'];
} catch (DoesNotExistException|MultipleObjectsReturnedException|Exception $e) {
$this->logger->warning('Exception occurred: ' . $e->getMessage() . ' Returning 0.');
return 0;
$counts = array_fill_keys($tableIds, 0);
foreach (array_chunk($tableIds, 1000 - 1) as $tableIdsChunk) {
$qb = $this->db->getQueryBuilder();
$qb->select('table_id', $qb->func()->count('*', 'counter'))
->from($this->table)
->where($qb->expr()->in('table_id', $qb->createNamedParameter($tableIdsChunk, IQueryBuilder::PARAM_INT_ARRAY)))
->groupBy('table_id');

$result = $qb->executeQuery();
while ($row = $result->fetch()) {
$counts[(int)$row['table_id']] = (int)$row['counter'];
}
$result->closeCursor();
Comment on lines +177 to +189

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

without try...catch, a \OCP\DB\Exception now propagates?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we really need that try/catch here? When exception should be possible here and we need to suppress it?

}

return $counts;
}

/**
Expand Down
7 changes: 6 additions & 1 deletion lib/Db/Row2Mapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -968,8 +968,13 @@ public function deleteAllForTable(int $tableId, array $columns): void {
}
}

/**
* @param int $tableId
* @return int
*/
public function countRowsForTable(int $tableId): int {
return $this->rowSleeveMapper->countRows($tableId);
$counts = $this->rowSleeveMapper->countRowsByTableIds([$tableId]);
return $counts[$tableId] ?? 0;
}

/**
Expand Down
38 changes: 22 additions & 16 deletions lib/Db/RowSleeveMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,24 +106,30 @@ public function deleteAllForTable(int $tableId): int {
}

/**
* @param int $tableId
* @return int
* @param int[] $tableIds
* @return array<int, int>
*/
public function countRows(int $tableId): int {
$qb = $this->db->getQueryBuilder();
$qb->select($qb->func()->count('*', 'counter'));
$qb->from($this->table, 't1');
$qb->where(
$qb->expr()->eq('table_id', $qb->createNamedParameter($tableId))
);

try {
$result = $this->findOneQuery($qb);
return (int)$result['counter'];
} catch (DoesNotExistException|MultipleObjectsReturnedException|Exception $e) {
$this->logger->warning('Exception occurred: ' . $e->getMessage() . ' Will return 0.');
return 0;
public function countRowsForTables(array $tableIds): array {
if (empty($tableIds)) {
return [];
}

$counts = array_fill_keys($tableIds, 0);
foreach (array_chunk($tableIds, 1000 - 1) as $tableIdsChunk) {
$qb = $this->db->getQueryBuilder();
$qb->select('table_id', $qb->func()->count('*', 'counter'))
->from($this->table)
->where($qb->expr()->in('table_id', $qb->createNamedParameter($tableIdsChunk, IQueryBuilder::PARAM_INT_ARRAY)))
->groupBy('table_id');

$result = $qb->executeQuery();
while ($row = $result->fetch()) {
$counts[(int)$row['table_id']] = (int)$row['counter'];
}
$result->closeCursor();
}

return $counts;
}

/**
Expand Down
76 changes: 73 additions & 3 deletions lib/Db/ShareMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public function findAllSharesFor(string $nodeType, array $receivers, string $use
return [];
}

$chunks = [];
$chunks = [[]];
// deduct extra parameters (sender, node type, receiver type)
foreach (array_chunk($receivers, 1000 - 3) as $receiversChunk) {
$qb = $this->db->getQueryBuilder();
Expand All @@ -119,12 +119,11 @@ public function findAllSharesFor(string $nodeType, array $receivers, string $use
/**
* @param string $nodeType
* @param int $nodeId
* @param string $sender
* @param array<string> $excluded receiver types to exclude from results
* @return Share[]
* @throws Exception
*/
public function findAllSharesForNode(string $nodeType, int $nodeId, string $sender = '', array $excluded = []): array {
public function findAllSharesForNode(string $nodeType, int $nodeId, array $excluded = []): array {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->table)
Expand All @@ -138,6 +137,77 @@ public function findAllSharesForNode(string $nodeType, int $nodeId, string $send
return $this->findEntities($qb);
}

/**
* @param string $nodeType
* @param int[] $nodeIds
* @param string $sender
* @param array<string> $excluded receiver types to exclude from results
* @return Share[]
* @throws Exception
*/
public function findAllSharesForNodes(string $nodeType, array $nodeIds, string $sender = '', array $excluded = []): array {
Comment thread
Koc marked this conversation as resolved.
if (empty($nodeIds)) {
return [];
}

$extraParams = 2;
if ($sender !== '') {
$extraParams++;
}
if (!empty($excluded)) {
$extraParams++;
}

$chunks = [[]];
foreach (array_chunk($nodeIds, 1000 - $extraParams) as $nodeIdsChunk) {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->table)
->andWhere($qb->expr()->eq('node_type', $qb->createNamedParameter($nodeType, IQueryBuilder::PARAM_STR)))
->andWhere($qb->expr()->in('node_id', $qb->createNamedParameter($nodeIdsChunk, IQueryBuilder::PARAM_INT_ARRAY)));

if ($sender !== '') {
$qb->andWhere($qb->expr()->eq('sender', $qb->createNamedParameter($sender, IQueryBuilder::PARAM_STR)));
}

if (!empty($excluded)) {
$qb->andWhere($qb->expr()->notIn('receiver_type', $qb->createNamedParameter($excluded, IQueryBuilder::PARAM_STR_ARRAY)));
}

$chunks[] = $this->findEntities($qb);
}

return array_merge(...$chunks);
}

/**
* @param int[] $tableIds
* @return int[]
*/
public function findLinkSharesForTables(array $tableIds): array {
if (empty($tableIds)) {
return [];
}

$linkTableIds = [];
foreach (array_chunk($tableIds, 1000 - 2) as $tableIdsChunk) {
$qb = $this->db->getQueryBuilder();
$qb->selectDistinct('node_id')
->from($this->table)
->andWhere($qb->expr()->eq('node_type', $qb->createNamedParameter('table', IQueryBuilder::PARAM_STR)))
->andWhere($qb->expr()->eq('receiver_type', $qb->createNamedParameter(ShareReceiverType::LINK, IQueryBuilder::PARAM_STR)))
->andWhere($qb->expr()->in('node_id', $qb->createNamedParameter($tableIdsChunk, IQueryBuilder::PARAM_INT_ARRAY)));

$result = $qb->executeQuery();
while ($row = $result->fetch()) {
$linkTableIds[] = (int)$row['node_id'];
}
$result->closeCursor();
}

return $linkTableIds;
}

/**
* @param string $nodeType
* @param int $nodeId
Expand Down
26 changes: 26 additions & 0 deletions lib/Db/ViewMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ public function insert(Entity $entity): View {
}

/**
* @deprecated Use {@link findAllByTableIds} instead
*
* @return View[]
* @throws Exception
*/
Expand All @@ -146,6 +148,30 @@ public function findAll(?int $tableId = null): array {
return $this->findEntities($qb);
}

/**
* @param int[] $tableIds
* @return View[]
* @throws Exception
*/
public function findAllByTableIds(array $tableIds): array {
if (empty($tableIds)) {
return [];
}

$chunks = [[]];
foreach (array_chunk($tableIds, self::DB_CHUNK_SIZE - 1) as $tableIdsChunk) {
$qb = $this->db->getQueryBuilder();
$qb->select('v.*', 't.ownership')
->from($this->table, 'v')
->innerJoin('v', 'tables_tables', 't', 't.id = v.table_id')
->where($qb->expr()->in('v.table_id', $qb->createNamedParameter($tableIdsChunk, IQueryBuilder::PARAM_INT_ARRAY)));

$chunks[] = $this->findEntities($qb);
}

return array_merge(...$chunks);
}

/**
* @return View[]
* @throws Exception
Expand Down
17 changes: 17 additions & 0 deletions lib/Helper/UserHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,23 @@ public function getUserDisplayName(string $userId): string {
}
}

/**
* @param string[] $userIds
* @return array<string, null|string>
*/
public function getUsersDisplayNames(array $userIds): array {
$displayNames = [];
foreach (array_unique($userIds) as $userId) {
if ($userId === '' || $userId === null) {
$displayNames[$userId] = $userId;
continue;
}
$displayName = $this->userManager->getDisplayName($userId);
$displayNames[$userId] = $displayName ?: $userId;
}
return $displayNames;
}

/**
* @throws InternalError
*/
Expand Down
24 changes: 16 additions & 8 deletions lib/Service/ColumnService.php
Original file line number Diff line number Diff line change
Expand Up @@ -668,16 +668,24 @@ public function findOrCreateColumnsByTitleForTableAsArray(?int $tableId, ?int $v
}

/**
* @param int $tableId
* @return int
* @throws PermissionError
* @param int[] $tableIds
* @param string|null $userId
* @return array<int, int>
*/
public function getColumnsCount(int $tableId): int {
if ($this->permissionsService->canReadColumnsByTableId($tableId)) {
return $this->mapper->countColumns($tableId);
} else {
throw new PermissionError('no read access for counting to table id = ' . $tableId);
public function getColumnsCountForTables(array $tableIds, ?string $userId = null): array {
$userId = $this->permissionsService->preCheckUserId($userId);
$readableTableIds = array_values(array_filter(
$tableIds,
fn (int $tableId): bool => $this->permissionsService->canReadColumnsByTableId($tableId, $userId),
));

$counts = $this->mapper->countColumnsForTables($readableTableIds);

$result = [];
foreach ($tableIds as $tableId) {
$result[$tableId] = $counts[$tableId] ?? 0;
}
return $result;
}

/**
Expand Down
25 changes: 7 additions & 18 deletions lib/Service/RowService.php
Original file line number Diff line number Diff line change
Expand Up @@ -860,28 +860,16 @@ public function deleteColumnDataFromRows(Column $column):void {
$this->row2Mapper->deleteDataForColumn($column);
}

/**
* @param int $tableId
* @return int
*
* @throws PermissionError
*/
public function getRowsCount(int $tableId): int {
if ($this->permissionsService->canReadRowsByElementId($tableId, 'table')) {
return $this->row2Mapper->countRowsForTable($tableId);
} else {
throw new PermissionError('no read access for counting to table id = ' . $tableId);
}
}

/**
* @param int[] $tableIds
* @param string|null $userId
* @return array<int, int>
*/
public function getRowsCountForTables(array $tableIds): array {
public function getRowsCountForTables(array $tableIds, ?string $userId = null): array {
$userId = $this->permissionsService->preCheckUserId($userId);
$readableTableIds = array_values(array_filter(
$tableIds,
fn (int $tableId): bool => $this->permissionsService->canReadRowsByElementId($tableId, 'table'),
fn (int $tableId): bool => $this->permissionsService->canReadRowsByElementId($tableId, 'table', $userId),
));

$counts = $this->row2Mapper->countRowsForTables($readableTableIds);
Expand All @@ -895,12 +883,13 @@ public function getRowsCountForTables(array $tableIds): array {

/**
* @param View $view
* @param string $userId
* @param string|null $userId
* @return int
*
* @throws PermissionError
*/
public function getViewRowsCount(View $view, string $userId): int {
public function getViewRowsCount(View $view, ?string $userId = null): int {
$userId = $this->permissionsService->preCheckUserId($userId);
if ($this->permissionsService->canReadRowsByElementId($view->getId(), 'view', $userId)) {
try {
return $this->row2Mapper->countRowsForView($view, $userId);
Expand Down
Loading
Loading