Skip to content

Commit

Permalink
Merge pull request #959 from hweihwang/feat/956
Browse files Browse the repository at this point in the history
  • Loading branch information
juliushaertl committed Apr 16, 2024
2 parents 38705d2 + f82b6df commit 6c85f7e
Show file tree
Hide file tree
Showing 21 changed files with 526 additions and 11 deletions.
17 changes: 17 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,31 @@
use Exception;
use OCA\Analytics\Datasource\DatasourceEvent;
use OCA\Tables\Capabilities;
use OCA\Tables\Event\RowDeletedEvent;
use OCA\Tables\Event\TableDeletedEvent;
use OCA\Tables\Event\TableOwnershipTransferredEvent;
use OCA\Tables\Event\ViewDeletedEvent;
use OCA\Tables\Listener\AnalyticsDatasourceListener;
use OCA\Tables\Listener\BeforeTemplateRenderedListener;
use OCA\Tables\Listener\LoadAdditionalListener;
use OCA\Tables\Listener\TablesReferenceListener;
use OCA\Tables\Listener\UserDeletedListener;
use OCA\Tables\Listener\WhenRowDeletedAuditLogListener;
use OCA\Tables\Listener\WhenTableDeletedAuditLogListener;
use OCA\Tables\Listener\WhenTableTransferredAuditLogListener;
use OCA\Tables\Listener\WhenViewDeletedAuditLogListener;
use OCA\Tables\Middleware\PermissionMiddleware;
use OCA\Tables\Reference\ContentReferenceProvider;
use OCA\Tables\Reference\ReferenceProvider;
use OCA\Tables\Search\SearchTablesProvider;
use OCA\Tables\Service\Support\AuditLogServiceInterface;
use OCA\Tables\Service\Support\DefaultAuditLogService;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent;
use OCP\AppFramework\IAppContainer;
use OCP\Collaboration\Reference\RenderReferenceEvent;
use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent;
use OCP\User\Events\BeforeUserDeletedEvent;
Expand Down Expand Up @@ -54,11 +65,17 @@ public function register(IRegistrationContext $context): void {
throw new Exception('Cannot include autoload. Did you run install dependencies using composer?');
}

$context->registerService(AuditLogServiceInterface::class, fn (IAppContainer $c) => $c->query(DefaultAuditLogService::class));

$context->registerEventListener(BeforeUserDeletedEvent::class, UserDeletedListener::class);
$context->registerEventListener(DatasourceEvent::class, AnalyticsDatasourceListener::class);
$context->registerEventListener(RenderReferenceEvent::class, TablesReferenceListener::class);
$context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class);
$context->registerEventListener(LoadAdditionalScriptsEvent::class, LoadAdditionalListener::class);
$context->registerEventListener(TableDeletedEvent::class, WhenTableDeletedAuditLogListener::class);
$context->registerEventListener(ViewDeletedEvent::class, WhenViewDeletedAuditLogListener::class);
$context->registerEventListener(RowDeletedEvent::class, WhenRowDeletedAuditLogListener::class);
$context->registerEventListener(TableOwnershipTransferredEvent::class, WhenTableTransferredAuditLogListener::class);

$context->registerSearchProvider(SearchTablesProvider::class);

Expand Down
14 changes: 12 additions & 2 deletions lib/Db/LegacyRowMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,12 @@ private function getInnerFilterExpressions($qb, $filterGroup, int $groupIndex):
return $innerFilterExpressions;
}

private function getFilterGroups($qb, $filters): array {
/**
* @param (float|int|string)[][][] $filters
*
* @psalm-param non-empty-list<list<array{columnId: int, operator: 'begins-with'|'contains'|'ends-with'|'is-empty'|'is-equal'|'is-greater-than'|'is-greater-than-or-equal'|'is-lower-than'|'is-lower-than-or-equal', value: float|int|string}>> $filters
*/
private function getFilterGroups(IQueryBuilder $qb, array $filters): array {
$filterGroups = [];
foreach ($filters as $groupIndex => $filterGroup) {
$filterGroups[] = $qb->expr()->andX(...$this->getInnerFilterExpressions($qb, $filterGroup, $groupIndex));
Expand Down Expand Up @@ -149,7 +154,12 @@ private function resolveSearchValue(string $unresolvedSearchValue, string $userI
}
}

private function addOrderByRules(IQueryBuilder $qb, $sortArray) {
/**
* @param (int|string)[][] $sortArray
*
* @psalm-param list<array{columnId?: int, columnType?: string, mode?: 'ASC'|'DESC'}> $sortArray
*/
private function addOrderByRules(IQueryBuilder $qb, array $sortArray) {
foreach ($sortArray as $index => $sortRule) {
$sortMode = $sortRule['mode'];
if (!in_array($sortMode, ['ASC', 'DESC'])) {
Expand Down
5 changes: 4 additions & 1 deletion lib/Db/RowCellSuper.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ public function __construct() {
$this->addType('rowId', 'integer');
}

public function jsonSerializePreparation($value): array {
/**
* @param float|null|string $value
*/
public function jsonSerializePreparation(string|float|null $value): array {
return [
'id' => $this->id,
'columnId' => $this->columnId,
Expand Down
18 changes: 18 additions & 0 deletions lib/Event/RowDeletedEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Event;

use OCA\Tables\Db\Row2;
use OCP\EventDispatcher\Event;

final class RowDeletedEvent extends Event {
public function __construct(protected Row2 $row) {
parent::__construct();
}

public function getRow(): Row2 {
return $this->row;
}
}
18 changes: 18 additions & 0 deletions lib/Event/TableDeletedEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Event;

use OCA\Tables\Db\Table;
use OCP\EventDispatcher\Event;

final class TableDeletedEvent extends Event {
public function __construct(protected Table $table) {
parent::__construct();
}

public function getTable(): Table {
return $this->table;
}
}
26 changes: 26 additions & 0 deletions lib/Event/TableOwnershipTransferredEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Event;

use OCA\Tables\Db\Table;
use OCP\EventDispatcher\Event;

final class TableOwnershipTransferredEvent extends Event {
public function __construct(protected Table $table, protected string $toUserId, protected ?string $fromUserId = null) {
parent::__construct();
}

public function getTable(): Table {
return $this->table;
}

public function getFromUserId(): string|null {
return $this->fromUserId;
}

public function getToUserId(): string {
return $this->toUserId;
}
}
18 changes: 18 additions & 0 deletions lib/Event/ViewDeletedEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Event;

use OCA\Tables\Db\View;
use OCP\EventDispatcher\Event;

final class ViewDeletedEvent extends Event {
public function __construct(protected View $view) {
parent::__construct();
}

public function getView(): View {
return $this->view;
}
}
31 changes: 31 additions & 0 deletions lib/Listener/WhenRowDeletedAuditLogListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Listener;

use OCA\Tables\Event\RowDeletedEvent;
use OCA\Tables\Service\Support\AuditLogServiceInterface;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;

/**
* @template-implements IEventListener<Event|RowDeletedEvent>
*/
final class WhenRowDeletedAuditLogListener implements IEventListener {
public function __construct(protected AuditLogServiceInterface $auditLogService) {
}

public function handle(Event $event): void {
if (!($event instanceof RowDeletedEvent)) {
return;
}

$row = $event->getRow();
$rowId = $row->getId();

$this->auditLogService->log("Row with ID: $rowId was deleted", [
'row' => $row->jsonSerialize(),
]);
}
}
30 changes: 30 additions & 0 deletions lib/Listener/WhenTableDeletedAuditLogListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Listener;

use OCA\Tables\Event\TableDeletedEvent;
use OCA\Tables\Service\Support\AuditLogServiceInterface;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;

/**
* @template-implements IEventListener<Event|TableDeletedEvent>
*/
final class WhenTableDeletedAuditLogListener implements IEventListener {
public function __construct(protected AuditLogServiceInterface $auditLogService) {
}

public function handle(Event $event): void {
if (!($event instanceof TableDeletedEvent)) {
return;
}

$table = $event->getTable();

$this->auditLogService->log("Table with ID: $table->id was deleted", [
'table' => $table->jsonSerialize(),
]);
}
}
34 changes: 34 additions & 0 deletions lib/Listener/WhenTableTransferredAuditLogListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Listener;

use OCA\Tables\Event\TableOwnershipTransferredEvent;
use OCA\Tables\Service\Support\AuditLogServiceInterface;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;

/**
* @template-implements IEventListener<Event|TableOwnershipTransferredEvent>
*/
final class WhenTableTransferredAuditLogListener implements IEventListener {
public function __construct(protected AuditLogServiceInterface $auditLogService) {
}

public function handle(Event $event): void {
if (!($event instanceof TableOwnershipTransferredEvent)) {
return;
}

$table = $event->getTable();
$fromUserId = $event->getFromUserId();
$toUserId = $event->getToUserId();

$this->auditLogService->log("Table with ID: $table->id was transferred from user with ID: $fromUserId to user with ID: $toUserId", [
'table' => $table->jsonSerialize(),
'fromUserId' => $fromUserId,
'toUserId' => $toUserId,
]);
}
}
30 changes: 30 additions & 0 deletions lib/Listener/WhenViewDeletedAuditLogListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Listener;

use OCA\Tables\Event\ViewDeletedEvent;
use OCA\Tables\Service\Support\AuditLogServiceInterface;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;

/**
* @template-implements IEventListener<Event|ViewDeletedEvent>
*/
final class WhenViewDeletedAuditLogListener implements IEventListener {
public function __construct(protected AuditLogServiceInterface $auditLogService) {
}

public function handle(Event $event): void {
if (!($event instanceof ViewDeletedEvent)) {
return;
}

$view = $event->getView();

$this->auditLogService->log("View with ID: $view->id was deleted", [
'view' => $view->jsonSerialize(),
]);
}
}
25 changes: 22 additions & 3 deletions lib/Service/RowService.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
use OCA\Tables\Errors\InternalError;
use OCA\Tables\Errors\NotFoundError;
use OCA\Tables\Errors\PermissionError;
use OCA\Tables\Event\RowDeletedEvent;
use OCA\Tables\ResponseDefinitions;
use OCA\Tables\Service\ColumnTypes\IColumnTypeBusiness;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\DB\Exception;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Server;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
Expand All @@ -33,13 +35,24 @@ class RowService extends SuperService {
private Row2Mapper $row2Mapper;
private array $tmpRows = []; // holds already loaded rows as a small cache

public function __construct(PermissionsService $permissionsService, LoggerInterface $logger, ?string $userId,
ColumnMapper $columnMapper, ViewMapper $viewMapper, TableMapper $tableMapper, Row2Mapper $row2Mapper) {
protected IEventDispatcher $eventDispatcher;

public function __construct(
PermissionsService $permissionsService,
LoggerInterface $logger,
?string $userId,
ColumnMapper $columnMapper,
ViewMapper $viewMapper,
TableMapper $tableMapper,
Row2Mapper $row2Mapper,
IEventDispatcher $eventDispatcher
) {
parent::__construct($logger, $userId, $permissionsService);
$this->columnMapper = $columnMapper;
$this->viewMapper = $viewMapper;
$this->tableMapper = $tableMapper;
$this->row2Mapper = $row2Mapper;
$this->eventDispatcher = $eventDispatcher;
}

/**
Expand Down Expand Up @@ -450,7 +463,13 @@ public function delete(int $id, ?int $viewId, string $userId): Row2 {
}

try {
return $this->filterRowResult($view ?? null, $this->row2Mapper->delete($item));
$deletedRow = $this->row2Mapper->delete($item);

$event = new RowDeletedEvent(row: $item);

$this->eventDispatcher->dispatchTyped($event);

return $this->filterRowResult($view ?? null, $deletedRow);
} catch (Exception $e) {
$this->logger->error($e->getMessage(), ['exception' => $e]);
throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': '.$e->getMessage());
Expand Down
9 changes: 9 additions & 0 deletions lib/Service/Support/AuditLogServiceInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Service\Support;

interface AuditLogServiceInterface {
public function log(string $message, array $context): void;
}
19 changes: 19 additions & 0 deletions lib/Service/Support/DefaultAuditLogService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Service\Support;

use OCP\EventDispatcher\IEventDispatcher;
use OCP\Log\Audit\CriticalActionPerformedEvent;

final class DefaultAuditLogService implements AuditLogServiceInterface {
public function __construct(private IEventDispatcher $eventDispatcher) {
}

public function log(string $message, array $context): void {
$auditEvent = new CriticalActionPerformedEvent($message, $context);

$this->eventDispatcher->dispatchTyped($auditEvent);
}
}
Loading

0 comments on commit 6c85f7e

Please sign in to comment.