From 4f06203f16a19668e776b31f9203025d957179cc Mon Sep 17 00:00:00 2001 From: johguentner Date: Thu, 2 Feb 2023 14:58:10 +0100 Subject: [PATCH 01/61] very prototypical implementation for NotionModels - command for creating NotionModels - add Notion Models for simple interation with Notion databases - add NotionQueryBuilder for simple query-behaviour for Notion databases (similar to eloquent) --- src/Console/Commands/MakeNotionModel.php | 98 ++++++++ src/LaravelNotionApiServiceProvider.php | 9 +- src/Models/NotionModel.php | 146 ++++++++++++ src/Models/NotionQueryBuilder.php | 270 +++++++++++++++++++++++ 4 files changed, 521 insertions(+), 2 deletions(-) create mode 100644 src/Console/Commands/MakeNotionModel.php create mode 100644 src/Models/NotionModel.php create mode 100644 src/Models/NotionQueryBuilder.php diff --git a/src/Console/Commands/MakeNotionModel.php b/src/Console/Commands/MakeNotionModel.php new file mode 100644 index 0000000..d95aa29 --- /dev/null +++ b/src/Console/Commands/MakeNotionModel.php @@ -0,0 +1,98 @@ +argument('database_id'); + $databaseName = $this->argument('database_name'); + + $notion = new Notion(config('laravel-notion-api.notion-api-token')); + + $this->info("Fetching structure of {$databaseId} database from Notion..."); + + $databaseStruct = $notion->databases()->find($databaseId); + $phpDocsProperties = ""; + $visibleArray = ""; + $propertyTypeMape = ""; + $propertyTitleMap = ""; + + if ($databaseName === null) { + $databaseName = Str::singular(Str::studly(Str::slug($databaseStruct->getTitle(), '_'))); + } + + foreach ($databaseStruct->getProperties() as $propertyInfo) { + $reflection = new \ReflectionMethod($propertyInfo, 'getContent'); + $propType = $reflection->getReturnType() ?? 'mixed'; + $notionPropType = Str::studly(Str::slug($propertyInfo->getType(), '_')); + + if ($reflection->getReturnType() !== null && !$propType->isBuiltin()) { + $propType = '\\' . $propType->getName(); + } + + $propName = Str::slug($propertyInfo->getTitle(), '_'); + $phpDocsProperties .= " * @property {$propType} \${$propName} $notionPropType \n"; + $visibleArray .= " '$propName',\n"; + } + + + + $contents = "info("Model for database {$this->argument('database_id')} has been created at 'app/NotionModels/$databaseName.php' ."); + return 0; + } +} diff --git a/src/LaravelNotionApiServiceProvider.php b/src/LaravelNotionApiServiceProvider.php index 353b6f0..9650f93 100644 --- a/src/LaravelNotionApiServiceProvider.php +++ b/src/LaravelNotionApiServiceProvider.php @@ -2,6 +2,7 @@ namespace FiveamCode\LaravelNotionApi; +use FiveamCode\LaravelNotionApi\Console\Commands\MakeNotionModel; use Illuminate\Support\ServiceProvider; /** @@ -16,8 +17,12 @@ public function boot() { if ($this->app->runningInConsole()) { $this->publishes([ - __DIR__.'/../config/config.php' => config_path('laravel-notion-api.php'), + __DIR__ . '/../config/config.php' => config_path('laravel-notion-api.php'), ], 'config'); + + $this->commands([ + MakeNotionModel::class, + ]); } } @@ -27,7 +32,7 @@ public function boot() public function register() { // Automatically apply the package configuration - $this->mergeConfigFrom(__DIR__.'/../config/config.php', 'laravel-notion-api'); + $this->mergeConfigFrom(__DIR__ . '/../config/config.php', 'laravel-notion-api'); $this->app->singleton(Notion::class, function () { return new Notion(config('laravel-notion-api.notion-api-token'), config('laravel-notion-api.version')); diff --git a/src/Models/NotionModel.php b/src/Models/NotionModel.php new file mode 100644 index 0000000..f4e49bf --- /dev/null +++ b/src/Models/NotionModel.php @@ -0,0 +1,146 @@ + + */ + public static ?Collection $cursorHistory = null; + + /** + * @var string + */ + public static $databaseId = null; + + /** + * @var string + */ + public static $preCacheKey = 'laravel-notion-api.notion-model-'; + + /** + * @var int + */ + public static $cacheDurationInSeconds = 0; + + /** + * @var boolean + */ + public static $convertPropsToText = false; + + public $props; + + public Page $page; + + + public function __construct($databaseId = null) + { + if ($databaseId == null) { + $databaseId = static::$databaseId; + } + } + + public static function createInstance(){ + return new static(); + } + + + /** + * @return string + */ + public static function databaseId(): string + { + if (static::$databaseId !== null) { + return static::$databaseId; + } + throw new \Exception('::getDatabaseId() or ::databaseId must be overridden'); + } + + /** + * @return + */ + public static function notionInstance(): Notion + { + return new Notion(config('laravel-notion-api.notion-api-token')); + } + + /** + * @return NotionModel + */ + public static function query(): NotionQueryBuilder + { + return new NotionQueryBuilder(static::class); + } + + /** + * @return void + */ + public static function purge(): void + { + Cache::forget(static::cacheKey()); + } + + public static function all() + { + return self::query()->get(); + } + + + + /** + * @return ?static + */ + public static function first() + { + return static::query() + ->limit(1) + ->get() + ->first(); + } + + /** + * @return static + */ + public static function find($pageId): Page + { + $page = static::notionInstance() + ->pages() + ->find($pageId); + + if ($page === null) { + return null; + } + + if (str_replace('-', '', $page->getParentId()) !== str_replace('-', '', static::databaseId())) { + throw new HandlingException('Page is not within the corresponding Database'); + } + + return $page; + } + + public static function getNextCursor(): ?string + { + return self::$nextCursor; + } + +} diff --git a/src/Models/NotionQueryBuilder.php b/src/Models/NotionQueryBuilder.php new file mode 100644 index 0000000..bbed8cd --- /dev/null +++ b/src/Models/NotionQueryBuilder.php @@ -0,0 +1,270 @@ +modelClass = $class; + $this->endpoint = $this->modelClass::notionInstance() + ->database($this->modelClass::$databaseId); + } + + public function pluck($value, $key = null): Collection + { + $pageCollection = $this->internalQuery(); + return $pageCollection->pluck('props.' . $value, $key !== null ? 'props.' . $key : null); + } + + private function queryToNotion(int $limit = 100): PageCollection + { + $notionQuery = $this->modelClass::notionInstance() + ->database($this->modelClass::databaseId()) + ->limit($limit); + + if ($this->filters) { + $notionQuery->filterBy($this->filters); + } + + if ($this->modelClass::$offset) { + $notionQuery->offset(new StartCursor($this->modelClass::$offset)); + } + + return $notionQuery->query(); + } + + /** + * @return Collection + */ + private function internalQuery(int $limit = 100): Collection + { + if ($this->modelClass::$cursorHistory === null) { + $this->modelClass::$cursorHistory = new Collection(); + } + + if ($this->modelClass::$cacheDurationInSeconds === 0) { + $queryResponse = $this->queryToNotion($limit); + } else { + $queryResponse = Cache::remember(static::cacheKey(), $this->modelClass::$cacheDurationInSeconds, function () use ($limit) { + return $this->queryToNotion($limit); + }); + } + + $instances = collect(); + + foreach ($queryResponse->asCollection() as $pageItem) { + $instance = $this->modelClass::createInstance($this->modelClass::$databaseId); + // $instance->page = $pageItem; + + // $instance->{'props'} = (object)[]; + foreach ($pageItem->getProperties() as $propertyItem) { + $propertyContent = $propertyItem->getContent(); + if ($this->modelClass::$convertPropsToText || $this->localConvertPropsToText) { + $propertyContent = $propertyItem->asText(); + } + $instance->{Str::slug($propertyItem->getTitle(), '_')} = $propertyContent; + } + + $instances->add($instance); + } + + self::$nextCursor = $queryResponse->nextCursor(); + $this->modelClass::$cursorHistory->add(self::$nextCursor); + + return $instances; + } + + /** + * @return Collection + */ + public function get() + { + return $this->internalQuery(); + } + + + /** + * @return string + */ + public function getAsJson() + { + return $this->internalQuery()->asJson(); + } + + public function getAll() + { + throw new \Exception('Not implemented yet'); + } + + public function getAllAsJson() + { + throw new \Exception('Not implemented yet'); + } + + public function propsToText() + { + $this->localConvertPropsToText = true; + return $this; + } + + + public function offset($offset) + { + $this->endpoint->offset($offset); + return $this; + } + + public function limit($offset) + { + $this->endpoint->limit($offset); + return $this; + } + + + public function orderBy($property, $direction = 'asc') + { + if ($this->sortings == null) { + $this->sortings = collect(); + } + + if ($direction == 'asc') { + $direction = 'ascending'; + } + if ($direction == 'desc') { + $direction = 'descending'; + } + + $this->sortings + ->add(Sorting::propertySort($property, $direction)); + + return $this; + } + + public function whereNull($property) + { + return $this->where($property, Operators::IS_EMPTY, null); + } + + public function whereNotNull($property) + { + return $this->where($property, Operators::IS_NOT_EMPTY, null); + } + + public function where($property, $operator, $value = null) + { + if ($this->filters == null) { + $this->filters = collect(); + } + + if ($value == null) { + $value = $operator; + $operator = Operators::EQUALS; + } else { + switch ($operator) { + case '=': + $operator = Operators::EQUALS; + break; + case '!=': + $operator = Operators::DOES_NOT_EQUAL; + break; + case '<': + $operator = Operators::LESS_THAN; + break; + case '<=': + $operator = Operators::LESS_THAN_OR_EQUAL_TO; + break; + case '>': + $operator = Operators::GREATER_THAN; + break; + case '>=': + $operator = Operators::GREATER_THAN_OR_EQUAL_TO; + break; + } + } + + if (Arr::has($this->modelClass::$propertyTitleMap, $property)) { + $property = $this->modelClass::$propertyTitleMap[$property]; + } + + if (is_string($value)) { + $this->filters->add( + Filter::textFilter($property, $operator, $value) + ); + } else if (is_numeric($value)) { + $this->filters->add( + Filter::numberFilter($property, $operator, $value) + ); + } else { + $this->filters->add( + Filter::textFilter($property, $operator, $value) + ); + } + + return $this; + } + + + + public function paginate($pageSize = 100) + { + $this->endpoint->limit($pageSize); + $offset = Request::get('cursor'); + + if ($offset !== null) { + $this->endpoint->offset(new StartCursor($offset)); + } + + $result = $this->internalQuery(); + + + return [ + 'per_page' => $pageSize, + 'next_cursor' => $result->getRawNextCursor(), + 'next_page_url' => Request::fullUrlWithQuery(['cursor' => $result->getRawNextCursor()]), + 'from' => $result->asCollection()->first()->getId(), + 'to' => $result->asCollection()->last()->getId(), + 'data' => $result->asCollection(), + ]; + } + + /** + * @return string + */ + private function cacheKey(): string + { + $postCacheKey = ''; + if ($this->nextCursor !== null) { + $postCacheKey = '-' . $this->nextCursor->__toString(); + } + + return $this->modelClass::$preCacheKey . $this->modelClass::$databaseId . $postCacheKey; + } +} From 1a52591e535989f7d2ff4db082f81357c60ed036 Mon Sep 17 00:00:00 2001 From: Di Date: Thu, 2 Feb 2023 14:58:28 +0100 Subject: [PATCH 02/61] Apply fixes from StyleCI (#101) --- src/Console/Commands/MakeNotionModel.php | 16 +++++++--------- src/LaravelNotionApiServiceProvider.php | 4 ++-- src/Models/NotionModel.php | 21 +++++---------------- src/Models/NotionQueryBuilder.php | 23 +++++++++-------------- 4 files changed, 23 insertions(+), 41 deletions(-) diff --git a/src/Console/Commands/MakeNotionModel.php b/src/Console/Commands/MakeNotionModel.php index d95aa29..799075b 100644 --- a/src/Console/Commands/MakeNotionModel.php +++ b/src/Console/Commands/MakeNotionModel.php @@ -30,7 +30,6 @@ class MakeNotionModel extends Command */ public function handle() { - $databaseId = $this->argument('database_id'); $databaseName = $this->argument('database_name'); @@ -39,10 +38,10 @@ public function handle() $this->info("Fetching structure of {$databaseId} database from Notion..."); $databaseStruct = $notion->databases()->find($databaseId); - $phpDocsProperties = ""; - $visibleArray = ""; - $propertyTypeMape = ""; - $propertyTitleMap = ""; + $phpDocsProperties = ''; + $visibleArray = ''; + $propertyTypeMape = ''; + $propertyTitleMap = ''; if ($databaseName === null) { $databaseName = Str::singular(Str::studly(Str::slug($databaseStruct->getTitle(), '_'))); @@ -53,8 +52,8 @@ public function handle() $propType = $reflection->getReturnType() ?? 'mixed'; $notionPropType = Str::studly(Str::slug($propertyInfo->getType(), '_')); - if ($reflection->getReturnType() !== null && !$propType->isBuiltin()) { - $propType = '\\' . $propType->getName(); + if ($reflection->getReturnType() !== null && ! $propType->isBuiltin()) { + $propType = '\\'.$propType->getName(); } $propName = Str::slug($propertyInfo->getTitle(), '_'); @@ -62,8 +61,6 @@ public function handle() $visibleArray .= " '$propName',\n"; } - - $contents = "info("Model for database {$this->argument('database_id')} has been created at 'app/NotionModels/$databaseName.php' ."); + return 0; } } diff --git a/src/LaravelNotionApiServiceProvider.php b/src/LaravelNotionApiServiceProvider.php index 9650f93..bcb1162 100644 --- a/src/LaravelNotionApiServiceProvider.php +++ b/src/LaravelNotionApiServiceProvider.php @@ -17,7 +17,7 @@ public function boot() { if ($this->app->runningInConsole()) { $this->publishes([ - __DIR__ . '/../config/config.php' => config_path('laravel-notion-api.php'), + __DIR__.'/../config/config.php' => config_path('laravel-notion-api.php'), ], 'config'); $this->commands([ @@ -32,7 +32,7 @@ public function boot() public function register() { // Automatically apply the package configuration - $this->mergeConfigFrom(__DIR__ . '/../config/config.php', 'laravel-notion-api'); + $this->mergeConfigFrom(__DIR__.'/../config/config.php', 'laravel-notion-api'); $this->app->singleton(Notion::class, function () { return new Notion(config('laravel-notion-api.notion-api-token'), config('laravel-notion-api.version')); diff --git a/src/Models/NotionModel.php b/src/Models/NotionModel.php index f4e49bf..d9ad872 100644 --- a/src/Models/NotionModel.php +++ b/src/Models/NotionModel.php @@ -2,19 +2,12 @@ namespace FiveamCode\LaravelNotionApi\Models; -use FiveamCode\LaravelNotionApi\Endpoints\Database; -use FiveamCode\LaravelNotionApi\Entities\Collections\PageCollection; use FiveamCode\LaravelNotionApi\Entities\Page; use FiveamCode\LaravelNotionApi\Exceptions\HandlingException; -use Illuminate\Support\Collection; use FiveamCode\LaravelNotionApi\Notion; -use FiveamCode\LaravelNotionApi\Query\Filters\Filter; -use FiveamCode\LaravelNotionApi\Query\Filters\Operators; -use FiveamCode\LaravelNotionApi\Query\Sorting; use FiveamCode\LaravelNotionApi\Query\StartCursor; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\Cache; -use Illuminate\Support\Facades\Request; -use Illuminate\Support\Str; class NotionModel { @@ -44,7 +37,7 @@ class NotionModel public static $cacheDurationInSeconds = 0; /** - * @var boolean + * @var bool */ public static $convertPropsToText = false; @@ -52,7 +45,6 @@ class NotionModel public Page $page; - public function __construct($databaseId = null) { if ($databaseId == null) { @@ -60,11 +52,11 @@ public function __construct($databaseId = null) } } - public static function createInstance(){ + public static function createInstance() + { return new static(); } - /** * @return string */ @@ -77,7 +69,7 @@ public static function databaseId(): string } /** - * @return + * @return */ public static function notionInstance(): Notion { @@ -105,8 +97,6 @@ public static function all() return self::query()->get(); } - - /** * @return ?static */ @@ -142,5 +132,4 @@ public static function getNextCursor(): ?string { return self::$nextCursor; } - } diff --git a/src/Models/NotionQueryBuilder.php b/src/Models/NotionQueryBuilder.php index bbed8cd..56db5f6 100644 --- a/src/Models/NotionQueryBuilder.php +++ b/src/Models/NotionQueryBuilder.php @@ -5,13 +5,11 @@ use FiveamCode\LaravelNotionApi\Endpoints\Database; use FiveamCode\LaravelNotionApi\Entities\Collections\PageCollection; use FiveamCode\LaravelNotionApi\Entities\Page; -use FiveamCode\LaravelNotionApi\Exceptions\HandlingException; -use Illuminate\Support\Collection; -use FiveamCode\LaravelNotionApi\Notion; use FiveamCode\LaravelNotionApi\Query\Filters\Filter; use FiveamCode\LaravelNotionApi\Query\Filters\Operators; use FiveamCode\LaravelNotionApi\Query\StartCursor; use Illuminate\Support\Arr; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Str; @@ -24,7 +22,6 @@ class NotionQueryBuilder private $modelClass = null; - public ?Database $endpoint = null; public ?Collection $filters = null; public ?Collection $sortings = null; @@ -41,7 +38,8 @@ public function __construct($class) public function pluck($value, $key = null): Collection { $pageCollection = $this->internalQuery(); - return $pageCollection->pluck('props.' . $value, $key !== null ? 'props.' . $key : null); + + return $pageCollection->pluck('props.'.$value, $key !== null ? 'props.'.$key : null); } private function queryToNotion(int $limit = 100): PageCollection @@ -110,7 +108,6 @@ public function get() return $this->internalQuery(); } - /** * @return string */ @@ -132,23 +129,24 @@ public function getAllAsJson() public function propsToText() { $this->localConvertPropsToText = true; + return $this; } - public function offset($offset) { $this->endpoint->offset($offset); + return $this; } public function limit($offset) { $this->endpoint->limit($offset); + return $this; } - public function orderBy($property, $direction = 'asc') { if ($this->sortings == null) { @@ -218,7 +216,7 @@ public function where($property, $operator, $value = null) $this->filters->add( Filter::textFilter($property, $operator, $value) ); - } else if (is_numeric($value)) { + } elseif (is_numeric($value)) { $this->filters->add( Filter::numberFilter($property, $operator, $value) ); @@ -231,8 +229,6 @@ public function where($property, $operator, $value = null) return $this; } - - public function paginate($pageSize = 100) { $this->endpoint->limit($pageSize); @@ -244,7 +240,6 @@ public function paginate($pageSize = 100) $result = $this->internalQuery(); - return [ 'per_page' => $pageSize, 'next_cursor' => $result->getRawNextCursor(), @@ -262,9 +257,9 @@ private function cacheKey(): string { $postCacheKey = ''; if ($this->nextCursor !== null) { - $postCacheKey = '-' . $this->nextCursor->__toString(); + $postCacheKey = '-'.$this->nextCursor->__toString(); } - return $this->modelClass::$preCacheKey . $this->modelClass::$databaseId . $postCacheKey; + return $this->modelClass::$preCacheKey.$this->modelClass::$databaseId.$postCacheKey; } } From bba2098ca4546cd3f0d18189622939e8f563899c Mon Sep 17 00:00:00 2001 From: johguentner Date: Sat, 4 Feb 2023 17:31:53 +0100 Subject: [PATCH 03/61] fix: after merge of filter-changes - add filterbags instead of collections --- src/Models/NotionQueryBuilder.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Models/NotionQueryBuilder.php b/src/Models/NotionQueryBuilder.php index 56db5f6..9d78e68 100644 --- a/src/Models/NotionQueryBuilder.php +++ b/src/Models/NotionQueryBuilder.php @@ -6,6 +6,7 @@ use FiveamCode\LaravelNotionApi\Entities\Collections\PageCollection; use FiveamCode\LaravelNotionApi\Entities\Page; use FiveamCode\LaravelNotionApi\Query\Filters\Filter; +use FiveamCode\LaravelNotionApi\Query\Filters\FilterBag; use FiveamCode\LaravelNotionApi\Query\Filters\Operators; use FiveamCode\LaravelNotionApi\Query\StartCursor; use Illuminate\Support\Arr; @@ -23,7 +24,7 @@ class NotionQueryBuilder private $modelClass = null; public ?Database $endpoint = null; - public ?Collection $filters = null; + public ?FilterBag $filters = null; public ?Collection $sortings = null; private $localConvertPropsToText = false; @@ -179,7 +180,7 @@ public function whereNotNull($property) public function where($property, $operator, $value = null) { if ($this->filters == null) { - $this->filters = collect(); + $this->filters = new FilterBag(); } if ($value == null) { @@ -213,15 +214,15 @@ public function where($property, $operator, $value = null) } if (is_string($value)) { - $this->filters->add( + $this->filters->addFilter( Filter::textFilter($property, $operator, $value) ); } elseif (is_numeric($value)) { - $this->filters->add( + $this->filters->addFilter( Filter::numberFilter($property, $operator, $value) ); } else { - $this->filters->add( + $this->filters->addFilter( Filter::textFilter($property, $operator, $value) ); } From c3d4b48526387a42da5104164acb89a727216cdd Mon Sep 17 00:00:00 2001 From: johguentner Date: Mon, 6 Feb 2023 16:06:02 +0100 Subject: [PATCH 04/61] add the ability to resolve users and parents - some entities have parents or expose user-ids, without additional information - by resolving these within the "endpoint" (not a real notion enpoint) ``Resolve::class``, the additional information can be easily obtained --- src/Endpoints/Resolve.php | 69 +++++++++++++++++++++++++++++++++++ src/Entities/NotionParent.php | 68 ++++++++++++++++++++++++++++++++++ src/Notion.php | 8 +++- src/Traits/HasParent.php | 12 ++++++ 4 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 src/Endpoints/Resolve.php create mode 100644 src/Entities/NotionParent.php diff --git a/src/Endpoints/Resolve.php b/src/Endpoints/Resolve.php new file mode 100644 index 0000000..0570922 --- /dev/null +++ b/src/Endpoints/Resolve.php @@ -0,0 +1,69 @@ +notion->users()->find($user->getId()); + } + + /** + * @param NotionParent $parent + * + * @return Page|Database|Block + * @throws HandlingException + * @throws NotionException + */ + public function parent(NotionParent $parent): Page|Database|Block + { + switch ($parent->getObjectType()) { + case 'page_id': + return $this->notion->pages()->find($parent->getId()); + case 'database_id': + return $this->notion->databases()->find($parent->getId()); + case 'block_id': + return $this->notion->block($parent->getId())->retrieve(); + case 'workspace_id': + throw new HandlingException('A Notion Workspace cannot be resolved by the Notion API.'); + default: + throw new HandlingException('Unknown parent type while resolving the notion parent'); + } + } +} diff --git a/src/Entities/NotionParent.php b/src/Entities/NotionParent.php new file mode 100644 index 0000000..2e49b6c --- /dev/null +++ b/src/Entities/NotionParent.php @@ -0,0 +1,68 @@ +fillFromRaw(); + } + + private function fillFromRaw(): void + { + parent::fillEntityBase(); + } + + /** + * @return bool + */ + public function isBlock(): bool + { + return $this->getObjectType() === 'block_id'; + } + + /** + * @return bool + */ + public function isPage(): bool + { + return $this->getObjectType() === 'page_id'; + } + + /** + * @return bool + */ + public function isDatabase(): bool + { + return $this->getObjectType() === 'database_id'; + } + + /** + * @return bool + */ + public function isWorkspace(): bool + { + return $this->getObjectType() === 'workspace_id'; + } +} diff --git a/src/Notion.php b/src/Notion.php index e371dc2..a7cffca 100644 --- a/src/Notion.php +++ b/src/Notion.php @@ -8,6 +8,7 @@ use FiveamCode\LaravelNotionApi\Endpoints\Databases; use FiveamCode\LaravelNotionApi\Endpoints\Endpoint; use FiveamCode\LaravelNotionApi\Endpoints\Pages; +use FiveamCode\LaravelNotionApi\Endpoints\Resolve; use FiveamCode\LaravelNotionApi\Endpoints\Search; use FiveamCode\LaravelNotionApi\Endpoints\Users; use FiveamCode\LaravelNotionApi\Exceptions\HandlingException; @@ -196,6 +197,11 @@ public function comments(): Comments return new Comments($this); } + public function resolve(): Resolve + { + return new Resolve($this); + } + /** * @return string */ @@ -221,7 +227,7 @@ public function getConnection(): ?PendingRequest */ public function checkValidVersion(string $version): void { - if (! $this->validVersions->contains($version)) { + if (!$this->validVersions->contains($version)) { throw HandlingException::instance('Invalid version for Notion-API endpoint', ['invalidVersion' => $version]); } } diff --git a/src/Traits/HasParent.php b/src/Traits/HasParent.php index 8356ae6..4d763c4 100644 --- a/src/Traits/HasParent.php +++ b/src/Traits/HasParent.php @@ -2,6 +2,7 @@ namespace FiveamCode\LaravelNotionApi\Traits; +use FiveamCode\LaravelNotionApi\Entities\NotionParent; use Illuminate\Support\Arr; /** @@ -54,4 +55,15 @@ public function getParentType(): string { return $this->parentType; } + + /** + * @return NotionParent + */ + public function getParent() + { + return new NotionParent([ + 'id' => $this->getParentId(), + 'object' => $this->getParentType() + ]); + } } From 31bd869723e175a81432d253b3909d751920dd02 Mon Sep 17 00:00:00 2001 From: Di Date: Mon, 6 Feb 2023 16:06:21 +0100 Subject: [PATCH 05/61] Apply fixes from StyleCI (#115) --- src/Endpoints/Resolve.php | 7 ++----- src/Notion.php | 2 +- src/Traits/HasParent.php | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Endpoints/Resolve.php b/src/Endpoints/Resolve.php index 0570922..35b8cec 100644 --- a/src/Endpoints/Resolve.php +++ b/src/Endpoints/Resolve.php @@ -3,12 +3,9 @@ namespace FiveamCode\LaravelNotionApi\Endpoints; use FiveamCode\LaravelNotionApi\Entities\Blocks\Block; -use FiveamCode\LaravelNotionApi\Entities\Collections\CommentCollection; -use FiveamCode\LaravelNotionApi\Entities\Comment; use FiveamCode\LaravelNotionApi\Entities\Database; use FiveamCode\LaravelNotionApi\Entities\NotionParent; use FiveamCode\LaravelNotionApi\Entities\Page; -use FiveamCode\LaravelNotionApi\Entities\Properties\Relation; use FiveamCode\LaravelNotionApi\Entities\User; use FiveamCode\LaravelNotionApi\Exceptions\HandlingException; use FiveamCode\LaravelNotionApi\Exceptions\NotionException; @@ -34,8 +31,8 @@ public function __construct(Notion $notion) /** * @param User $user - * * @return User + * * @throws HandlingException * @throws NotionException */ @@ -46,8 +43,8 @@ public function user(User $user): User /** * @param NotionParent $parent - * * @return Page|Database|Block + * * @throws HandlingException * @throws NotionException */ diff --git a/src/Notion.php b/src/Notion.php index a7cffca..9d8f7ba 100644 --- a/src/Notion.php +++ b/src/Notion.php @@ -227,7 +227,7 @@ public function getConnection(): ?PendingRequest */ public function checkValidVersion(string $version): void { - if (!$this->validVersions->contains($version)) { + if (! $this->validVersions->contains($version)) { throw HandlingException::instance('Invalid version for Notion-API endpoint', ['invalidVersion' => $version]); } } diff --git a/src/Traits/HasParent.php b/src/Traits/HasParent.php index 4d763c4..5bd8501 100644 --- a/src/Traits/HasParent.php +++ b/src/Traits/HasParent.php @@ -63,7 +63,7 @@ public function getParent() { return new NotionParent([ 'id' => $this->getParentId(), - 'object' => $this->getParentType() + 'object' => $this->getParentType(), ]); } } From 9a3dbb3fcbe0eb028e4159150a2d745d97c4d0ba Mon Sep 17 00:00:00 2001 From: johguentner Date: Mon, 6 Feb 2023 21:07:45 +0100 Subject: [PATCH 06/61] fix: modify changed method within `NotionParent` --- src/Entities/NotionParent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Entities/NotionParent.php b/src/Entities/NotionParent.php index 2e49b6c..bdb5c19 100644 --- a/src/Entities/NotionParent.php +++ b/src/Entities/NotionParent.php @@ -31,7 +31,7 @@ protected function setResponseData(array $responseData): void private function fillFromRaw(): void { - parent::fillEntityBase(); + parent::fillEssentials(); } /** From cf07ff980f88f8639ee4cfb7daefff5229fdc9fc Mon Sep 17 00:00:00 2001 From: johguentner Date: Thu, 16 Feb 2023 12:39:30 +0000 Subject: [PATCH 07/61] add `asText` override to title and text property --- src/Entities/Properties/Text.php | 8 ++++++++ src/Entities/Properties/Title.php | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/src/Entities/Properties/Text.php b/src/Entities/Properties/Text.php index 7fad01c..1553723 100644 --- a/src/Entities/Properties/Text.php +++ b/src/Entities/Properties/Text.php @@ -69,6 +69,14 @@ protected function fillText(): void $this->plainText = $this->content->getPlainText(); } + /** + * @return string + */ + public function asText(): string + { + return $this->getPlainText(); + } + /** * @return RichText */ diff --git a/src/Entities/Properties/Title.php b/src/Entities/Properties/Title.php index 4962a06..134ea0f 100644 --- a/src/Entities/Properties/Title.php +++ b/src/Entities/Properties/Title.php @@ -68,6 +68,14 @@ private function fillText(): void $this->plainText = $this->content->getPlainText(); } + /** + * @return string + */ + public function asText(): string + { + return $this->getPlainText(); + } + /** * @return RichText */ From 8c53b2a0ab3b6442348980d953800e95402728e8 Mon Sep 17 00:00:00 2001 From: johguentner Date: Thu, 16 Feb 2023 12:40:10 +0000 Subject: [PATCH 08/61] polish notion model creation and usage --- src/Console/Commands/MakeNotionModel.php | 15 ++++++++++----- src/Models/NotionModel.php | 18 +++++++++++++++--- src/Models/NotionQueryBuilder.php | 24 +++++++++++++++++------- 3 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/Console/Commands/MakeNotionModel.php b/src/Console/Commands/MakeNotionModel.php index 799075b..9e98671 100644 --- a/src/Console/Commands/MakeNotionModel.php +++ b/src/Console/Commands/MakeNotionModel.php @@ -21,7 +21,7 @@ class MakeNotionModel extends Command * * @var string */ - protected $description = 'Make Notion Model'; + protected $description = 'Make Notion Model based on a provided {database_id}'; /** * Execute the console command. @@ -59,6 +59,9 @@ public function handle() $propName = Str::slug($propertyInfo->getTitle(), '_'); $phpDocsProperties .= " * @property {$propType} \${$propName} $notionPropType \n"; $visibleArray .= " '$propName',\n"; + $propertyTypeMape .= " '$propName' => '$notionPropType',\n"; + $propertyTitleMap .= " '$propName' => '{$propertyInfo->getTitle()}',\n"; + } $contents = "page; + } + public static function createInstance() { return new static(); @@ -77,13 +80,22 @@ public static function notionInstance(): Notion } /** - * @return NotionModel + * @return NotionQueryBuilder */ public static function query(): NotionQueryBuilder { return new NotionQueryBuilder(static::class); } + + /** + * @return NotionQueryBuilder + */ + public static function where($property, $operator, $value = null) + { + return static::query()->where($property, $operator, $value); + } + /** * @return void */ diff --git a/src/Models/NotionQueryBuilder.php b/src/Models/NotionQueryBuilder.php index 9d78e68..2bd4d5b 100644 --- a/src/Models/NotionQueryBuilder.php +++ b/src/Models/NotionQueryBuilder.php @@ -40,7 +40,7 @@ public function pluck($value, $key = null): Collection { $pageCollection = $this->internalQuery(); - return $pageCollection->pluck('props.'.$value, $key !== null ? 'props.'.$key : null); + return $pageCollection->pluck('props.' . $value, $key !== null ? 'props.' . $key : null); } private function queryToNotion(int $limit = 100): PageCollection @@ -81,9 +81,8 @@ private function internalQuery(int $limit = 100): Collection foreach ($queryResponse->asCollection() as $pageItem) { $instance = $this->modelClass::createInstance($this->modelClass::$databaseId); - // $instance->page = $pageItem; - - // $instance->{'props'} = (object)[]; + $instance->page = $pageItem; + foreach ($pageItem->getProperties() as $propertyItem) { $propertyContent = $propertyItem->getContent(); if ($this->modelClass::$convertPropsToText || $this->localConvertPropsToText) { @@ -109,6 +108,14 @@ public function get() return $this->internalQuery(); } + /** + * @return static + */ + public function first() + { + return $this->get()->first(); + } + /** * @return string */ @@ -187,7 +194,7 @@ public function where($property, $operator, $value = null) $value = $operator; $operator = Operators::EQUALS; } else { - switch ($operator) { + switch (Str::lower($operator)) { case '=': $operator = Operators::EQUALS; break; @@ -206,6 +213,9 @@ public function where($property, $operator, $value = null) case '>=': $operator = Operators::GREATER_THAN_OR_EQUAL_TO; break; + case 'contains': + $operator = Operators::CONTAINS; + break; } } @@ -258,9 +268,9 @@ private function cacheKey(): string { $postCacheKey = ''; if ($this->nextCursor !== null) { - $postCacheKey = '-'.$this->nextCursor->__toString(); + $postCacheKey = '-' . $this->nextCursor->__toString(); } - return $this->modelClass::$preCacheKey.$this->modelClass::$databaseId.$postCacheKey; + return $this->modelClass::$preCacheKey . $this->modelClass::$databaseId . $postCacheKey; } } From ea5cc25c3e93d1ad7b822915bf1a276c5fd8dd92 Mon Sep 17 00:00:00 2001 From: Di Date: Thu, 16 Feb 2023 12:40:29 +0000 Subject: [PATCH 09/61] Apply fixes from StyleCI (#120) --- src/Console/Commands/MakeNotionModel.php | 1 - src/Models/NotionModel.php | 1 - src/Models/NotionQueryBuilder.php | 9 ++++----- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Console/Commands/MakeNotionModel.php b/src/Console/Commands/MakeNotionModel.php index 9e98671..3fe31df 100644 --- a/src/Console/Commands/MakeNotionModel.php +++ b/src/Console/Commands/MakeNotionModel.php @@ -61,7 +61,6 @@ public function handle() $visibleArray .= " '$propName',\n"; $propertyTypeMape .= " '$propName' => '$notionPropType',\n"; $propertyTitleMap .= " '$propName' => '{$propertyInfo->getTitle()}',\n"; - } $contents = "internalQuery(); - return $pageCollection->pluck('props.' . $value, $key !== null ? 'props.' . $key : null); + return $pageCollection->pluck('props.'.$value, $key !== null ? 'props.'.$key : null); } private function queryToNotion(int $limit = 100): PageCollection @@ -82,7 +81,7 @@ private function internalQuery(int $limit = 100): Collection foreach ($queryResponse->asCollection() as $pageItem) { $instance = $this->modelClass::createInstance($this->modelClass::$databaseId); $instance->page = $pageItem; - + foreach ($pageItem->getProperties() as $propertyItem) { $propertyContent = $propertyItem->getContent(); if ($this->modelClass::$convertPropsToText || $this->localConvertPropsToText) { @@ -268,9 +267,9 @@ private function cacheKey(): string { $postCacheKey = ''; if ($this->nextCursor !== null) { - $postCacheKey = '-' . $this->nextCursor->__toString(); + $postCacheKey = '-'.$this->nextCursor->__toString(); } - return $this->modelClass::$preCacheKey . $this->modelClass::$databaseId . $postCacheKey; + return $this->modelClass::$preCacheKey.$this->modelClass::$databaseId.$postCacheKey; } } From bbaa2a9d0463aaadb6d55c41aecb6427a0245439 Mon Sep 17 00:00:00 2001 From: johguentner Date: Thu, 16 Feb 2023 13:01:57 +0000 Subject: [PATCH 10/61] fix: remove duplicated `asText` --- src/Entities/Properties/Text.php | 10 +--------- src/Entities/Properties/Title.php | 8 -------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/src/Entities/Properties/Text.php b/src/Entities/Properties/Text.php index 7e44660..48509d5 100644 --- a/src/Entities/Properties/Text.php +++ b/src/Entities/Properties/Text.php @@ -68,15 +68,7 @@ protected function fillText(): void $this->content = new RichText($this->rawContent); $this->plainText = $this->content->getPlainText(); } - - /** - * @return string - */ - public function asText(): string - { - return $this->getPlainText(); - } - + /** * @return RichText */ diff --git a/src/Entities/Properties/Title.php b/src/Entities/Properties/Title.php index 674b6a4..5d7e502 100644 --- a/src/Entities/Properties/Title.php +++ b/src/Entities/Properties/Title.php @@ -68,14 +68,6 @@ private function fillText(): void $this->plainText = $this->content->getPlainText(); } - /** - * @return string - */ - public function asText(): string - { - return $this->getPlainText(); - } - /** * @return RichText */ From 4cbdff95c5e3e8ae42242bb3a1409e2cf8985190 Mon Sep 17 00:00:00 2001 From: Di Date: Thu, 16 Feb 2023 13:02:14 +0000 Subject: [PATCH 11/61] Apply fixes from StyleCI (#122) --- src/Entities/Properties/Text.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Entities/Properties/Text.php b/src/Entities/Properties/Text.php index 48509d5..84df2e4 100644 --- a/src/Entities/Properties/Text.php +++ b/src/Entities/Properties/Text.php @@ -68,7 +68,7 @@ protected function fillText(): void $this->content = new RichText($this->rawContent); $this->plainText = $this->content->getPlainText(); } - + /** * @return RichText */ From 911d8c6dfbc8bdba90686b2a7896013e58c4b35e Mon Sep 17 00:00:00 2001 From: johguentner Date: Thu, 16 Feb 2023 15:26:59 +0000 Subject: [PATCH 12/61] polish: exclude `$page` of `NotionModel` - for json_encode --- src/Models/NotionModel.php | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Models/NotionModel.php b/src/Models/NotionModel.php index ee325bf..a1fe681 100644 --- a/src/Models/NotionModel.php +++ b/src/Models/NotionModel.php @@ -8,8 +8,9 @@ use FiveamCode\LaravelNotionApi\Query\StartCursor; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Cache; +use JsonSerializable; -class NotionModel +class NotionModel implements JsonSerializable { /** * @var ?string @@ -55,6 +56,24 @@ public function getPage(): Page return $this->page; } + /** + * @return array + */ + public function toArray(): array + { + $array = get_object_vars($this); + unset($array['page']); + return $array; + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + return $this->toArray(); + } + public static function createInstance() { return new static(); From f828d7d3047159d8e8f368489d86bbbb0e4c62cc Mon Sep 17 00:00:00 2001 From: Di Date: Thu, 16 Feb 2023 15:27:17 +0000 Subject: [PATCH 13/61] Apply fixes from StyleCI (#123) --- src/Models/NotionModel.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Models/NotionModel.php b/src/Models/NotionModel.php index a1fe681..96e9e0d 100644 --- a/src/Models/NotionModel.php +++ b/src/Models/NotionModel.php @@ -57,12 +57,13 @@ public function getPage(): Page } /** - * @return array + * @return array */ public function toArray(): array { $array = get_object_vars($this); unset($array['page']); + return $array; } From 3c9c8458daa6a2432f07487ae460bd91d223e743 Mon Sep 17 00:00:00 2001 From: johguentner Date: Thu, 16 Feb 2023 16:55:50 +0000 Subject: [PATCH 14/61] add prototypical relation resolving --- src/Endpoints/Resolve.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/Endpoints/Resolve.php b/src/Endpoints/Resolve.php index 35b8cec..c00fe2f 100644 --- a/src/Endpoints/Resolve.php +++ b/src/Endpoints/Resolve.php @@ -3,13 +3,16 @@ namespace FiveamCode\LaravelNotionApi\Endpoints; use FiveamCode\LaravelNotionApi\Entities\Blocks\Block; +use FiveamCode\LaravelNotionApi\Entities\Collections\PageCollection; use FiveamCode\LaravelNotionApi\Entities\Database; use FiveamCode\LaravelNotionApi\Entities\NotionParent; use FiveamCode\LaravelNotionApi\Entities\Page; +use FiveamCode\LaravelNotionApi\Entities\Properties\Relation; use FiveamCode\LaravelNotionApi\Entities\User; use FiveamCode\LaravelNotionApi\Exceptions\HandlingException; use FiveamCode\LaravelNotionApi\Exceptions\NotionException; use FiveamCode\LaravelNotionApi\Notion; +use Illuminate\Support\Collection; /** * Class Resolve. @@ -63,4 +66,29 @@ public function parent(NotionParent $parent): Page|Database|Block throw new HandlingException('Unknown parent type while resolving the notion parent'); } } + + /** + * @param Relation $relation + * @return Collection + * + * @throws HandlingException + * @throws NotionException + */ + public function relations(Relation $relation, bool $onlyTitles = false): Collection + { + $pages = collect(); + $relationIds = $relation->getRelation()->map(function ($o) { + return $o['id']; + }); + + foreach ($relationIds as $relationId) { + if ($onlyTitles) { + $pages->add($this->notion->pages()->find($relationId)->getTitle()); + } else { + $pages->add($this->notion->pages()->find($relationId)); + } + } + + return $pages; + } } From 29c991a6f084748a6292579f744ba8cf182a0d09 Mon Sep 17 00:00:00 2001 From: Di Date: Thu, 16 Feb 2023 16:56:08 +0000 Subject: [PATCH 15/61] Apply fixes from StyleCI (#124) --- src/Endpoints/Resolve.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Endpoints/Resolve.php b/src/Endpoints/Resolve.php index c00fe2f..1c84f41 100644 --- a/src/Endpoints/Resolve.php +++ b/src/Endpoints/Resolve.php @@ -3,7 +3,6 @@ namespace FiveamCode\LaravelNotionApi\Endpoints; use FiveamCode\LaravelNotionApi\Entities\Blocks\Block; -use FiveamCode\LaravelNotionApi\Entities\Collections\PageCollection; use FiveamCode\LaravelNotionApi\Entities\Database; use FiveamCode\LaravelNotionApi\Entities\NotionParent; use FiveamCode\LaravelNotionApi\Entities\Page; From 27620d33850718dec04b2908bfb0d3bfec083831 Mon Sep 17 00:00:00 2001 From: Di Date: Thu, 16 Feb 2023 16:56:21 +0000 Subject: [PATCH 16/61] Apply fixes from StyleCI (#125) --- src/Endpoints/Resolve.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Endpoints/Resolve.php b/src/Endpoints/Resolve.php index c00fe2f..1c84f41 100644 --- a/src/Endpoints/Resolve.php +++ b/src/Endpoints/Resolve.php @@ -3,7 +3,6 @@ namespace FiveamCode\LaravelNotionApi\Endpoints; use FiveamCode\LaravelNotionApi\Entities\Blocks\Block; -use FiveamCode\LaravelNotionApi\Entities\Collections\PageCollection; use FiveamCode\LaravelNotionApi\Entities\Database; use FiveamCode\LaravelNotionApi\Entities\NotionParent; use FiveamCode\LaravelNotionApi\Entities\Page; From c7a5bf2c8c53bdf676e52fcead04831d1f756b44 Mon Sep 17 00:00:00 2001 From: johguentner Date: Fri, 28 Apr 2023 23:46:45 +0900 Subject: [PATCH 17/61] create trait for title attribute --- src/Entities/Database.php | 29 ++---------------- src/Traits/HasTitle.php | 62 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 27 deletions(-) create mode 100644 src/Traits/HasTitle.php diff --git a/src/Entities/Database.php b/src/Entities/Database.php index 9df0eee..e19d3f3 100644 --- a/src/Entities/Database.php +++ b/src/Entities/Database.php @@ -8,6 +8,7 @@ use FiveamCode\LaravelNotionApi\Traits\HasArchive; use FiveamCode\LaravelNotionApi\Traits\HasParent; use FiveamCode\LaravelNotionApi\Traits\HasTimestamps; +use FiveamCode\LaravelNotionApi\Traits\HasTitle; use Illuminate\Support\Arr; use Illuminate\Support\Collection; @@ -16,12 +17,8 @@ */ class Database extends Entity { - use HasTimestamps, HasArchive, HasParent; + use HasTimestamps, HasArchive, HasParent, HasTitle; - /** - * @var string - */ - protected string $title = ''; /** * @var string @@ -53,11 +50,6 @@ class Database extends Entity */ private string $url; - /** - * @var ?RichText - */ - protected ?RichText $richTitle = null; - /** * @var ?RichText */ @@ -102,21 +94,12 @@ private function fillFromRaw() parent::fillEssentials(); $this->fillIcon(); $this->fillCover(); - $this->fillTitle(); $this->fillIsInline(); $this->fillDescription(); $this->fillProperties(); $this->fillDatabaseUrl(); } - private function fillTitle(): void - { - if (Arr::exists($this->responseData, 'title') && is_array($this->responseData['title'])) { - $this->title = Arr::first($this->responseData['title'], null, ['plain_text' => ''])['plain_text']; - $this->richTitle = new RichText($this->responseData['title']); - } - } - private function fillIsInline(): void { if (Arr::exists($this->responseData, 'is_inline')) { @@ -193,14 +176,6 @@ public function getProperty(string $propertyKey): ?Property return $this->propertyMap[$propertyKey]; } - /** - * @return string - */ - public function getTitle(): string - { - return $this->title; - } - /** * @return bool */ diff --git a/src/Traits/HasTitle.php b/src/Traits/HasTitle.php new file mode 100644 index 0000000..bed56eb --- /dev/null +++ b/src/Traits/HasTitle.php @@ -0,0 +1,62 @@ +fillTitle(); + } + + private function fillTitle(): void + { + if (Arr::exists($this->responseData, 'title') && is_array($this->responseData['title'])) { + $this->title = Arr::first($this->responseData['title'], null, ['plain_text' => ''])['plain_text']; + $this->richTitle = new RichText($this->responseData['title']); + } + } + + public function setTitle($title): self + { + $this->title = $title; + $this->responseData['title'] = [ + [ + 'type' => 'text', + 'text' => [ + 'content' => $title + ] + ] + ]; + return $this; + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } +} From f19db046aa0360d69960433dfe3083bc7184e2e1 Mon Sep 17 00:00:00 2001 From: johguentner Date: Fri, 28 Apr 2023 23:47:50 +0900 Subject: [PATCH 18/61] add property type names within `Property::class` --- src/Entities/Properties/Property.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Entities/Properties/Property.php b/src/Entities/Properties/Property.php index e647f31..332bd73 100644 --- a/src/Entities/Properties/Property.php +++ b/src/Entities/Properties/Property.php @@ -11,6 +11,26 @@ */ class Property extends Entity { + const TITLE = 'title'; + const RICH_TEXT = 'rich_text'; + const NUMBER = 'number'; + const SELECT = 'select'; + const MULTI_SELECT = 'multi_select'; + const DATE = 'date'; + const PEOPLE = 'people'; + const FILES = 'files'; + const CHECKBOX = 'checkbox'; + const URL = 'url'; + const EMAIL = 'email'; + const PHONE_NUMBER = 'phone_number'; + const FORMULA = 'formula'; + const RELATION = 'relation'; + const ROLLUP = 'rollup'; + const CREATED_TIME = 'created_time'; + const CREATED_BY = 'created_by'; + const LAST_EDITED_TIME = 'last_edited_time'; + const LAST_EDITED_BY = 'last_edited_by'; + /** * @var string */ From 8963193b86199bd5b6a716473b565b23a294d4cb Mon Sep 17 00:00:00 2001 From: johguentner Date: Fri, 28 Apr 2023 23:48:36 +0900 Subject: [PATCH 19/61] add comment for clarification - why `HasTitle` trait is not used within `Page::class` --- src/Entities/Page.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Entities/Page.php b/src/Entities/Page.php index c857162..d64d0c1 100644 --- a/src/Entities/Page.php +++ b/src/Entities/Page.php @@ -113,7 +113,7 @@ private function fillFromRaw(): void { parent::fillEssentials(); $this->fillProperties(); - $this->fillTitle(); // This has to be called after fillProperties(), since title is provided by properties + $this->fillTitle(); // This has to be called after fillProperties(), since title is provided by properties (hence this is not a trait!) $this->fillPageUrl(); $this->fillIcon(); $this->fillCover(); From 29d56f537f43029ea1a763fffb9bda830b29b6df Mon Sep 17 00:00:00 2001 From: johguentner Date: Fri, 28 Apr 2023 23:49:12 +0900 Subject: [PATCH 20/61] add `HasTitle` traidMapping of `Entity::class` --- src/Entities/Entity.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Entities/Entity.php b/src/Entities/Entity.php index b23671f..705b716 100644 --- a/src/Entities/Entity.php +++ b/src/Entities/Entity.php @@ -91,6 +91,9 @@ private function fillTraitAttributes(): void 'FiveamCode\LaravelNotionApi\Traits\HasArchive' => function ($entity) { $entity->fillArchivedAttributes(); }, + 'FiveamCode\LaravelNotionApi\Traits\HasTitle' => function ($entity) { + $entity->fillTitleAttributes(); + }, ]; $traits = $this->class_uses_deep($this); From 835679261030eced9b0af479d873c0811781219c Mon Sep 17 00:00:00 2001 From: johguentner Date: Fri, 28 Apr 2023 23:50:56 +0900 Subject: [PATCH 21/61] implementation: start with database-building - class for building Notion databases and their properties --- src/Builder/DatabaseBuilder.php | 89 +++++++++++++++++++++++++++++++++ src/Builder/PropertyBuilder.php | 49 ++++++++++++++++++ src/Endpoints/Databases.php | 14 ++++++ 3 files changed, 152 insertions(+) create mode 100644 src/Builder/DatabaseBuilder.php create mode 100644 src/Builder/PropertyBuilder.php diff --git a/src/Builder/DatabaseBuilder.php b/src/Builder/DatabaseBuilder.php new file mode 100644 index 0000000..f51409c --- /dev/null +++ b/src/Builder/DatabaseBuilder.php @@ -0,0 +1,89 @@ +payload = [ + 'title' => [ + [ + 'text' => [ + 'content' => '' + ] + ] + ], + 'parent' => [], + 'properties' => [], + ]; + } + + public function createInPage($pageId): Database + { + $this->payload['parent'] = [ + 'page_id' => $pageId + ]; + + if ($this->payload['properties'] === []) { + $this->addTitleProperty(); + } + + return $this->databasesEndpoint->create($this->payload()); + } + + public function title($title): DatabaseBuilder + { + $this->payload['title'] = [ + [ + 'text' => [ + 'content' => $title + ] + ] + ]; + return $this; + } + + public function inline(): DatabaseBuilder + { + $this->payload['is_inline'] = true; + return $this; + } + + public function addTitleProperty($name = 'Name') + { + $this->addProperty($name, PropertyBuilder::title()); + return $this; + } + + public function addProperty(string $title, string|PropertyBuilder $property): DatabaseBuilder + { + if (is_string($property)) { + $property = PropertyBuilder::plain($property); + } + + $this->payload['properties'][$title] = $property->payload(); + return $this; + } + + public function addRawProperty(string $title, string $propertyType, array $content = null): DatabaseBuilder + { + $this->payload['properties'][$title] = []; + $this->payload['properties'][$title][$propertyType] = $content ?? new \stdClass(); + return $this; + } + + public function payload(): array + { + return $this->payload; + } +} \ No newline at end of file diff --git a/src/Builder/PropertyBuilder.php b/src/Builder/PropertyBuilder.php new file mode 100644 index 0000000..ede0be4 --- /dev/null +++ b/src/Builder/PropertyBuilder.php @@ -0,0 +1,49 @@ + $type, + $type => new \stdClass(), + ]); + } + + public static function title(): PropertyBuilder + { + return self::plain(Property::TITLE); + } + + public static function richText(): PropertyBuilder + { + return self::plain(Property::RICH_TEXT); + } + + + public static function number($format = 'number'): PropertyBuilder + { + return new PropertyBuilder([ + 'type' => Property::NUMBER, + Property::NUMBER => [ + 'format' => $format, + ] + ]); + } + + private function __construct(private $payload) + { + } + + public function payload(): array + { + return $this->payload; + } +} diff --git a/src/Endpoints/Databases.php b/src/Endpoints/Databases.php index 80381cf..95d32b1 100644 --- a/src/Endpoints/Databases.php +++ b/src/Endpoints/Databases.php @@ -2,6 +2,7 @@ namespace FiveamCode\LaravelNotionApi\Endpoints; +use FiveamCode\LaravelNotionApi\Builder\DatabaseBuilder; use FiveamCode\LaravelNotionApi\Entities\Collections\DatabaseCollection; use FiveamCode\LaravelNotionApi\Entities\Database; use FiveamCode\LaravelNotionApi\Exceptions\HandlingException; @@ -52,4 +53,17 @@ public function find(string $databaseId): Database return new Database($result); } + + public function build() + { + return new DatabaseBuilder($this); + } + + public function create(array $payload): Database + { + $result = $this + ->post($this->url(Endpoint::DATABASES), $payload); + + return new Database($result->json()); + } } From 0deaee7e1672d2fa093e609dde5ba2fb9350dc50 Mon Sep 17 00:00:00 2001 From: Di Date: Fri, 28 Apr 2023 23:51:15 +0900 Subject: [PATCH 22/61] Apply fixes from StyleCI (#134) --- src/Builder/DatabaseBuilder.php | 22 +++++++++++++--------- src/Builder/PropertyBuilder.php | 3 +-- src/Entities/Database.php | 1 - src/Traits/HasTitle.php | 7 ++++--- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/Builder/DatabaseBuilder.php b/src/Builder/DatabaseBuilder.php index f51409c..81516e6 100644 --- a/src/Builder/DatabaseBuilder.php +++ b/src/Builder/DatabaseBuilder.php @@ -4,7 +4,6 @@ use FiveamCode\LaravelNotionApi\Endpoints\Databases; use FiveamCode\LaravelNotionApi\Entities\Database; -use FiveamCode\LaravelNotionApi\Entities\Properties\Property; /** * Class DatabaseBuilder. @@ -19,9 +18,9 @@ public function __construct(private Databases $databasesEndpoint) 'title' => [ [ 'text' => [ - 'content' => '' - ] - ] + 'content' => '', + ], + ], ], 'parent' => [], 'properties' => [], @@ -31,7 +30,7 @@ public function __construct(private Databases $databasesEndpoint) public function createInPage($pageId): Database { $this->payload['parent'] = [ - 'page_id' => $pageId + 'page_id' => $pageId, ]; if ($this->payload['properties'] === []) { @@ -46,22 +45,25 @@ public function title($title): DatabaseBuilder $this->payload['title'] = [ [ 'text' => [ - 'content' => $title - ] - ] + 'content' => $title, + ], + ], ]; + return $this; } public function inline(): DatabaseBuilder { $this->payload['is_inline'] = true; + return $this; } public function addTitleProperty($name = 'Name') { $this->addProperty($name, PropertyBuilder::title()); + return $this; } @@ -72,6 +74,7 @@ public function addProperty(string $title, string|PropertyBuilder $property): Da } $this->payload['properties'][$title] = $property->payload(); + return $this; } @@ -79,6 +82,7 @@ public function addRawProperty(string $title, string $propertyType, array $conte { $this->payload['properties'][$title] = []; $this->payload['properties'][$title][$propertyType] = $content ?? new \stdClass(); + return $this; } @@ -86,4 +90,4 @@ public function payload(): array { return $this->payload; } -} \ No newline at end of file +} diff --git a/src/Builder/PropertyBuilder.php b/src/Builder/PropertyBuilder.php index ede0be4..0783ccf 100644 --- a/src/Builder/PropertyBuilder.php +++ b/src/Builder/PropertyBuilder.php @@ -27,14 +27,13 @@ public static function richText(): PropertyBuilder return self::plain(Property::RICH_TEXT); } - public static function number($format = 'number'): PropertyBuilder { return new PropertyBuilder([ 'type' => Property::NUMBER, Property::NUMBER => [ 'format' => $format, - ] + ], ]); } diff --git a/src/Entities/Database.php b/src/Entities/Database.php index e19d3f3..f959d86 100644 --- a/src/Entities/Database.php +++ b/src/Entities/Database.php @@ -19,7 +19,6 @@ class Database extends Entity { use HasTimestamps, HasArchive, HasParent, HasTitle; - /** * @var string */ diff --git a/src/Traits/HasTitle.php b/src/Traits/HasTitle.php index bed56eb..d5f641f 100644 --- a/src/Traits/HasTitle.php +++ b/src/Traits/HasTitle.php @@ -45,10 +45,11 @@ public function setTitle($title): self [ 'type' => 'text', 'text' => [ - 'content' => $title - ] - ] + 'content' => $title, + ], + ], ]; + return $this; } From 44aee37de87906ce05afe610b18276a01640416e Mon Sep 17 00:00:00 2001 From: johguentner Date: Sat, 29 Apr 2023 22:04:18 +0900 Subject: [PATCH 23/61] implement further and polish database creation - fix missing parent type - refactor method names to shorter and (hopefully) more readable - introduce `DatabaseSchemeBuilder::class`, which allows a more eloquent definition of a new database structure (similar to Laravel migrations) - allow to add multiple properties at the same time (bulk) - add all further properties (listed within the Notion API docs) --- src/Builder/DatabaseBuilder.php | 35 ++++-- src/Builder/DatabaseSchemeBuilder.php | 150 +++++++++++++++++++++++++ src/Builder/PropertyBuilder.php | 156 +++++++++++++++++++++++--- src/Entities/Properties/Property.php | 1 + 4 files changed, 319 insertions(+), 23 deletions(-) create mode 100644 src/Builder/DatabaseSchemeBuilder.php diff --git a/src/Builder/DatabaseBuilder.php b/src/Builder/DatabaseBuilder.php index f51409c..78546af 100644 --- a/src/Builder/DatabaseBuilder.php +++ b/src/Builder/DatabaseBuilder.php @@ -5,6 +5,7 @@ use FiveamCode\LaravelNotionApi\Endpoints\Databases; use FiveamCode\LaravelNotionApi\Entities\Database; use FiveamCode\LaravelNotionApi\Entities\Properties\Property; +use Illuminate\Support\Collection; /** * Class DatabaseBuilder. @@ -16,6 +17,8 @@ class DatabaseBuilder public function __construct(private Databases $databasesEndpoint) { $this->payload = [ + 'is_inline' => false, + 'parent' => [], 'title' => [ [ 'text' => [ @@ -23,7 +26,6 @@ public function __construct(private Databases $databasesEndpoint) ] ] ], - 'parent' => [], 'properties' => [], ]; } @@ -31,11 +33,12 @@ public function __construct(private Databases $databasesEndpoint) public function createInPage($pageId): Database { $this->payload['parent'] = [ + 'type' => 'page_id', 'page_id' => $pageId ]; if ($this->payload['properties'] === []) { - $this->addTitleProperty(); + $this->addTitle(); } return $this->databasesEndpoint->create($this->payload()); @@ -59,23 +62,37 @@ public function inline(): DatabaseBuilder return $this; } - public function addTitleProperty($name = 'Name') + public function addTitle($name = 'Name') { - $this->addProperty($name, PropertyBuilder::title()); + $this->add(PropertyBuilder::title($name)); return $this; } - public function addProperty(string $title, string|PropertyBuilder $property): DatabaseBuilder + public function add(PropertyBuilder|Collection|DatabaseSchemeBuilder $properties): DatabaseBuilder { - if (is_string($property)) { - $property = PropertyBuilder::plain($property); + if ($properties instanceof PropertyBuilder) { + $properties = collect([$properties]); + } + + if ($properties instanceof DatabaseSchemeBuilder) { + $properties = $properties->getProperties(); } - $this->payload['properties'][$title] = $property->payload(); + $properties->each(function (PropertyBuilder $property) { + $this->payload['properties'][$property->getName()] = $property->payload(); + }); + return $this; } - public function addRawProperty(string $title, string $propertyType, array $content = null): DatabaseBuilder + public function scheme(callable $callback): DatabaseBuilder + { + $builder = new DatabaseSchemeBuilder(); + $callback($builder); + return $this->add($builder); + } + + public function addRaw(string $title, string $propertyType, array $content = null): DatabaseBuilder { $this->payload['properties'][$title] = []; $this->payload['properties'][$title][$propertyType] = $content ?? new \stdClass(); diff --git a/src/Builder/DatabaseSchemeBuilder.php b/src/Builder/DatabaseSchemeBuilder.php new file mode 100644 index 0000000..c774c14 --- /dev/null +++ b/src/Builder/DatabaseSchemeBuilder.php @@ -0,0 +1,150 @@ +properties = collect(); + } + + public function push(PropertyBuilder $builder): DatabaseSchemeBuilder + { + $this->properties->push($builder); + return $this; + } + + public function raw(string $name, string $type, array|object $content): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::raw($name, $type, $content)); + } + + public function plain(string $name, string $type): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::plain($name, $type)); + } + + public function title(string $name = 'Name'): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::title($name)); + } + + public function richText(string $name = 'Text'): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::richText($name)); + } + + public function checkbox(string $name = 'Checkbox'): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::checkbox($name)); + } + + public function status(string $name = 'Status'): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::status($name)); + } + + public function select(string $name, array $options): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::select($name, $options)); + } + + public function multiSelect(string $name, array $options): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::multiSelect($name, $options)); + } + + public function number(string $name = 'Number', $format = 'number'): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::number($name, $format)); + } + + public function date(string $name = 'Date'): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::date($name)); + } + + public function relation(string $name, string $databaseId): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::relation($name, $databaseId)); + } + + public function formula(string $name, string $expression): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::formula($name, $expression)); + } + + public function rollup(string $name, string $rollupProperty, string $relationProperty, string $function): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::rollup($name, $rollupProperty, $relationProperty, $function)); + } + + public function rollupByName(string $name, string $rollupPropertyName, string $relationPropertyName, string $function): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::rollupByName($name, $rollupPropertyName, $relationPropertyName, $function)); + } + + public function rollupById(string $name, string $rollupPropertyId, string $relationPropertyId, string $function): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::rollupById($name, $rollupPropertyId, $relationPropertyId, $function)); + } + + public function url(string $name = 'Url'): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::url($name)); + } + + public function email(string $name = 'Email'): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::email($name)); + } + + public function phoneNumber(string $name = 'Phone Number'): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::phoneNumber($name)); + } + + public function people(string $name = 'People'): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::people($name)); + } + + public function files(string $name = 'Files'): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::files($name)); + } + + public function createdBy(string $name = 'Created By'): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::createdBy($name)); + } + + public function createdTime(string $name = 'Created Time'): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::createdTime($name)); + } + + public function lastEditedBy(string $name = 'Last Edited Time'): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::lastEditedBy($name)); + } + + public function lastEditedTime(string $name = 'Last Edited Time'): DatabaseSchemeBuilder + { + return $this->push(PropertyBuilder::lastEditedTime($name)); + } + + public function getProperties(): Collection + { + return $this->properties; + } +} diff --git a/src/Builder/PropertyBuilder.php b/src/Builder/PropertyBuilder.php index ede0be4..42f5d50 100644 --- a/src/Builder/PropertyBuilder.php +++ b/src/Builder/PropertyBuilder.php @@ -3,43 +3,171 @@ namespace FiveamCode\LaravelNotionApi\Builder; use FiveamCode\LaravelNotionApi\Entities\Properties\Property; +use FiveamCode\LaravelNotionApi\Exceptions\HandlingException; /** * Class PropertyBuilder. */ class PropertyBuilder { - public static function plain($type): PropertyBuilder + + public static function bulk(): DatabaseSchemeBuilder { - return new PropertyBuilder([ + return new DatabaseSchemeBuilder(); + } + + public static function raw(string $name, string $type, array|object $content): PropertyBuilder + { + return new PropertyBuilder($name, [ 'type' => $type, - $type => new \stdClass(), + $type => $content, ]); } - public static function title(): PropertyBuilder + public static function plain(string $name, string $type): PropertyBuilder + { + return self::raw($name, $type, new \stdClass()); + } + + public static function title(string $name = 'Name'): PropertyBuilder { - return self::plain(Property::TITLE); + return self::plain($name, Property::TITLE); } - public static function richText(): PropertyBuilder + public static function richText(string $name = 'Text'): PropertyBuilder { - return self::plain(Property::RICH_TEXT); + return self::plain($name, Property::RICH_TEXT); } + public static function checkbox(string $name = 'Checkbox'): PropertyBuilder + { + return self::plain($name, Property::CHECKBOX); + } - public static function number($format = 'number'): PropertyBuilder + public static function status(string $name): PropertyBuilder { - return new PropertyBuilder([ - 'type' => Property::NUMBER, - Property::NUMBER => [ - 'format' => $format, - ] + return self::plain($name, Property::STATUS); + } + + public static function select(string $name, array $options): PropertyBuilder + { + return self::raw($name, Property::SELECT, [ + 'options' => $options, ]); } - private function __construct(private $payload) + public static function multiSelect(string $name, array $options): PropertyBuilder { + return self::raw($name, Property::MULTI_SELECT, [ + 'options' => $options, + ]); + } + + public static function number(string $name = 'Number', $format = 'number'): PropertyBuilder + { + return self::raw($name, Property::NUMBER, [ + 'format' => $format, + ]); + } + + public static function date(string $name = 'Date'): PropertyBuilder + { + return self::plain($name, Property::DATE); + } + + public static function relation(string $name, string $databaseId): PropertyBuilder + { + return self::raw($name, Property::RELATION, [ + 'database_id' => $databaseId, + ]); + } + + public static function formula(string $name, string $expression) + { + return self::raw($name, Property::FORMULA, [ + 'expression' => $expression + ]); + } + + public static function rollup(string $name, string $rollupProperty, string $relationProperty, string $function): PropertyBuilder + { + return self::rollupByName($name, $rollupProperty, $relationProperty, $function); + } + + public static function rollupByName(string $name, string $rollupPropertyName, string $relationPropertyName, string $function): PropertyBuilder + { + return self::raw($name, Property::ROLLUP, [ + 'relation_property_name' => $relationPropertyName, + 'rollup_property_name' => $rollupPropertyName, + 'function' => $function + ]); + } + + public static function rollupById(string $name, string $rollupPropertyId, string $relationPropertyId, string $function): PropertyBuilder + { + return self::raw($name, Property::ROLLUP, [ + 'relation_property_id' => $relationPropertyId, + 'rollup_property_id' => $rollupPropertyId, + 'function' => $function + ]); + } + + public static function url(string $name = 'Url'): PropertyBuilder + { + return self::plain($name, Property::URL); + } + + public static function email(string $name = 'Email'): PropertyBuilder + { + return self::plain($name, Property::EMAIL); + } + + public static function phoneNumber(string $name = 'Phone Number'): PropertyBuilder + { + return self::plain($name, Property::PHONE_NUMBER); + } + + public static function people(string $name = 'People'): PropertyBuilder + { + return self::plain($name, Property::PEOPLE); + } + + public static function files(string $name = 'Files'): PropertyBuilder + { + return self::plain($name, Property::FILES); + } + + public static function createdBy(string $name = 'Created By'): PropertyBuilder + { + return self::plain($name, Property::CREATED_BY); + } + + public static function createdTime(string $name = 'Created Time'): PropertyBuilder + { + return self::plain($name, Property::CREATED_TIME); + } + + public static function lastEditedBy(string $name = 'Last Edited By'): PropertyBuilder + { + return self::plain($name, Property::LAST_EDITED_BY); + } + + public static function lastEditedTime(string $name = 'Last Edited Time'): PropertyBuilder + { + return self::plain($name, Property::LAST_EDITED_TIME); + } + + private function __construct(private string $name, private array $payload) + { + } + + public function getName(): string + { + if ($this->name == '') { + throw new HandlingException("Properties must have a name. No name given for the property structure:" . json_encode($this->payload)); + } + + return $this->name; } public function payload(): array diff --git a/src/Entities/Properties/Property.php b/src/Entities/Properties/Property.php index 332bd73..63916f1 100644 --- a/src/Entities/Properties/Property.php +++ b/src/Entities/Properties/Property.php @@ -14,6 +14,7 @@ class Property extends Entity const TITLE = 'title'; const RICH_TEXT = 'rich_text'; const NUMBER = 'number'; + const STATUS = 'status'; const SELECT = 'select'; const MULTI_SELECT = 'multi_select'; const DATE = 'date'; From 589455a0c6c02e0fcae583f89534907f7d9f2759 Mon Sep 17 00:00:00 2001 From: Di Date: Sat, 29 Apr 2023 22:08:26 +0900 Subject: [PATCH 24/61] Apply fixes from StyleCI (#136) --- src/Builder/DatabaseBuilder.php | 4 +++- src/Builder/DatabaseSchemeBuilder.php | 2 +- src/Builder/PropertyBuilder.php | 9 ++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Builder/DatabaseBuilder.php b/src/Builder/DatabaseBuilder.php index 66f36a5..188ace9 100644 --- a/src/Builder/DatabaseBuilder.php +++ b/src/Builder/DatabaseBuilder.php @@ -33,7 +33,7 @@ public function createInPage($pageId): Database { $this->payload['parent'] = [ 'type' => 'page_id', - 'page_id' => $pageId + 'page_id' => $pageId, ]; if ($this->payload['properties'] === []) { @@ -66,6 +66,7 @@ public function inline(): DatabaseBuilder public function addTitle($name = 'Name') { $this->add(PropertyBuilder::title($name)); + return $this; } @@ -90,6 +91,7 @@ public function scheme(callable $callback): DatabaseBuilder { $builder = new DatabaseSchemeBuilder(); $callback($builder); + return $this->add($builder); } diff --git a/src/Builder/DatabaseSchemeBuilder.php b/src/Builder/DatabaseSchemeBuilder.php index c774c14..45cfef8 100644 --- a/src/Builder/DatabaseSchemeBuilder.php +++ b/src/Builder/DatabaseSchemeBuilder.php @@ -2,7 +2,6 @@ namespace FiveamCode\LaravelNotionApi\Builder; -use FiveamCode\LaravelNotionApi\Entities\Properties\Property; use Illuminate\Support\Collection; /** @@ -20,6 +19,7 @@ public function __construct() public function push(PropertyBuilder $builder): DatabaseSchemeBuilder { $this->properties->push($builder); + return $this; } diff --git a/src/Builder/PropertyBuilder.php b/src/Builder/PropertyBuilder.php index 42f5d50..973de96 100644 --- a/src/Builder/PropertyBuilder.php +++ b/src/Builder/PropertyBuilder.php @@ -10,7 +10,6 @@ */ class PropertyBuilder { - public static function bulk(): DatabaseSchemeBuilder { return new DatabaseSchemeBuilder(); @@ -85,7 +84,7 @@ public static function relation(string $name, string $databaseId): PropertyBuild public static function formula(string $name, string $expression) { return self::raw($name, Property::FORMULA, [ - 'expression' => $expression + 'expression' => $expression, ]); } @@ -99,7 +98,7 @@ public static function rollupByName(string $name, string $rollupPropertyName, st return self::raw($name, Property::ROLLUP, [ 'relation_property_name' => $relationPropertyName, 'rollup_property_name' => $rollupPropertyName, - 'function' => $function + 'function' => $function, ]); } @@ -108,7 +107,7 @@ public static function rollupById(string $name, string $rollupPropertyId, string return self::raw($name, Property::ROLLUP, [ 'relation_property_id' => $relationPropertyId, 'rollup_property_id' => $rollupPropertyId, - 'function' => $function + 'function' => $function, ]); } @@ -164,7 +163,7 @@ private function __construct(private string $name, private array $payload) public function getName(): string { if ($this->name == '') { - throw new HandlingException("Properties must have a name. No name given for the property structure:" . json_encode($this->payload)); + throw new HandlingException('Properties must have a name. No name given for the property structure:'.json_encode($this->payload)); } return $this->name; From 478f224fdd473db6221d343c083cd86b5ec7fdf4 Mon Sep 17 00:00:00 2001 From: johguentner Date: Sat, 29 Apr 2023 22:45:30 +0900 Subject: [PATCH 25/61] add further database attributes - cover, icon and description - polish typing --- src/Builder/DatabaseBuilder.php | 45 +++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/Builder/DatabaseBuilder.php b/src/Builder/DatabaseBuilder.php index 66f36a5..e61cd92 100644 --- a/src/Builder/DatabaseBuilder.php +++ b/src/Builder/DatabaseBuilder.php @@ -43,7 +43,7 @@ public function createInPage($pageId): Database return $this->databasesEndpoint->create($this->payload()); } - public function title($title): DatabaseBuilder + public function title(string $title): DatabaseBuilder { $this->payload['title'] = [ [ @@ -52,18 +52,59 @@ public function title($title): DatabaseBuilder ], ], ]; + return $this; + } + public function description(string $description): DatabaseBuilder + { + $this->payload['description'] = [ + [ + 'text' => [ + 'content' => $description, + ], + ], + ]; return $this; } public function inline(): DatabaseBuilder { $this->payload['is_inline'] = true; + return $this; + } + + public function iconEmoji(string $icon): DatabaseBuilder + { + $this->payload['icon'] = [ + 'type' => 'emoji', + 'emoji' => $icon, + ]; + return $this; + } + + public function iconExternal(string $url): DatabaseBuilder + { + $this->payload['icon'] = [ + 'type' => 'external', + 'external' => [ + 'url' => $url, + ], + ]; + return $this; + } + public function coverExternal(string $url): DatabaseBuilder + { + $this->payload['cover'] = [ + 'type' => 'external', + 'external' => [ + 'url' => $url, + ], + ]; return $this; } - public function addTitle($name = 'Name') + public function addTitle(string $name = 'Name') { $this->add(PropertyBuilder::title($name)); return $this; From 667928ede1b3084dddf627214af23ff8c8445461 Mon Sep 17 00:00:00 2001 From: Di Date: Sat, 29 Apr 2023 22:45:56 +0900 Subject: [PATCH 26/61] Apply fixes from StyleCI (#137) --- src/Builder/DatabaseBuilder.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Builder/DatabaseBuilder.php b/src/Builder/DatabaseBuilder.php index 2e3100d..172912d 100644 --- a/src/Builder/DatabaseBuilder.php +++ b/src/Builder/DatabaseBuilder.php @@ -52,6 +52,7 @@ public function title(string $title): DatabaseBuilder ], ], ]; + return $this; } @@ -64,12 +65,14 @@ public function description(string $description): DatabaseBuilder ], ], ]; + return $this; } public function inline(): DatabaseBuilder { $this->payload['is_inline'] = true; + return $this; } @@ -79,6 +82,7 @@ public function iconEmoji(string $icon): DatabaseBuilder 'type' => 'emoji', 'emoji' => $icon, ]; + return $this; } @@ -90,6 +94,7 @@ public function iconExternal(string $url): DatabaseBuilder 'url' => $url, ], ]; + return $this; } @@ -101,6 +106,7 @@ public function coverExternal(string $url): DatabaseBuilder 'url' => $url, ], ]; + return $this; } From 2e7043893bd0f6b0e12b5204900981c7863b7a22 Mon Sep 17 00:00:00 2001 From: johguentner Date: Sun, 30 Apr 2023 18:08:37 +0900 Subject: [PATCH 27/61] fix: in `HttpRecorder`, allow query to be empty --- src/Macros/PestHttpRecorder.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Macros/PestHttpRecorder.php b/src/Macros/PestHttpRecorder.php index 7d69c37..9048a05 100644 --- a/src/Macros/PestHttpRecorder.php +++ b/src/Macros/PestHttpRecorder.php @@ -60,9 +60,13 @@ public function handle(Request $request) // create specific filename for storing snapshots $method = Str::lower($request->method()); $name = Str::slug(Str::replace('/', '-', $urlInfo['path'])); - $query = Str::slug(Str::replace('&', '_', Str::replace('=', '-', $urlInfo['query']))); + $query = Str::slug(Str::replace('&', '_', Str::replace('=', '-', $urlInfo['query'] ?? null))); - $fileName = "{$method}_{$name}_{$query}.json"; + if($query != ''){ + $query = "_{$query}"; + } + + $fileName = "{$method}_{$name}{$query}.json"; $directoryPath = "tests/{$this->snapshotDirectory}"; $filePath = "{$directoryPath}/{$fileName}"; @@ -78,6 +82,7 @@ public function handle(Request $request) $recordedResponse = [ 'status' => $response->getStatusCode(), + // 'payload' =>json_decode($request->body(), true), //TODO: potentially add request payload to snapshot 'data' => json_decode($response->getBody()->getContents(), true), ]; From f6c870decd9c85f0523a7948b1a6c1e7e7c384b2 Mon Sep 17 00:00:00 2001 From: johguentner Date: Sun, 30 Apr 2023 18:08:53 +0900 Subject: [PATCH 28/61] fix: missing default name for status properties --- src/Builder/PropertyBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Builder/PropertyBuilder.php b/src/Builder/PropertyBuilder.php index 973de96..b40975e 100644 --- a/src/Builder/PropertyBuilder.php +++ b/src/Builder/PropertyBuilder.php @@ -43,7 +43,7 @@ public static function checkbox(string $name = 'Checkbox'): PropertyBuilder return self::plain($name, Property::CHECKBOX); } - public static function status(string $name): PropertyBuilder + public static function status(string $name = 'Status'): PropertyBuilder { return self::plain($name, Property::STATUS); } From 97be9810922f9d1655fc0c83d551840a63b55151 Mon Sep 17 00:00:00 2001 From: johguentner Date: Sun, 30 Apr 2023 18:09:09 +0900 Subject: [PATCH 29/61] add tests for db creation in databases endpoint --- .../RecordedEndpointDatabasesCreationTest.php | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 tests/RecordedEndpointDatabasesCreationTest.php diff --git a/tests/RecordedEndpointDatabasesCreationTest.php b/tests/RecordedEndpointDatabasesCreationTest.php new file mode 100644 index 0000000..464543a --- /dev/null +++ b/tests/RecordedEndpointDatabasesCreationTest.php @@ -0,0 +1,105 @@ +storeIn('snapshots/databases'); +}); + +it('should create a new database with all available properties', function () { + + $selectOptions = [ + [ + 'name' => 'testing', + 'color' => 'blue' + ] + ]; + + $multiSelectOptions = [ + [ + 'name' => 'testing2', + 'color' => 'yellow' + ] + ]; + + $scheme = PropertyBuilder::bulk() + ->title('Test Title') + ->plain('Test Custom RichText', 'rich_text') + ->richText('Test RichText') + ->checkbox('Test Checkbox') + // ->status() //TODO: Currently not supported due to Notion API versioning + ->select('Test Select', $selectOptions) + ->multiSelect('Test MultiSelect', $multiSelectOptions) + ->number('Test Number', 'dollar') + ->date('Test Date') + ->formula('Test Formula', 'prop("Test MultiSelect")') + ->url('Test Url') + ->email('Test Email') + ->phoneNumber('Test PhoneNumber') + ->people('Test People') + ->files('Test Files') + ->createdBy('Test Created By') + ->createdTime('Test Created Time') + ->lastEditedBy('Test Last Edited By') + ->lastEditedTime('Test Last Edited Time'); + + $databaseEntity = \Notion::databases() + ->build() + // ->inline() //TODO: Currently not supported due to Notion API versioning + ->title('Created By Testing Database') + ->coverExternal('https://example.com/cover.jpg') + ->iconExternal('https://example.com/cover.jpg') + ->description('This Database has been created by a Pest Test from Laravel') + ->add($scheme) + ->createInPage('0adbc2eb57e84569a700a70d537615be'); + + expect($databaseEntity->getProperties())->toHaveCount(18); + expect($databaseEntity->getProperty('Test Title'))->toBeInstanceOf(Title::class); + expect($databaseEntity->getProperty('Test Custom RichText'))->toBeInstanceOf(Text::class); + expect($databaseEntity->getProperty('Test RichText'))->toBeInstanceOf(Text::class); + expect($databaseEntity->getProperty('Test Checkbox'))->toBeInstanceOf(Checkbox::class); + expect($databaseEntity->getProperty('Test Select'))->toBeInstanceOf(Select::class); + expect($databaseEntity->getProperty('Test MultiSelect'))->toBeInstanceOf(MultiSelect::class); + expect($databaseEntity->getProperty('Test Number'))->toBeInstanceOf(Number::class); + expect($databaseEntity->getProperty('Test Date'))->toBeInstanceOf(Date::class); + expect($databaseEntity->getProperty('Test Formula'))->toBeInstanceOf(Formula::class); + expect($databaseEntity->getProperty('Test Url'))->toBeInstanceOf(Url::class); + expect($databaseEntity->getProperty('Test Email'))->toBeInstanceOf(Email::class); + expect($databaseEntity->getProperty('Test PhoneNumber'))->toBeInstanceOf(PhoneNumber::class); + expect($databaseEntity->getProperty('Test People'))->toBeInstanceOf(People::class); + expect($databaseEntity->getProperty('Test Files'))->toBeInstanceOf(Files::class); + expect($databaseEntity->getProperty('Test Created By'))->toBeInstanceOf(CreatedBy::class); + expect($databaseEntity->getProperty('Test Created Time'))->toBeInstanceOf(CreatedTime::class); + expect($databaseEntity->getProperty('Test Last Edited By'))->toBeInstanceOf(LastEditedBy::class); + expect($databaseEntity->getProperty('Test Last Edited Time'))->toBeInstanceOf(LastEditedTime::class); + + expect($databaseEntity->getProperty('Test Select')->getOptions())->toHaveCount(count($selectOptions)); + expect($databaseEntity->getProperty('Test Select')->getOptions()[0]->getName())->toEqual($selectOptions[0]['name']); + expect($databaseEntity->getProperty('Test Select')->getOptions()[0]->getColor())->toEqual($selectOptions[0]['color']); + + expect($databaseEntity->getProperty('Test MultiSelect')->getOptions())->toHaveCount(count($multiSelectOptions)); + expect($databaseEntity->getProperty('Test MultiSelect')->getOptions()[0]->getName())->toEqual($multiSelectOptions[0]['name']); + expect($databaseEntity->getProperty('Test MultiSelect')->getOptions()[0]->getColor())->toEqual($multiSelectOptions[0]['color']); + + expect($databaseEntity->getProperty('Test Number')->getRawResponse()['number']['format'])->toBe('dollar'); +}); From 53c15fbcae9c9a3924aa9fb0a6ca3bdc01444479 Mon Sep 17 00:00:00 2001 From: johguentner Date: Sun, 30 Apr 2023 18:41:28 +0900 Subject: [PATCH 30/61] polish `PestHttpRecorder::class` - remove adding query to file-name - instead add short hash of query to file-name - or (if given) allow user to set a specific name for upcoming query - additionally save header, method and payload within the snapshot --- src/Macros/PestHttpRecorder.php | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/Macros/PestHttpRecorder.php b/src/Macros/PestHttpRecorder.php index 9048a05..f42509b 100644 --- a/src/Macros/PestHttpRecorder.php +++ b/src/Macros/PestHttpRecorder.php @@ -4,7 +4,9 @@ use GuzzleHttp\Client; use Illuminate\Http\Client\Request; +use Illuminate\Support\Arr; use Illuminate\Support\Facades\File; +use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Http; use Illuminate\Support\Str; @@ -37,6 +39,9 @@ class HttpRecorder private $usePrettyJson = true; + private $requestNames = []; + + public function storeIn($directory) { $this->snapshotDirectory = $directory; @@ -51,26 +56,33 @@ public function minifyJson() return $this; } + public function nameForNextRequest($name) + { + array_push($this->requestNames, $name); + } + public function handle(Request $request) { $forceRecording = in_array('--force-recording', $_SERVER['argv']); $urlInfo = parse_url($request->url()); + $payload = null; // create specific filename for storing snapshots + $header = $request->headers(); $method = Str::lower($request->method()); $name = Str::slug(Str::replace('/', '-', $urlInfo['path'])); - $query = Str::slug(Str::replace('&', '_', Str::replace('=', '-', $urlInfo['query'] ?? null))); + $payload = ($method === 'get') ? $urlInfo['query'] : $request->body(); + $queryName = array_pop($this->requestNames) ?? hash('adler32', $payload); - if($query != ''){ - $query = "_{$query}"; - } - - $fileName = "{$method}_{$name}{$query}.json"; + $fileName = "{$method}_{$name}_{$queryName}.json"; $directoryPath = "tests/{$this->snapshotDirectory}"; $filePath = "{$directoryPath}/{$fileName}"; - if ($forceRecording || ! File::exists($filePath)) { + // filter out Notion API Token Header + $header = Arr::except($header, ['Authorization']); + + if ($forceRecording || !File::exists($filePath)) { File::makeDirectory($directoryPath, 0744, true, true); $client = new Client(); @@ -81,8 +93,10 @@ public function handle(Request $request) ]); $recordedResponse = [ + 'header' => $header, + 'method' => $method, 'status' => $response->getStatusCode(), - // 'payload' =>json_decode($request->body(), true), //TODO: potentially add request payload to snapshot + 'payload' => ($method === 'get') ? $payload : json_decode($payload, true), 'data' => json_decode($response->getBody()->getContents(), true), ]; From 2edd4ea181877485c8e289a2bf7f70e2c5d0c520 Mon Sep 17 00:00:00 2001 From: johguentner Date: Sun, 30 Apr 2023 18:41:58 +0900 Subject: [PATCH 31/61] add query names to `RecordedEndpoint` tests --- tests/RecordedEndpointCommentsTest.php | 7 ++++++- tests/RecordedEndpointDatabasesCreationTest.php | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/RecordedEndpointCommentsTest.php b/tests/RecordedEndpointCommentsTest.php index 15ae88a..9fb24a9 100644 --- a/tests/RecordedEndpointCommentsTest.php +++ b/tests/RecordedEndpointCommentsTest.php @@ -7,12 +7,16 @@ use FiveamCode\LaravelNotionApi\Exceptions\NotionException; use Illuminate\Support\Facades\Http; +$httpRecorder = null; + beforeEach(function () { - Http::recordAndFakeLater('https://api.notion.com/v1/comments*') + $this->httpRecorder = Http::recordAndFakeLater('https://api.notion.com/v1/comments*') ->storeIn('snapshots/comments'); }); it('should fetch list of comments with an accurate representation of attributes', function () { + $this->httpRecorder->nameForNextRequest('list-of-comments'); + $commentCollection = \Notion::comments()->ofBlock('cb588bcbcbdb4f2eac3db05446b8f5d9'); $collection = $commentCollection->asCollection(); @@ -41,6 +45,7 @@ }); it('should throw correct exception if block_id has not been found when listing comments', function () { + $this->httpRecorder->nameForNextRequest('comment-not-found'); $this->expectException(NotionException::class); $this->expectExceptionMessage('Not Found'); $this->expectExceptionCode(404); diff --git a/tests/RecordedEndpointDatabasesCreationTest.php b/tests/RecordedEndpointDatabasesCreationTest.php index 464543a..580bcd3 100644 --- a/tests/RecordedEndpointDatabasesCreationTest.php +++ b/tests/RecordedEndpointDatabasesCreationTest.php @@ -21,13 +21,17 @@ use FiveamCode\LaravelNotionApi\Entities\Properties\Url; use Illuminate\Support\Facades\Http; +$httpRecorder = null; + beforeEach(function () { - Http::recordAndFakeLater('https://api.notion.com/v1/databases*') + $this->httpRecorder = Http::recordAndFakeLater('https://api.notion.com/v1/databases*') ->storeIn('snapshots/databases'); }); it('should create a new database with all available properties', function () { + $this->httpRecorder->nameForNextRequest('all-properties'); + $selectOptions = [ [ 'name' => 'testing', From 039f8f9e4f244aeb7dd05aca2eb81941e60445a2 Mon Sep 17 00:00:00 2001 From: johguentner Date: Sun, 30 Apr 2023 18:43:27 +0900 Subject: [PATCH 32/61] update existing snapshots - based on the modifications of the previous commit regarding the `PestHttpRecorder` polish --- ...-45ca-9715-9fa147ef6b17-page-size-100.json | 9 - .../get_v1-comments_comment-not-found.json | 22 ++ ... => get_v1-comments_list-of-comments.json} | 13 + .../post_v1-databases_all-properties.json | 329 ++++++++++++++++++ 4 files changed, 364 insertions(+), 9 deletions(-) delete mode 100644 tests/snapshots/comments/get_v1-comments_block-id-cbf6b0af-6eaa-45ca-9715-9fa147ef6b17-page-size-100.json create mode 100644 tests/snapshots/comments/get_v1-comments_comment-not-found.json rename tests/snapshots/comments/{get_v1-comments_block-id-cb588bcbcbdb4f2eac3db05446b8f5d9-page-size-100.json => get_v1-comments_list-of-comments.json} (84%) create mode 100644 tests/snapshots/databases/post_v1-databases_all-properties.json diff --git a/tests/snapshots/comments/get_v1-comments_block-id-cbf6b0af-6eaa-45ca-9715-9fa147ef6b17-page-size-100.json b/tests/snapshots/comments/get_v1-comments_block-id-cbf6b0af-6eaa-45ca-9715-9fa147ef6b17-page-size-100.json deleted file mode 100644 index 743a987..0000000 --- a/tests/snapshots/comments/get_v1-comments_block-id-cbf6b0af-6eaa-45ca-9715-9fa147ef6b17-page-size-100.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "status": 404, - "data": { - "object": "error", - "status": 404, - "code": "object_not_found", - "message": "Could not find block with ID: cbf6b0af-6eaa-45ca-9715-9fa147ef6b17. Make sure the relevant pages and databases are shared with your integration." - } -} \ No newline at end of file diff --git a/tests/snapshots/comments/get_v1-comments_comment-not-found.json b/tests/snapshots/comments/get_v1-comments_comment-not-found.json new file mode 100644 index 0000000..1aba430 --- /dev/null +++ b/tests/snapshots/comments/get_v1-comments_comment-not-found.json @@ -0,0 +1,22 @@ +{ + "header": { + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "get", + "status": 404, + "payload": "block_id=cbf6b0af-6eaa-45ca-9715-9fa147ef6b17&page_size=100&", + "data": { + "object": "error", + "status": 404, + "code": "object_not_found", + "message": "Could not find block with ID: cbf6b0af-6eaa-45ca-9715-9fa147ef6b17. Make sure the relevant pages and databases are shared with your integration." + } +} \ No newline at end of file diff --git a/tests/snapshots/comments/get_v1-comments_block-id-cb588bcbcbdb4f2eac3db05446b8f5d9-page-size-100.json b/tests/snapshots/comments/get_v1-comments_list-of-comments.json similarity index 84% rename from tests/snapshots/comments/get_v1-comments_block-id-cb588bcbcbdb4f2eac3db05446b8f5d9-page-size-100.json rename to tests/snapshots/comments/get_v1-comments_list-of-comments.json index 5769c30..e92b7b9 100644 --- a/tests/snapshots/comments/get_v1-comments_block-id-cb588bcbcbdb4f2eac3db05446b8f5d9-page-size-100.json +++ b/tests/snapshots/comments/get_v1-comments_list-of-comments.json @@ -1,5 +1,18 @@ { + "header": { + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "get", "status": 200, + "payload": "block_id=cb588bcbcbdb4f2eac3db05446b8f5d9&page_size=100&", "data": { "object": "list", "results": [ diff --git a/tests/snapshots/databases/post_v1-databases_all-properties.json b/tests/snapshots/databases/post_v1-databases_all-properties.json new file mode 100644 index 0000000..78f7f60 --- /dev/null +++ b/tests/snapshots/databases/post_v1-databases_all-properties.json @@ -0,0 +1,329 @@ +{ + "header": { + "Content-Length": [ + "1498" + ], + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Content-Type": [ + "application\/json" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "post", + "status": 200, + "payload": { + "is_inline": false, + "parent": { + "type": "page_id", + "page_id": "0adbc2eb57e84569a700a70d537615be" + }, + "title": [ + { + "text": { + "content": "Created By Testing Database" + } + } + ], + "properties": { + "Test Title": { + "type": "title", + "title": [] + }, + "Test Custom RichText": { + "type": "rich_text", + "rich_text": [] + }, + "Test RichText": { + "type": "rich_text", + "rich_text": [] + }, + "Test Checkbox": { + "type": "checkbox", + "checkbox": [] + }, + "Test Select": { + "type": "select", + "select": { + "options": [ + { + "name": "testing", + "color": "blue" + } + ] + } + }, + "Test MultiSelect": { + "type": "multi_select", + "multi_select": { + "options": [ + { + "name": "testing2", + "color": "yellow" + } + ] + } + }, + "Test Number": { + "type": "number", + "number": { + "format": "dollar" + } + }, + "Test Date": { + "type": "date", + "date": [] + }, + "Test Formula": { + "type": "formula", + "formula": { + "expression": "prop(\"Test MultiSelect\")" + } + }, + "Test Url": { + "type": "url", + "url": [] + }, + "Test Email": { + "type": "email", + "email": [] + }, + "Test PhoneNumber": { + "type": "phone_number", + "phone_number": [] + }, + "Test People": { + "type": "people", + "people": [] + }, + "Test Files": { + "type": "files", + "files": [] + }, + "Test Created By": { + "type": "created_by", + "created_by": [] + }, + "Test Created Time": { + "type": "created_time", + "created_time": [] + }, + "Test Last Edited By": { + "type": "last_edited_by", + "last_edited_by": [] + }, + "Test Last Edited Time": { + "type": "last_edited_time", + "last_edited_time": [] + } + }, + "cover": { + "type": "external", + "external": { + "url": "https:\/\/example.com\/cover.jpg" + } + }, + "icon": { + "type": "external", + "external": { + "url": "https:\/\/example.com\/cover.jpg" + } + }, + "description": [ + { + "text": { + "content": "This Database has been created by a Pest Test from Laravel" + } + } + ] + }, + "data": { + "object": "database", + "id": "baa6be67-5de6-4128-bc41-04272961506f", + "cover": { + "type": "external", + "external": { + "url": "https:\/\/example.com\/cover.jpg" + } + }, + "icon": { + "type": "external", + "external": { + "url": "https:\/\/example.com\/cover.jpg" + } + }, + "created_time": "2023-04-30T09:37:00.000Z", + "created_by": { + "object": "user", + "id": "1068e45a-6f6d-4b78-abd0-0d1d44bde855" + }, + "last_edited_by": { + "object": "user", + "id": "1068e45a-6f6d-4b78-abd0-0d1d44bde855" + }, + "last_edited_time": "2023-04-30T09:37:00.000Z", + "title": [ + { + "type": "text", + "text": { + "content": "Created By Testing Database", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "Created By Testing Database", + "href": null + } + ], + "description": [], + "is_inline": false, + "properties": { + "Test PhoneNumber": { + "id": "AIv", + "name": "Test Date", + "type": "date", + "date": [] + }, + "Test Email": { + "id": "`Xl_", + "name": "Test Email", + "type": "email", + "email": [] + }, + "Test People": { + "id": "`fWn", + "name": "Test People", + "type": "people", + "people": [] + }, + "Test Created Time": { + "id": "bjoD", + "name": "Test Created Time", + "type": "created_time", + "created_time": [] + }, + "Test Created By": { + "id": "jLFx", + "name": "Test Created By", + "type": "created_by", + "created_by": [] + }, + "Test Files": { + "id": "pBRs", + "name": "Test Files", + "type": "files", + "files": [] + }, + "Test Last Edited Time": { + "id": "uEkS", + "name": "Test Last Edited Time", + "type": "last_edited_time", + "last_edited_time": [] + }, + "Test Url": { + "id": "v?Pt", + "name": "Test Url", + "type": "url", + "url": [] + }, + "Test Formula": { + "id": "x\\{j", + "name": "Test Formula", + "type": "formula", + "formula": { + "expression": "prop(\"Test MultiSelect\")" + } + }, + "Test RichText": { + "id": "z;Oz", + "name": "Test RichText", + "type": "rich_text", + "rich_text": [] + }, + "Test Custom RichText": { + "id": "z|Z]", + "name": "Test Custom RichText", + "type": "rich_text", + "rich_text": [] + }, + "Test Checkbox": { + "id": "~KYE", + "name": "Test Checkbox", + "type": "checkbox", + "checkbox": [] + }, + "Test Title": { + "id": "title", + "name": "Test Title", + "type": "title", + "title": [] + } + }, + "parent": { + "type": "page_id", + "page_id": "0adbc2eb-57e8-4569-a700-a70d537615be" + }, + "url": "https:\/\/www.notion.so\/baa6be675de64128bc4104272961506f", + "archived": false + } +} \ No newline at end of file From ad5d85d2ea2a14120cd878bab70ad44e9c2a24b5 Mon Sep 17 00:00:00 2001 From: Di Date: Sun, 30 Apr 2023 18:43:43 +0900 Subject: [PATCH 33/61] Apply fixes from StyleCI (#141) --- src/Macros/PestHttpRecorder.php | 4 +--- tests/RecordedEndpointDatabasesCreationTest.php | 10 ++++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Macros/PestHttpRecorder.php b/src/Macros/PestHttpRecorder.php index f42509b..6433509 100644 --- a/src/Macros/PestHttpRecorder.php +++ b/src/Macros/PestHttpRecorder.php @@ -6,7 +6,6 @@ use Illuminate\Http\Client\Request; use Illuminate\Support\Arr; use Illuminate\Support\Facades\File; -use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Http; use Illuminate\Support\Str; @@ -41,7 +40,6 @@ class HttpRecorder private $requestNames = []; - public function storeIn($directory) { $this->snapshotDirectory = $directory; @@ -82,7 +80,7 @@ public function handle(Request $request) // filter out Notion API Token Header $header = Arr::except($header, ['Authorization']); - if ($forceRecording || !File::exists($filePath)) { + if ($forceRecording || ! File::exists($filePath)) { File::makeDirectory($directoryPath, 0744, true, true); $client = new Client(); diff --git a/tests/RecordedEndpointDatabasesCreationTest.php b/tests/RecordedEndpointDatabasesCreationTest.php index 580bcd3..1aed468 100644 --- a/tests/RecordedEndpointDatabasesCreationTest.php +++ b/tests/RecordedEndpointDatabasesCreationTest.php @@ -1,6 +1,5 @@ httpRecorder->nameForNextRequest('all-properties'); $selectOptions = [ [ 'name' => 'testing', - 'color' => 'blue' - ] + 'color' => 'blue', + ], ]; $multiSelectOptions = [ [ 'name' => 'testing2', - 'color' => 'yellow' - ] + 'color' => 'yellow', + ], ]; $scheme = PropertyBuilder::bulk() From 39d981d9e5bfa43eaab40f0379e8a6c714249d72 Mon Sep 17 00:00:00 2001 From: johguentner Date: Sun, 30 Apr 2023 22:31:18 +0900 Subject: [PATCH 34/61] add no-title-property test --- .../RecordedEndpointDatabasesCreationTest.php | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/RecordedEndpointDatabasesCreationTest.php b/tests/RecordedEndpointDatabasesCreationTest.php index 1aed468..5285279 100644 --- a/tests/RecordedEndpointDatabasesCreationTest.php +++ b/tests/RecordedEndpointDatabasesCreationTest.php @@ -27,6 +27,18 @@ ->storeIn('snapshots/databases'); }); +it('should throw a handling exception if no title property is added', function(){ + $this->httpRecorder->nameForNextRequest('400-no-title-property'); + $this->expectException(\FiveamCode\LaravelNotionApi\Exceptions\NotionException::class); + $this->expectExceptionMessage('Bad Request: (validation_error) (Title is not provided)'); + $this->expectExceptionCode(400); + + \Notion::databases() + ->build() + ->add(PropertyBuilder::checkbox('Test Checkbox')) + ->createInPage('0adbc2eb57e84569a700a70d537615be'); +}); + it('should create a new database with all available properties', function () { $this->httpRecorder->nameForNextRequest('all-properties'); @@ -74,6 +86,13 @@ ->description('This Database has been created by a Pest Test from Laravel') ->add($scheme) ->createInPage('0adbc2eb57e84569a700a70d537615be'); + + expect($databaseEntity->getCover())->toEqual('https://example.com/cover.jpg'); + expect($databaseEntity->getIcon())->toEqual('https://example.com/cover.jpg'); + //TODO: Currently not supported due to Notion API versioning + // expect($databaseEntity->getDescription())->toEqual('This Database has been created by a Pest Test from Laravel'); + expect($databaseEntity->getTitle())->toEqual('Created By Testing Database'); + expect($databaseEntity->getParentId())->toEqual('0adbc2eb-57e8-4569-a700-a70d537615be'); expect($databaseEntity->getProperties())->toHaveCount(18); expect($databaseEntity->getProperty('Test Title'))->toBeInstanceOf(Title::class); @@ -104,4 +123,4 @@ expect($databaseEntity->getProperty('Test MultiSelect')->getOptions()[0]->getColor())->toEqual($multiSelectOptions[0]['color']); expect($databaseEntity->getProperty('Test Number')->getRawResponse()['number']['format'])->toBe('dollar'); -}); +}); \ No newline at end of file From 71416dcfc522c94ac893a771fe6586d7ba571168 Mon Sep 17 00:00:00 2001 From: johguentner Date: Sun, 30 Apr 2023 22:31:30 +0900 Subject: [PATCH 35/61] update current snapshots (database creation) --- ...st_v1-databases_400-no-title-property.json | 47 ++++++ .../post_v1-databases_all-properties.json | 154 +++++++++--------- 2 files changed, 124 insertions(+), 77 deletions(-) create mode 100644 tests/snapshots/databases/post_v1-databases_400-no-title-property.json diff --git a/tests/snapshots/databases/post_v1-databases_400-no-title-property.json b/tests/snapshots/databases/post_v1-databases_400-no-title-property.json new file mode 100644 index 0000000..4d80e4c --- /dev/null +++ b/tests/snapshots/databases/post_v1-databases_400-no-title-property.json @@ -0,0 +1,47 @@ +{ + "header": { + "Content-Length": [ + "191" + ], + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Content-Type": [ + "application\/json" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "post", + "status": 400, + "payload": { + "is_inline": false, + "parent": { + "type": "page_id", + "page_id": "0adbc2eb57e84569a700a70d537615be" + }, + "title": [ + { + "text": { + "content": "" + } + } + ], + "properties": { + "Test Checkbox": { + "type": "checkbox", + "checkbox": [] + } + } + }, + "data": { + "object": "error", + "status": 400, + "code": "validation_error", + "message": "Title is not provided" + } +} \ No newline at end of file diff --git a/tests/snapshots/databases/post_v1-databases_all-properties.json b/tests/snapshots/databases/post_v1-databases_all-properties.json index 78f7f60..7cf61ba 100644 --- a/tests/snapshots/databases/post_v1-databases_all-properties.json +++ b/tests/snapshots/databases/post_v1-databases_all-properties.json @@ -145,7 +145,7 @@ }, "data": { "object": "database", - "id": "baa6be67-5de6-4128-bc41-04272961506f", + "id": "44cb2b4d-87c7-411d-b911-b6cde4f236d8", "cover": { "type": "external", "external": { @@ -158,7 +158,7 @@ "url": "https:\/\/example.com\/cover.jpg" } }, - "created_time": "2023-04-30T09:37:00.000Z", + "created_time": "2023-04-30T13:29:00.000Z", "created_by": { "object": "user", "id": "1068e45a-6f6d-4b78-abd0-0d1d44bde855" @@ -167,7 +167,7 @@ "object": "user", "id": "1068e45a-6f6d-4b78-abd0-0d1d44bde855" }, - "last_edited_time": "2023-04-30T09:37:00.000Z", + "last_edited_time": "2023-04-30T13:29:00.000Z", "title": [ { "type": "text", @@ -190,128 +190,128 @@ "description": [], "is_inline": false, "properties": { - "Test PhoneNumber": { - "id": "AIv", - "name": "Test Date", - "type": "date", - "date": [] - }, "Test Email": { - "id": "`Xl_", + "id": "[;@E", "name": "Test Email", "type": "email", "email": [] }, - "Test People": { - "id": "`fWn", - "name": "Test People", - "type": "people", - "people": [] + "Test Last Edited By": { + "id": "]AIb", + "name": "Test Last Edited By", + "type": "last_edited_by", + "last_edited_by": [] + }, + "Test PhoneNumber": { + "id": "cZgy", + "name": "Test PhoneNumber", + "type": "phone_number", + "phone_number": [] + }, + "Test Select": { + "id": "knn_", + "name": "Test Select", + "type": "select", + "select": { + "options": [ + { + "id": "5d914a90-fedd-4b31-868e-ff0b10408244", + "name": "testing", + "color": "blue" + } + ] + } }, "Test Created Time": { - "id": "bjoD", + "id": "m}Nt", "name": "Test Created Time", "type": "created_time", "created_time": [] }, "Test Created By": { - "id": "jLFx", + "id": "s}Yd", "name": "Test Created By", "type": "created_by", "created_by": [] }, "Test Files": { - "id": "pBRs", + "id": "u:sB", "name": "Test Files", "type": "files", "files": [] }, - "Test Last Edited Time": { - "id": "uEkS", - "name": "Test Last Edited Time", - "type": "last_edited_time", - "last_edited_time": [] - }, - "Test Url": { - "id": "v?Pt", - "name": "Test Url", - "type": "url", - "url": [] - }, - "Test Formula": { - "id": "x\\{j", - "name": "Test Formula", - "type": "formula", - "formula": { - "expression": "prop(\"Test MultiSelect\")" - } + "Test Checkbox": { + "id": "xddf", + "name": "Test Checkbox", + "type": "checkbox", + "checkbox": [] }, "Test RichText": { - "id": "z;Oz", + "id": "|@=x", "name": "Test RichText", "type": "rich_text", "rich_text": [] }, - "Test Custom RichText": { - "id": "z|Z]", - "name": "Test Custom RichText", - "type": "rich_text", - "rich_text": [] - }, - "Test Checkbox": { - "id": "~KYE", - "name": "Test Checkbox", - "type": "checkbox", - "checkbox": [] - }, "Test Title": { "id": "title", "name": "Test Title", @@ -323,7 +323,7 @@ "type": "page_id", "page_id": "0adbc2eb-57e8-4569-a700-a70d537615be" }, - "url": "https:\/\/www.notion.so\/baa6be675de64128bc4104272961506f", + "url": "https:\/\/www.notion.so\/44cb2b4d87c7411db911b6cde4f236d8", "archived": false } } \ No newline at end of file From 5ef1f9384ec4534cd4a463d2a9e46cb87c1c2ec7 Mon Sep 17 00:00:00 2001 From: Di Date: Sun, 30 Apr 2023 22:31:44 +0900 Subject: [PATCH 36/61] Apply fixes from StyleCI (#142) --- tests/RecordedEndpointDatabasesCreationTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/RecordedEndpointDatabasesCreationTest.php b/tests/RecordedEndpointDatabasesCreationTest.php index 5285279..95f862d 100644 --- a/tests/RecordedEndpointDatabasesCreationTest.php +++ b/tests/RecordedEndpointDatabasesCreationTest.php @@ -27,7 +27,7 @@ ->storeIn('snapshots/databases'); }); -it('should throw a handling exception if no title property is added', function(){ +it('should throw a handling exception if no title property is added', function () { $this->httpRecorder->nameForNextRequest('400-no-title-property'); $this->expectException(\FiveamCode\LaravelNotionApi\Exceptions\NotionException::class); $this->expectExceptionMessage('Bad Request: (validation_error) (Title is not provided)'); @@ -86,7 +86,7 @@ ->description('This Database has been created by a Pest Test from Laravel') ->add($scheme) ->createInPage('0adbc2eb57e84569a700a70d537615be'); - + expect($databaseEntity->getCover())->toEqual('https://example.com/cover.jpg'); expect($databaseEntity->getIcon())->toEqual('https://example.com/cover.jpg'); //TODO: Currently not supported due to Notion API versioning @@ -123,4 +123,4 @@ expect($databaseEntity->getProperty('Test MultiSelect')->getOptions()[0]->getColor())->toEqual($multiSelectOptions[0]['color']); expect($databaseEntity->getProperty('Test Number')->getRawResponse()['number']['format'])->toBe('dollar'); -}); \ No newline at end of file +}); From fe961c850ebc3bbba4d4b03ba878bd8f8904fd5b Mon Sep 17 00:00:00 2001 From: johguentner Date: Tue, 2 May 2023 12:49:59 +0900 Subject: [PATCH 37/61] add and polish phpdocs --- src/Builder/DatabaseBuilder.php | 80 +++++++++++++++ src/Builder/DatabaseSchemeBuilder.php | 136 ++++++++++++++++++++++++- src/Builder/PropertyBuilder.php | 140 +++++++++++++++++++++++++- src/Endpoints/Databases.php | 26 ++++- 4 files changed, 376 insertions(+), 6 deletions(-) diff --git a/src/Builder/DatabaseBuilder.php b/src/Builder/DatabaseBuilder.php index 172912d..a7b1d82 100644 --- a/src/Builder/DatabaseBuilder.php +++ b/src/Builder/DatabaseBuilder.php @@ -11,8 +11,15 @@ */ class DatabaseBuilder { + /** + * @var array + */ private array $payload; + /** + * DatabaseBuilder constructor. + * @param Databases $databasesEndpoint + */ public function __construct(private Databases $databasesEndpoint) { $this->payload = [ @@ -29,6 +36,12 @@ public function __construct(private Databases $databasesEndpoint) ]; } + /** + * Creates database within given page. + * + * @param string $pageId + * @return Database + */ public function createInPage($pageId): Database { $this->payload['parent'] = [ @@ -43,6 +56,12 @@ public function createInPage($pageId): Database return $this->databasesEndpoint->create($this->payload()); } + /** + * Sets the title for the database creation. + * + * @param string $title + * @return DatabaseBuilder + */ public function title(string $title): DatabaseBuilder { $this->payload['title'] = [ @@ -56,6 +75,12 @@ public function title(string $title): DatabaseBuilder return $this; } + /** + * Sets the description for the database creation. + * + * @param string $description + * @return DatabaseBuilder + */ public function description(string $description): DatabaseBuilder { $this->payload['description'] = [ @@ -69,6 +94,12 @@ public function description(string $description): DatabaseBuilder return $this; } + /** + * Sets the created database as inline (currently not supported). + * @todo increase Notion API Version, to make this work + * + * @return DatabaseBuilder + */ public function inline(): DatabaseBuilder { $this->payload['is_inline'] = true; @@ -76,6 +107,12 @@ public function inline(): DatabaseBuilder return $this; } + /** + * Sets the icon for the database creation. + * + * @param string $icon + * @return DatabaseBuilder + */ public function iconEmoji(string $icon): DatabaseBuilder { $this->payload['icon'] = [ @@ -86,6 +123,12 @@ public function iconEmoji(string $icon): DatabaseBuilder return $this; } + /** + * Sets the icon for the database creation. + * + * @param string $url + * @return DatabaseBuilder + */ public function iconExternal(string $url): DatabaseBuilder { $this->payload['icon'] = [ @@ -98,6 +141,12 @@ public function iconExternal(string $url): DatabaseBuilder return $this; } + /** + * Sets the cover for the database creation. + * + * @param string $url + * @return DatabaseBuilder + */ public function coverExternal(string $url): DatabaseBuilder { $this->payload['cover'] = [ @@ -110,6 +159,12 @@ public function coverExternal(string $url): DatabaseBuilder return $this; } + /** + * Adds the property `title` database creation. + * + * @param string $name + * @return DatabaseBuilder + */ public function addTitle(string $name = 'Name') { $this->add(PropertyBuilder::title($name)); @@ -117,6 +172,12 @@ public function addTitle(string $name = 'Name') return $this; } + /** + * Adds one or multiple properties to the database creation. + * + * @param PropertyBuilder|Collection|DatabaseSchemeBuilder $properties + * @return DatabaseBuilder + */ public function add(PropertyBuilder|Collection|DatabaseSchemeBuilder $properties): DatabaseBuilder { if ($properties instanceof PropertyBuilder) { @@ -134,6 +195,12 @@ public function add(PropertyBuilder|Collection|DatabaseSchemeBuilder $properties return $this; } + /** + * Adds multiple properties to the database creation, similar to a Laravel migration. + * + * @param callable $callback + * @return DatabaseBuilder + */ public function scheme(callable $callback): DatabaseBuilder { $builder = new DatabaseSchemeBuilder(); @@ -142,6 +209,14 @@ public function scheme(callable $callback): DatabaseBuilder return $this->add($builder); } + /** + * Adds a raw property to the database creation. + * + * @param string $title + * @param string $propertyType + * @param array|null $content + * @return DatabaseBuilder + */ public function addRaw(string $title, string $propertyType, array $content = null): DatabaseBuilder { $this->payload['properties'][$title] = []; @@ -150,6 +225,11 @@ public function addRaw(string $title, string $propertyType, array $content = nul return $this; } + /** + * Returns the payload for the database creation. + * + * @return array + */ public function payload(): array { return $this->payload; diff --git a/src/Builder/DatabaseSchemeBuilder.php b/src/Builder/DatabaseSchemeBuilder.php index 45cfef8..5d57b23 100644 --- a/src/Builder/DatabaseSchemeBuilder.php +++ b/src/Builder/DatabaseSchemeBuilder.php @@ -9,13 +9,23 @@ */ class DatabaseSchemeBuilder { + /** + * @var Collection|null + */ private ?Collection $properties = null; + /** + * DatabaseSchemeBuilder constructor. + */ public function __construct() { $this->properties = collect(); } + /** + * @param PropertyBuilder $builder + * @return DatabaseSchemeBuilder + */ public function push(PropertyBuilder $builder): DatabaseSchemeBuilder { $this->properties->push($builder); @@ -23,126 +33,250 @@ public function push(PropertyBuilder $builder): DatabaseSchemeBuilder return $this; } + /** + * Add raw property to the database scheme. + * Please reference the Notion API documentation for the content array/object structure. + * + * @param string $name + * @param string $type + * @param array|object $content + * @return DatabaseSchemeBuilder + */ public function raw(string $name, string $type, array|object $content): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::raw($name, $type, $content)); } + /** + * Add plain property to the database scheme. + * For simply adding properties, without required content. + * + * @param string $name + * @param string $type + * @return DatabaseSchemeBuilder + */ public function plain(string $name, string $type): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::plain($name, $type)); } + /** + * @param string $name + * @return DatabaseSchemeBuilder + */ public function title(string $name = 'Name'): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::title($name)); } + /** + * @param string $name + * @return DatabaseSchemeBuilder + */ public function richText(string $name = 'Text'): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::richText($name)); } + /** + * @param string $name + * @return DatabaseSchemeBuilder + */ public function checkbox(string $name = 'Checkbox'): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::checkbox($name)); } + /** + * (currently not supported) + * @todo increase Notion API Version, to make this work + * + * @param string $name + * @return DatabaseSchemeBuilder + */ public function status(string $name = 'Status'): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::status($name)); } + /** + * @param string $name + * @return DatabaseSchemeBuilder + */ public function select(string $name, array $options): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::select($name, $options)); } + /** + * @param string $name + * @param array $options + * @return DatabaseSchemeBuilder + */ public function multiSelect(string $name, array $options): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::multiSelect($name, $options)); } - public function number(string $name = 'Number', $format = 'number'): DatabaseSchemeBuilder + /** + * @param string $name + * @param string $format + * @return DatabaseSchemeBuilder + */ + public function number(string $name = 'Number', string $format = 'number'): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::number($name, $format)); } + /** + * @param string $name + * @return DatabaseSchemeBuilder + */ public function date(string $name = 'Date'): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::date($name)); } + /** + * @param string $name + * @param string $databaseId + * @return DatabaseSchemeBuilder + */ public function relation(string $name, string $databaseId): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::relation($name, $databaseId)); } + /** + * @param string $name + * @param string $expression + * @return DatabaseSchemeBuilder + */ public function formula(string $name, string $expression): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::formula($name, $expression)); } + /** + * @param string $name + * @param string $rollupProperty + * @param string $relationProperty + * @param string $function + * @return DatabaseSchemeBuilder + */ public function rollup(string $name, string $rollupProperty, string $relationProperty, string $function): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::rollup($name, $rollupProperty, $relationProperty, $function)); } + /** + * @param string $name + * @param string $rollupPropertyName + * @param string $relationPropertyName + * @param string $function + * @return DatabaseSchemeBuilder + */ public function rollupByName(string $name, string $rollupPropertyName, string $relationPropertyName, string $function): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::rollupByName($name, $rollupPropertyName, $relationPropertyName, $function)); } + /** + * @param string $name + * @param string $rollupPropertyId + * @param string $relationPropertyId + * @param string $function + * @return DatabaseSchemeBuilder + */ public function rollupById(string $name, string $rollupPropertyId, string $relationPropertyId, string $function): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::rollupById($name, $rollupPropertyId, $relationPropertyId, $function)); } + /** + * @param string $name + * @return DatabaseSchemeBuilder + */ public function url(string $name = 'Url'): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::url($name)); } + /** + * @param string $name + * @return DatabaseSchemeBuilder + */ public function email(string $name = 'Email'): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::email($name)); } + /** + * @param string $name + * @return DatabaseSchemeBuilder + */ public function phoneNumber(string $name = 'Phone Number'): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::phoneNumber($name)); } + /** + * @param string $name + * @return DatabaseSchemeBuilder + */ public function people(string $name = 'People'): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::people($name)); } + /** + * @param string $name + * @return DatabaseSchemeBuilder + */ public function files(string $name = 'Files'): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::files($name)); } + /** + * @param string $name + * @return DatabaseSchemeBuilder + */ public function createdBy(string $name = 'Created By'): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::createdBy($name)); } + /** + * @param string $name + * @return DatabaseSchemeBuilder + */ public function createdTime(string $name = 'Created Time'): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::createdTime($name)); } + /** + * @param string $name + * @return DatabaseSchemeBuilder + */ public function lastEditedBy(string $name = 'Last Edited Time'): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::lastEditedBy($name)); } + /** + * @param string $name + * @return DatabaseSchemeBuilder + */ public function lastEditedTime(string $name = 'Last Edited Time'): DatabaseSchemeBuilder { return $this->push(PropertyBuilder::lastEditedTime($name)); } + /** + * @return Collection + */ public function getProperties(): Collection { return $this->properties; diff --git a/src/Builder/PropertyBuilder.php b/src/Builder/PropertyBuilder.php index b40975e..19bd57d 100644 --- a/src/Builder/PropertyBuilder.php +++ b/src/Builder/PropertyBuilder.php @@ -10,11 +10,25 @@ */ class PropertyBuilder { + /** + * Create a new PropertyBuilder instance, for adding multiple properties at once. + * + * @return DatabaseSchemeBuilder + */ public static function bulk(): DatabaseSchemeBuilder { return new DatabaseSchemeBuilder(); } + /** + * Add raw property to the database scheme. + * Please reference the Notion API documentation for the content array/object structure. + * + * @param string $name + * @param string $type + * @param array|object $content + * @return PropertyBuilder + */ public static function raw(string $name, string $type, array|object $content): PropertyBuilder { return new PropertyBuilder($name, [ @@ -23,31 +37,63 @@ public static function raw(string $name, string $type, array|object $content): P ]); } + /** + * Add plain property to the database scheme. + * For simply adding properties, without required content. + * + * @param string $name + * @param string $type + * @return PropertyBuilder + */ public static function plain(string $name, string $type): PropertyBuilder { return self::raw($name, $type, new \stdClass()); } + /** + * @param string $name + * @return PropertyBuilder + */ public static function title(string $name = 'Name'): PropertyBuilder { return self::plain($name, Property::TITLE); } + /** + * @param string $name + * @return PropertyBuilder + */ public static function richText(string $name = 'Text'): PropertyBuilder { return self::plain($name, Property::RICH_TEXT); } + /** + * @param string $name + * @return PropertyBuilder + */ public static function checkbox(string $name = 'Checkbox'): PropertyBuilder { return self::plain($name, Property::CHECKBOX); } + /** + * (currently not supported) + * @todo increase Notion API Version, to make this work + * + * @param string $name + * @return PropertyBuilder + */ public static function status(string $name = 'Status'): PropertyBuilder { return self::plain($name, Property::STATUS); } + /** + * @param string $name + * @param array $options + * @return PropertyBuilder + */ public static function select(string $name, array $options): PropertyBuilder { return self::raw($name, Property::SELECT, [ @@ -55,6 +101,11 @@ public static function select(string $name, array $options): PropertyBuilder ]); } + /** + * @param string $name + * @param array $options + * @return PropertyBuilder + */ public static function multiSelect(string $name, array $options): PropertyBuilder { return self::raw($name, Property::MULTI_SELECT, [ @@ -62,6 +113,11 @@ public static function multiSelect(string $name, array $options): PropertyBuilde ]); } + /** + * @param string $name + * @param string $format + * @return PropertyBuilder + */ public static function number(string $name = 'Number', $format = 'number'): PropertyBuilder { return self::raw($name, Property::NUMBER, [ @@ -69,11 +125,20 @@ public static function number(string $name = 'Number', $format = 'number'): Prop ]); } + /** + * @param string $name + * @return PropertyBuilder + */ public static function date(string $name = 'Date'): PropertyBuilder { return self::plain($name, Property::DATE); } + /** + * @param string $name + * @param string $databaseId + * @return PropertyBuilder + */ public static function relation(string $name, string $databaseId): PropertyBuilder { return self::raw($name, Property::RELATION, [ @@ -81,6 +146,11 @@ public static function relation(string $name, string $databaseId): PropertyBuild ]); } + /** + * @param string $name + * @param string $expression + * @return PropertyBuilder + */ public static function formula(string $name, string $expression) { return self::raw($name, Property::FORMULA, [ @@ -88,11 +158,25 @@ public static function formula(string $name, string $expression) ]); } + /** + * @param string $name + * @param string $rollupProperty + * @param string $relationProperty + * @param string $function + * @return PropertyBuilder + */ public static function rollup(string $name, string $rollupProperty, string $relationProperty, string $function): PropertyBuilder { return self::rollupByName($name, $rollupProperty, $relationProperty, $function); } + /** + * @param string $name + * @param string $rollupPropertyName + * @param string $relationPropertyName + * @param string $function + * @return PropertyBuilder + */ public static function rollupByName(string $name, string $rollupPropertyName, string $relationPropertyName, string $function): PropertyBuilder { return self::raw($name, Property::ROLLUP, [ @@ -102,6 +186,13 @@ public static function rollupByName(string $name, string $rollupPropertyName, st ]); } + /** + * @param string $name + * @param string $rollupPropertyId + * @param string $relationPropertyId + * @param string $function + * @return PropertyBuilder + */ public static function rollupById(string $name, string $rollupPropertyId, string $relationPropertyId, string $function): PropertyBuilder { return self::raw($name, Property::ROLLUP, [ @@ -111,64 +202,111 @@ public static function rollupById(string $name, string $rollupPropertyId, string ]); } + /** + * @param string $name + * @return PropertyBuilder + */ public static function url(string $name = 'Url'): PropertyBuilder { return self::plain($name, Property::URL); } + /** + * @param string $name + * @return PropertyBuilder + */ public static function email(string $name = 'Email'): PropertyBuilder { return self::plain($name, Property::EMAIL); } + /** + * @param string $name + * @return PropertyBuilder + */ public static function phoneNumber(string $name = 'Phone Number'): PropertyBuilder { return self::plain($name, Property::PHONE_NUMBER); } + /** + * @param string $name + * @return PropertyBuilder + */ public static function people(string $name = 'People'): PropertyBuilder { return self::plain($name, Property::PEOPLE); } + /** + * @param string $name + * @return PropertyBuilder + */ public static function files(string $name = 'Files'): PropertyBuilder { return self::plain($name, Property::FILES); } + /** + * @param string $name + * @return PropertyBuilder + */ public static function createdBy(string $name = 'Created By'): PropertyBuilder { return self::plain($name, Property::CREATED_BY); } + /** + * @param string $name + * @return PropertyBuilder + */ public static function createdTime(string $name = 'Created Time'): PropertyBuilder { return self::plain($name, Property::CREATED_TIME); } + /** + * @param string $name + * @return PropertyBuilder + */ public static function lastEditedBy(string $name = 'Last Edited By'): PropertyBuilder { return self::plain($name, Property::LAST_EDITED_BY); } + /** + * @param string $name + * @return PropertyBuilder + */ public static function lastEditedTime(string $name = 'Last Edited Time'): PropertyBuilder { return self::plain($name, Property::LAST_EDITED_TIME); } + /** + * @param string $name + * @param array $payload + */ private function __construct(private string $name, private array $payload) { } + /** + * @return string + * @throws HandlingException + */ public function getName(): string { if ($this->name == '') { - throw new HandlingException('Properties must have a name. No name given for the property structure:'.json_encode($this->payload)); + throw new HandlingException('Properties must have a name. No name given for the property structure:' . json_encode($this->payload)); } return $this->name; } + /** + * @return array + */ public function payload(): array { return $this->payload; diff --git a/src/Endpoints/Databases.php b/src/Endpoints/Databases.php index 95d32b1..4bd408c 100644 --- a/src/Endpoints/Databases.php +++ b/src/Endpoints/Databases.php @@ -18,8 +18,8 @@ class Databases extends Endpoint implements EndpointInterface { /** * List databases - * url: https://api.notion.com/{version}/databases - * notion-api-docs: https://developers.notion.com/reference/get-databases. + * @url https://api.notion.com/{version}/databases + * @reference https://developers.notion.com/reference/get-databases. * * @return DatabaseCollection * @@ -37,8 +37,8 @@ public function all(): DatabaseCollection /** * Retrieve a database - * url: https://api.notion.com/{version}/databases/{database_id} - * notion-api-docs: https://developers.notion.com/reference/retrieve-a-database. + * @url https://api.notion.com/{version}/databases/{database_id} + * @reference https://developers.notion.com/reference/retrieve-a-database. * * @param string $databaseId * @return Database @@ -54,11 +54,29 @@ public function find(string $databaseId): Database return new Database($result); } + /** + * Returns a `DatabaseBuilder`reference, which helps building + * the scheme and information for creation a database + * + * @return DatabaseBuilder + */ public function build() { return new DatabaseBuilder($this); } + /** + * Create a database + * Recommendation: use `build()` to eloquently create databases + * @url https://api.notion.com/{version}/databases (post) + * @reference https://developers.notion.com/reference/create-a-database. + * + * @param array $payload + * @return Database + * + * @throws HandlingException + * @throws NotionException + */ public function create(array $payload): Database { $result = $this From fe0707c6c0380e475d5087d4a80dd84c8f9ac85c Mon Sep 17 00:00:00 2001 From: Di Date: Tue, 2 May 2023 12:50:16 +0900 Subject: [PATCH 38/61] Apply fixes from StyleCI (#144) --- src/Builder/DatabaseBuilder.php | 52 ++++++++-------- src/Builder/DatabaseSchemeBuilder.php | 81 ++++++++++++------------ src/Builder/PropertyBuilder.php | 90 ++++++++++++++------------- src/Endpoints/Databases.php | 22 ++++--- 4 files changed, 128 insertions(+), 117 deletions(-) diff --git a/src/Builder/DatabaseBuilder.php b/src/Builder/DatabaseBuilder.php index a7b1d82..434f703 100644 --- a/src/Builder/DatabaseBuilder.php +++ b/src/Builder/DatabaseBuilder.php @@ -18,7 +18,8 @@ class DatabaseBuilder /** * DatabaseBuilder constructor. - * @param Databases $databasesEndpoint + * + * @param Databases $databasesEndpoint */ public function __construct(private Databases $databasesEndpoint) { @@ -38,8 +39,8 @@ public function __construct(private Databases $databasesEndpoint) /** * Creates database within given page. - * - * @param string $pageId + * + * @param string $pageId * @return Database */ public function createInPage($pageId): Database @@ -58,8 +59,8 @@ public function createInPage($pageId): Database /** * Sets the title for the database creation. - * - * @param string $title + * + * @param string $title * @return DatabaseBuilder */ public function title(string $title): DatabaseBuilder @@ -77,8 +78,8 @@ public function title(string $title): DatabaseBuilder /** * Sets the description for the database creation. - * - * @param string $description + * + * @param string $description * @return DatabaseBuilder */ public function description(string $description): DatabaseBuilder @@ -96,8 +97,9 @@ public function description(string $description): DatabaseBuilder /** * Sets the created database as inline (currently not supported). + * * @todo increase Notion API Version, to make this work - * + * * @return DatabaseBuilder */ public function inline(): DatabaseBuilder @@ -109,8 +111,8 @@ public function inline(): DatabaseBuilder /** * Sets the icon for the database creation. - * - * @param string $icon + * + * @param string $icon * @return DatabaseBuilder */ public function iconEmoji(string $icon): DatabaseBuilder @@ -125,8 +127,8 @@ public function iconEmoji(string $icon): DatabaseBuilder /** * Sets the icon for the database creation. - * - * @param string $url + * + * @param string $url * @return DatabaseBuilder */ public function iconExternal(string $url): DatabaseBuilder @@ -143,8 +145,8 @@ public function iconExternal(string $url): DatabaseBuilder /** * Sets the cover for the database creation. - * - * @param string $url + * + * @param string $url * @return DatabaseBuilder */ public function coverExternal(string $url): DatabaseBuilder @@ -161,8 +163,8 @@ public function coverExternal(string $url): DatabaseBuilder /** * Adds the property `title` database creation. - * - * @param string $name + * + * @param string $name * @return DatabaseBuilder */ public function addTitle(string $name = 'Name') @@ -174,8 +176,8 @@ public function addTitle(string $name = 'Name') /** * Adds one or multiple properties to the database creation. - * - * @param PropertyBuilder|Collection|DatabaseSchemeBuilder $properties + * + * @param PropertyBuilder|Collection|DatabaseSchemeBuilder $properties * @return DatabaseBuilder */ public function add(PropertyBuilder|Collection|DatabaseSchemeBuilder $properties): DatabaseBuilder @@ -197,8 +199,8 @@ public function add(PropertyBuilder|Collection|DatabaseSchemeBuilder $properties /** * Adds multiple properties to the database creation, similar to a Laravel migration. - * - * @param callable $callback + * + * @param callable $callback * @return DatabaseBuilder */ public function scheme(callable $callback): DatabaseBuilder @@ -211,10 +213,10 @@ public function scheme(callable $callback): DatabaseBuilder /** * Adds a raw property to the database creation. - * - * @param string $title - * @param string $propertyType - * @param array|null $content + * + * @param string $title + * @param string $propertyType + * @param array|null $content * @return DatabaseBuilder */ public function addRaw(string $title, string $propertyType, array $content = null): DatabaseBuilder @@ -227,7 +229,7 @@ public function addRaw(string $title, string $propertyType, array $content = nul /** * Returns the payload for the database creation. - * + * * @return array */ public function payload(): array diff --git a/src/Builder/DatabaseSchemeBuilder.php b/src/Builder/DatabaseSchemeBuilder.php index 5d57b23..ede2ff3 100644 --- a/src/Builder/DatabaseSchemeBuilder.php +++ b/src/Builder/DatabaseSchemeBuilder.php @@ -23,7 +23,7 @@ public function __construct() } /** - * @param PropertyBuilder $builder + * @param PropertyBuilder $builder * @return DatabaseSchemeBuilder */ public function push(PropertyBuilder $builder): DatabaseSchemeBuilder @@ -36,7 +36,7 @@ public function push(PropertyBuilder $builder): DatabaseSchemeBuilder /** * Add raw property to the database scheme. * Please reference the Notion API documentation for the content array/object structure. - * + * * @param string $name * @param string $type * @param array|object $content @@ -50,7 +50,7 @@ public function raw(string $name, string $type, array|object $content): Database /** * Add plain property to the database scheme. * For simply adding properties, without required content. - * + * * @param string $name * @param string $type * @return DatabaseSchemeBuilder @@ -61,7 +61,7 @@ public function plain(string $name, string $type): DatabaseSchemeBuilder } /** - * @param string $name + * @param string $name * @return DatabaseSchemeBuilder */ public function title(string $name = 'Name'): DatabaseSchemeBuilder @@ -70,7 +70,7 @@ public function title(string $name = 'Name'): DatabaseSchemeBuilder } /** - * @param string $name + * @param string $name * @return DatabaseSchemeBuilder */ public function richText(string $name = 'Text'): DatabaseSchemeBuilder @@ -79,7 +79,7 @@ public function richText(string $name = 'Text'): DatabaseSchemeBuilder } /** - * @param string $name + * @param string $name * @return DatabaseSchemeBuilder */ public function checkbox(string $name = 'Checkbox'): DatabaseSchemeBuilder @@ -88,10 +88,11 @@ public function checkbox(string $name = 'Checkbox'): DatabaseSchemeBuilder } /** - * (currently not supported) + * (currently not supported). + * * @todo increase Notion API Version, to make this work - * - * @param string $name + * + * @param string $name * @return DatabaseSchemeBuilder */ public function status(string $name = 'Status'): DatabaseSchemeBuilder @@ -100,7 +101,7 @@ public function status(string $name = 'Status'): DatabaseSchemeBuilder } /** - * @param string $name + * @param string $name * @return DatabaseSchemeBuilder */ public function select(string $name, array $options): DatabaseSchemeBuilder @@ -109,8 +110,8 @@ public function select(string $name, array $options): DatabaseSchemeBuilder } /** - * @param string $name - * @param array $options + * @param string $name + * @param array $options * @return DatabaseSchemeBuilder */ public function multiSelect(string $name, array $options): DatabaseSchemeBuilder @@ -119,8 +120,8 @@ public function multiSelect(string $name, array $options): DatabaseSchemeBuilder } /** - * @param string $name - * @param string $format + * @param string $name + * @param string $format * @return DatabaseSchemeBuilder */ public function number(string $name = 'Number', string $format = 'number'): DatabaseSchemeBuilder @@ -129,7 +130,7 @@ public function number(string $name = 'Number', string $format = 'number'): Data } /** - * @param string $name + * @param string $name * @return DatabaseSchemeBuilder */ public function date(string $name = 'Date'): DatabaseSchemeBuilder @@ -138,8 +139,8 @@ public function date(string $name = 'Date'): DatabaseSchemeBuilder } /** - * @param string $name - * @param string $databaseId + * @param string $name + * @param string $databaseId * @return DatabaseSchemeBuilder */ public function relation(string $name, string $databaseId): DatabaseSchemeBuilder @@ -148,8 +149,8 @@ public function relation(string $name, string $databaseId): DatabaseSchemeBuilde } /** - * @param string $name - * @param string $expression + * @param string $name + * @param string $expression * @return DatabaseSchemeBuilder */ public function formula(string $name, string $expression): DatabaseSchemeBuilder @@ -158,10 +159,10 @@ public function formula(string $name, string $expression): DatabaseSchemeBuilder } /** - * @param string $name - * @param string $rollupProperty - * @param string $relationProperty - * @param string $function + * @param string $name + * @param string $rollupProperty + * @param string $relationProperty + * @param string $function * @return DatabaseSchemeBuilder */ public function rollup(string $name, string $rollupProperty, string $relationProperty, string $function): DatabaseSchemeBuilder @@ -170,10 +171,10 @@ public function rollup(string $name, string $rollupProperty, string $relationPro } /** - * @param string $name - * @param string $rollupPropertyName - * @param string $relationPropertyName - * @param string $function + * @param string $name + * @param string $rollupPropertyName + * @param string $relationPropertyName + * @param string $function * @return DatabaseSchemeBuilder */ public function rollupByName(string $name, string $rollupPropertyName, string $relationPropertyName, string $function): DatabaseSchemeBuilder @@ -182,10 +183,10 @@ public function rollupByName(string $name, string $rollupPropertyName, string $r } /** - * @param string $name - * @param string $rollupPropertyId - * @param string $relationPropertyId - * @param string $function + * @param string $name + * @param string $rollupPropertyId + * @param string $relationPropertyId + * @param string $function * @return DatabaseSchemeBuilder */ public function rollupById(string $name, string $rollupPropertyId, string $relationPropertyId, string $function): DatabaseSchemeBuilder @@ -194,7 +195,7 @@ public function rollupById(string $name, string $rollupPropertyId, string $relat } /** - * @param string $name + * @param string $name * @return DatabaseSchemeBuilder */ public function url(string $name = 'Url'): DatabaseSchemeBuilder @@ -203,7 +204,7 @@ public function url(string $name = 'Url'): DatabaseSchemeBuilder } /** - * @param string $name + * @param string $name * @return DatabaseSchemeBuilder */ public function email(string $name = 'Email'): DatabaseSchemeBuilder @@ -212,7 +213,7 @@ public function email(string $name = 'Email'): DatabaseSchemeBuilder } /** - * @param string $name + * @param string $name * @return DatabaseSchemeBuilder */ public function phoneNumber(string $name = 'Phone Number'): DatabaseSchemeBuilder @@ -221,7 +222,7 @@ public function phoneNumber(string $name = 'Phone Number'): DatabaseSchemeBuilde } /** - * @param string $name + * @param string $name * @return DatabaseSchemeBuilder */ public function people(string $name = 'People'): DatabaseSchemeBuilder @@ -230,7 +231,7 @@ public function people(string $name = 'People'): DatabaseSchemeBuilder } /** - * @param string $name + * @param string $name * @return DatabaseSchemeBuilder */ public function files(string $name = 'Files'): DatabaseSchemeBuilder @@ -239,7 +240,7 @@ public function files(string $name = 'Files'): DatabaseSchemeBuilder } /** - * @param string $name + * @param string $name * @return DatabaseSchemeBuilder */ public function createdBy(string $name = 'Created By'): DatabaseSchemeBuilder @@ -248,7 +249,7 @@ public function createdBy(string $name = 'Created By'): DatabaseSchemeBuilder } /** - * @param string $name + * @param string $name * @return DatabaseSchemeBuilder */ public function createdTime(string $name = 'Created Time'): DatabaseSchemeBuilder @@ -257,7 +258,7 @@ public function createdTime(string $name = 'Created Time'): DatabaseSchemeBuilde } /** - * @param string $name + * @param string $name * @return DatabaseSchemeBuilder */ public function lastEditedBy(string $name = 'Last Edited Time'): DatabaseSchemeBuilder @@ -266,7 +267,7 @@ public function lastEditedBy(string $name = 'Last Edited Time'): DatabaseSchemeB } /** - * @param string $name + * @param string $name * @return DatabaseSchemeBuilder */ public function lastEditedTime(string $name = 'Last Edited Time'): DatabaseSchemeBuilder diff --git a/src/Builder/PropertyBuilder.php b/src/Builder/PropertyBuilder.php index 19bd57d..793ac87 100644 --- a/src/Builder/PropertyBuilder.php +++ b/src/Builder/PropertyBuilder.php @@ -12,7 +12,7 @@ class PropertyBuilder { /** * Create a new PropertyBuilder instance, for adding multiple properties at once. - * + * * @return DatabaseSchemeBuilder */ public static function bulk(): DatabaseSchemeBuilder @@ -23,7 +23,7 @@ public static function bulk(): DatabaseSchemeBuilder /** * Add raw property to the database scheme. * Please reference the Notion API documentation for the content array/object structure. - * + * * @param string $name * @param string $type * @param array|object $content @@ -40,7 +40,7 @@ public static function raw(string $name, string $type, array|object $content): P /** * Add plain property to the database scheme. * For simply adding properties, without required content. - * + * * @param string $name * @param string $type * @return PropertyBuilder @@ -51,7 +51,7 @@ public static function plain(string $name, string $type): PropertyBuilder } /** - * @param string $name + * @param string $name * @return PropertyBuilder */ public static function title(string $name = 'Name'): PropertyBuilder @@ -60,7 +60,7 @@ public static function title(string $name = 'Name'): PropertyBuilder } /** - * @param string $name + * @param string $name * @return PropertyBuilder */ public static function richText(string $name = 'Text'): PropertyBuilder @@ -69,7 +69,7 @@ public static function richText(string $name = 'Text'): PropertyBuilder } /** - * @param string $name + * @param string $name * @return PropertyBuilder */ public static function checkbox(string $name = 'Checkbox'): PropertyBuilder @@ -78,10 +78,11 @@ public static function checkbox(string $name = 'Checkbox'): PropertyBuilder } /** - * (currently not supported) + * (currently not supported). + * * @todo increase Notion API Version, to make this work - * - * @param string $name + * + * @param string $name * @return PropertyBuilder */ public static function status(string $name = 'Status'): PropertyBuilder @@ -90,8 +91,8 @@ public static function status(string $name = 'Status'): PropertyBuilder } /** - * @param string $name - * @param array $options + * @param string $name + * @param array $options * @return PropertyBuilder */ public static function select(string $name, array $options): PropertyBuilder @@ -102,8 +103,8 @@ public static function select(string $name, array $options): PropertyBuilder } /** - * @param string $name - * @param array $options + * @param string $name + * @param array $options * @return PropertyBuilder */ public static function multiSelect(string $name, array $options): PropertyBuilder @@ -114,8 +115,8 @@ public static function multiSelect(string $name, array $options): PropertyBuilde } /** - * @param string $name - * @param string $format + * @param string $name + * @param string $format * @return PropertyBuilder */ public static function number(string $name = 'Number', $format = 'number'): PropertyBuilder @@ -126,7 +127,7 @@ public static function number(string $name = 'Number', $format = 'number'): Prop } /** - * @param string $name + * @param string $name * @return PropertyBuilder */ public static function date(string $name = 'Date'): PropertyBuilder @@ -135,8 +136,8 @@ public static function date(string $name = 'Date'): PropertyBuilder } /** - * @param string $name - * @param string $databaseId + * @param string $name + * @param string $databaseId * @return PropertyBuilder */ public static function relation(string $name, string $databaseId): PropertyBuilder @@ -147,8 +148,8 @@ public static function relation(string $name, string $databaseId): PropertyBuild } /** - * @param string $name - * @param string $expression + * @param string $name + * @param string $expression * @return PropertyBuilder */ public static function formula(string $name, string $expression) @@ -159,10 +160,10 @@ public static function formula(string $name, string $expression) } /** - * @param string $name - * @param string $rollupProperty - * @param string $relationProperty - * @param string $function + * @param string $name + * @param string $rollupProperty + * @param string $relationProperty + * @param string $function * @return PropertyBuilder */ public static function rollup(string $name, string $rollupProperty, string $relationProperty, string $function): PropertyBuilder @@ -171,10 +172,10 @@ public static function rollup(string $name, string $rollupProperty, string $rela } /** - * @param string $name - * @param string $rollupPropertyName - * @param string $relationPropertyName - * @param string $function + * @param string $name + * @param string $rollupPropertyName + * @param string $relationPropertyName + * @param string $function * @return PropertyBuilder */ public static function rollupByName(string $name, string $rollupPropertyName, string $relationPropertyName, string $function): PropertyBuilder @@ -187,10 +188,10 @@ public static function rollupByName(string $name, string $rollupPropertyName, st } /** - * @param string $name - * @param string $rollupPropertyId - * @param string $relationPropertyId - * @param string $function + * @param string $name + * @param string $rollupPropertyId + * @param string $relationPropertyId + * @param string $function * @return PropertyBuilder */ public static function rollupById(string $name, string $rollupPropertyId, string $relationPropertyId, string $function): PropertyBuilder @@ -203,7 +204,7 @@ public static function rollupById(string $name, string $rollupPropertyId, string } /** - * @param string $name + * @param string $name * @return PropertyBuilder */ public static function url(string $name = 'Url'): PropertyBuilder @@ -212,7 +213,7 @@ public static function url(string $name = 'Url'): PropertyBuilder } /** - * @param string $name + * @param string $name * @return PropertyBuilder */ public static function email(string $name = 'Email'): PropertyBuilder @@ -221,7 +222,7 @@ public static function email(string $name = 'Email'): PropertyBuilder } /** - * @param string $name + * @param string $name * @return PropertyBuilder */ public static function phoneNumber(string $name = 'Phone Number'): PropertyBuilder @@ -230,7 +231,7 @@ public static function phoneNumber(string $name = 'Phone Number'): PropertyBuild } /** - * @param string $name + * @param string $name * @return PropertyBuilder */ public static function people(string $name = 'People'): PropertyBuilder @@ -239,7 +240,7 @@ public static function people(string $name = 'People'): PropertyBuilder } /** - * @param string $name + * @param string $name * @return PropertyBuilder */ public static function files(string $name = 'Files'): PropertyBuilder @@ -248,7 +249,7 @@ public static function files(string $name = 'Files'): PropertyBuilder } /** - * @param string $name + * @param string $name * @return PropertyBuilder */ public static function createdBy(string $name = 'Created By'): PropertyBuilder @@ -257,7 +258,7 @@ public static function createdBy(string $name = 'Created By'): PropertyBuilder } /** - * @param string $name + * @param string $name * @return PropertyBuilder */ public static function createdTime(string $name = 'Created Time'): PropertyBuilder @@ -266,7 +267,7 @@ public static function createdTime(string $name = 'Created Time'): PropertyBuild } /** - * @param string $name + * @param string $name * @return PropertyBuilder */ public static function lastEditedBy(string $name = 'Last Edited By'): PropertyBuilder @@ -275,7 +276,7 @@ public static function lastEditedBy(string $name = 'Last Edited By'): PropertyBu } /** - * @param string $name + * @param string $name * @return PropertyBuilder */ public static function lastEditedTime(string $name = 'Last Edited Time'): PropertyBuilder @@ -284,8 +285,8 @@ public static function lastEditedTime(string $name = 'Last Edited Time'): Proper } /** - * @param string $name - * @param array $payload + * @param string $name + * @param array $payload */ private function __construct(private string $name, private array $payload) { @@ -293,12 +294,13 @@ private function __construct(private string $name, private array $payload) /** * @return string + * * @throws HandlingException */ public function getName(): string { if ($this->name == '') { - throw new HandlingException('Properties must have a name. No name given for the property structure:' . json_encode($this->payload)); + throw new HandlingException('Properties must have a name. No name given for the property structure:'.json_encode($this->payload)); } return $this->name; diff --git a/src/Endpoints/Databases.php b/src/Endpoints/Databases.php index 4bd408c..fa39d38 100644 --- a/src/Endpoints/Databases.php +++ b/src/Endpoints/Databases.php @@ -17,8 +17,10 @@ class Databases extends Endpoint implements EndpointInterface { /** - * List databases + * List databases. + * * @url https://api.notion.com/{version}/databases + * * @reference https://developers.notion.com/reference/get-databases. * * @return DatabaseCollection @@ -36,8 +38,10 @@ public function all(): DatabaseCollection } /** - * Retrieve a database + * Retrieve a database. + * * @url https://api.notion.com/{version}/databases/{database_id} + * * @reference https://developers.notion.com/reference/retrieve-a-database. * * @param string $databaseId @@ -55,9 +59,9 @@ public function find(string $databaseId): Database } /** - * Returns a `DatabaseBuilder`reference, which helps building - * the scheme and information for creation a database - * + * Returns a `DatabaseBuilder`reference, which helps building + * the scheme and information for creation a database. + * * @return DatabaseBuilder */ public function build() @@ -67,13 +71,15 @@ public function build() /** * Create a database - * Recommendation: use `build()` to eloquently create databases + * Recommendation: use `build()` to eloquently create databases. + * * @url https://api.notion.com/{version}/databases (post) + * * @reference https://developers.notion.com/reference/create-a-database. - * + * * @param array $payload * @return Database - * + * * @throws HandlingException * @throws NotionException */ From 246396fd9a98ec44be333b35541043fe760d5664 Mon Sep 17 00:00:00 2001 From: johguentner Date: Tue, 2 May 2023 14:10:26 +0900 Subject: [PATCH 39/61] polish phpdocs of comment endpoint --- src/Endpoints/Comments.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Endpoints/Comments.php b/src/Endpoints/Comments.php index f220c66..c25a1be 100644 --- a/src/Endpoints/Comments.php +++ b/src/Endpoints/Comments.php @@ -39,13 +39,12 @@ public function __construct(Notion $notion) /** * Retrieve a list of comments - * url: https://api.notion.com/{version}/comments?block_id=* [get] - * notion-api-docs: https://developers.notion.com/reference/retrieve-a-comment. + * @url https://api.notion.com/{version}/comments?block_id=* [get] + * @reference https://developers.notion.com/reference/retrieve-a-comment. * * @param string $blockId * @return CommentCollection * - * @throws HandlingException * @throws NotionException */ public function ofBlock(string $blockId): CommentCollection @@ -89,13 +88,12 @@ public function onPage(string $pageId): self /** * Create a comment - * url: https://api.notion.com/{version}/comments [post] - * notion-api-docs: https://developers.notion.com/reference/create-a-comment. + * @url https://api.notion.com/{version}/comments [post] + * @reference https://developers.notion.com/reference/create-a-comment. * * @param CommentEntity $comment * @return CommentEntity * - * @throws HandlingException * @throws NotionException */ public function create($comment): CommentEntity From d27f4ff18a7c9e2954989a73f3192c09b5e627b2 Mon Sep 17 00:00:00 2001 From: Di Date: Tue, 2 May 2023 14:10:44 +0900 Subject: [PATCH 40/61] Apply fixes from StyleCI (#145) --- src/Endpoints/Comments.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Endpoints/Comments.php b/src/Endpoints/Comments.php index c25a1be..5d8d64f 100644 --- a/src/Endpoints/Comments.php +++ b/src/Endpoints/Comments.php @@ -38,8 +38,10 @@ public function __construct(Notion $notion) } /** - * Retrieve a list of comments + * Retrieve a list of comments. + * * @url https://api.notion.com/{version}/comments?block_id=* [get] + * * @reference https://developers.notion.com/reference/retrieve-a-comment. * * @param string $blockId @@ -87,8 +89,10 @@ public function onPage(string $pageId): self } /** - * Create a comment + * Create a comment. + * * @url https://api.notion.com/{version}/comments [post] + * * @reference https://developers.notion.com/reference/create-a-comment. * * @param CommentEntity $comment From 9a3730bd7c2f73dcbb3860d7417f6501d19033d2 Mon Sep 17 00:00:00 2001 From: johguentner Date: Tue, 2 May 2023 14:12:40 +0900 Subject: [PATCH 41/61] polish: add newline to improve readability --- src/Entities/NotionParent.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Entities/NotionParent.php b/src/Entities/NotionParent.php index bdb5c19..c5dbae0 100644 --- a/src/Entities/NotionParent.php +++ b/src/Entities/NotionParent.php @@ -18,6 +18,7 @@ class NotionParent extends Entity protected function setResponseData(array $responseData): void { parent::setResponseData($responseData); + if ( $responseData['object'] !== 'page_id' && $responseData['object'] !== 'database_id' @@ -26,6 +27,7 @@ protected function setResponseData(array $responseData): void ) { throw HandlingException::instance('invalid json-array: the given object is not a valid parent'); } + $this->fillFromRaw(); } From 55fe9582af275966d82450c65a730a77a01986a1 Mon Sep 17 00:00:00 2001 From: Di Date: Tue, 2 May 2023 14:12:57 +0900 Subject: [PATCH 42/61] Apply fixes from StyleCI (#146) --- src/Entities/NotionParent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Entities/NotionParent.php b/src/Entities/NotionParent.php index c5dbae0..bf2e2a0 100644 --- a/src/Entities/NotionParent.php +++ b/src/Entities/NotionParent.php @@ -18,7 +18,7 @@ class NotionParent extends Entity protected function setResponseData(array $responseData): void { parent::setResponseData($responseData); - + if ( $responseData['object'] !== 'page_id' && $responseData['object'] !== 'database_id' From 2b11b703be79d1833dc9e8e4fd7e660fb890e6a2 Mon Sep 17 00:00:00 2001 From: johguentner Date: Wed, 3 May 2023 08:36:20 +0900 Subject: [PATCH 43/61] add `parentOf` to access parents easily --- src/Endpoints/Resolve.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/Endpoints/Resolve.php b/src/Endpoints/Resolve.php index 1c84f41..5ca189f 100644 --- a/src/Endpoints/Resolve.php +++ b/src/Endpoints/Resolve.php @@ -4,6 +4,7 @@ use FiveamCode\LaravelNotionApi\Entities\Blocks\Block; use FiveamCode\LaravelNotionApi\Entities\Database; +use FiveamCode\LaravelNotionApi\Entities\Entity; use FiveamCode\LaravelNotionApi\Entities\NotionParent; use FiveamCode\LaravelNotionApi\Entities\Page; use FiveamCode\LaravelNotionApi\Entities\Properties\Relation; @@ -11,6 +12,7 @@ use FiveamCode\LaravelNotionApi\Exceptions\HandlingException; use FiveamCode\LaravelNotionApi\Exceptions\NotionException; use FiveamCode\LaravelNotionApi\Notion; +use FiveamCode\LaravelNotionApi\Traits\HasParent; use Illuminate\Support\Collection; /** @@ -32,6 +34,8 @@ public function __construct(Notion $notion) } /** + * Resolve User + * * @param User $user * @return User * @@ -44,6 +48,26 @@ public function user(User $user): User } /** + * Resolve Parent of an entity + * + * @param Entity $entity + * @return Page|Database|Block + * + * @throws HandlingException + * @throws NotionException + */ + public function parentOf(Entity $entity) + { + if (!in_array(HasParent::class, class_uses_recursive(get_class($entity)))) { + throw new HandlingException("The given entity '{$entity->getObjectType()}' does not have a parent."); + } + + return $this->parent($entity->getParent()); + } + + /** + * Resolve Parent + * * @param NotionParent $parent * @return Page|Database|Block * @@ -67,6 +91,8 @@ public function parent(NotionParent $parent): Page|Database|Block } /** + * Resolve Relations + * * @param Relation $relation * @return Collection * From a82ebeb993949e21f045962adfdf97643132b22d Mon Sep 17 00:00:00 2001 From: Di Date: Wed, 3 May 2023 08:36:38 +0900 Subject: [PATCH 44/61] Apply fixes from StyleCI (#147) --- src/Endpoints/Resolve.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Endpoints/Resolve.php b/src/Endpoints/Resolve.php index 5ca189f..1d11b1d 100644 --- a/src/Endpoints/Resolve.php +++ b/src/Endpoints/Resolve.php @@ -34,8 +34,8 @@ public function __construct(Notion $notion) } /** - * Resolve User - * + * Resolve User. + * * @param User $user * @return User * @@ -48,17 +48,17 @@ public function user(User $user): User } /** - * Resolve Parent of an entity - * + * Resolve Parent of an entity. + * * @param Entity $entity * @return Page|Database|Block - * + * * @throws HandlingException * @throws NotionException */ public function parentOf(Entity $entity) { - if (!in_array(HasParent::class, class_uses_recursive(get_class($entity)))) { + if (! in_array(HasParent::class, class_uses_recursive(get_class($entity)))) { throw new HandlingException("The given entity '{$entity->getObjectType()}' does not have a parent."); } @@ -66,8 +66,8 @@ public function parentOf(Entity $entity) } /** - * Resolve Parent - * + * Resolve Parent. + * * @param NotionParent $parent * @return Page|Database|Block * @@ -91,8 +91,8 @@ public function parent(NotionParent $parent): Page|Database|Block } /** - * Resolve Relations - * + * Resolve Relations. + * * @param Relation $relation * @return Collection * From eb7b39bd61a6fcd82a2a9894a5a3d52fab354d99 Mon Sep 17 00:00:00 2001 From: johguentner Date: Sun, 30 Apr 2023 18:41:28 +0900 Subject: [PATCH 45/61] polish `PestHttpRecorder::class` - remove adding query to file-name - instead add short hash of query to file-name - or (if given) allow user to set a specific name for upcoming query - additionally save header, method and payload within the snapshot --- src/Macros/PestHttpRecorder.php | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/Macros/PestHttpRecorder.php b/src/Macros/PestHttpRecorder.php index 7d69c37..f42509b 100644 --- a/src/Macros/PestHttpRecorder.php +++ b/src/Macros/PestHttpRecorder.php @@ -4,7 +4,9 @@ use GuzzleHttp\Client; use Illuminate\Http\Client\Request; +use Illuminate\Support\Arr; use Illuminate\Support\Facades\File; +use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Http; use Illuminate\Support\Str; @@ -37,6 +39,9 @@ class HttpRecorder private $usePrettyJson = true; + private $requestNames = []; + + public function storeIn($directory) { $this->snapshotDirectory = $directory; @@ -51,22 +56,33 @@ public function minifyJson() return $this; } + public function nameForNextRequest($name) + { + array_push($this->requestNames, $name); + } + public function handle(Request $request) { $forceRecording = in_array('--force-recording', $_SERVER['argv']); $urlInfo = parse_url($request->url()); + $payload = null; // create specific filename for storing snapshots + $header = $request->headers(); $method = Str::lower($request->method()); $name = Str::slug(Str::replace('/', '-', $urlInfo['path'])); - $query = Str::slug(Str::replace('&', '_', Str::replace('=', '-', $urlInfo['query']))); + $payload = ($method === 'get') ? $urlInfo['query'] : $request->body(); + $queryName = array_pop($this->requestNames) ?? hash('adler32', $payload); - $fileName = "{$method}_{$name}_{$query}.json"; + $fileName = "{$method}_{$name}_{$queryName}.json"; $directoryPath = "tests/{$this->snapshotDirectory}"; $filePath = "{$directoryPath}/{$fileName}"; - if ($forceRecording || ! File::exists($filePath)) { + // filter out Notion API Token Header + $header = Arr::except($header, ['Authorization']); + + if ($forceRecording || !File::exists($filePath)) { File::makeDirectory($directoryPath, 0744, true, true); $client = new Client(); @@ -77,7 +93,10 @@ public function handle(Request $request) ]); $recordedResponse = [ + 'header' => $header, + 'method' => $method, 'status' => $response->getStatusCode(), + 'payload' => ($method === 'get') ? $payload : json_decode($payload, true), 'data' => json_decode($response->getBody()->getContents(), true), ]; From cd8116de25fe87b3862120e89ce1bf6078b70494 Mon Sep 17 00:00:00 2001 From: Di Date: Wed, 3 May 2023 09:33:09 +0900 Subject: [PATCH 46/61] Apply fixes from StyleCI (#148) --- src/Macros/PestHttpRecorder.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Macros/PestHttpRecorder.php b/src/Macros/PestHttpRecorder.php index f42509b..6433509 100644 --- a/src/Macros/PestHttpRecorder.php +++ b/src/Macros/PestHttpRecorder.php @@ -6,7 +6,6 @@ use Illuminate\Http\Client\Request; use Illuminate\Support\Arr; use Illuminate\Support\Facades\File; -use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Http; use Illuminate\Support\Str; @@ -41,7 +40,6 @@ class HttpRecorder private $requestNames = []; - public function storeIn($directory) { $this->snapshotDirectory = $directory; @@ -82,7 +80,7 @@ public function handle(Request $request) // filter out Notion API Token Header $header = Arr::except($header, ['Authorization']); - if ($forceRecording || !File::exists($filePath)) { + if ($forceRecording || ! File::exists($filePath)) { File::makeDirectory($directoryPath, 0744, true, true); $client = new Client(); From e73207a0345c1eca22edfd6cab893d7247c94f0e Mon Sep 17 00:00:00 2001 From: johguentner Date: Fri, 9 Jun 2023 18:57:29 +0200 Subject: [PATCH 47/61] add tests for `Notion::resolve()`; polish record - polish `PestHttpRecorder::class` --- src/Endpoints/Resolve.php | 7 +- src/Entities/NotionParent.php | 2 +- src/Macros/PestHttpRecorder.php | 2 +- tests/RecordedEndpointResolveTest.php | 94 +++++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 tests/RecordedEndpointResolveTest.php diff --git a/src/Endpoints/Resolve.php b/src/Endpoints/Resolve.php index 1d11b1d..3019bd9 100644 --- a/src/Endpoints/Resolve.php +++ b/src/Endpoints/Resolve.php @@ -74,7 +74,7 @@ public function parentOf(Entity $entity) * @throws HandlingException * @throws NotionException */ - public function parent(NotionParent $parent): Page|Database|Block + public function parent(NotionParent $parent): Page|Database|Block|NotionParent { switch ($parent->getObjectType()) { case 'page_id': @@ -83,8 +83,9 @@ public function parent(NotionParent $parent): Page|Database|Block return $this->notion->databases()->find($parent->getId()); case 'block_id': return $this->notion->block($parent->getId())->retrieve(); - case 'workspace_id': - throw new HandlingException('A Notion Workspace cannot be resolved by the Notion API.'); + case 'workspace': + return $parent; + // throw new HandlingException('A Notion Workspace cannot be resolved by the Notion API.'); default: throw new HandlingException('Unknown parent type while resolving the notion parent'); } diff --git a/src/Entities/NotionParent.php b/src/Entities/NotionParent.php index bf2e2a0..dba500b 100644 --- a/src/Entities/NotionParent.php +++ b/src/Entities/NotionParent.php @@ -22,7 +22,7 @@ protected function setResponseData(array $responseData): void if ( $responseData['object'] !== 'page_id' && $responseData['object'] !== 'database_id' - && $responseData['object'] !== 'workspace_id' + && $responseData['object'] !== 'workspace' && $responseData['object'] !== 'block_id' ) { throw HandlingException::instance('invalid json-array: the given object is not a valid parent'); diff --git a/src/Macros/PestHttpRecorder.php b/src/Macros/PestHttpRecorder.php index f42509b..4f5c466 100644 --- a/src/Macros/PestHttpRecorder.php +++ b/src/Macros/PestHttpRecorder.php @@ -72,7 +72,7 @@ public function handle(Request $request) $header = $request->headers(); $method = Str::lower($request->method()); $name = Str::slug(Str::replace('/', '-', $urlInfo['path'])); - $payload = ($method === 'get') ? $urlInfo['query'] : $request->body(); + $payload = ($method === 'get') ? ($urlInfo['query'] ?? null) : $request->body(); $queryName = array_pop($this->requestNames) ?? hash('adler32', $payload); $fileName = "{$method}_{$name}_{$queryName}.json"; diff --git a/tests/RecordedEndpointResolveTest.php b/tests/RecordedEndpointResolveTest.php new file mode 100644 index 0000000..c2aa597 --- /dev/null +++ b/tests/RecordedEndpointResolveTest.php @@ -0,0 +1,94 @@ +httpRecorder = Http::recordAndFakeLater([ + 'https://api.notion.com/v1/databases*', + 'https://api.notion.com/v1/pages*', + 'https://api.notion.com/v1/blocks*', + 'https://api.notion.com/v1/users*', + ])->storeIn('snapshots/resolve'); +}); + +it('should resolve the users of specific page properties', function () { + $this->httpRecorder->nameForNextRequest('for-user-resolve'); + $page = Notion::pages()->find('8890c263e97c45339ef5616d5e75360e'); + + $createdBy = $page->getProperty('Created by'); + $lastEditedBy = $page->getProperty('Last edited by'); + $person = $page->getProperty('Person'); + + $createdByUser = Notion::resolve()->user($createdBy->getUser()); + $lastEditedByUser = Notion::resolve()->user($lastEditedBy->getUser()); + $personUser = Notion::resolve()->user($person->getPeople()->first()); + + expect($createdByUser)->toBeInstanceOf(\FiveamCode\LaravelNotionApi\Entities\User::class); + expect($createdByUser->getName())->toBe('TestUser for NotionForLaravel'); + expect($createdByUser->getId())->toBe('455aad58-7aec-4a39-8c0f-37cab3ca38f5'); + + expect($lastEditedByUser)->toBeInstanceOf(\FiveamCode\LaravelNotionApi\Entities\User::class); + expect($lastEditedByUser->getName())->toBe('TestUser for NotionForLaravel'); + expect($lastEditedByUser->getId())->toBe('455aad58-7aec-4a39-8c0f-37cab3ca38f5'); + + expect($personUser)->toBeInstanceOf(\FiveamCode\LaravelNotionApi\Entities\User::class); + expect($personUser->getName())->toBe('TestUser for NotionForLaravel'); + expect($personUser->getId())->toBe('455aad58-7aec-4a39-8c0f-37cab3ca38f5'); +}); + +it('should resolve the page parent of a page', function () { + $page = Notion::pages()->find('a652fac351cc4cc79f5b17eb702793ed'); + $parentPage = Notion::resolve()->parent($page->getParent()); + + expect($parentPage)->toBeInstanceOf(\FiveamCode\LaravelNotionApi\Entities\Page::class); + expect($parentPage->getId())->toBe('5ac149b9-d8f1-4d8d-ac05-facefc16ebf7'); + expect($parentPage->getTitle())->toBe('Resolve Endpoint - Testing Suite'); +}); + +it('should resolve the database parent of a page', function(){ + $page = Notion::pages()->find('415d9b6c6e454f42aab2b6e13804cfe9'); + + $database = Notion::resolve()->parent($page->getParent()); + expect($database)->toBeInstanceOf(\FiveamCode\LaravelNotionApi\Entities\Database::class); + expect($database->getId())->toBe('8a0ef209-8c8a-4fd1-a21c-db7ab327e870'); + expect($database->getTitle())->toBe('Test Table as Parent'); +}); + +it('should resolve the block parent of a block', function(){ + $block = Notion::block('d5f9419b44204c909501b1e2b7569503')->retrieve(); + + $parentBlock = Notion::resolve()->parent($block->getParent()); + expect($parentBlock)->toBeInstanceOf(\FiveamCode\LaravelNotionApi\Entities\Blocks\Block::class); + expect($parentBlock->getId())->toBe('0971ac1a-b6f2-4acc-b706-f5f2ed16ffd6'); + expect($parentBlock->getType())->toBe('paragraph'); +}); + +it('should resolve the page parent of a block', function(){ + $block = Notion::block('0971ac1a-b6f2-4acc-b706-f5f2ed16ffd6')->retrieve(); + + $pageParent = Notion::resolve()->parent($block->getParent()); + expect($pageParent)->toBeInstanceOf(\FiveamCode\LaravelNotionApi\Entities\Page::class); + expect($pageParent->getId())->toBe('d946d011-966d-4b14-973f-dc5580f5b024'); + expect($pageParent->getTitle())->toBe('Page for Block Parent Resolve Testing'); +}); + +it('should throw a handling exception when unknown parent type', function(){ + expect(fn() => new NotionParent(['object' => 'unknown', 'id' => '1234']))->toThrow('invalid json-array: the given object is not a valid parent'); +}); + +it('should resolve the pages of a database relation', function(){ + $page = Notion::pages()->find('1c56e2ad3d95458c935dae6d57769037'); + + $relationPropertyItems = $page->getProperty('Parent Relation Database'); + $relationPages = Notion::resolve()->relations($relationPropertyItems); + + expect($relationPages)->toBeInstanceOf(\Illuminate\Support\Collection::class); + expect($relationPages->count())->toBe(3); + expect($relationPages->first())->toBeInstanceOf(\FiveamCode\LaravelNotionApi\Entities\Page::class); + expect($relationPages->first()->getId())->toBe('cfb10a19-30cc-43a9-8db0-04c43f8cf315'); + expect($relationPages->first()->getTitle())->toBe('test 1'); +}); From 13a560d64cfb69c68c591c5bc40e3f44168dadb4 Mon Sep 17 00:00:00 2001 From: johguentner Date: Fri, 9 Jun 2023 18:58:19 +0200 Subject: [PATCH 48/61] build snapshots for resolve and - ... rebuild snapshots for comments (due to changed file-naming structure) --- ...100.json => get_v1-comments_1c611225.json} | 13 ++ .../comments/get_v1-comments_4aed127b.json | 22 ++++ ...-45ca-9715-9fa147ef6b17-page-size-100.json | 9 -- ...-b6f2-4acc-b706-f5f2ed16ffd6_00000001.json | 59 +++++++++ ...419b44204c909501b1e2b7569503_00000001.json | 59 +++++++++ ...-8c8a-4fd1-a21c-db7ab327e870_00000001.json | 81 ++++++++++++ ...-d38f-484b-a74b-d3273932e9b4_00000001.json | 74 +++++++++++ ...e2ad3d95458c935dae6d57769037_00000001.json | 80 ++++++++++++ ...9b6c6e454f42aab2b6e13804cfe9_00000001.json | 69 ++++++++++ ...-d8f1-4d8d-ac05-facefc16ebf7_00000001.json | 69 ++++++++++ ...45339ef5616d5e75360e_for-user-resolve.json | 119 ++++++++++++++++++ ...fac351cc4cc79f5b17eb702793ed_00000001.json | 69 ++++++++++ ...-30cc-43a9-8db0-04c43f8cf315_00000001.json | 74 +++++++++++ ...-966d-4b14-973f-dc5580f5b024_00000001.json | 69 ++++++++++ ...-0118-461d-a9ed-09c9a6f1e4e2_00000001.json | 74 +++++++++++ ...-7aec-4a39-8c0f-37cab3ca38f5_00000001.json | 26 ++++ 16 files changed, 957 insertions(+), 9 deletions(-) rename tests/snapshots/comments/{get_v1-comments_block-id-cb588bcbcbdb4f2eac3db05446b8f5d9-page-size-100.json => get_v1-comments_1c611225.json} (84%) create mode 100644 tests/snapshots/comments/get_v1-comments_4aed127b.json delete mode 100644 tests/snapshots/comments/get_v1-comments_block-id-cbf6b0af-6eaa-45ca-9715-9fa147ef6b17-page-size-100.json create mode 100644 tests/snapshots/resolve/get_v1-blocks-0971ac1a-b6f2-4acc-b706-f5f2ed16ffd6_00000001.json create mode 100644 tests/snapshots/resolve/get_v1-blocks-d5f9419b44204c909501b1e2b7569503_00000001.json create mode 100644 tests/snapshots/resolve/get_v1-databases-8a0ef209-8c8a-4fd1-a21c-db7ab327e870_00000001.json create mode 100644 tests/snapshots/resolve/get_v1-pages-05b473e4-d38f-484b-a74b-d3273932e9b4_00000001.json create mode 100644 tests/snapshots/resolve/get_v1-pages-1c56e2ad3d95458c935dae6d57769037_00000001.json create mode 100644 tests/snapshots/resolve/get_v1-pages-415d9b6c6e454f42aab2b6e13804cfe9_00000001.json create mode 100644 tests/snapshots/resolve/get_v1-pages-5ac149b9-d8f1-4d8d-ac05-facefc16ebf7_00000001.json create mode 100644 tests/snapshots/resolve/get_v1-pages-8890c263e97c45339ef5616d5e75360e_for-user-resolve.json create mode 100644 tests/snapshots/resolve/get_v1-pages-a652fac351cc4cc79f5b17eb702793ed_00000001.json create mode 100644 tests/snapshots/resolve/get_v1-pages-cfb10a19-30cc-43a9-8db0-04c43f8cf315_00000001.json create mode 100644 tests/snapshots/resolve/get_v1-pages-d946d011-966d-4b14-973f-dc5580f5b024_00000001.json create mode 100644 tests/snapshots/resolve/get_v1-pages-e226b338-0118-461d-a9ed-09c9a6f1e4e2_00000001.json create mode 100644 tests/snapshots/resolve/get_v1-users-455aad58-7aec-4a39-8c0f-37cab3ca38f5_00000001.json diff --git a/tests/snapshots/comments/get_v1-comments_block-id-cb588bcbcbdb4f2eac3db05446b8f5d9-page-size-100.json b/tests/snapshots/comments/get_v1-comments_1c611225.json similarity index 84% rename from tests/snapshots/comments/get_v1-comments_block-id-cb588bcbcbdb4f2eac3db05446b8f5d9-page-size-100.json rename to tests/snapshots/comments/get_v1-comments_1c611225.json index 5769c30..e92b7b9 100644 --- a/tests/snapshots/comments/get_v1-comments_block-id-cb588bcbcbdb4f2eac3db05446b8f5d9-page-size-100.json +++ b/tests/snapshots/comments/get_v1-comments_1c611225.json @@ -1,5 +1,18 @@ { + "header": { + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "get", "status": 200, + "payload": "block_id=cb588bcbcbdb4f2eac3db05446b8f5d9&page_size=100&", "data": { "object": "list", "results": [ diff --git a/tests/snapshots/comments/get_v1-comments_4aed127b.json b/tests/snapshots/comments/get_v1-comments_4aed127b.json new file mode 100644 index 0000000..1aba430 --- /dev/null +++ b/tests/snapshots/comments/get_v1-comments_4aed127b.json @@ -0,0 +1,22 @@ +{ + "header": { + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "get", + "status": 404, + "payload": "block_id=cbf6b0af-6eaa-45ca-9715-9fa147ef6b17&page_size=100&", + "data": { + "object": "error", + "status": 404, + "code": "object_not_found", + "message": "Could not find block with ID: cbf6b0af-6eaa-45ca-9715-9fa147ef6b17. Make sure the relevant pages and databases are shared with your integration." + } +} \ No newline at end of file diff --git a/tests/snapshots/comments/get_v1-comments_block-id-cbf6b0af-6eaa-45ca-9715-9fa147ef6b17-page-size-100.json b/tests/snapshots/comments/get_v1-comments_block-id-cbf6b0af-6eaa-45ca-9715-9fa147ef6b17-page-size-100.json deleted file mode 100644 index 743a987..0000000 --- a/tests/snapshots/comments/get_v1-comments_block-id-cbf6b0af-6eaa-45ca-9715-9fa147ef6b17-page-size-100.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "status": 404, - "data": { - "object": "error", - "status": 404, - "code": "object_not_found", - "message": "Could not find block with ID: cbf6b0af-6eaa-45ca-9715-9fa147ef6b17. Make sure the relevant pages and databases are shared with your integration." - } -} \ No newline at end of file diff --git a/tests/snapshots/resolve/get_v1-blocks-0971ac1a-b6f2-4acc-b706-f5f2ed16ffd6_00000001.json b/tests/snapshots/resolve/get_v1-blocks-0971ac1a-b6f2-4acc-b706-f5f2ed16ffd6_00000001.json new file mode 100644 index 0000000..6feb7cd --- /dev/null +++ b/tests/snapshots/resolve/get_v1-blocks-0971ac1a-b6f2-4acc-b706-f5f2ed16ffd6_00000001.json @@ -0,0 +1,59 @@ +{ + "header": { + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "get", + "status": 200, + "payload": null, + "data": { + "object": "block", + "id": "0971ac1a-b6f2-4acc-b706-f5f2ed16ffd6", + "parent": { + "type": "page_id", + "page_id": "d946d011-966d-4b14-973f-dc5580f5b024" + }, + "created_time": "2023-06-09T16:38:00.000Z", + "last_edited_time": "2023-06-09T16:39:00.000Z", + "created_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "last_edited_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "has_children": true, + "archived": false, + "type": "paragraph", + "paragraph": { + "color": "default", + "text": [ + { + "type": "text", + "text": { + "content": "This is a parent block", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "This is a parent block", + "href": null + } + ] + } + } +} \ No newline at end of file diff --git a/tests/snapshots/resolve/get_v1-blocks-d5f9419b44204c909501b1e2b7569503_00000001.json b/tests/snapshots/resolve/get_v1-blocks-d5f9419b44204c909501b1e2b7569503_00000001.json new file mode 100644 index 0000000..66bc60c --- /dev/null +++ b/tests/snapshots/resolve/get_v1-blocks-d5f9419b44204c909501b1e2b7569503_00000001.json @@ -0,0 +1,59 @@ +{ + "header": { + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "get", + "status": 200, + "payload": null, + "data": { + "object": "block", + "id": "d5f9419b-4420-4c90-9501-b1e2b7569503", + "parent": { + "type": "block_id", + "block_id": "0971ac1a-b6f2-4acc-b706-f5f2ed16ffd6" + }, + "created_time": "2023-06-09T16:39:00.000Z", + "last_edited_time": "2023-06-09T16:39:00.000Z", + "created_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "last_edited_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "has_children": false, + "archived": false, + "type": "paragraph", + "paragraph": { + "color": "default", + "text": [ + { + "type": "text", + "text": { + "content": "Of this child block", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "Of this child block", + "href": null + } + ] + } + } +} \ No newline at end of file diff --git a/tests/snapshots/resolve/get_v1-databases-8a0ef209-8c8a-4fd1-a21c-db7ab327e870_00000001.json b/tests/snapshots/resolve/get_v1-databases-8a0ef209-8c8a-4fd1-a21c-db7ab327e870_00000001.json new file mode 100644 index 0000000..485076f --- /dev/null +++ b/tests/snapshots/resolve/get_v1-databases-8a0ef209-8c8a-4fd1-a21c-db7ab327e870_00000001.json @@ -0,0 +1,81 @@ +{ + "header": { + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "get", + "status": 200, + "payload": null, + "data": { + "object": "database", + "id": "8a0ef209-8c8a-4fd1-a21c-db7ab327e870", + "cover": null, + "icon": { + "type": "external", + "external": { + "url": "https:\/\/www.notion.so\/icons\/people_red.svg" + } + }, + "created_time": "2023-06-09T16:32:00.000Z", + "created_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "last_edited_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "last_edited_time": "2023-06-09T16:35:00.000Z", + "title": [ + { + "type": "text", + "text": { + "content": "Test Table as Parent", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "Test Table as Parent", + "href": null + } + ], + "description": [], + "is_inline": true, + "properties": { + "Tags": { + "id": "[PdA", + "name": "Tags", + "type": "multi_select", + "multi_select": { + "options": [] + } + }, + "Name": { + "id": "title", + "name": "Name", + "type": "title", + "title": [] + } + }, + "parent": { + "type": "page_id", + "page_id": "c3b3afe9-1381-470f-a8b1-4a44b9a3bf81" + }, + "url": "https:\/\/www.notion.so\/8a0ef2098c8a4fd1a21cdb7ab327e870", + "public_url": null, + "archived": false + } +} \ No newline at end of file diff --git a/tests/snapshots/resolve/get_v1-pages-05b473e4-d38f-484b-a74b-d3273932e9b4_00000001.json b/tests/snapshots/resolve/get_v1-pages-05b473e4-d38f-484b-a74b-d3273932e9b4_00000001.json new file mode 100644 index 0000000..21e6075 --- /dev/null +++ b/tests/snapshots/resolve/get_v1-pages-05b473e4-d38f-484b-a74b-d3273932e9b4_00000001.json @@ -0,0 +1,74 @@ +{ + "header": { + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "get", + "status": 200, + "payload": null, + "data": { + "object": "page", + "id": "05b473e4-d38f-484b-a74b-d3273932e9b4", + "created_time": "2023-06-09T16:50:00.000Z", + "last_edited_time": "2023-06-09T16:51:00.000Z", + "created_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "last_edited_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "cover": null, + "icon": null, + "parent": { + "type": "database_id", + "database_id": "96f3b744-c9b5-48f2-849f-521aa7a83f27" + }, + "archived": false, + "properties": { + "Origin Relation Database ": { + "id": "RI]J", + "type": "relation", + "relation": [ + { + "id": "1c56e2ad-3d95-458c-935d-ae6d57769037" + } + ], + "has_more": false + }, + "Name": { + "id": "title", + "type": "title", + "title": [ + { + "type": "text", + "text": { + "content": "test 3", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "test 3", + "href": null + } + ] + } + }, + "url": "https:\/\/www.notion.so\/test-3-05b473e4d38f484ba74bd3273932e9b4", + "public_url": null + } +} \ No newline at end of file diff --git a/tests/snapshots/resolve/get_v1-pages-1c56e2ad3d95458c935dae6d57769037_00000001.json b/tests/snapshots/resolve/get_v1-pages-1c56e2ad3d95458c935dae6d57769037_00000001.json new file mode 100644 index 0000000..f2517d6 --- /dev/null +++ b/tests/snapshots/resolve/get_v1-pages-1c56e2ad3d95458c935dae6d57769037_00000001.json @@ -0,0 +1,80 @@ +{ + "header": { + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "get", + "status": 200, + "payload": null, + "data": { + "object": "page", + "id": "1c56e2ad-3d95-458c-935d-ae6d57769037", + "created_time": "2023-06-09T16:50:00.000Z", + "last_edited_time": "2023-06-09T16:52:00.000Z", + "created_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "last_edited_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "cover": null, + "icon": null, + "parent": { + "type": "database_id", + "database_id": "274ec07d-ae73-4f3a-a907-5f879ca0b6d7" + }, + "archived": false, + "properties": { + "Parent Relation Database": { + "id": "GyPD", + "type": "relation", + "relation": [ + { + "id": "cfb10a19-30cc-43a9-8db0-04c43f8cf315" + }, + { + "id": "e226b338-0118-461d-a9ed-09c9a6f1e4e2" + }, + { + "id": "05b473e4-d38f-484b-a74b-d3273932e9b4" + } + ], + "has_more": false + }, + "Name": { + "id": "title", + "type": "title", + "title": [ + { + "type": "text", + "text": { + "content": "Origin Relation Page", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "Origin Relation Page", + "href": null + } + ] + } + }, + "url": "https:\/\/www.notion.so\/Origin-Relation-Page-1c56e2ad3d95458c935dae6d57769037", + "public_url": null + } +} \ No newline at end of file diff --git a/tests/snapshots/resolve/get_v1-pages-415d9b6c6e454f42aab2b6e13804cfe9_00000001.json b/tests/snapshots/resolve/get_v1-pages-415d9b6c6e454f42aab2b6e13804cfe9_00000001.json new file mode 100644 index 0000000..d9436d9 --- /dev/null +++ b/tests/snapshots/resolve/get_v1-pages-415d9b6c6e454f42aab2b6e13804cfe9_00000001.json @@ -0,0 +1,69 @@ +{ + "header": { + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "get", + "status": 200, + "payload": null, + "data": { + "object": "page", + "id": "415d9b6c-6e45-4f42-aab2-b6e13804cfe9", + "created_time": "2023-06-09T16:32:00.000Z", + "last_edited_time": "2023-06-09T16:32:00.000Z", + "created_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "last_edited_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "cover": null, + "icon": null, + "parent": { + "type": "database_id", + "database_id": "8a0ef209-8c8a-4fd1-a21c-db7ab327e870" + }, + "archived": false, + "properties": { + "Tags": { + "id": "[PdA", + "type": "multi_select", + "multi_select": [] + }, + "Name": { + "id": "title", + "type": "title", + "title": [ + { + "type": "text", + "text": { + "content": "Child Page", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "Child Page", + "href": null + } + ] + } + }, + "url": "https:\/\/www.notion.so\/Child-Page-415d9b6c6e454f42aab2b6e13804cfe9", + "public_url": null + } +} \ No newline at end of file diff --git a/tests/snapshots/resolve/get_v1-pages-5ac149b9-d8f1-4d8d-ac05-facefc16ebf7_00000001.json b/tests/snapshots/resolve/get_v1-pages-5ac149b9-d8f1-4d8d-ac05-facefc16ebf7_00000001.json new file mode 100644 index 0000000..4099414 --- /dev/null +++ b/tests/snapshots/resolve/get_v1-pages-5ac149b9-d8f1-4d8d-ac05-facefc16ebf7_00000001.json @@ -0,0 +1,69 @@ +{ + "header": { + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "get", + "status": 200, + "payload": null, + "data": { + "object": "page", + "id": "5ac149b9-d8f1-4d8d-ac05-facefc16ebf7", + "created_time": "2023-05-03T00:06:00.000Z", + "last_edited_time": "2023-06-09T16:49:00.000Z", + "created_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "last_edited_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "cover": null, + "icon": { + "type": "external", + "external": { + "url": "https:\/\/www.notion.so\/icons\/dependency_red.svg" + } + }, + "parent": { + "type": "page_id", + "page_id": "91f70932-ee63-47b5-9bc2-43e09b4cc9b0" + }, + "archived": false, + "properties": { + "title": { + "id": "title", + "type": "title", + "title": [ + { + "type": "text", + "text": { + "content": "Resolve Endpoint - Testing Suite", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "Resolve Endpoint - Testing Suite", + "href": null + } + ] + } + }, + "url": "https:\/\/www.notion.so\/Resolve-Endpoint-Testing-Suite-5ac149b9d8f14d8dac05facefc16ebf7", + "public_url": null + } +} \ No newline at end of file diff --git a/tests/snapshots/resolve/get_v1-pages-8890c263e97c45339ef5616d5e75360e_for-user-resolve.json b/tests/snapshots/resolve/get_v1-pages-8890c263e97c45339ef5616d5e75360e_for-user-resolve.json new file mode 100644 index 0000000..686dc2f --- /dev/null +++ b/tests/snapshots/resolve/get_v1-pages-8890c263e97c45339ef5616d5e75360e_for-user-resolve.json @@ -0,0 +1,119 @@ +{ + "header": { + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "get", + "status": 200, + "payload": null, + "data": { + "object": "page", + "id": "8890c263-e97c-4533-9ef5-616d5e75360e", + "created_time": "2023-06-09T16:14:00.000Z", + "last_edited_time": "2023-06-09T16:14:00.000Z", + "created_by": { + "object": "user", + "id": "455aad58-7aec-4a39-8c0f-37cab3ca38f5" + }, + "last_edited_by": { + "object": "user", + "id": "455aad58-7aec-4a39-8c0f-37cab3ca38f5" + }, + "cover": null, + "icon": null, + "parent": { + "type": "database_id", + "database_id": "f853b17f-0e70-45f8-8185-29bbe705b2b4" + }, + "archived": false, + "properties": { + "Last edited by": { + "id": "[Pd_", + "type": "last_edited_by", + "last_edited_by": { + "object": "user", + "id": "455aad58-7aec-4a39-8c0f-37cab3ca38f5", + "name": "TestUser for NotionForLaravel", + "avatar_url": null, + "type": "person", + "person": { + "email": "testuser@5amco.de" + } + } + }, + "Created by": { + "id": "bE]Q", + "type": "created_by", + "created_by": { + "object": "user", + "id": "455aad58-7aec-4a39-8c0f-37cab3ca38f5", + "name": "TestUser for NotionForLaravel", + "avatar_url": null, + "type": "person", + "person": { + "email": "testuser@5amco.de" + } + } + }, + "Tags": { + "id": "k}C>", + "type": "multi_select", + "multi_select": [ + { + "id": "769bb074-e4ca-459a-b24f-181d5babfcc6", + "name": "test page 1", + "color": "purple" + } + ] + }, + "Person": { + "id": "vFp]", + "type": "people", + "people": [ + { + "object": "user", + "id": "455aad58-7aec-4a39-8c0f-37cab3ca38f5", + "name": "TestUser for NotionForLaravel", + "avatar_url": null, + "type": "person", + "person": { + "email": "testuser@5amco.de" + } + } + ] + }, + "Name": { + "id": "title", + "type": "title", + "title": [ + { + "type": "text", + "text": { + "content": "Test Page 1", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "Test Page 1", + "href": null + } + ] + } + }, + "url": "https:\/\/www.notion.so\/Test-Page-1-8890c263e97c45339ef5616d5e75360e", + "public_url": null + } +} \ No newline at end of file diff --git a/tests/snapshots/resolve/get_v1-pages-a652fac351cc4cc79f5b17eb702793ed_00000001.json b/tests/snapshots/resolve/get_v1-pages-a652fac351cc4cc79f5b17eb702793ed_00000001.json new file mode 100644 index 0000000..df4f764 --- /dev/null +++ b/tests/snapshots/resolve/get_v1-pages-a652fac351cc4cc79f5b17eb702793ed_00000001.json @@ -0,0 +1,69 @@ +{ + "header": { + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "get", + "status": 200, + "payload": null, + "data": { + "object": "page", + "id": "a652fac3-51cc-4cc7-9f5b-17eb702793ed", + "created_time": "2023-05-03T00:07:00.000Z", + "last_edited_time": "2023-06-09T16:38:00.000Z", + "created_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "last_edited_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "cover": null, + "icon": { + "type": "external", + "external": { + "url": "https:\/\/www.notion.so\/icons\/people_red.svg" + } + }, + "parent": { + "type": "page_id", + "page_id": "5ac149b9-d8f1-4d8d-ac05-facefc16ebf7" + }, + "archived": false, + "properties": { + "title": { + "id": "title", + "type": "title", + "title": [ + { + "type": "text", + "text": { + "content": "Page for Page Parent Resolve Testing", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "Page for Page Parent Resolve Testing", + "href": null + } + ] + } + }, + "url": "https:\/\/www.notion.so\/Page-for-Page-Parent-Resolve-Testing-a652fac351cc4cc79f5b17eb702793ed", + "public_url": null + } +} \ No newline at end of file diff --git a/tests/snapshots/resolve/get_v1-pages-cfb10a19-30cc-43a9-8db0-04c43f8cf315_00000001.json b/tests/snapshots/resolve/get_v1-pages-cfb10a19-30cc-43a9-8db0-04c43f8cf315_00000001.json new file mode 100644 index 0000000..cce5b53 --- /dev/null +++ b/tests/snapshots/resolve/get_v1-pages-cfb10a19-30cc-43a9-8db0-04c43f8cf315_00000001.json @@ -0,0 +1,74 @@ +{ + "header": { + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "get", + "status": 200, + "payload": null, + "data": { + "object": "page", + "id": "cfb10a19-30cc-43a9-8db0-04c43f8cf315", + "created_time": "2023-06-09T16:50:00.000Z", + "last_edited_time": "2023-06-09T16:51:00.000Z", + "created_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "last_edited_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "cover": null, + "icon": null, + "parent": { + "type": "database_id", + "database_id": "96f3b744-c9b5-48f2-849f-521aa7a83f27" + }, + "archived": false, + "properties": { + "Origin Relation Database ": { + "id": "RI]J", + "type": "relation", + "relation": [ + { + "id": "1c56e2ad-3d95-458c-935d-ae6d57769037" + } + ], + "has_more": false + }, + "Name": { + "id": "title", + "type": "title", + "title": [ + { + "type": "text", + "text": { + "content": "test 1", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "test 1", + "href": null + } + ] + } + }, + "url": "https:\/\/www.notion.so\/test-1-cfb10a1930cc43a98db004c43f8cf315", + "public_url": null + } +} \ No newline at end of file diff --git a/tests/snapshots/resolve/get_v1-pages-d946d011-966d-4b14-973f-dc5580f5b024_00000001.json b/tests/snapshots/resolve/get_v1-pages-d946d011-966d-4b14-973f-dc5580f5b024_00000001.json new file mode 100644 index 0000000..e71edcb --- /dev/null +++ b/tests/snapshots/resolve/get_v1-pages-d946d011-966d-4b14-973f-dc5580f5b024_00000001.json @@ -0,0 +1,69 @@ +{ + "header": { + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "get", + "status": 200, + "payload": null, + "data": { + "object": "page", + "id": "d946d011-966d-4b14-973f-dc5580f5b024", + "created_time": "2023-06-09T16:38:00.000Z", + "last_edited_time": "2023-06-09T16:39:00.000Z", + "created_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "last_edited_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "cover": null, + "icon": { + "type": "external", + "external": { + "url": "https:\/\/www.notion.so\/icons\/traffic-cone_red.svg" + } + }, + "parent": { + "type": "page_id", + "page_id": "5ac149b9-d8f1-4d8d-ac05-facefc16ebf7" + }, + "archived": false, + "properties": { + "title": { + "id": "title", + "type": "title", + "title": [ + { + "type": "text", + "text": { + "content": "Page for Block Parent Resolve Testing", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "Page for Block Parent Resolve Testing", + "href": null + } + ] + } + }, + "url": "https:\/\/www.notion.so\/Page-for-Block-Parent-Resolve-Testing-d946d011966d4b14973fdc5580f5b024", + "public_url": null + } +} \ No newline at end of file diff --git a/tests/snapshots/resolve/get_v1-pages-e226b338-0118-461d-a9ed-09c9a6f1e4e2_00000001.json b/tests/snapshots/resolve/get_v1-pages-e226b338-0118-461d-a9ed-09c9a6f1e4e2_00000001.json new file mode 100644 index 0000000..5e245fd --- /dev/null +++ b/tests/snapshots/resolve/get_v1-pages-e226b338-0118-461d-a9ed-09c9a6f1e4e2_00000001.json @@ -0,0 +1,74 @@ +{ + "header": { + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "get", + "status": 200, + "payload": null, + "data": { + "object": "page", + "id": "e226b338-0118-461d-a9ed-09c9a6f1e4e2", + "created_time": "2023-06-09T16:50:00.000Z", + "last_edited_time": "2023-06-09T16:51:00.000Z", + "created_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "last_edited_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "cover": null, + "icon": null, + "parent": { + "type": "database_id", + "database_id": "96f3b744-c9b5-48f2-849f-521aa7a83f27" + }, + "archived": false, + "properties": { + "Origin Relation Database ": { + "id": "RI]J", + "type": "relation", + "relation": [ + { + "id": "1c56e2ad-3d95-458c-935d-ae6d57769037" + } + ], + "has_more": false + }, + "Name": { + "id": "title", + "type": "title", + "title": [ + { + "type": "text", + "text": { + "content": "test 2", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "test 2", + "href": null + } + ] + } + }, + "url": "https:\/\/www.notion.so\/test-2-e226b3380118461da9ed09c9a6f1e4e2", + "public_url": null + } +} \ No newline at end of file diff --git a/tests/snapshots/resolve/get_v1-users-455aad58-7aec-4a39-8c0f-37cab3ca38f5_00000001.json b/tests/snapshots/resolve/get_v1-users-455aad58-7aec-4a39-8c0f-37cab3ca38f5_00000001.json new file mode 100644 index 0000000..0d2daf2 --- /dev/null +++ b/tests/snapshots/resolve/get_v1-users-455aad58-7aec-4a39-8c0f-37cab3ca38f5_00000001.json @@ -0,0 +1,26 @@ +{ + "header": { + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "get", + "status": 200, + "payload": null, + "data": { + "object": "user", + "id": "455aad58-7aec-4a39-8c0f-37cab3ca38f5", + "name": "TestUser for NotionForLaravel", + "avatar_url": null, + "type": "person", + "person": { + "email": "testuser@5amco.de" + } + } +} \ No newline at end of file From 44626bb2ba775742d3cd91ba094eba5a8bd9d57a Mon Sep 17 00:00:00 2001 From: Di Date: Fri, 9 Jun 2023 18:58:35 +0200 Subject: [PATCH 49/61] Apply fixes from StyleCI (#152) --- tests/RecordedEndpointResolveTest.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/RecordedEndpointResolveTest.php b/tests/RecordedEndpointResolveTest.php index c2aa597..e2d7ed6 100644 --- a/tests/RecordedEndpointResolveTest.php +++ b/tests/RecordedEndpointResolveTest.php @@ -1,7 +1,6 @@ getTitle())->toBe('Resolve Endpoint - Testing Suite'); }); -it('should resolve the database parent of a page', function(){ +it('should resolve the database parent of a page', function () { $page = Notion::pages()->find('415d9b6c6e454f42aab2b6e13804cfe9'); $database = Notion::resolve()->parent($page->getParent()); @@ -58,7 +57,7 @@ expect($database->getTitle())->toBe('Test Table as Parent'); }); -it('should resolve the block parent of a block', function(){ +it('should resolve the block parent of a block', function () { $block = Notion::block('d5f9419b44204c909501b1e2b7569503')->retrieve(); $parentBlock = Notion::resolve()->parent($block->getParent()); @@ -67,7 +66,7 @@ expect($parentBlock->getType())->toBe('paragraph'); }); -it('should resolve the page parent of a block', function(){ +it('should resolve the page parent of a block', function () { $block = Notion::block('0971ac1a-b6f2-4acc-b706-f5f2ed16ffd6')->retrieve(); $pageParent = Notion::resolve()->parent($block->getParent()); @@ -76,11 +75,11 @@ expect($pageParent->getTitle())->toBe('Page for Block Parent Resolve Testing'); }); -it('should throw a handling exception when unknown parent type', function(){ - expect(fn() => new NotionParent(['object' => 'unknown', 'id' => '1234']))->toThrow('invalid json-array: the given object is not a valid parent'); +it('should throw a handling exception when unknown parent type', function () { + expect(fn () => new NotionParent(['object' => 'unknown', 'id' => '1234']))->toThrow('invalid json-array: the given object is not a valid parent'); }); -it('should resolve the pages of a database relation', function(){ +it('should resolve the pages of a database relation', function () { $page = Notion::pages()->find('1c56e2ad3d95458c935dae6d57769037'); $relationPropertyItems = $page->getProperty('Parent Relation Database'); From b01fc99ced9ef0b3fb497585f9ebb00689c174c8 Mon Sep 17 00:00:00 2001 From: johguentner Date: Sat, 10 Jun 2023 09:54:21 +0200 Subject: [PATCH 50/61] add simple phpdbg code coverage (cmd) --- .gitignore | 3 ++- composer.json | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 903b824..bfab0ce 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ vendor .phpunit.result.cache coverage/ .phpunit.cache/ -.env* \ No newline at end of file +.env* +coverage-report \ No newline at end of file diff --git a/composer.json b/composer.json index 8e23c63..4c8c627 100644 --- a/composer.json +++ b/composer.json @@ -49,10 +49,13 @@ }, "scripts": { "test": "vendor/bin/pest", - "test-coverage": "vendor/bin/pest --coverage-html coverage" + "test-coverage": "phpdbg -qrr ./vendor/bin/pest --coverage-html ./coverage-report" }, "config": { - "sort-packages": true + "sort-packages": true, + "allow-plugins": { + "pestphp/pest-plugin": true + } }, "extra": { "laravel": { From 0cbd9de42d608d60c94fdba5bf68f6ea031cc591 Mon Sep 17 00:00:00 2001 From: johguentner Date: Sat, 10 Jun 2023 09:54:33 +0200 Subject: [PATCH 51/61] add additional tests for resolve endpoint --- tests/RecordedEndpointResolveTest.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/RecordedEndpointResolveTest.php b/tests/RecordedEndpointResolveTest.php index e2d7ed6..6bc9ca9 100644 --- a/tests/RecordedEndpointResolveTest.php +++ b/tests/RecordedEndpointResolveTest.php @@ -1,6 +1,8 @@ toBeInstanceOf(\FiveamCode\LaravelNotionApi\Entities\Page::class); expect($pageParent->getId())->toBe('d946d011-966d-4b14-973f-dc5580f5b024'); expect($pageParent->getTitle())->toBe('Page for Block Parent Resolve Testing'); + + $pageParent = Notion::resolve()->parentOf($block); + expect($pageParent)->toBeInstanceOf(\FiveamCode\LaravelNotionApi\Entities\Page::class); + expect($pageParent->getId())->toBe('d946d011-966d-4b14-973f-dc5580f5b024'); + expect($pageParent->getTitle())->toBe('Page for Block Parent Resolve Testing'); }); it('should throw a handling exception when unknown parent type', function () { expect(fn () => new NotionParent(['object' => 'unknown', 'id' => '1234']))->toThrow('invalid json-array: the given object is not a valid parent'); }); +it('should throw a handling exception when entity without parent', function () { + $entityWithoutParent = new User(['object' => 'user', 'id' => '1234']); + expect(fn () => Notion::resolve()->parentOf($entityWithoutParent))->toThrow("The given entity 'user' does not have a parent."); +}); + it('should resolve the pages of a database relation', function () { $page = Notion::pages()->find('1c56e2ad3d95458c935dae6d57769037'); @@ -91,3 +103,16 @@ expect($relationPages->first()->getId())->toBe('cfb10a19-30cc-43a9-8db0-04c43f8cf315'); expect($relationPages->first()->getTitle())->toBe('test 1'); }); + +it('should resolve the page titles of a database relation', function () { + $page = Notion::pages()->find('1c56e2ad3d95458c935dae6d57769037'); + + $relationPropertyItems = $page->getProperty('Parent Relation Database'); + $relationPageTitles = Notion::resolve()->relations($relationPropertyItems, true); + + expect($relationPageTitles)->toBeInstanceOf(\Illuminate\Support\Collection::class); + expect($relationPageTitles->count())->toBe(3); + expect($relationPageTitles->first())->toBeString(); + expect($relationPageTitles->first())->toBe('test 1'); +}); + From 1f6aa11147b780ad930fadeba2af8890623a5ba9 Mon Sep 17 00:00:00 2001 From: Di Date: Sat, 10 Jun 2023 09:54:48 +0200 Subject: [PATCH 52/61] Apply fixes from StyleCI (#153) --- tests/RecordedEndpointResolveTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/RecordedEndpointResolveTest.php b/tests/RecordedEndpointResolveTest.php index 6bc9ca9..ef5d8e3 100644 --- a/tests/RecordedEndpointResolveTest.php +++ b/tests/RecordedEndpointResolveTest.php @@ -1,6 +1,5 @@ first())->toBeString(); expect($relationPageTitles->first())->toBe('test 1'); }); - From a3898799c78ec37d584851c51a5ce1b6fb7a3f89 Mon Sep 17 00:00:00 2001 From: johguentner Date: Sat, 10 Jun 2023 10:37:33 +0200 Subject: [PATCH 53/61] add missing properties for database creation test --- .../RecordedEndpointDatabasesCreationTest.php | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/tests/RecordedEndpointDatabasesCreationTest.php b/tests/RecordedEndpointDatabasesCreationTest.php index 95f862d..291575d 100644 --- a/tests/RecordedEndpointDatabasesCreationTest.php +++ b/tests/RecordedEndpointDatabasesCreationTest.php @@ -14,6 +14,8 @@ use FiveamCode\LaravelNotionApi\Entities\Properties\Number; use FiveamCode\LaravelNotionApi\Entities\Properties\People; use FiveamCode\LaravelNotionApi\Entities\Properties\PhoneNumber; +use FiveamCode\LaravelNotionApi\Entities\Properties\Relation; +use FiveamCode\LaravelNotionApi\Entities\Properties\Rollup; use FiveamCode\LaravelNotionApi\Entities\Properties\Select; use FiveamCode\LaravelNotionApi\Entities\Properties\Text; use FiveamCode\LaravelNotionApi\Entities\Properties\Title; @@ -33,7 +35,7 @@ $this->expectExceptionMessage('Bad Request: (validation_error) (Title is not provided)'); $this->expectExceptionCode(400); - \Notion::databases() + Notion::databases() ->build() ->add(PropertyBuilder::checkbox('Test Checkbox')) ->createInPage('0adbc2eb57e84569a700a70d537615be'); @@ -72,12 +74,14 @@ ->phoneNumber('Test PhoneNumber') ->people('Test People') ->files('Test Files') + ->relation('Test Relation', '375da18ab01d42d18e95a9dc6a901db1') + ->rollup('Test Rollup', 'Tag', 'Test Relation', 'unique') ->createdBy('Test Created By') ->createdTime('Test Created Time') ->lastEditedBy('Test Last Edited By') ->lastEditedTime('Test Last Edited Time'); - $databaseEntity = \Notion::databases() + $databaseEntity = Notion::databases() ->build() // ->inline() //TODO: Currently not supported due to Notion API versioning ->title('Created By Testing Database') @@ -94,7 +98,7 @@ expect($databaseEntity->getTitle())->toEqual('Created By Testing Database'); expect($databaseEntity->getParentId())->toEqual('0adbc2eb-57e8-4569-a700-a70d537615be'); - expect($databaseEntity->getProperties())->toHaveCount(18); + expect($databaseEntity->getProperties())->toHaveCount(20); expect($databaseEntity->getProperty('Test Title'))->toBeInstanceOf(Title::class); expect($databaseEntity->getProperty('Test Custom RichText'))->toBeInstanceOf(Text::class); expect($databaseEntity->getProperty('Test RichText'))->toBeInstanceOf(Text::class); @@ -109,11 +113,19 @@ expect($databaseEntity->getProperty('Test PhoneNumber'))->toBeInstanceOf(PhoneNumber::class); expect($databaseEntity->getProperty('Test People'))->toBeInstanceOf(People::class); expect($databaseEntity->getProperty('Test Files'))->toBeInstanceOf(Files::class); + expect($databaseEntity->getProperty('Test Relation'))->toBeInstanceOf(Relation::class); + expect($databaseEntity->getProperty('Test Rollup'))->toBeInstanceOf(Rollup::class); expect($databaseEntity->getProperty('Test Created By'))->toBeInstanceOf(CreatedBy::class); expect($databaseEntity->getProperty('Test Created Time'))->toBeInstanceOf(CreatedTime::class); expect($databaseEntity->getProperty('Test Last Edited By'))->toBeInstanceOf(LastEditedBy::class); expect($databaseEntity->getProperty('Test Last Edited Time'))->toBeInstanceOf(LastEditedTime::class); + expect($databaseEntity->getProperty('Test Relation')->getRelation()[0])->toBe('375da18a-b01d-42d1-8e95-a9dc6a901db1'); + + expect($databaseEntity->getProperty('Test Rollup')->getContent()["rollup_property_name"])->toBe("Tag"); + expect($databaseEntity->getProperty('Test Rollup')->getContent()["relation_property_name"])->toBe("Test Relation"); + expect($databaseEntity->getProperty('Test Rollup')->getContent()["function"])->toBe("unique"); + expect($databaseEntity->getProperty('Test Select')->getOptions())->toHaveCount(count($selectOptions)); expect($databaseEntity->getProperty('Test Select')->getOptions()[0]->getName())->toEqual($selectOptions[0]['name']); expect($databaseEntity->getProperty('Test Select')->getOptions()[0]->getColor())->toEqual($selectOptions[0]['color']); @@ -124,3 +136,28 @@ expect($databaseEntity->getProperty('Test Number')->getRawResponse()['number']['format'])->toBe('dollar'); }); + +it('should create a new database with default title property', function () { + $this->httpRecorder->nameForNextRequest('with-emoji-icon'); + + $databaseEntity = Notion::databases() + ->build() + ->createInPage('0adbc2eb57e84569a700a70d537615be'); + + expect($databaseEntity->getProperties())->toHaveCount(1); + expect($databaseEntity->getProperty('Name'))->toBeInstanceOf(Title::class); +}); + + +it('should create a new database with emoji icon', function () { + $this->httpRecorder->nameForNextRequest('only-title-properties'); + + $databaseEntity = Notion::databases() + ->build() + ->iconEmoji('👍') + ->createInPage('0adbc2eb57e84569a700a70d537615be'); + + expect($databaseEntity->getProperties())->toHaveCount(1); + expect($databaseEntity->getProperty('Name'))->toBeInstanceOf(Title::class); + expect($databaseEntity->getIcon())->toBe('👍'); +}); From 9d2e153d2d31c71884bb45090121715bf6bf9c9f Mon Sep 17 00:00:00 2001 From: johguentner Date: Sat, 10 Jun 2023 10:37:44 +0200 Subject: [PATCH 54/61] updated snapshots (database creation) --- .../post_v1-databases_all-properties.json | 197 +++++++++++------- ...st_v1-databases_only-title-properties.json | 100 +++++++++ .../post_v1-databases_with-emoji-icon.json | 93 +++++++++ 3 files changed, 310 insertions(+), 80 deletions(-) create mode 100644 tests/snapshots/databases/post_v1-databases_only-title-properties.json create mode 100644 tests/snapshots/databases/post_v1-databases_with-emoji-icon.json diff --git a/tests/snapshots/databases/post_v1-databases_all-properties.json b/tests/snapshots/databases/post_v1-databases_all-properties.json index 7cf61ba..6046862 100644 --- a/tests/snapshots/databases/post_v1-databases_all-properties.json +++ b/tests/snapshots/databases/post_v1-databases_all-properties.json @@ -1,7 +1,7 @@ { "header": { "Content-Length": [ - "1498" + "1729" ], "User-Agent": [ "GuzzleHttp\/7" @@ -106,6 +106,20 @@ "type": "files", "files": [] }, + "Test Relation": { + "type": "relation", + "relation": { + "database_id": "375da18ab01d42d18e95a9dc6a901db1" + } + }, + "Test Rollup": { + "type": "rollup", + "rollup": { + "relation_property_name": "Test Relation", + "rollup_property_name": "Tag", + "function": "unique" + } + }, "Test Created By": { "type": "created_by", "created_by": [] @@ -145,7 +159,7 @@ }, "data": { "object": "database", - "id": "44cb2b4d-87c7-411d-b911-b6cde4f236d8", + "id": "8b0013db-0fbf-49a5-ad64-9de6d4670e17", "cover": { "type": "external", "external": { @@ -158,7 +172,7 @@ "url": "https:\/\/example.com\/cover.jpg" } }, - "created_time": "2023-04-30T13:29:00.000Z", + "created_time": "2023-06-10T08:30:00.000Z", "created_by": { "object": "user", "id": "1068e45a-6f6d-4b78-abd0-0d1d44bde855" @@ -167,7 +181,7 @@ "object": "user", "id": "1068e45a-6f6d-4b78-abd0-0d1d44bde855" }, - "last_edited_time": "2023-04-30T13:29:00.000Z", + "last_edited_time": "2023-06-10T08:30:00.000Z", "title": [ { "type": "text", @@ -190,127 +204,149 @@ "description": [], "is_inline": false, "properties": { - "Test Formula": { - "id": ";klo", - "name": "Test Formula", - "type": "formula", - "formula": { - "expression": "prop(\"Test MultiSelect\")" - } - }, "Test People": { - "id": "IPOv", + "id": ":[aJ", "name": "Test People", "type": "people", "people": [] }, "Test Date": { - "id": "I~Vh", + "id": ";LyC", "name": "Test Date", "type": "date", "date": [] }, - "Test Last Edited Time": { - "id": "JI[t", - "name": "Test Last Edited Time", - "type": "last_edited_time", - "last_edited_time": [] + "Test Number": { + "id": "<`a@", + "name": "Test Number", + "type": "number", + "number": { + "format": "dollar" + } }, - "Test Url": { - "id": "KubS", - "name": "Test Url", - "type": "url", - "url": [] + "Test Created By": { + "id": "Anad", + "function": "unique" } }, - "Test Created Time": { - "id": "m}Nt", - "name": "Test Created Time", - "type": "created_time", - "created_time": [] + "Test Custom RichText": { + "id": "iaDK", + "name": "Test Custom RichText", + "type": "rich_text", + "rich_text": [] }, - "Test Created By": { - "id": "s}Yd", - "name": "Test Created By", - "type": "created_by", - "created_by": [] + "Test Relation": { + "id": "m>ad", + "name": "Test Relation", + "type": "relation", + "relation": { + "database_id": "375da18a-b01d-42d1-8e95-a9dc6a901db1", + "synced_property_name": "Related to Created By Testing Database (Test Relation)", + "synced_property_id": "{Ykb" + } }, - "Test Files": { - "id": "u:sB", - "name": "Test Files", - "type": "files", - "files": [] + "Test Email": { + "id": "pZRE", + "name": "Test Email", + "type": "email", + "email": [] }, "Test Checkbox": { - "id": "xddf", + "id": "r@Xw", "name": "Test Checkbox", "type": "checkbox", "checkbox": [] }, - "Test RichText": { - "id": "|@=x", - "name": "Test RichText", - "type": "rich_text", - "rich_text": [] + "Test Last Edited By": { + "id": "rXhE", + "name": "Test Last Edited By", + "type": "last_edited_by", + "last_edited_by": [] + }, + "Test Created Time": { + "id": "rejS", + "name": "Test Created Time", + "type": "created_time", + "created_time": [] + }, + "Test Last Edited Time": { + "id": "yXTc", + "name": "Test Last Edited Time", + "type": "last_edited_time", + "last_edited_time": [] }, "Test Title": { "id": "title", @@ -323,7 +359,8 @@ "type": "page_id", "page_id": "0adbc2eb-57e8-4569-a700-a70d537615be" }, - "url": "https:\/\/www.notion.so\/44cb2b4d87c7411db911b6cde4f236d8", + "url": "https:\/\/www.notion.so\/8b0013db0fbf49a5ad649de6d4670e17", + "public_url": null, "archived": false } } \ No newline at end of file diff --git a/tests/snapshots/databases/post_v1-databases_only-title-properties.json b/tests/snapshots/databases/post_v1-databases_only-title-properties.json new file mode 100644 index 0000000..77f4903 --- /dev/null +++ b/tests/snapshots/databases/post_v1-databases_only-title-properties.json @@ -0,0 +1,100 @@ +{ + "header": { + "Content-Length": [ + "223" + ], + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Content-Type": [ + "application\/json" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "post", + "status": 200, + "payload": { + "is_inline": false, + "parent": { + "type": "page_id", + "page_id": "0adbc2eb57e84569a700a70d537615be" + }, + "title": [ + { + "text": { + "content": "" + } + } + ], + "properties": { + "Name": { + "type": "title", + "title": [] + } + }, + "icon": { + "type": "emoji", + "emoji": "\ud83d\udc4d" + } + }, + "data": { + "object": "database", + "id": "0bd8bcfc-36b0-4f6d-9726-25ba075fa2f1", + "cover": null, + "icon": { + "type": "emoji", + "emoji": "\ud83d\udc4d" + }, + "created_time": "2023-06-10T08:06:00.000Z", + "created_by": { + "object": "user", + "id": "1068e45a-6f6d-4b78-abd0-0d1d44bde855" + }, + "last_edited_by": { + "object": "user", + "id": "1068e45a-6f6d-4b78-abd0-0d1d44bde855" + }, + "last_edited_time": "2023-06-10T08:06:00.000Z", + "title": [ + { + "type": "text", + "text": { + "content": "", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "", + "href": null + } + ], + "description": [], + "is_inline": false, + "properties": { + "Name": { + "id": "title", + "name": "Name", + "type": "title", + "title": [] + } + }, + "parent": { + "type": "page_id", + "page_id": "0adbc2eb-57e8-4569-a700-a70d537615be" + }, + "url": "https:\/\/www.notion.so\/0bd8bcfc36b04f6d972625ba075fa2f1", + "public_url": null, + "archived": false + } +} \ No newline at end of file diff --git a/tests/snapshots/databases/post_v1-databases_with-emoji-icon.json b/tests/snapshots/databases/post_v1-databases_with-emoji-icon.json new file mode 100644 index 0000000..52c54f5 --- /dev/null +++ b/tests/snapshots/databases/post_v1-databases_with-emoji-icon.json @@ -0,0 +1,93 @@ +{ + "header": { + "Content-Length": [ + "176" + ], + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Content-Type": [ + "application\/json" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "post", + "status": 200, + "payload": { + "is_inline": false, + "parent": { + "type": "page_id", + "page_id": "0adbc2eb57e84569a700a70d537615be" + }, + "title": [ + { + "text": { + "content": "" + } + } + ], + "properties": { + "Name": { + "type": "title", + "title": [] + } + } + }, + "data": { + "object": "database", + "id": "8e0c5fe2-9c95-43d9-aa0a-6ef47c97904b", + "cover": null, + "icon": null, + "created_time": "2023-06-10T08:06:00.000Z", + "created_by": { + "object": "user", + "id": "1068e45a-6f6d-4b78-abd0-0d1d44bde855" + }, + "last_edited_by": { + "object": "user", + "id": "1068e45a-6f6d-4b78-abd0-0d1d44bde855" + }, + "last_edited_time": "2023-06-10T08:06:00.000Z", + "title": [ + { + "type": "text", + "text": { + "content": "", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "", + "href": null + } + ], + "description": [], + "is_inline": false, + "properties": { + "Name": { + "id": "title", + "name": "Name", + "type": "title", + "title": [] + } + }, + "parent": { + "type": "page_id", + "page_id": "0adbc2eb-57e8-4569-a700-a70d537615be" + }, + "url": "https:\/\/www.notion.so\/8e0c5fe29c9543d9aa0a6ef47c97904b", + "public_url": null, + "archived": false + } +} \ No newline at end of file From fe76f7313ab59bb0e1019d7b390e53b214758638 Mon Sep 17 00:00:00 2001 From: Di Date: Sat, 10 Jun 2023 10:38:01 +0200 Subject: [PATCH 55/61] Apply fixes from StyleCI (#154) --- tests/RecordedEndpointDatabasesCreationTest.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/RecordedEndpointDatabasesCreationTest.php b/tests/RecordedEndpointDatabasesCreationTest.php index 291575d..950da37 100644 --- a/tests/RecordedEndpointDatabasesCreationTest.php +++ b/tests/RecordedEndpointDatabasesCreationTest.php @@ -122,9 +122,9 @@ expect($databaseEntity->getProperty('Test Relation')->getRelation()[0])->toBe('375da18a-b01d-42d1-8e95-a9dc6a901db1'); - expect($databaseEntity->getProperty('Test Rollup')->getContent()["rollup_property_name"])->toBe("Tag"); - expect($databaseEntity->getProperty('Test Rollup')->getContent()["relation_property_name"])->toBe("Test Relation"); - expect($databaseEntity->getProperty('Test Rollup')->getContent()["function"])->toBe("unique"); + expect($databaseEntity->getProperty('Test Rollup')->getContent()['rollup_property_name'])->toBe('Tag'); + expect($databaseEntity->getProperty('Test Rollup')->getContent()['relation_property_name'])->toBe('Test Relation'); + expect($databaseEntity->getProperty('Test Rollup')->getContent()['function'])->toBe('unique'); expect($databaseEntity->getProperty('Test Select')->getOptions())->toHaveCount(count($selectOptions)); expect($databaseEntity->getProperty('Test Select')->getOptions()[0]->getName())->toEqual($selectOptions[0]['name']); @@ -143,12 +143,11 @@ $databaseEntity = Notion::databases() ->build() ->createInPage('0adbc2eb57e84569a700a70d537615be'); - + expect($databaseEntity->getProperties())->toHaveCount(1); expect($databaseEntity->getProperty('Name'))->toBeInstanceOf(Title::class); }); - it('should create a new database with emoji icon', function () { $this->httpRecorder->nameForNextRequest('only-title-properties'); @@ -156,7 +155,7 @@ ->build() ->iconEmoji('👍') ->createInPage('0adbc2eb57e84569a700a70d537615be'); - + expect($databaseEntity->getProperties())->toHaveCount(1); expect($databaseEntity->getProperty('Name'))->toBeInstanceOf(Title::class); expect($databaseEntity->getIcon())->toBe('👍'); From f3aa5498a723c74c0cacfec347d7fd1b3da68540 Mon Sep 17 00:00:00 2001 From: johguentner Date: Sat, 10 Jun 2023 10:51:33 +0200 Subject: [PATCH 56/61] fix type for workspace in `NotionParent::class` --- src/Entities/NotionParent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Entities/NotionParent.php b/src/Entities/NotionParent.php index dba500b..a3b861e 100644 --- a/src/Entities/NotionParent.php +++ b/src/Entities/NotionParent.php @@ -65,6 +65,6 @@ public function isDatabase(): bool */ public function isWorkspace(): bool { - return $this->getObjectType() === 'workspace_id'; + return $this->getObjectType() === 'workspace'; } } From 7b7395bdfaca924444c73a2a71f5bf5bb51e0d79 Mon Sep 17 00:00:00 2001 From: johguentner Date: Sat, 10 Jun 2023 10:52:03 +0200 Subject: [PATCH 57/61] add resolve/parent tests regarding NotionParent - specifically regarding type checking --- tests/RecordedEndpointResolveTest.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/RecordedEndpointResolveTest.php b/tests/RecordedEndpointResolveTest.php index ef5d8e3..6437489 100644 --- a/tests/RecordedEndpointResolveTest.php +++ b/tests/RecordedEndpointResolveTest.php @@ -44,14 +44,29 @@ $page = Notion::pages()->find('a652fac351cc4cc79f5b17eb702793ed'); $parentPage = Notion::resolve()->parent($page->getParent()); + expect($page->getParent()->isPage())->toBeTrue(); + expect($parentPage)->toBeInstanceOf(\FiveamCode\LaravelNotionApi\Entities\Page::class); expect($parentPage->getId())->toBe('5ac149b9-d8f1-4d8d-ac05-facefc16ebf7'); expect($parentPage->getTitle())->toBe('Resolve Endpoint - Testing Suite'); }); +it('should return the workspace parent of a page without resolving it', function () { + $page = Notion::pages()->find('91f70932ee6347b59bc243e09b4cc9b0'); + $parentWorkspace = Notion::resolve()->parent($page->getParent()); + + expect($page->getParent()->isWorkspace())->toBeTrue(); + + expect($parentWorkspace)->toBeInstanceOf(NotionParent::class); + expect($parentWorkspace->getId())->toBe('1'); + expect($parentWorkspace->getObjectType())->toBe('workspace'); +}); + it('should resolve the database parent of a page', function () { $page = Notion::pages()->find('415d9b6c6e454f42aab2b6e13804cfe9'); + expect($page->getParent()->isDatabase())->toBeTrue(); + $database = Notion::resolve()->parent($page->getParent()); expect($database)->toBeInstanceOf(\FiveamCode\LaravelNotionApi\Entities\Database::class); expect($database->getId())->toBe('8a0ef209-8c8a-4fd1-a21c-db7ab327e870'); @@ -61,6 +76,8 @@ it('should resolve the block parent of a block', function () { $block = Notion::block('d5f9419b44204c909501b1e2b7569503')->retrieve(); + expect($block->getParent()->isBlock())->toBeTrue(); + $parentBlock = Notion::resolve()->parent($block->getParent()); expect($parentBlock)->toBeInstanceOf(\FiveamCode\LaravelNotionApi\Entities\Blocks\Block::class); expect($parentBlock->getId())->toBe('0971ac1a-b6f2-4acc-b706-f5f2ed16ffd6'); From 016009ed68b0519f6ca444f7849f1bd4266b26d4 Mon Sep 17 00:00:00 2001 From: johguentner Date: Sat, 10 Jun 2023 10:52:13 +0200 Subject: [PATCH 58/61] add snapshot for parent testing --- ...0932ee6347b59bc243e09b4cc9b0_00000001.json | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 tests/snapshots/resolve/get_v1-pages-91f70932ee6347b59bc243e09b4cc9b0_00000001.json diff --git a/tests/snapshots/resolve/get_v1-pages-91f70932ee6347b59bc243e09b4cc9b0_00000001.json b/tests/snapshots/resolve/get_v1-pages-91f70932ee6347b59bc243e09b4cc9b0_00000001.json new file mode 100644 index 0000000..0c6e22e --- /dev/null +++ b/tests/snapshots/resolve/get_v1-pages-91f70932ee6347b59bc243e09b4cc9b0_00000001.json @@ -0,0 +1,69 @@ +{ + "header": { + "User-Agent": [ + "GuzzleHttp\/7" + ], + "Host": [ + "api.notion.com" + ], + "Notion-Version": [ + "2021-05-13" + ] + }, + "method": "get", + "status": 200, + "payload": null, + "data": { + "object": "page", + "id": "91f70932-ee63-47b5-9bc2-43e09b4cc9b0", + "created_time": "2021-06-12T16:36:00.000Z", + "last_edited_time": "2023-05-03T00:06:00.000Z", + "created_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "last_edited_by": { + "object": "user", + "id": "04536682-603a-4531-a18f-4fa89fdfb4a8" + }, + "cover": null, + "icon": { + "type": "external", + "external": { + "url": "https:\/\/www.notion.so\/icons\/chemistry_red.svg" + } + }, + "parent": { + "type": "workspace", + "workspace": true + }, + "archived": false, + "properties": { + "title": { + "id": "title", + "type": "title", + "title": [ + { + "type": "text", + "text": { + "content": "Testing Suite Content", + "link": null + }, + "annotations": { + "bold": false, + "italic": false, + "strikethrough": false, + "underline": false, + "code": false, + "color": "default" + }, + "plain_text": "Testing Suite Content", + "href": null + } + ] + } + }, + "url": "https:\/\/www.notion.so\/Testing-Suite-Content-91f70932ee6347b59bc243e09b4cc9b0", + "public_url": null + } +} \ No newline at end of file From f9457280086bf90923bfba756fcab132b35aecd1 Mon Sep 17 00:00:00 2001 From: Di Date: Sat, 10 Jun 2023 10:52:54 +0200 Subject: [PATCH 59/61] Apply fixes from StyleCI (#155) --- tests/RecordedEndpointResolveTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/RecordedEndpointResolveTest.php b/tests/RecordedEndpointResolveTest.php index 6437489..6c3e599 100644 --- a/tests/RecordedEndpointResolveTest.php +++ b/tests/RecordedEndpointResolveTest.php @@ -56,7 +56,7 @@ $parentWorkspace = Notion::resolve()->parent($page->getParent()); expect($page->getParent()->isWorkspace())->toBeTrue(); - + expect($parentWorkspace)->toBeInstanceOf(NotionParent::class); expect($parentWorkspace->getId())->toBe('1'); expect($parentWorkspace->getObjectType())->toBe('workspace'); From 8f80b4a1fdc974a0f3b6a2083f06eeb105fcc811 Mon Sep 17 00:00:00 2001 From: johguentner Date: Fri, 16 Jun 2023 15:20:03 +0200 Subject: [PATCH 60/61] move make-notion-model content to blade - prototypical --- src/Console/Commands/MakeNotionModel.php | 23 ------------------ .../Commands/stub/notion-model.blade.php | 24 +++++++++++++++++++ 2 files changed, 24 insertions(+), 23 deletions(-) create mode 100644 src/Console/Commands/stub/notion-model.blade.php diff --git a/src/Console/Commands/MakeNotionModel.php b/src/Console/Commands/MakeNotionModel.php index 3fe31df..56be0a5 100644 --- a/src/Console/Commands/MakeNotionModel.php +++ b/src/Console/Commands/MakeNotionModel.php @@ -64,30 +64,7 @@ public function handle() } $contents = " Date: Fri, 16 Jun 2023 15:20:24 +0200 Subject: [PATCH 61/61] Apply fixes from StyleCI (#157) --- src/Console/Commands/MakeNotionModel.php | 4 +- src/Endpoints/Database.php | 2 +- src/Entities/Blocks/Block.php | 2 +- src/Entities/Page.php | 60 +++++++++++------------ src/Entities/Properties/Checkbox.php | 2 +- src/Entities/Properties/Date.php | 8 +-- src/Entities/Properties/Email.php | 2 +- src/Entities/Properties/MultiSelect.php | 2 +- src/Entities/Properties/People.php | 2 +- src/Entities/Properties/PhoneNumber.php | 2 +- src/Entities/Properties/Property.php | 2 +- src/Entities/Properties/Relation.php | 2 +- src/Entities/Properties/Select.php | 2 +- src/Entities/Properties/Text.php | 2 +- src/Entities/Properties/Title.php | 2 +- src/Entities/Properties/Url.php | 2 +- src/Entities/PropertyItems/SelectItem.php | 4 +- src/Query/Filters/Filter.php | 6 +-- tests/EndpointBlocksTest.php | 2 +- 19 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/Console/Commands/MakeNotionModel.php b/src/Console/Commands/MakeNotionModel.php index 56be0a5..027fa08 100644 --- a/src/Console/Commands/MakeNotionModel.php +++ b/src/Console/Commands/MakeNotionModel.php @@ -63,10 +63,10 @@ public function handle() $propertyTitleMap .= " '$propName' => '{$propertyInfo->getTitle()}',\n"; } - $contents = "