notion 1.0.1 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +116 -4
- data/lib/notion_api/blocks.rb +19 -982
- data/lib/notion_api/core.rb +85 -6
- data/lib/notion_api/notion_types/bulleted_block.rb +17 -0
- data/lib/notion_api/notion_types/callout_block.rb +16 -0
- data/lib/notion_api/notion_types/code_block.rb +16 -0
- data/lib/notion_api/notion_types/collection_view_blocks.rb +316 -0
- data/lib/notion_api/notion_types/column_list_block.rb +16 -0
- data/lib/notion_api/notion_types/divider_block.rb +15 -0
- data/lib/notion_api/notion_types/header_block.rb +16 -0
- data/lib/notion_api/notion_types/image_block.rb +16 -0
- data/lib/notion_api/notion_types/latex_block.rb +16 -0
- data/lib/notion_api/notion_types/numbered_block.rb +15 -0
- data/lib/notion_api/notion_types/page_block.rb +130 -0
- data/lib/notion_api/notion_types/quote_block.rb +16 -0
- data/lib/notion_api/notion_types/sub_header_block.rb +16 -0
- data/lib/notion_api/notion_types/sub_sub_header.rb +16 -0
- data/lib/notion_api/notion_types/table_of_contents_block.rb +15 -0
- data/lib/notion_api/notion_types/template.rb +360 -0
- data/lib/notion_api/notion_types/text_block.rb +16 -0
- data/lib/notion_api/notion_types/todo_block.rb +60 -0
- data/lib/notion_api/notion_types/toggle_block.rb +16 -0
- data/lib/notion_api/utils.rb +35 -4
- data/lib/notion_api/version.rb +1 -1
- metadata +21 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04355fc0473c8f446e79ec4904105c0fb4fcb8a436032099e59d41ce6abbc9fc
|
4
|
+
data.tar.gz: df7cf2d629fcd8c9dcf076a3186c2d49deef0f73454c051a2ad5530ffa98501d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2359d17e2408b50b04a3ae1c9b4015de93b4e7d92b06a5b64d6cc8af48380e2affa7e4eb17d20e35def404116bdecef838bd9ec19c9c39867c05116de02eca40
|
7
|
+
data.tar.gz: febb7a95cc0bd70c59e921a6479b4e4f7c80b6ad1443366aef0658358877876a04b37f9993827e15fe6d9eb0386efb7fa082063b0e6758e8ddeead1bb9dd5aa2
|
data/README.md
CHANGED
@@ -1,5 +1,30 @@
|
|
1
|
+
|
2
|
+
|
1
3
|
# Unofficial Notion Client for Ruby.
|
2
|
-
[![
|
4
|
+
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/f13e49a8807e4fe297273f48bd8d7a61)](https://app.codacy.com/gh/danmurphy1217/notion-ruby?utm_source=github.com&utm_medium=referral&utm_content=danmurphy1217/notion-ruby&utm_campaign=Badge_Grade)
|
5
|
+
[![Build Status](https://travis-ci.com/danmurphy1217/notion-ruby.svg?branch=master)](https://travis-ci.com/danmurphy1217/notion-ruby) [![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop-hq/rubocop) [![Gem Version](https://badge.fury.io/rb/notion.svg)](https://badge.fury.io/rb/notion)
|
6
|
+
|
7
|
+
- Read the [blog post](https://towardsdatascience.com/introducing-the-notion-api-ruby-gem-d47d4a6ef0ca), which outlines why I built this and some of the functionality.
|
8
|
+
- Check out the [Gem](https://rubygems.org/gems/notion)!
|
9
|
+
|
10
|
+
## Table of Contents
|
11
|
+
- [Unofficial Notion Client for Ruby.](#unofficial-notion-client-for-ruby)
|
12
|
+
- [Table of Contents](#table-of-contents)
|
13
|
+
- [Getting Started](#getting-started)
|
14
|
+
- [Installation](#installation)
|
15
|
+
- [Retrieving a Page](#retrieving-a-page)
|
16
|
+
- [Retrieving a CollectionView Page](#retrieving-a-collectionview-page)
|
17
|
+
- [Retrieving a Block within the Page](#retrieving-a-block-within-the-page)
|
18
|
+
- [Get a Block](#get-a-block)
|
19
|
+
- [Get a Collection View](#get-a-collection-view)
|
20
|
+
- [Creating New Blocks](#creating-new-blocks)
|
21
|
+
- [Create a block whose parent is the page](#create-a-block-whose-parent-is-the-page)
|
22
|
+
- [Create a block whose parent is another block](#create-a-block-whose-parent-is-another-block)
|
23
|
+
- [Creating New Collections](#creating-new-collections)
|
24
|
+
- [Updating Collection View Cells](#updating-collection-view-cells)
|
25
|
+
- [Troubleshooting](#troubleshooting)
|
26
|
+
- [No results returned when attempting to get a page](#no-results-returned-when-attempting-to-get-a-page)
|
27
|
+
- [Retrieve a full-page Collection View](#retrieve-a-full-page-collection-view)
|
3
28
|
|
4
29
|
## Getting Started
|
5
30
|
### Installation
|
@@ -9,7 +34,7 @@ gem install notion
|
|
9
34
|
```
|
10
35
|
Then, place this at the top of your file:
|
11
36
|
```ruby
|
12
|
-
require 'notion_api'
|
37
|
+
require 'notion_api'
|
13
38
|
```
|
14
39
|
To get started using the gem, you'll first need to retrieve your token_v2 credentials by signing into Notion online, navigating to the developer tools, inspecting the cookies, and finding the value associated with the **token_v2** key.
|
15
40
|
|
@@ -37,6 +62,11 @@ The following attributes can be read from any block class instance:
|
|
37
62
|
3. `parent_id`: the parent ID of the block.
|
38
63
|
4. `type`: the type of the block.
|
39
64
|
|
65
|
+
To update the title of the page:
|
66
|
+
![Update the title of a page](https://github.com/danmurphy1217/notion-ruby/blob/master/gifs/change_title.gif)
|
67
|
+
|
68
|
+
## Retrieving a CollectionView Page
|
69
|
+
This is achieved by passing the ID of the Collection View to the `get_page` method. Currently, the full URL of a Collection View Page is not supported (next up on the features list!). Once you retrieve the Collection View Page, all of the methods exposed to a normal Collection View instance are available (such as `.rows`, `.row(<row_id>)`, and all else outlined in [Updating a Collection](#updating-collection-view-cells)).
|
40
70
|
## Retrieving a Block within the Page
|
41
71
|
Now that you have retrieved a Notion Page, you have full access to the blocks on that page. You can retrieve a specific block or collection view, retrieve all children IDs (array of children IDs), or retrieve all children (array of children class instances).
|
42
72
|
|
@@ -48,6 +78,7 @@ To retrieve a specific block, you can use the `get_block` method. This method ac
|
|
48
78
|
#<TextBlock id="2cbbe0bf-34cd-409b-9162-64284b33e526" title="TEST" parent_id="d2ce338f-19e8-47f5-86bd-17679f490e66">
|
49
79
|
```
|
50
80
|
Any Notion Block has access to the following methods:
|
81
|
+
|
51
82
|
1. `title=` → change the title of a block.
|
52
83
|
```ruby
|
53
84
|
>>> @block = @client.get_block("2cbbe0bf-34cd-409b-9162-64284b33e526")
|
@@ -57,6 +88,8 @@ Any Notion Block has access to the following methods:
|
|
57
88
|
>>> @block.title
|
58
89
|
"New Title Here"
|
59
90
|
```
|
91
|
+
For example:
|
92
|
+
![Update the title of a block](https://github.com/danmurphy1217/notion-ruby/blob/master/gifs/change%20block%20title.gif)
|
60
93
|
2. `convert` → convert a block to a different type.
|
61
94
|
```ruby
|
62
95
|
>>> @block = @client.get_block("2cbbe0bf-34cd-409b-9162-64284b33e526")
|
@@ -68,12 +101,17 @@ Any Notion Block has access to the following methods:
|
|
68
101
|
>>> @new_block # new class instance returned...
|
69
102
|
#<NotionAPI::CalloutBlock:0x00007ffb75b19ea0 id="2cbbe0bf-34cd-409b-9162-64284b33e526" title="New Title Here" parent_id="d2ce338f-19e8-47f5-86bd-17679f490e66">
|
70
103
|
```
|
104
|
+
For example:
|
105
|
+
![Convert a page](https://github.com/danmurphy1217/notion-ruby/blob/master/gifs/change%20to%20todo%2C%20check.gif)
|
106
|
+
|
71
107
|
3. `duplicate`→ duplicate the current block.
|
72
108
|
```ruby
|
73
109
|
>>> @block = @client.get_block("2cbbe0bf-34cd-409b-9162-64284b33e526")
|
74
110
|
>>> @block.duplicate # block is duplicated and placed directly after the current block
|
75
111
|
>>> @block.duplicate("f13da22b-9012-4c49-ac41-6b7f97bd519e") # the duplicated block is placed after 'f13da22b-9012-4c49-ac41-6b7f97bd519e'
|
76
112
|
```
|
113
|
+
For example:
|
114
|
+
![Convert a page](https://github.com/danmurphy1217/notion-ruby/blob/master/gifs/duplicate.gif)
|
77
115
|
4. `move` → move a block to another location.
|
78
116
|
```ruby
|
79
117
|
>>> @block = @client.get_block("2cbbe0bf-34cd-409b-9162-64284b33e526")
|
@@ -81,7 +119,9 @@ Any Notion Block has access to the following methods:
|
|
81
119
|
>>> @block.move(@target_block) # @block moved to **after** @target_block
|
82
120
|
>>> @block.move(@target_block, "before") # @block moved to **before** @target_block
|
83
121
|
```
|
84
|
-
|
122
|
+
For example:
|
123
|
+
![move a block](https://github.com/danmurphy1217/notion-ruby/blob/master/gifs/move_before_and_after.gif)
|
124
|
+
### Get a Collection View
|
85
125
|
To retrieve a collection, you use the `get_collection` method. This method is designed to work with Table collections, but the codebase is actively being updated to support others:
|
86
126
|
```ruby
|
87
127
|
>>> @page = @client.get_page("https://www.notion.so/danmurphy/TEST-PAGE-d2ce338f19e847f586bd17679f490e66")
|
@@ -110,6 +150,27 @@ ent.rb
|
|
110
150
|
```
|
111
151
|
|
112
152
|
## Creating New Blocks
|
153
|
+
Here's a high-level example:
|
154
|
+
![create a callout a block](https://github.com/danmurphy1217/notion-ruby/blob/master/gifs/create.gif)
|
155
|
+
The block types available to the `create` method are:
|
156
|
+
1. `DividerBlock`
|
157
|
+
2. `TodoBlock`
|
158
|
+
3. `CodeBlock`
|
159
|
+
4. `HeaderBlock`
|
160
|
+
5. `SubHeaderBlock`
|
161
|
+
6. `SubSubHeaderBlock`
|
162
|
+
7. `PageBlock`
|
163
|
+
8. `ToggleBlock`
|
164
|
+
9. `BulletedBlock`
|
165
|
+
10. `NumberedBlock`
|
166
|
+
11. `QuoteBlock`
|
167
|
+
12. `CalloutBlock`
|
168
|
+
13. `LatexBlock`
|
169
|
+
14. `TextBlock`
|
170
|
+
15. `ImageBlock` and
|
171
|
+
16. `TableOfContentsBlock`.
|
172
|
+
If you want to create a collection, utilize the `create_collection` method [defined below].
|
173
|
+
|
113
174
|
To create a new block, you have a few options:
|
114
175
|
### Create a block whose parent is the page
|
115
176
|
If you want to create a new block whose parent ID is the **page**, call the `create` method on the PageBlock instance.
|
@@ -181,11 +242,14 @@ Let's say we have the following JSON data:
|
|
181
242
|
}
|
182
243
|
]
|
183
244
|
```
|
184
|
-
A new collection containing this data is created with the following code:
|
245
|
+
A new table collection view containing this data is created with the following code:
|
185
246
|
```ruby
|
186
247
|
>>> @page = @client.get_page("https://www.notion.so/danmurphy/Notion-API-Testing-66447bc817f044bc81ed3cf4802e9b00")
|
187
248
|
>>> @page.create_collection("table", "title for table", JSON.parse(File.read("./path/to/emoji_json_data.json")))
|
188
249
|
```
|
250
|
+
Here's an example with a larger dataset:
|
251
|
+
![create a collection view table](https://github.com/danmurphy1217/notion-ruby/blob/master/gifs/create%20collection.gif)
|
252
|
+
|
189
253
|
Additionally, say you already have a Table and want to add a new row with it containing the following data:
|
190
254
|
```ruby
|
191
255
|
{
|
@@ -203,3 +267,51 @@ Additionally, say you already have a Table and want to add a new row with it con
|
|
203
267
|
>>> @collection = @page.get_collection("f1664a99-165b-49cc-811c-84f37655908a")
|
204
268
|
>>> @collection.add_row(JSON.parse(File.read("path/to/new_emoji_row.json")))
|
205
269
|
```
|
270
|
+
|
271
|
+
The first argument passed to `create_collection` determines which type of collection view to create. In the above example, a "table" is created, but other supported options are:
|
272
|
+
1. list
|
273
|
+
2. board
|
274
|
+
3. calendar
|
275
|
+
4. timeline
|
276
|
+
5. gallery
|
277
|
+
|
278
|
+
## Updating Collection View Cells
|
279
|
+
When you retrieve a `CollectionViewRow` instance with `.row(<row_id>)` or a list of `CollectionViewRow` instances with `.rows`, a handful of methods are created. Each row instance has access attributes that represent the properties in the Notion Collection View. So, let's say we are working with the following Notion Collection View:
|
280
|
+
| emoji | description | category | aliases | tags | unicode_version | ios_version |
|
281
|
+
|-------|--------------|---------------------|---------|---------|-----------------|-------------|
|
282
|
+
| 😉 | "winking face" | "Smileys & Emotion" | "wink" | "flirt" | "6.0" | "6.0" |
|
283
|
+
|
284
|
+
If you wanted to update the unicode and ios versions, you could use the following code:
|
285
|
+
```ruby
|
286
|
+
>>> collection_view = @page.get_collection("1234567") # the ID of the collection block is 1234567
|
287
|
+
>>> rows = collection_view.rows
|
288
|
+
>>> row[0].unicode_version = "updated version here!"
|
289
|
+
>>> row[0].ios_version = "I was updated too!"
|
290
|
+
```
|
291
|
+
Now, your Collection View will look like this:
|
292
|
+
| emoji | description | category | aliases | tags | unicode_version | ios_version |
|
293
|
+
|-------|--------------|---------------------|---------|---------|-----------------|-------------|
|
294
|
+
| 😉 | "winking face" | "Smileys & Emotion" | "wink" | "flirt" | "updated version here!" | "I was updated too!" |
|
295
|
+
|
296
|
+
You can also add new rows with the `.add_row({<data!>})` method and add new properties with the `.add_property("name_of_property", "type_of_property")` method.
|
297
|
+
|
298
|
+
**One important thing to be aware of:**
|
299
|
+
When adding a row with `.add_row`, the hash of data passed must be in the same order as it appears in your Notion Collection View.
|
300
|
+
## Troubleshooting
|
301
|
+
### No results returned when attempting to get a page
|
302
|
+
If an empty hash is returned when you attempt to retrieve a Notion page, you'll need to include the `x-notion-active-user-header` when instantiating the Notion Client.
|
303
|
+
The endpoint used by this wrapper to load a page is `/loadPageChunk`, check out the request headers in your developer tools Network tab.
|
304
|
+
|
305
|
+
From here, you can instantiate the Notion Client with the following code:
|
306
|
+
```ruby
|
307
|
+
>>> @client = NotionAPI::Client.new(
|
308
|
+
"<insert_v2_token_here>",
|
309
|
+
"<insert_x_notion_active_user_header_here>"
|
310
|
+
)
|
311
|
+
```
|
312
|
+
### Retrieve a full-page Collection View
|
313
|
+
Currently, either a "normal" Page URL or the Page Block ID is accepted to the `get_page` method. Therefore, if you pass the full URL to the CV Table, it will raise an error:
|
314
|
+
```text
|
315
|
+
the URL or ID passed to the get_page method must be that of a Page Block.
|
316
|
+
```
|
317
|
+
To avoid this, you must pass only the ID of the full-page collection-view to the `get_page` method. This is next up on the features list, so passing the full URL will be supported soon:smile:
|
data/lib/notion_api/blocks.rb
CHANGED
@@ -1,986 +1,23 @@
|
|
1
|
-
|
1
|
+
require_relative "notion_types/template"
|
2
|
+
require_relative "notion_types/bulleted_block"
|
3
|
+
require_relative "notion_types/callout_block"
|
4
|
+
require_relative "notion_types/code_block"
|
5
|
+
require_relative "notion_types/collection_view_blocks"
|
6
|
+
require_relative "notion_types/column_list_block"
|
7
|
+
require_relative "notion_types/divider_block"
|
8
|
+
require_relative "notion_types/quote_block"
|
9
|
+
require_relative "notion_types/page_block"
|
10
|
+
require_relative "notion_types/image_block"
|
11
|
+
require_relative "notion_types/latex_block"
|
12
|
+
require_relative "notion_types/numbered_block"
|
13
|
+
require_relative "notion_types/header_block"
|
14
|
+
require_relative "notion_types/sub_header_block"
|
15
|
+
require_relative "notion_types/sub_sub_header"
|
16
|
+
require_relative "notion_types/table_of_contents_block"
|
17
|
+
require_relative "notion_types/text_block"
|
18
|
+
require_relative "notion_types/todo_block"
|
19
|
+
require_relative "notion_types/toggle_block"
|
2
20
|
|
3
|
-
require_relative 'core'
|
4
|
-
require 'httparty'
|
5
|
-
|
6
|
-
module NotionAPI
|
7
|
-
# Base Template for all blocks. Inherits core methods from the Block class defined in block.rb
|
8
|
-
class BlockTemplate < Core
|
9
|
-
include Utils
|
10
|
-
|
11
|
-
attr_reader :id, :title, :parent_id
|
12
|
-
|
13
|
-
def initialize(id, title, parent_id)
|
14
|
-
@id = id
|
15
|
-
@title = title
|
16
|
-
@parent_id = parent_id
|
17
|
-
end
|
18
|
-
|
19
|
-
def title=(new_title)
|
20
|
-
# ! Change the title of a block.
|
21
|
-
# ! new_title -> new title for the block : ``str``
|
22
|
-
request_id = extract_id(SecureRandom.hex(16))
|
23
|
-
transaction_id = extract_id(SecureRandom.hex(16))
|
24
|
-
space_id = extract_id(SecureRandom.hex(16))
|
25
|
-
update_title(new_title.to_s, request_id, transaction_id, space_id)
|
26
|
-
@title = new_title
|
27
|
-
end
|
28
|
-
|
29
|
-
def convert(block_class_to_convert_to)
|
30
|
-
# ! convert a block from its current type to another.
|
31
|
-
# ! block_class_to_convert_to -> the type of block to convert to : ``cls``
|
32
|
-
if type == block_class_to_convert_to.notion_type
|
33
|
-
# if converting to same type, skip and return self
|
34
|
-
self
|
35
|
-
else
|
36
|
-
# setup cookies, headers, and grab/create static vars for request
|
37
|
-
cookies = Core.options['cookies']
|
38
|
-
headers = Core.options['headers']
|
39
|
-
request_url = URLS[:UPDATE_BLOCK]
|
40
|
-
|
41
|
-
# set random IDs for request
|
42
|
-
request_id = extract_id(SecureRandom.hex(16))
|
43
|
-
transaction_id = extract_id(SecureRandom.hex(16))
|
44
|
-
space_id = extract_id(SecureRandom.hex(16))
|
45
|
-
request_ids = {
|
46
|
-
request_id: request_id,
|
47
|
-
transaction_id: transaction_id,
|
48
|
-
space_id: space_id
|
49
|
-
}
|
50
|
-
|
51
|
-
# build hash's that contain the operations to send to Notions backend
|
52
|
-
convert_type_hash = Utils::BlockComponents.convert_type(@id, block_class_to_convert_to)
|
53
|
-
last_edited_time_parent_hash = Utils::BlockComponents.last_edited_time(@parent_id)
|
54
|
-
last_edited_time_child_hash = Utils::BlockComponents.last_edited_time(@id)
|
55
|
-
|
56
|
-
operations = [
|
57
|
-
convert_type_hash,
|
58
|
-
last_edited_time_parent_hash,
|
59
|
-
last_edited_time_child_hash
|
60
|
-
]
|
61
|
-
|
62
|
-
request_body = build_payload(operations, request_ids)
|
63
|
-
response = HTTParty.post(
|
64
|
-
request_url,
|
65
|
-
body: request_body.to_json,
|
66
|
-
cookies: cookies,
|
67
|
-
headers: headers
|
68
|
-
)
|
69
|
-
unless response.code == 200; raise "There was an issue completing your request. Here is the response from Notion: #{response.body}, and here is the payload that was sent: #{operations}.
|
70
|
-
Please try again, and if issues persist open an issue in GitHub."; end
|
71
|
-
|
72
|
-
block_class_to_convert_to.new(@id, @title, @parent_id)
|
73
|
-
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def duplicate(target_block = nil)
|
78
|
-
# ! duplicate the block that this method is invoked upon.
|
79
|
-
# ! target_block -> the block to place the duplicated block after. Can be any valid Block ID! : ``str``
|
80
|
-
cookies = Core.options['cookies']
|
81
|
-
headers = Core.options['headers']
|
82
|
-
request_url = URLS[:UPDATE_BLOCK]
|
83
|
-
|
84
|
-
new_block_id = extract_id(SecureRandom.hex(16))
|
85
|
-
request_id = extract_id(SecureRandom.hex(16))
|
86
|
-
transaction_id = extract_id(SecureRandom.hex(16))
|
87
|
-
space_id = extract_id(SecureRandom.hex(16))
|
88
|
-
|
89
|
-
root_children = children_ids(@id)
|
90
|
-
sub_children = []
|
91
|
-
root_children.each { |root_id| sub_children.push(children_ids(root_id)) }
|
92
|
-
|
93
|
-
request_ids = {
|
94
|
-
request_id: request_id,
|
95
|
-
transaction_id: transaction_id,
|
96
|
-
space_id: space_id
|
97
|
-
}
|
98
|
-
body = {
|
99
|
-
pageId: @id,
|
100
|
-
chunkNumber: 0,
|
101
|
-
limit: 100,
|
102
|
-
verticalColumns: false
|
103
|
-
}
|
104
|
-
|
105
|
-
user_notion_id = get_notion_id(body)
|
106
|
-
|
107
|
-
block = target_block ? get(target_block) : self # allows dev to place block anywhere!
|
108
|
-
|
109
|
-
duplicate_hash = Utils::BlockComponents.duplicate(type, @title, block.id, new_block_id, user_notion_id, root_children)
|
110
|
-
set_parent_alive_hash = Utils::BlockComponents.set_parent_to_alive(block.parent_id, new_block_id)
|
111
|
-
block_location_hash = Utils::BlockComponents.block_location_add(block.parent_id, block.id, new_block_id, target_block, 'listAfter')
|
112
|
-
last_edited_time_parent_hash = Utils::BlockComponents.last_edited_time(block.parent_id)
|
113
|
-
last_edited_time_child_hash = Utils::BlockComponents.last_edited_time(block.id)
|
114
|
-
|
115
|
-
operations = [
|
116
|
-
duplicate_hash,
|
117
|
-
set_parent_alive_hash,
|
118
|
-
block_location_hash,
|
119
|
-
last_edited_time_parent_hash,
|
120
|
-
last_edited_time_child_hash
|
121
|
-
]
|
122
|
-
|
123
|
-
request_body = build_payload(operations, request_ids)
|
124
|
-
response = HTTParty.post(
|
125
|
-
request_url,
|
126
|
-
body: request_body.to_json,
|
127
|
-
cookies: cookies,
|
128
|
-
headers: headers
|
129
|
-
)
|
130
|
-
unless response.code == 200; raise "There was an issue completing your request. Here is the response from Notion: #{response.body}, and here is the payload that was sent: #{operations}.
|
131
|
-
Please try again, and if issues persist open an issue in GitHub."; end
|
132
|
-
|
133
|
-
class_to_return = NotionAPI.const_get(Classes.select { |cls| NotionAPI.const_get(cls).notion_type == type }.join.to_s)
|
134
|
-
class_to_return.new(new_block_id, @title, block.parent_id)
|
135
|
-
end
|
136
|
-
|
137
|
-
def move(target_block, position = 'after')
|
138
|
-
# ! move the block to a new location.
|
139
|
-
# ! target_block -> the targetted block to move to. : ``str``
|
140
|
-
# ! position -> where the block should be listed, in positions relative to the target_block [before, after, top-child, last-child]
|
141
|
-
positions_hash = {
|
142
|
-
'after' => 'listAfter',
|
143
|
-
'before' => 'listBefore'
|
144
|
-
}
|
145
|
-
|
146
|
-
unless positions_hash.keys.include?(position); raise ArgumentError, "Invalid position. You said: #{position}, valid options are: #{positions_hash.keys.join(', ')}"; end
|
147
|
-
|
148
|
-
position_command = positions_hash[position]
|
149
|
-
cookies = Core.options['cookies']
|
150
|
-
headers = Core.options['headers']
|
151
|
-
request_url = URLS[:UPDATE_BLOCK]
|
152
|
-
|
153
|
-
request_id = extract_id(SecureRandom.hex(16))
|
154
|
-
transaction_id = extract_id(SecureRandom.hex(16))
|
155
|
-
space_id = extract_id(SecureRandom.hex(16))
|
156
|
-
|
157
|
-
request_ids = {
|
158
|
-
request_id: request_id,
|
159
|
-
transaction_id: transaction_id,
|
160
|
-
space_id: space_id
|
161
|
-
}
|
162
|
-
|
163
|
-
check_parents = (@parent_id == target_block.parent_id)
|
164
|
-
set_block_dead_hash = Utils::BlockComponents.set_block_to_dead(@id) # kill the block this method is invoked on...
|
165
|
-
block_location_remove_hash = Utils::BlockComponents.block_location_remove(@parent_id, @id) # remove the block this method is invoked on...
|
166
|
-
parent_location_hash = Utils::BlockComponents.parent_location_add(check_parents ? @parent_id : target_block.parent_id, @id) # set parent location to alive
|
167
|
-
block_location_add_hash = Utils::BlockComponents.block_location_add(check_parents ? @parent_id : target_block.parent_id, @id, target_block.id, position_command)
|
168
|
-
last_edited_time_parent_hash = Utils::BlockComponents.last_edited_time(@parent_id)
|
169
|
-
|
170
|
-
if check_parents
|
171
|
-
last_edited_time_child_hash = Utils::BlockComponents.last_edited_time(@id)
|
172
|
-
operations = [
|
173
|
-
set_block_dead_hash,
|
174
|
-
block_location_remove_hash,
|
175
|
-
parent_location_hash,
|
176
|
-
block_location_add_hash,
|
177
|
-
last_edited_time_parent_hash,
|
178
|
-
last_edited_time_child_hash
|
179
|
-
]
|
180
|
-
else
|
181
|
-
last_edited_time_new_parent_hash = Utils::BlockComponents.last_edited_time(target_block.parent_id)
|
182
|
-
last_edited_time_child_hash = Utils::BlockComponents.last_edited_time(@id)
|
183
|
-
@parent_id = target_block.parent_id
|
184
|
-
operations = [
|
185
|
-
set_block_dead_hash,
|
186
|
-
block_location_remove_hash,
|
187
|
-
parent_location_hash,
|
188
|
-
block_location_add_hash,
|
189
|
-
last_edited_time_parent_hash,
|
190
|
-
last_edited_time_new_parent_hash,
|
191
|
-
last_edited_time_child_hash
|
192
|
-
]
|
193
|
-
end
|
194
|
-
request_body = build_payload(operations, request_ids)
|
195
|
-
response = HTTParty.post(
|
196
|
-
request_url,
|
197
|
-
body: request_body.to_json,
|
198
|
-
cookies: cookies,
|
199
|
-
headers: headers
|
200
|
-
)
|
201
|
-
unless response.code == 200; raise "There was an issue completing your request. Here is the response from Notion: #{response.body}, and here is the payload that was sent: #{operations}.
|
202
|
-
Please try again, and if issues persist open an issue in GitHub."; end
|
203
|
-
|
204
|
-
self
|
205
|
-
end
|
206
|
-
|
207
|
-
def create(block_type, block_title, target = nil, position = 'after')
|
208
|
-
# ! create a new block
|
209
|
-
# ! block_type -> the type of block to create : ``cls``
|
210
|
-
# ! block_title -> the title of the new block : ``str``
|
211
|
-
# ! target -> the block_id that the new block should be placed after. ``str``
|
212
|
-
# ! position -> 'after' or 'before'
|
213
|
-
positions_hash = {
|
214
|
-
'after' => 'listAfter',
|
215
|
-
'before' => 'listBefore'
|
216
|
-
}
|
217
|
-
unless positions_hash.keys.include?(position); raise "Invalid position. You said: #{position}, valid options are: #{positions_hash.keys.join(', ')}"; end
|
218
|
-
|
219
|
-
position_command = positions_hash[position]
|
220
|
-
|
221
|
-
cookies = Core.options['cookies']
|
222
|
-
headers = Core.options['headers']
|
223
|
-
|
224
|
-
new_block_id = extract_id(SecureRandom.hex(16))
|
225
|
-
request_id = extract_id(SecureRandom.hex(16))
|
226
|
-
transaction_id = extract_id(SecureRandom.hex(16))
|
227
|
-
space_id = extract_id(SecureRandom.hex(16))
|
228
|
-
|
229
|
-
request_ids = {
|
230
|
-
request_id: request_id,
|
231
|
-
transaction_id: transaction_id,
|
232
|
-
space_id: space_id
|
233
|
-
}
|
234
|
-
|
235
|
-
create_hash = Utils::BlockComponents.create(new_block_id, block_type.notion_type)
|
236
|
-
set_parent_alive_hash = Utils::BlockComponents.set_parent_to_alive(@id, new_block_id)
|
237
|
-
block_location_hash = Utils::BlockComponents.block_location_add(@id, @id, new_block_id, target, position_command)
|
238
|
-
last_edited_time_parent_hash = Utils::BlockComponents.last_edited_time(@id)
|
239
|
-
last_edited_time_child_hash = Utils::BlockComponents.last_edited_time(@id)
|
240
|
-
title_hash = Utils::BlockComponents.title(new_block_id, block_title)
|
241
|
-
|
242
|
-
operations = [
|
243
|
-
create_hash,
|
244
|
-
set_parent_alive_hash,
|
245
|
-
block_location_hash,
|
246
|
-
last_edited_time_parent_hash,
|
247
|
-
last_edited_time_child_hash,
|
248
|
-
title_hash
|
249
|
-
]
|
250
|
-
|
251
|
-
request_url = URLS[:UPDATE_BLOCK]
|
252
|
-
request_body = build_payload(operations, request_ids)
|
253
|
-
response = HTTParty.post(
|
254
|
-
request_url,
|
255
|
-
body: request_body.to_json,
|
256
|
-
cookies: cookies,
|
257
|
-
headers: headers
|
258
|
-
)
|
259
|
-
unless response.code == 200; raise "There was an issue completing your request. Here is the response from Notion: #{response.body}, and here is the payload that was sent: #{operations}.
|
260
|
-
Please try again, and if issues persist open an issue in GitHub."; end
|
261
|
-
|
262
|
-
block_type.new(new_block_id, block_title, @id)
|
263
|
-
end
|
264
|
-
|
265
|
-
private
|
266
|
-
|
267
|
-
def get(url_or_id)
|
268
|
-
# ! retrieve a Notion Block and return its instantiated class object.
|
269
|
-
# ! url_or_id -> the block ID or URL : ``str``
|
270
|
-
clean_id = extract_id(url_or_id)
|
271
|
-
|
272
|
-
request_body = {
|
273
|
-
pageId: clean_id,
|
274
|
-
chunkNumber: 0,
|
275
|
-
limit: 100,
|
276
|
-
verticalColumns: false
|
277
|
-
}
|
278
|
-
jsonified_record_response = get_all_block_info(clean_id, request_body)
|
279
|
-
i = 0
|
280
|
-
while jsonified_record_response.empty? || jsonified_record_response['block'].empty?
|
281
|
-
return {} if i >= 10
|
282
|
-
|
283
|
-
jsonified_record_response = get_all_block_info(clean_id, request_body)
|
284
|
-
i += 1
|
285
|
-
end
|
286
|
-
block_type = extract_type(clean_id, jsonified_record_response)
|
287
|
-
block_parent_id = extract_parent_id(clean_id, jsonified_record_response)
|
288
|
-
|
289
|
-
if block_type.nil?
|
290
|
-
{}
|
291
|
-
else
|
292
|
-
block_class = NotionAPI.const_get(BLOCK_TYPES[block_type].to_s)
|
293
|
-
if block_class == NotionAPI::CollectionView
|
294
|
-
block_collection_id = extract_collection_id(clean_id, jsonified_record_response)
|
295
|
-
block_view_id = extract_view_ids(clean_id, jsonified_record_response)
|
296
|
-
collection_title = extract_collection_title(clean_id, block_collection_id, jsonified_record_response)
|
297
|
-
block_class.new(clean_id, collection_title, block_parent_id, block_collection_id, block_view_id.join)
|
298
|
-
else
|
299
|
-
block_title = extract_title(clean_id, jsonified_record_response)
|
300
|
-
block_class.new(clean_id, block_title, block_parent_id)
|
301
|
-
end
|
302
|
-
end
|
303
|
-
end
|
304
|
-
|
305
|
-
def update_title(new_title, request_id, transaction_id, space_id)
|
306
|
-
# ! Helper method for sending POST request to change title of block.
|
307
|
-
# ! new_title -> new title for the block : ``str``
|
308
|
-
# ! request_id -> the unique ID for the request key. Generated using SecureRandom : ``str``
|
309
|
-
# ! transaction_id -> the unique ID for the transaction key. Generated using SecureRandom: ``str``
|
310
|
-
# ! transaction_id -> the unique ID for the space key. Generated using SecureRandom: ``str``
|
311
|
-
# setup cookies, headers, and grab/create static vars for request
|
312
|
-
cookies = Core.options['cookies']
|
313
|
-
headers = Core.options['headers']
|
314
|
-
request_url = URLS[:UPDATE_BLOCK]
|
315
|
-
|
316
|
-
# set unique IDs for request
|
317
|
-
request_ids = {
|
318
|
-
request_id: request_id,
|
319
|
-
transaction_id: transaction_id,
|
320
|
-
space_id: space_id
|
321
|
-
}
|
322
|
-
|
323
|
-
# build and set operations to send to Notion
|
324
|
-
title_hash = Utils::BlockComponents.title(@id, new_title)
|
325
|
-
last_edited_time_child_hash = Utils::BlockComponents.last_edited_time(@id)
|
326
|
-
operations = [
|
327
|
-
title_hash,
|
328
|
-
last_edited_time_child_hash
|
329
|
-
]
|
330
|
-
|
331
|
-
request_body = build_payload(operations, request_ids) # defined in utils.rb
|
332
|
-
|
333
|
-
response = HTTParty.post(
|
334
|
-
request_url,
|
335
|
-
body: request_body.to_json,
|
336
|
-
cookies: cookies,
|
337
|
-
headers: headers
|
338
|
-
)
|
339
|
-
response.body
|
340
|
-
end
|
341
|
-
end
|
342
|
-
|
343
|
-
# divider block: ---------
|
344
|
-
class DividerBlock < BlockTemplate
|
345
|
-
@notion_type = 'divider'
|
346
|
-
@type = 'divider'
|
347
|
-
|
348
|
-
def type
|
349
|
-
NotionAPI::DividerBlock.notion_type
|
350
|
-
end
|
351
|
-
|
352
|
-
class << self
|
353
|
-
attr_reader :notion_type, :type
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
|
-
# To-Do block: best for checklists and tracking to-dos.
|
358
|
-
class TodoBlock < BlockTemplate
|
359
|
-
@notion_type = 'to_do'
|
360
|
-
@type = 'to_do'
|
361
|
-
|
362
|
-
def type
|
363
|
-
NotionAPI::TodoBlock.notion_type
|
364
|
-
end
|
365
|
-
|
366
|
-
class << self
|
367
|
-
attr_reader :notion_type, :type
|
368
|
-
end
|
369
|
-
|
370
|
-
def checked=(checked_value)
|
371
|
-
# ! change the checked property of the Todo Block.
|
372
|
-
# ! checked_value -> boolean value used to determine whether the block should be checked [yes] or not [no] : ``str``
|
373
|
-
# set static variables for request
|
374
|
-
cookies = Core.options['cookies']
|
375
|
-
headers = Core.options['headers']
|
376
|
-
request_url = URLS[:UPDATE_BLOCK]
|
377
|
-
|
378
|
-
# set unique values for request
|
379
|
-
request_id = extract_id(SecureRandom.hex(16))
|
380
|
-
transaction_id = extract_id(SecureRandom.hex(16))
|
381
|
-
space_id = extract_id(SecureRandom.hex(16))
|
382
|
-
request_ids = {
|
383
|
-
request_id: request_id,
|
384
|
-
transaction_id: transaction_id,
|
385
|
-
space_id: space_id
|
386
|
-
}
|
387
|
-
|
388
|
-
if %w[yes no].include?(checked_value.downcase)
|
389
|
-
checked_hash = Utils::BlockComponents.checked_todo(@id, checked_value.downcase)
|
390
|
-
last_edited_time_parent_hash = Utils::BlockComponents.last_edited_time(@parent_id)
|
391
|
-
last_edited_time_child_hash = Utils::BlockComponents.last_edited_time(@id)
|
392
|
-
|
393
|
-
operations = [
|
394
|
-
checked_hash,
|
395
|
-
last_edited_time_parent_hash,
|
396
|
-
last_edited_time_child_hash
|
397
|
-
]
|
398
|
-
request_body = build_payload(operations, request_ids)
|
399
|
-
response = HTTParty.post(
|
400
|
-
request_url,
|
401
|
-
body: request_body.to_json,
|
402
|
-
cookies: cookies,
|
403
|
-
headers: headers
|
404
|
-
)
|
405
|
-
unless response.code == 200; raise "There was an issue completing your request. Here is the response from Notion: #{response.body}, and here is the payload that was sent: #{operations}.
|
406
|
-
Please try again, and if issues persist open an issue in GitHub."; end
|
407
|
-
|
408
|
-
true
|
409
|
-
else
|
410
|
-
false
|
411
|
-
end
|
412
|
-
end
|
413
|
-
end
|
414
|
-
|
415
|
-
# Code block: used to store code, should be assigned a coding language.
|
416
|
-
class CodeBlock < BlockTemplate
|
417
|
-
@notion_type = 'code'
|
418
|
-
@type = 'code'
|
419
|
-
|
420
|
-
def type
|
421
|
-
NotionAPI::CodeBlock.notion_type
|
422
|
-
end
|
423
|
-
|
424
|
-
class << self
|
425
|
-
attr_reader :notion_type, :type
|
426
|
-
end
|
427
|
-
end
|
428
|
-
|
429
|
-
# Header block: H1
|
430
|
-
class HeaderBlock < BlockTemplate
|
431
|
-
@notion_type = 'header'
|
432
|
-
@type = 'header'
|
433
|
-
|
434
|
-
def type
|
435
|
-
NotionAPI::HeaderBlock.notion_type
|
436
|
-
end
|
437
|
-
|
438
|
-
class << self
|
439
|
-
attr_reader :notion_type, :type
|
440
|
-
end
|
441
|
-
end
|
442
|
-
|
443
|
-
# SubHeader Block: H2
|
444
|
-
class SubHeaderBlock < BlockTemplate
|
445
|
-
@notion_type = 'sub_header'
|
446
|
-
@type = 'sub_header'
|
447
|
-
|
448
|
-
def type
|
449
|
-
NotionAPI::SubHeaderBlock.notion_type
|
450
|
-
end
|
451
|
-
|
452
|
-
class << self
|
453
|
-
attr_reader :notion_type, :type
|
454
|
-
end
|
455
|
-
end
|
456
|
-
|
457
|
-
# Sub-Sub Header Block: H3
|
458
|
-
class SubSubHeaderBlock < BlockTemplate
|
459
|
-
@notion_type = 'sub_sub_header'
|
460
|
-
@type = 'sub_sub_header'
|
461
|
-
|
462
|
-
def type
|
463
|
-
NotionAPI::SubSubHeaderBlock.notion_type
|
464
|
-
end
|
465
|
-
|
466
|
-
class << self
|
467
|
-
attr_reader :notion_type, :type
|
468
|
-
end
|
469
|
-
end
|
470
|
-
|
471
|
-
# Page Block, entrypoint for the application
|
472
|
-
class PageBlock < BlockTemplate
|
473
|
-
@notion_type = 'page'
|
474
|
-
@type = 'page'
|
475
|
-
|
476
|
-
def type
|
477
|
-
NotionAPI::PageBlock.notion_type
|
478
|
-
end
|
479
|
-
|
480
|
-
class << self
|
481
|
-
attr_reader :notion_type, :type
|
482
|
-
end
|
483
|
-
|
484
|
-
def get_block(url_or_id)
|
485
|
-
# ! retrieve a Notion Block and return its instantiated class object.
|
486
|
-
# ! url_or_id -> the block ID or URL : ``str``
|
487
|
-
get(url_or_id)
|
488
|
-
end
|
489
|
-
|
490
|
-
def get_collection(url_or_id)
|
491
|
-
# ! retrieve a Notion Collection and return its instantiated class object.
|
492
|
-
# ! url_or_id -> the block ID or URL : ``str``
|
493
|
-
clean_id = extract_id(url_or_id)
|
494
|
-
|
495
|
-
request_body = {
|
496
|
-
pageId: clean_id,
|
497
|
-
chunkNumber: 0,
|
498
|
-
limit: 100,
|
499
|
-
verticalColumns: false
|
500
|
-
}
|
501
|
-
jsonified_record_response = get_all_block_info(clean_id, request_body)
|
502
|
-
i = 0
|
503
|
-
while jsonified_record_response.empty? || jsonified_record_response['block'].empty?
|
504
|
-
return {} if i >= 10
|
505
|
-
|
506
|
-
jsonified_record_response = get_all_block_info(clean_id, request_body)
|
507
|
-
i += 1
|
508
|
-
end
|
509
|
-
block_parent_id = extract_parent_id(clean_id, jsonified_record_response)
|
510
|
-
block_collection_id = extract_collection_id(clean_id, jsonified_record_response)
|
511
|
-
block_view_id = extract_view_ids(clean_id, jsonified_record_response).join
|
512
|
-
block_title = extract_collection_title(clean_id, block_collection_id, jsonified_record_response)
|
513
|
-
|
514
|
-
CollectionView.new(clean_id, block_title, block_parent_id, block_collection_id, block_view_id)
|
515
|
-
end
|
516
|
-
|
517
|
-
def create_collection(collection_type, collection_title, data)
|
518
|
-
# ! create a Notion Collection View and return its instantiated class object.
|
519
|
-
# ! _collection_type -> the type of collection to create : ``str``
|
520
|
-
# ! collection_title -> the title of the collection view : ``str``
|
521
|
-
# ! data -> JSON data to add to the table : ``str``
|
522
|
-
|
523
|
-
valid_types = %w[table board list timeline calendar gallery]
|
524
|
-
unless valid_types.include?(collection_type) ; raise ArgumentError, "That collection type is not yet supported. Try: #{valid_types.join}."; end
|
525
|
-
cookies = Core.options['cookies']
|
526
|
-
headers = Core.options['headers']
|
527
|
-
|
528
|
-
new_block_id = extract_id(SecureRandom.hex(16))
|
529
|
-
parent_id = extract_id(SecureRandom.hex(16))
|
530
|
-
collection_id = extract_id(SecureRandom.hex(16))
|
531
|
-
view_id = extract_id(SecureRandom.hex(16))
|
532
|
-
|
533
|
-
children = []
|
534
|
-
alive_blocks = []
|
535
|
-
data.each do |_row|
|
536
|
-
child = extract_id(SecureRandom.hex(16))
|
537
|
-
children.push(child)
|
538
|
-
alive_blocks.push(Utils::CollectionViewComponents.set_collection_blocks_alive(child, collection_id))
|
539
|
-
end
|
540
|
-
|
541
|
-
request_id = extract_id(SecureRandom.hex(16))
|
542
|
-
transaction_id = extract_id(SecureRandom.hex(16))
|
543
|
-
space_id = extract_id(SecureRandom.hex(16))
|
544
|
-
|
545
|
-
request_ids = {
|
546
|
-
request_id: request_id,
|
547
|
-
transaction_id: transaction_id,
|
548
|
-
space_id: space_id
|
549
|
-
}
|
550
|
-
|
551
|
-
create_collection_view = Utils::CollectionViewComponents.create_collection_view(new_block_id, collection_id, view_id)
|
552
|
-
configure_view = Utils::CollectionViewComponents.set_view_config(collection_type, new_block_id, view_id, children)
|
553
|
-
|
554
|
-
# returns the JSON and some useful column mappings...
|
555
|
-
column_data = Utils::CollectionViewComponents.set_collection_columns(collection_id, new_block_id, data)
|
556
|
-
configure_columns_hash = column_data[0]
|
557
|
-
column_mappings = column_data[1]
|
558
|
-
set_parent_alive_hash = Utils::BlockComponents.set_parent_to_alive(@id, new_block_id)
|
559
|
-
add_block_hash = Utils::BlockComponents.block_location_add(@id, @id, new_block_id, nil, 'listAfter')
|
560
|
-
new_block_edited_time = Utils::BlockComponents.last_edited_time(new_block_id)
|
561
|
-
collection_title_hash = Utils::CollectionViewComponents.set_collection_title(collection_title, collection_id)
|
562
|
-
|
563
|
-
operations = [
|
564
|
-
create_collection_view,
|
565
|
-
configure_view,
|
566
|
-
configure_columns_hash,
|
567
|
-
set_parent_alive_hash,
|
568
|
-
add_block_hash,
|
569
|
-
new_block_edited_time,
|
570
|
-
collection_title_hash
|
571
|
-
]
|
572
|
-
operations << alive_blocks
|
573
|
-
all_ops = operations.flatten
|
574
|
-
data.each_with_index do |row, i|
|
575
|
-
child = children[i]
|
576
|
-
row.keys.each_with_index do |col_name, j|
|
577
|
-
child_component = Utils::CollectionViewComponents.insert_data(child, j.zero? ? 'title' : col_name, row[col_name], column_mappings[j])
|
578
|
-
all_ops.push(child_component)
|
579
|
-
end
|
580
|
-
end
|
581
|
-
|
582
|
-
request_url = URLS[:UPDATE_BLOCK]
|
583
|
-
request_body = build_payload(all_ops, request_ids)
|
584
|
-
response = HTTParty.post(
|
585
|
-
request_url,
|
586
|
-
body: request_body.to_json,
|
587
|
-
cookies: cookies,
|
588
|
-
headers: headers
|
589
|
-
)
|
590
|
-
|
591
|
-
unless response.code == 200; raise "There was an issue completing your request. Here is the response from Notion: #{response.body}, and here is the payload that was sent: #{operations}.
|
592
|
-
Please try again, and if issues persist open an issue in GitHub."; end
|
593
|
-
|
594
|
-
CollectionView.new(new_block_id, collection_title, parent_id, collection_id, view_id)
|
595
|
-
end
|
596
|
-
end
|
597
|
-
|
598
|
-
# Toggle block: best for storing children blocks
|
599
|
-
class ToggleBlock < BlockTemplate
|
600
|
-
@notion_type = 'toggle'
|
601
|
-
@type = 'toggle'
|
602
|
-
|
603
|
-
def type
|
604
|
-
NotionAPI::ToggleBlock.notion_type
|
605
|
-
end
|
606
|
-
|
607
|
-
class << self
|
608
|
-
attr_reader :notion_type, :type
|
609
|
-
end
|
610
|
-
end
|
611
|
-
|
612
|
-
# Bullet list block: best for an unordered list
|
613
|
-
class BulletedBlock < BlockTemplate
|
614
|
-
@notion_type = 'bulleted_list'
|
615
|
-
@type = 'bulleted_list'
|
616
|
-
|
617
|
-
def type
|
618
|
-
NotionAPI::BulletedBlock.notion_type
|
619
|
-
end
|
620
|
-
|
621
|
-
class << self
|
622
|
-
attr_reader :notion_type, :type
|
623
|
-
end
|
624
|
-
end
|
625
|
-
|
626
|
-
# Numbered list Block: best for an ordered list
|
627
|
-
class NumberedBlock < BlockTemplate
|
628
|
-
@notion_type = 'numbered_list'
|
629
|
-
@type = 'numbered_list'
|
630
|
-
|
631
|
-
def type
|
632
|
-
NotionAPI::NumberedBlock.notion_type
|
633
|
-
end
|
634
|
-
|
635
|
-
class << self
|
636
|
-
attr_reader :notion_type, :type
|
637
|
-
end
|
638
|
-
end
|
639
|
-
|
640
|
-
# best for memorable information
|
641
|
-
class QuoteBlock < BlockTemplate
|
642
|
-
@notion_type = 'quote'
|
643
|
-
@type = 'quote'
|
644
|
-
|
645
|
-
def type
|
646
|
-
NotionAPI::QuoteBlock.notion_type
|
647
|
-
end
|
648
|
-
|
649
|
-
class << self
|
650
|
-
attr_reader :notion_type, :type
|
651
|
-
end
|
652
|
-
end
|
653
|
-
|
654
|
-
# same as quote... works similarly to page block
|
655
|
-
class CalloutBlock < BlockTemplate
|
656
|
-
@notion_type = 'callout'
|
657
|
-
@type = 'callout'
|
658
|
-
|
659
|
-
def type
|
660
|
-
NotionAPI::CalloutBlock.notion_type
|
661
|
-
end
|
662
|
-
|
663
|
-
class << self
|
664
|
-
attr_reader :notion_type, :type
|
665
|
-
end
|
666
|
-
end
|
667
|
-
|
668
|
-
# simiilar to code block but for mathematical functions.
|
669
|
-
class LatexBlock < BlockTemplate
|
670
|
-
@notion_type = 'equation'
|
671
|
-
@type = 'equation'
|
672
|
-
|
673
|
-
def type
|
674
|
-
NotionAPI::LatexBlock.notion_type
|
675
|
-
end
|
676
|
-
|
677
|
-
class << self
|
678
|
-
attr_reader :notion_type, :type
|
679
|
-
end
|
680
|
-
end
|
681
|
-
|
682
|
-
# good for just about anything (-:
|
683
|
-
class TextBlock < BlockTemplate
|
684
|
-
@notion_type = 'text'
|
685
|
-
@type = 'text'
|
686
|
-
|
687
|
-
def type
|
688
|
-
NotionAPI::TextBlock.notion_type
|
689
|
-
end
|
690
|
-
|
691
|
-
class << self
|
692
|
-
attr_reader :notion_type, :type
|
693
|
-
end
|
694
|
-
end
|
695
|
-
|
696
|
-
# good for visual information
|
697
|
-
class ImageBlock < BlockTemplate
|
698
|
-
@notion_type = 'image'
|
699
|
-
@type = 'image'
|
700
|
-
|
701
|
-
def type
|
702
|
-
NotionAPI::ImageBlock.notion_type
|
703
|
-
end
|
704
|
-
|
705
|
-
class << self
|
706
|
-
attr_reader :notion_type, :type
|
707
|
-
end
|
708
|
-
end
|
709
|
-
|
710
|
-
# maps out the headers - sub-headers - sub-sub-headers on the page
|
711
|
-
class TableOfContentsBlock < BlockTemplate
|
712
|
-
@notion_type = 'table_of_contents'
|
713
|
-
@type = 'table_of_contents'
|
714
|
-
|
715
|
-
def type
|
716
|
-
NotionAPI::TableOfContentsBlock.notion_type
|
717
|
-
end
|
718
|
-
|
719
|
-
class << self
|
720
|
-
attr_reader :notion_type, :type
|
721
|
-
end
|
722
|
-
end
|
723
|
-
|
724
|
-
# no use case for this yet.
|
725
|
-
class ColumnListBlock < BlockTemplate
|
726
|
-
@notion_type = 'column_list'
|
727
|
-
@type = 'column_list'
|
728
|
-
|
729
|
-
def type
|
730
|
-
NotionAPI::ColumnListBlock.notion_type
|
731
|
-
end
|
732
|
-
|
733
|
-
class << self
|
734
|
-
attr_reader :notion_type, :type
|
735
|
-
end
|
736
|
-
end
|
737
|
-
|
738
|
-
# no use case for this yet.
|
739
|
-
class ColumnBlock < BlockTemplate
|
740
|
-
@notion_type = 'column'
|
741
|
-
@type = 'column'
|
742
|
-
|
743
|
-
def type
|
744
|
-
NotionAPI::ColumnBlock.notion_type
|
745
|
-
end
|
746
|
-
|
747
|
-
class << self
|
748
|
-
attr_reader :notion_type, :type
|
749
|
-
end
|
750
|
-
end
|
751
|
-
end
|
752
|
-
|
753
|
-
module NotionAPI
|
754
|
-
# collection views such as tables and timelines.
|
755
|
-
class CollectionView < Core
|
756
|
-
attr_reader :id, :title, :parent_id, :collection_id, :view_id
|
757
|
-
|
758
|
-
@notion_type = 'collection_view'
|
759
|
-
@type = 'collection_view'
|
760
|
-
|
761
|
-
def type
|
762
|
-
NotionAPI::CollectionView.notion_type
|
763
|
-
end
|
764
|
-
|
765
|
-
class << self
|
766
|
-
attr_reader :notion_type, :type
|
767
|
-
end
|
768
|
-
|
769
|
-
def initialize(id, title, parent_id, collection_id, view_id)
|
770
|
-
@id = id
|
771
|
-
@title = title
|
772
|
-
@parent_id = parent_id
|
773
|
-
@collection_id = collection_id
|
774
|
-
@view_id = view_id
|
775
|
-
end
|
776
|
-
|
777
|
-
def add_row(data)
|
778
|
-
# ! add new row to Collection View table.
|
779
|
-
# ! data -> data to add to table : ``hash``
|
780
|
-
|
781
|
-
cookies = Core.options['cookies']
|
782
|
-
headers = Core.options['headers']
|
783
|
-
|
784
|
-
request_id = extract_id(SecureRandom.hex(16))
|
785
|
-
transaction_id = extract_id(SecureRandom.hex(16))
|
786
|
-
space_id = extract_id(SecureRandom.hex(16))
|
787
|
-
new_block_id = extract_id(SecureRandom.hex(16))
|
788
|
-
schema = extract_collection_schema(@collection_id, @view_id)
|
789
|
-
keys = schema.keys
|
790
|
-
col_map = {}
|
791
|
-
keys.map { |key| col_map[schema[key]['name']] = key }
|
792
|
-
|
793
|
-
request_ids = {
|
794
|
-
request_id: request_id,
|
795
|
-
transaction_id: transaction_id,
|
796
|
-
space_id: space_id
|
797
|
-
}
|
798
|
-
|
799
|
-
instantiate_row = Utils::CollectionViewComponents.add_new_row(new_block_id)
|
800
|
-
set_block_alive = Utils::CollectionViewComponents.set_collection_blocks_alive(new_block_id, @collection_id)
|
801
|
-
new_block_edited_time = Utils::BlockComponents.last_edited_time(new_block_id)
|
802
|
-
parent_edited_time = Utils::BlockComponents.last_edited_time(@parent_id)
|
803
|
-
|
804
|
-
operations = [
|
805
|
-
instantiate_row,
|
806
|
-
set_block_alive,
|
807
|
-
new_block_edited_time,
|
808
|
-
parent_edited_time
|
809
|
-
]
|
810
|
-
|
811
|
-
data.keys.each_with_index do |col_name, j|
|
812
|
-
child_component = Utils::CollectionViewComponents.insert_data(new_block_id, j.zero? ? 'title' : col_map[col_name], data[col_name], j.zero? ? schema['title']["type"] : schema[col_map[col_name]]['type'])
|
813
|
-
operations.push(child_component)
|
814
|
-
end
|
815
|
-
|
816
|
-
request_url = URLS[:UPDATE_BLOCK]
|
817
|
-
request_body = build_payload(operations, request_ids)
|
818
|
-
response = HTTParty.post(
|
819
|
-
request_url,
|
820
|
-
body: request_body.to_json,
|
821
|
-
cookies: cookies,
|
822
|
-
headers: headers
|
823
|
-
)
|
824
|
-
|
825
|
-
unless response.code == 200; raise "There was an issue completing your request. Here is the response from Notion: #{response.body}, and here is the payload that was sent: #{operations}.
|
826
|
-
Please try again, and if issues persist open an issue in GitHub."; end
|
827
|
-
|
828
|
-
NotionAPI::CollectionViewRow.new(new_block_id, @parent_id, @collection_id, @view_id)
|
829
|
-
end
|
830
|
-
|
831
|
-
def add_property(name, type)
|
832
|
-
# ! add a property (column) to the table.
|
833
|
-
# ! name -> name of the property : ``str``
|
834
|
-
# ! type -> type of the property : ``str``
|
835
|
-
cookies = Core.options['cookies']
|
836
|
-
headers = Core.options['headers']
|
837
|
-
|
838
|
-
request_id = extract_id(SecureRandom.hex(16))
|
839
|
-
transaction_id = extract_id(SecureRandom.hex(16))
|
840
|
-
space_id = extract_id(SecureRandom.hex(16))
|
841
|
-
|
842
|
-
request_ids = {
|
843
|
-
request_id: request_id,
|
844
|
-
transaction_id: transaction_id,
|
845
|
-
space_id: space_id
|
846
|
-
}
|
847
|
-
|
848
|
-
# create updated schema
|
849
|
-
schema = extract_collection_schema(@collection_id, @view_id)
|
850
|
-
schema[name] = {
|
851
|
-
name: name,
|
852
|
-
type: type
|
853
|
-
}
|
854
|
-
new_schema = {
|
855
|
-
schema: schema
|
856
|
-
}
|
857
|
-
|
858
|
-
add_collection_property = Utils::CollectionViewComponents.add_collection_property(@collection_id, new_schema)
|
859
|
-
|
860
|
-
operations = [
|
861
|
-
add_collection_property
|
862
|
-
]
|
863
|
-
|
864
|
-
request_url = URLS[:UPDATE_BLOCK]
|
865
|
-
request_body = build_payload(operations, request_ids)
|
866
|
-
response = HTTParty.post(
|
867
|
-
request_url,
|
868
|
-
body: request_body.to_json,
|
869
|
-
cookies: cookies,
|
870
|
-
headers: headers
|
871
|
-
)
|
872
|
-
unless response.code == 200; raise "There was an issue completing your request. Here is the response from Notion: #{response.body}, and here is the payload that was sent: #{operations}.
|
873
|
-
Please try again, and if issues persist open an issue in GitHub."; end
|
874
|
-
|
875
|
-
true
|
876
|
-
end
|
877
|
-
|
878
|
-
def row(row_id)
|
879
|
-
# ! retrieve a row from a CollectionView Table.
|
880
|
-
# ! row_id -> the ID for the row to retrieve: ``str``
|
881
|
-
clean_id = extract_id(row_id)
|
882
|
-
|
883
|
-
request_body = {
|
884
|
-
pageId: clean_id,
|
885
|
-
chunkNumber: 0,
|
886
|
-
limit: 100,
|
887
|
-
verticalColumns: false
|
888
|
-
}
|
889
|
-
jsonified_record_response = get_all_block_info(clean_id, request_body)
|
890
|
-
schema = extract_collection_schema(@collection_id, @view_id)
|
891
|
-
keys = schema.keys
|
892
|
-
column_names = keys.map { |key| schema[key]['name'] }
|
893
|
-
i = 0
|
894
|
-
while jsonified_record_response.empty? || jsonified_record_response['block'].empty?
|
895
|
-
return {} if i >= 10
|
896
|
-
|
897
|
-
jsonified_record_response = get_all_block_info(clean_id, request_body)
|
898
|
-
i += 1
|
899
|
-
end
|
900
|
-
row_jsonified_response = jsonified_record_response['block'][clean_id]['value']['properties']
|
901
|
-
row_data = {}
|
902
|
-
keys.each_with_index { |key, idx| row_data[column_names[idx]] = row_jsonified_response[key] ? row_jsonified_response[key].flatten : [] }
|
903
|
-
row_data
|
904
|
-
end
|
905
|
-
|
906
|
-
def row_ids
|
907
|
-
# ! retrieve all Collection View table rows.
|
908
|
-
clean_id = extract_id(@id)
|
909
|
-
|
910
|
-
request_body = {
|
911
|
-
pageId: clean_id,
|
912
|
-
chunkNumber: 0,
|
913
|
-
limit: 100,
|
914
|
-
verticalColumns: false
|
915
|
-
}
|
916
|
-
|
917
|
-
jsonified_record_response = get_all_block_info(clean_id, request_body)
|
918
|
-
i = 0
|
919
|
-
while jsonified_record_response.empty? || jsonified_record_response['block'].empty?
|
920
|
-
return {} if i >= 10
|
921
|
-
|
922
|
-
jsonified_record_response = get_all_block_info(clean_id, request_body)
|
923
|
-
i += 1
|
924
|
-
end
|
925
|
-
|
926
|
-
jsonified_record_response['collection_view'][@view_id]['value']['page_sort']
|
927
|
-
end
|
928
|
-
|
929
|
-
def rows
|
930
|
-
# ! returns all rows as instantiated class instances.
|
931
|
-
row_id_array = row_ids
|
932
|
-
parent_id = @parent_id
|
933
|
-
collection_id = @collection_id
|
934
|
-
view_id = @view_id
|
935
|
-
|
936
|
-
row_id_array.map { |row_id| NotionAPI::CollectionViewRow.new(row_id, parent_id, collection_id, view_id) }
|
937
|
-
end
|
938
|
-
|
939
|
-
private
|
940
|
-
|
941
|
-
def extract_collection_schema(collection_id, view_id)
|
942
|
-
# ! retrieve the collection scehma. Useful for 'building' the backbone for a table.
|
943
|
-
# ! collection_id -> the collection ID : ``str``
|
944
|
-
# ! view_id -> the view ID : ``str``
|
945
|
-
cookies = Core.options['cookies']
|
946
|
-
headers = Core.options['headers']
|
947
|
-
|
948
|
-
query_collection_hash = Utils::CollectionViewComponents.query_collection(collection_id, view_id, '')
|
949
|
-
|
950
|
-
request_url = URLS[:GET_COLLECTION]
|
951
|
-
response = HTTParty.post(
|
952
|
-
request_url,
|
953
|
-
body: query_collection_hash.to_json,
|
954
|
-
cookies: cookies,
|
955
|
-
headers: headers
|
956
|
-
)
|
957
|
-
response['recordMap']['collection'][collection_id]['value']['schema']
|
958
|
-
end
|
959
|
-
end
|
960
|
-
# Class for each row in a Collection View Table.
|
961
|
-
class CollectionViewRow < Core
|
962
|
-
@notion_type = 'table_row'
|
963
|
-
@type = 'table_row'
|
964
|
-
|
965
|
-
def type
|
966
|
-
NotionAPI::CollectionViewRow.notion_type
|
967
|
-
end
|
968
|
-
|
969
|
-
class << self
|
970
|
-
attr_reader :notion_type, :type, :parent_id
|
971
|
-
end
|
972
|
-
|
973
|
-
attr_reader :parent_id, :id
|
974
|
-
def initialize(id, parent_id, collection_id, view_id)
|
975
|
-
@id = id
|
976
|
-
@parent_id = parent_id
|
977
|
-
@collection_id = collection_id
|
978
|
-
@view_id = view_id
|
979
|
-
end
|
980
|
-
end
|
981
|
-
end
|
982
|
-
|
983
|
-
# gather a list of all the classes defined here...
|
984
21
|
Classes = NotionAPI.constants.select { |c| NotionAPI.const_get(c).is_a? Class and c.to_s != 'BlockTemplate' and c.to_s != 'Core' and c.to_s !='Client' }
|
985
22
|
notion_types = []
|
986
23
|
Classes.each { |cls| notion_types.push(NotionAPI.const_get(cls).notion_type) }
|