Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Feature/notion models and commands #121

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
johguentner wants to merge 82 commits into dev
base: dev
Choose a base branch
Loading
from feature/notion-models-and-commands
Draft
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
4f06203
very prototypical implementation for NotionModels
johguentner Feb 2, 2023
1a52591
Apply fixes from StyleCI (#101)
mechelon Feb 2, 2023
2ff9739
Merge branch 'dev' into feature/notion-models-and-commands
johguentner Feb 2, 2023
b828f88
Merge branch 'feature/notion-models-and-commands' of https://github.c...
johguentner Feb 2, 2023
bba2098
fix: after merge of filter-changes
johguentner Feb 4, 2023
c3d4b48
add the ability to resolve users and parents
johguentner Feb 6, 2023
31bd869
Apply fixes from StyleCI (#115)
mechelon Feb 6, 2023
27f4fe9
Merge branch 'dev' into feature/resolve
johguentner Feb 6, 2023
9a3dbb3
fix: modify changed method within `NotionParent`
johguentner Feb 6, 2023
cf07ff9
add `asText` override to title and text property
johguentner Feb 16, 2023
8c53b2a
polish notion model creation and usage
johguentner Feb 16, 2023
ea5cc25
Apply fixes from StyleCI (#120)
mechelon Feb 16, 2023
9fe5ae3
Merge branch 'dev' into feature/notion-models-and-commands
johguentner Feb 16, 2023
18240e4
Merge branch 'feature/notion-models-and-commands' of https://github.c...
johguentner Feb 16, 2023
bbaa2a9
fix: remove duplicated `asText`
johguentner Feb 16, 2023
4cbdff9
Apply fixes from StyleCI (#122)
mechelon Feb 16, 2023
911d8c6
polish: exclude `$page` of `NotionModel`
johguentner Feb 16, 2023
99c2523
Merge branch 'feature/notion-models-and-commands' of https://github.c...
johguentner Feb 16, 2023
516ccc7
Merge branch 'feature/resolve' into feature/notion-models-and-commands
johguentner Feb 16, 2023
f828d7d
Apply fixes from StyleCI (#123)
mechelon Feb 16, 2023
3c9c845
add prototypical relation resolving
johguentner Feb 16, 2023
0f180a9
Merge branch 'feature/resolve' into feature/notion-models-and-commands
johguentner Feb 16, 2023
29c991a
Apply fixes from StyleCI (#124)
mechelon Feb 16, 2023
27620d3
Apply fixes from StyleCI (#125)
mechelon Feb 16, 2023
c7a5bf2
create trait for title attribute
johguentner Apr 28, 2023
f19db04
add property type names within `Property::class`
johguentner Apr 28, 2023
8963193
add comment for clarification
johguentner Apr 28, 2023
29d56f5
add `HasTitle` traidMapping of `Entity::class`
johguentner Apr 28, 2023
8356792
implementation: start with database-building
johguentner Apr 28, 2023
0deaee7
Apply fixes from StyleCI (#134)
mechelon Apr 28, 2023
44aee37
implement further and polish database creation
johguentner Apr 29, 2023
766c7ab
Merge branch 'feature/database-creation' of https://github.com/5am-co...
johguentner Apr 29, 2023
589455a
Apply fixes from StyleCI (#136)
mechelon Apr 29, 2023
478f224
add further database attributes
johguentner Apr 29, 2023
b9f3eda
Merge branch 'feature/database-creation' of https://github.com/5am-co...
johguentner Apr 29, 2023
667928e
Apply fixes from StyleCI (#137)
mechelon Apr 29, 2023
85190f9
Merge branch 'dev' into feature/database-creation
johguentner Apr 30, 2023
2e70438
fix: in `HttpRecorder`, allow query to be empty
johguentner Apr 30, 2023
f6c870d
fix: missing default name for status properties
johguentner Apr 30, 2023
97be981
add tests for db creation in databases endpoint
johguentner Apr 30, 2023
53c15fb
polish `PestHttpRecorder::class`
johguentner Apr 30, 2023
2edd4ea
add query names to `RecordedEndpoint` tests
johguentner Apr 30, 2023
039f8f9
update existing snapshots
johguentner Apr 30, 2023
ad5d85d
Apply fixes from StyleCI (#141)
mechelon Apr 30, 2023
39d981d
add no-title-property test
johguentner Apr 30, 2023
71416dc
update current snapshots (database creation)
johguentner Apr 30, 2023
5ef1f93
Apply fixes from StyleCI (#142)
mechelon Apr 30, 2023
04f9be6
Merge branch 'dev' into feature/database-creation
johguentner Apr 30, 2023
68cb62f
Merge branch 'dev' into feature/resolve
johguentner Apr 30, 2023
fe961c8
add and polish phpdocs
johguentner May 2, 2023
fe0707c
Apply fixes from StyleCI (#144)
mechelon May 2, 2023
1e4f0ff
Merge branch 'dev' into feature/resolve
johguentner May 2, 2023
246396f
polish phpdocs of comment endpoint
johguentner May 2, 2023
d27f4ff
Apply fixes from StyleCI (#145)
mechelon May 2, 2023
9a3730b
polish: add newline to improve readability
johguentner May 2, 2023
69e15bd
Merge branch 'feature/resolve' of https://github.com/5am-code/laravel...
johguentner May 2, 2023
55fe958
Apply fixes from StyleCI (#146)
mechelon May 2, 2023
4244807
git
johguentner May 2, 2023
2b11b70
add `parentOf` to access parents easily
johguentner May 2, 2023
a82ebeb
Apply fixes from StyleCI (#147)
mechelon May 2, 2023
eb7b39b
polish `PestHttpRecorder::class`
johguentner Apr 30, 2023
c83c9b1
Merge branch 'feature/resolve' of https://github.com/5am-code/laravel...
johguentner May 3, 2023
cd8116d
Apply fixes from StyleCI (#148)
mechelon May 3, 2023
e73207a
add tests for `Notion::resolve()`; polish record
johguentner Jun 9, 2023
13a560d
build snapshots for resolve and
johguentner Jun 9, 2023
1c27736
Merge branch 'feature/resolve' of https://github.com/5am-code/laravel...
johguentner Jun 9, 2023
44626bb
Apply fixes from StyleCI (#152)
mechelon Jun 9, 2023
b01fc99
add simple phpdbg code coverage (cmd)
johguentner Jun 10, 2023
0cbd9de
add additional tests for resolve endpoint
johguentner Jun 10, 2023
1f6aa11
Apply fixes from StyleCI (#153)
mechelon Jun 10, 2023
54f10a3
Merge branch 'feature/resolve' into feature/database-creation
johguentner Jun 10, 2023
a389879
add missing properties for database creation test
johguentner Jun 10, 2023
9d2e153
updated snapshots (database creation)
johguentner Jun 10, 2023
fe76f73
Apply fixes from StyleCI (#154)
mechelon Jun 10, 2023
f3aa549
fix type for workspace in `NotionParent::class`
johguentner Jun 10, 2023
7b7395b
add resolve/parent tests regarding NotionParent
johguentner Jun 10, 2023
016009e
add snapshot for parent testing
johguentner Jun 10, 2023
f945728
Apply fixes from StyleCI (#155)
mechelon Jun 10, 2023
4418da5
Merge branch 'feature/resolve' into feature/notion-models-and-commands
johguentner Jun 16, 2023
8dff823
Merge branch 'feature/database-creation' into feature/notion-models-a...
johguentner Jun 16, 2023
8f80b4a
move make-notion-model content to blade
johguentner Jun 16, 2023
4a17d50
Apply fixes from StyleCI (#157)
mechelon Jun 16, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ vendor
.phpunit.result.cache
coverage/
.phpunit.cache/
.env*
.env*
coverage-report
7 changes: 5 additions & 2 deletions composer.json
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
18 changes: 10 additions & 8 deletions src/Endpoints/Comments.php
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,15 @@ 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.
* 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
* @return CommentCollection
*
* @throws HandlingException
* @throws NotionException
*/
public function ofBlock(string $blockId): CommentCollection
Expand Down Expand Up @@ -88,14 +89,15 @@ 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.
* 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
Expand Down
33 changes: 30 additions & 3 deletions src/Endpoints/Resolve.php
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@

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;
use FiveamCode\LaravelNotionApi\Entities\User;
use FiveamCode\LaravelNotionApi\Exceptions\HandlingException;
use FiveamCode\LaravelNotionApi\Exceptions\NotionException;
use FiveamCode\LaravelNotionApi\Notion;
use FiveamCode\LaravelNotionApi\Traits\HasParent;
use Illuminate\Support\Collection;

/**
Expand All @@ -32,6 +34,8 @@ public function __construct(Notion $notion)
}

/**
* Resolve User.
*
* @param User $user
* @return User
*
Expand All @@ -44,13 +48,33 @@ 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
*
* @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':
Expand All @@ -59,14 +83,17 @@ 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');
}
}

/**
* Resolve Relations.
*
* @param Relation $relation
* @return Collection<Page>
*
Expand Down
6 changes: 4 additions & 2 deletions src/Entities/NotionParent.php
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@ class NotionParent extends Entity
protected function setResponseData(array $responseData): void
{
parent::setResponseData($responseData);

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');
}

$this->fillFromRaw();
}

Expand Down Expand Up @@ -63,6 +65,6 @@ public function isDatabase(): bool
*/
public function isWorkspace(): bool
{
return $this->getObjectType() === 'workspace_id';
return $this->getObjectType() === 'workspace';
}
}
21 changes: 19 additions & 2 deletions src/Macros/PestHttpRecorder.php
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use GuzzleHttp\Client;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
Expand Down Expand Up @@ -37,6 +38,8 @@ class HttpRecorder

private $usePrettyJson = true;

private $requestNames = [];

public function storeIn($directory)
{
$this->snapshotDirectory = $directory;
Expand All @@ -51,21 +54,32 @@ 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'] ?? null) : $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}";

// filter out Notion API Token Header
$header = Arr::except($header, ['Authorization']);

if ($forceRecording || ! File::exists($filePath)) {
File::makeDirectory($directoryPath, 0744, true, true);

Expand All @@ -77,7 +91,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),
];

Expand Down
133 changes: 133 additions & 0 deletions tests/RecordedEndpointResolveTest.php
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?php

use FiveamCode\LaravelNotionApi\Entities\NotionParent;
use FiveamCode\LaravelNotionApi\Entities\User;
use Illuminate\Support\Facades\Http;

$httpRecorder = null;

beforeEach(function () {
$this->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($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');
expect($database->getTitle())->toBe('Test Table as Parent');
});

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');
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');

$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');

$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');
});

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');
});
Original file line number Diff line number Diff line change
@@ -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": [
Expand Down
Loading

AltStyle によって変換されたページ (->オリジナル) /