diff --git a/composer.json b/composer.json index 55890f7..e8c69bd 100644 --- a/composer.json +++ b/composer.json @@ -18,8 +18,7 @@ }, "require": { "php": ">=8.0", - "ext-pdo": "*", - "utopia-php/database": "0.33.*" + "utopia-php/database": "0.34.*" }, "require-dev": { "phpunit/phpunit": "^9.3", diff --git a/composer.lock b/composer.lock index 489100f..58ac377 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "916b34831c3963d2e03c950efa45abe3", + "content-hash": "4933f47ed6926e987299c0dc6b3b7a11", "packages": [ { "name": "composer/package-versions-deprecated", @@ -336,19 +336,20 @@ }, { "name": "utopia-php/database", - "version": "0.33.0", + "version": "0.34.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "7453256728053cddfb0c872ac8ca60157c4d8a11" + "reference": "c0b2d93cd5b867f9816d89aa7883dda7e8373ea5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/7453256728053cddfb0c872ac8ca60157c4d8a11", - "reference": "7453256728053cddfb0c872ac8ca60157c4d8a11", + "url": "https://api.github.com/repos/utopia-php/database/zipball/c0b2d93cd5b867f9816d89aa7883dda7e8373ea5", + "reference": "c0b2d93cd5b867f9816d89aa7883dda7e8373ea5", "shasum": "" }, "require": { + "ext-pdo": "*", "php": ">=8.0", "utopia-php/cache": "0.8.*", "utopia-php/framework": "0.*.*", @@ -358,11 +359,14 @@ "ext-mongodb": "*", "ext-redis": "*", "fakerphp/faker": "^1.14", + "laravel/pint": "1.4.*", "mongodb/mongodb": "1.8.0", + "pcov/clobber": "^2.0", + "phpstan/phpstan": "1.9.*", "phpunit/phpunit": "^9.4", + "rregeer/phpunit-coverage-check": "^0.3.1", "swoole/ide-helper": "4.8.0", - "utopia-php/cli": "^0.14.0", - "vimeo/psalm": "4.0.1" + "utopia-php/cli": "^0.14.0" }, "type": "library", "autoload": { @@ -374,7 +378,7 @@ "license": [ "MIT" ], - "description": "A simple library to manage application persistency using multiple database adapters", + "description": "A simple library to manage application persistence using multiple database adapters", "keywords": [ "database", "framework", @@ -384,9 +388,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.33.0" + "source": "https://github.com/utopia-php/database/tree/0.34.0" }, - "time": "2023-03-08T08:46:35+00:00" + "time": "2023-03-23T05:24:05+00:00" }, { "name": "utopia-php/framework", @@ -858,16 +862,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.6", + "version": "1.10.7", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "50d089a3e0904b0fe7e2cf2d4fd37d427d64235a" + "reference": "b10ceb526d9607903c5b2673f1fc8775dbe48975" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/50d089a3e0904b0fe7e2cf2d4fd37d427d64235a", - "reference": "50d089a3e0904b0fe7e2cf2d4fd37d427d64235a", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b10ceb526d9607903c5b2673f1fc8775dbe48975", + "reference": "b10ceb526d9607903c5b2673f1fc8775dbe48975", "shasum": "" }, "require": { @@ -896,8 +900,11 @@ "static analysis" ], "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.10.6" + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" }, "funding": [ { @@ -913,7 +920,7 @@ "type": "tidelift" } ], - "time": "2023-03-09T16:55:12+00:00" + "time": "2023-03-16T15:24:20+00:00" }, { "name": "phpunit/php-code-coverage", @@ -2356,8 +2363,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=8.0", - "ext-pdo": "*" + "php": ">=8.0" }, "platform-dev": [], "plugin-api-version": "2.3.0" diff --git a/src/Audit/Audit.php b/src/Audit/Audit.php index c9218fe..d7cb90a 100644 --- a/src/Audit/Audit.php +++ b/src/Audit/Audit.php @@ -2,11 +2,12 @@ namespace Utopia\Audit; -use Exception as GlobalException; use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; -use Utopia\Database\Exception\Duplicate; +use Utopia\Database\Exception\Authorization as AuthorizationException; +use Utopia\Database\Exception\Duplicate as DuplicateException; +use Utopia\Database\Exception\Structure as StructureException; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Exception; @@ -27,9 +28,8 @@ public function __construct(Database $db) * * @return void * - * @throws GlobalException - * @throws Exception - * @throws Duplicate + * @throws DuplicateException + * @throws \Exception */ public function setup(): void { @@ -159,6 +159,7 @@ public function setup(): void /** * Add event log. * + * @param string $userInternalId * @param string $userId * @param string $event * @param string $resource @@ -167,6 +168,11 @@ public function setup(): void * @param string $location * @param array $data * @return bool + * + * @throws AuthorizationException + * @throws StructureException + * @throws \Exception + * @throws \Throwable */ public function log(string $userInternalId, string $userId, string $event, string $resource, string $userAgent, string $ip, string $location, array $data = []): bool { @@ -192,21 +198,27 @@ public function log(string $userInternalId, string $userId, string $event, strin * Get all logs by user ID. * * @param string $userId - * @param int $limit - * @param int $offset + * @param int|null $limit + * @param int|null $offset * @param Document|null $orderAfter - * @return Document[] + * @return array + * + * @throws \Exception */ - public function getLogsByUser(string $userId, int $limit = 25, int $offset = 0, Document $orderAfter = null): array + public function getLogsByUser(string $userId, ?int $limit = null, ?int $offset = null, ?Document $orderAfter = null): array { - /** @var Document[] $result */ + /** @var array $result */ $result = Authorization::skip(function () use ($userId, $limit, $offset, $orderAfter) { - $queries = $this->buildQuery(['userId' => $userId], Query::TYPE_EQUAL); - - $queries[] = Query::limit($limit); - $queries[] = Query::offset($offset); + $queries[] = Query::equal('userId', [$userId]); $queries[] = Query::orderDesc(''); - if ($orderAfter) { + + if (! \is_null($limit)) { + $queries[] = Query::limit($limit); + } + if (! \is_null($offset)) { + $queries[] = Query::offset($offset); + } + if (! \is_null($orderAfter)) { $queries[] = Query::cursorAfter($orderAfter); } @@ -231,7 +243,7 @@ public function countLogsByUser(string $userId): int $count = Authorization::skip(function () use ($userId) { return $this->db->count( collection: Audit::COLLECTION, - queries: $this->buildQuery(['userId' => $userId], Query::TYPE_EQUAL) + queries: [Query::equal('userId', [$userId])] ); }); @@ -242,21 +254,27 @@ public function countLogsByUser(string $userId): int * Get all logs by resource. * * @param string $resource - * @param int $limit - * @param int $offset + * @param int|null $limit + * @param int|null $offset * @param Document|null $orderAfter - * @return Document[] + * @return array + * + * @throws \Exception */ - public function getLogsByResource(string $resource, int $limit = 25, int $offset = 0, Document $orderAfter = null): array + public function getLogsByResource(string $resource, ?int $limit = 25, ?int $offset = null, ?Document $orderAfter = null): array { - /** @var Document[] $results */ - $results = Authorization::skip(function () use ($resource, $limit, $offset, $orderAfter) { - $queries = $this->buildQuery(['resource' => $resource], Query::TYPE_EQUAL); - - $queries[] = Query::limit($limit); - $queries[] = Query::offset($offset); + /** @var array $result */ + $result = Authorization::skip(function () use ($resource, $limit, $offset, $orderAfter) { + $queries[] = Query::equal('resource', [$resource]); $queries[] = Query::orderDesc(''); - if ($orderAfter) { + + if (! \is_null($limit)) { + $queries[] = Query::limit($limit); + } + if (! \is_null($offset)) { + $queries[] = Query::offset($offset); + } + if (! \is_null($orderAfter)) { $queries[] = Query::cursorAfter($orderAfter); } @@ -266,7 +284,7 @@ public function getLogsByResource(string $resource, int $limit = 25, int $offset ); }); - return $results; + return $result; } /** @@ -274,14 +292,18 @@ public function getLogsByResource(string $resource, int $limit = 25, int $offset * * @param string $resource * @return int + * + * @throws \Exception */ public function countLogsByResource(string $resource): int { /** @var int $count */ - $count = Authorization::skip(fn () => $this->db->count( - collection: Audit::COLLECTION, - queries: $this->buildQuery(['resource' => $resource], Query::TYPE_EQUAL) - )); + $count = Authorization::skip(function () use ($resource) { + return $this->db->count( + collection: Audit::COLLECTION, + queries: [Query::equal('resource', [$resource])] + ); + }); return $count; } @@ -291,24 +313,28 @@ public function countLogsByResource(string $resource): int * * @param string $userId * @param array $events - * @param int $limit - * @param int $offset + * @param int|null $limit + * @param int|null $offset * @param Document|null $orderAfter - * @return Document[] + * @return array + * + * @throws \Exception */ - public function getLogsByUserAndEvents(string $userId, array $events, int $limit = 25, int $offset = 0, Document $orderAfter = null): array + public function getLogsByUserAndEvents(string $userId, array $events, ?int $limit = null, ?int $offset = null, ?Document $orderAfter = null): array { - /** @var Document[] $results */ - $results = Authorization::skip(function () use ($userId, $events, $limit, $offset, $orderAfter) { - $queries = $this->buildQuery([ - 'userId' => $userId, - 'event' => $events, - ], Query::TYPE_EQUAL); - - $queries[] = Query::limit($limit); - $queries[] = Query::offset($offset); + /** @var array $result */ + $result = Authorization::skip(function () use ($userId, $events, $limit, $offset, $orderAfter) { + $queries[] = Query::equal('userId', [$userId]); + $queries[] = Query::equal('event', $events); $queries[] = Query::orderDesc(''); - if ($orderAfter) { + + if (! \is_null($limit)) { + $queries[] = Query::limit($limit); + } + if (! \is_null($offset)) { + $queries[] = Query::offset($offset); + } + if (! \is_null($orderAfter)) { $queries[] = Query::cursorAfter($orderAfter); } @@ -318,7 +344,7 @@ public function getLogsByUserAndEvents(string $userId, array $events, int $limit ); }); - return $results; + return $result; } /** @@ -327,17 +353,21 @@ public function getLogsByUserAndEvents(string $userId, array $events, int $limit * @param string $userId * @param array $events * @return int + * + * @throws \Exception */ public function countLogsByUserAndEvents(string $userId, array $events): int { /** @var int $count */ - $count = Authorization::skip(fn () => $this->db->count( - collection: Audit::COLLECTION, - queries: $this->buildQuery([ - 'userId' => $userId, - 'event' => $events, - ], Query::TYPE_EQUAL) - )); + $count = Authorization::skip(function () use ($userId, $events) { + return $this->db->count( + collection: Audit::COLLECTION, + queries: [ + Query::equal('userId', [$userId]), + Query::equal('event', $events), + ] + ); + }); return $count; } @@ -347,24 +377,28 @@ public function countLogsByUserAndEvents(string $userId, array $events): int * * @param string $resource * @param array $events - * @param int $limit - * @param int $offset + * @param int|null $limit + * @param int|null $offset * @param Document|null $orderAfter - * @return Document[] + * @return array + * + * @throws \Exception */ - public function getLogsByResourceAndEvents(string $resource, array $events, int $limit = 25, int $offset = 0, Document $orderAfter = null): array + public function getLogsByResourceAndEvents(string $resource, array $events, ?int $limit = null, ?int $offset = null, ?Document $orderAfter = null): array { - /** @var Document[] $results */ - $results = Authorization::skip(function () use ($resource, $events, $limit, $offset, $orderAfter) { - $queries = $this->buildQuery([ - 'resource' => $resource, - 'event' => $events, - ], Query::TYPE_EQUAL); - - $queries[] = Query::limit($limit); - $queries[] = Query::offset($offset); + /** @var array $result */ + $result = Authorization::skip(function () use ($resource, $events, $limit, $offset, $orderAfter) { + $queries[] = Query::equal('resource', [$resource]); + $queries[] = Query::equal('event', $events); $queries[] = Query::orderDesc(''); - if ($orderAfter) { + + if (! \is_null($limit)) { + $queries[] = Query::limit($limit); + } + if (! \is_null($offset)) { + $queries[] = Query::offset($offset); + } + if (! \is_null($orderAfter)) { $queries[] = Query::cursorAfter($orderAfter); } @@ -374,7 +408,7 @@ public function getLogsByResourceAndEvents(string $resource, array $events, int ); }); - return $results; + return $result; } /** @@ -383,6 +417,8 @@ public function getLogsByResourceAndEvents(string $resource, array $events, int * @param string $resource * @param array $events * @return int + * + * @throws \Exception */ public function countLogsByResourceAndEvents(string $resource, array $events): int { @@ -390,10 +426,10 @@ public function countLogsByResourceAndEvents(string $resource, array $events): i $count = Authorization::skip(function () use ($resource, $events) { return $this->db->count( collection: Audit::COLLECTION, - queries: $this->buildQuery([ - 'resource' => $resource, - 'event' => $events, - ], Query::TYPE_EQUAL) + queries: [ + Query::equal('resource', [$resource]), + Query::equal('event', $events), + ] ); }); @@ -405,6 +441,9 @@ public function countLogsByResourceAndEvents(string $resource, array $events): i * * @param string $datetime * @return bool + * + * @throws AuthorizationException + * @throws \Exception */ public function cleanup(string $datetime): bool { @@ -412,9 +451,9 @@ public function cleanup(string $datetime): bool do { $documents = $this->db->find( collection: Audit::COLLECTION, - queries: $this->buildQuery([ - 'time' => $datetime, - ], Query::TYPE_LESSER) + queries: [ + Query::lessThan('time', $datetime), + ] ); foreach ($documents as $document) { @@ -425,33 +464,4 @@ public function cleanup(string $datetime): bool return true; } - - /** - * Builds an array of Query objects from - * an assoc array of $key => $value pairs - * - * The `$method` is applied to each k/v pair - * - * @param array $values - * @param string $method - * @return Query[] - * - * @throws Exception - */ - private function buildQuery(array $values, string $method): array - { - if (! Query::isMethod($method)) { - throw new Exception('Method not supported'); - } - - $query = []; - foreach ($values as $key => $value) { - if (! \is_array($value)) { - $value = [$value]; - } - $query[] = new Query($method, $key, $value); - } - - return $query; - } }