Skip to content

Commit bf575a0

Browse files
committed
re-factor blocks into their own files to better modularize the API, add emoji generation for callout and page blocks, and support duplication of styles AND titles with the duplicate method
1 parent d26b4f7 commit bf575a0

24 files changed

+1064
-988
lines changed

lib/notion_api/blocks.rb

Lines changed: 19 additions & 982 deletions
Large diffs are not rendered by default.

lib/notion_api/core.rb

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,29 @@ def get_last_page_block_id(url_or_id)
113113
children_ids(url_or_id).empty? ? [] : children_ids(url_or_id)[-1]
114114
end
115115

116+
def get_block_props_and_format(clean_id, block_title)
117+
request_body = {
118+
pageId: clean_id,
119+
chunkNumber: 0,
120+
limit: 100,
121+
verticalColumns: false
122+
}
123+
jsonified_record_response = get_all_block_info(clean_id, request_body)
124+
i = 0
125+
while jsonified_record_response.empty?
126+
return {:properties => {title: [[block_title]]}, :format => {}} if i >= 10
127+
128+
jsonified_record_response = get_all_block_info(clean_id, request_body)
129+
i += 1
130+
end
131+
properties = jsonified_record_response['block'][clean_id]['value']['properties']
132+
formats = jsonified_record_response['block'][clean_id]['value']['format']
133+
return {
134+
:properties => properties,
135+
:format => formats
136+
}
137+
end
138+
116139
def get_all_block_info(_clean_id, body)
117140
# ! retrieves all info pertaining to a block Id.
118141
# ! clean_id -> the block ID or URL cleaned : ``str``
@@ -193,7 +216,7 @@ def extract_collection_id(clean_id, jsonified_record_response)
193216
def extract_view_ids(clean_id, jsonified_record_response)
194217
jsonified_record_response['block'][clean_id]['value']['view_ids'] || []
195218
end
196-
219+
197220
def extract_id(url_or_id)
198221
# ! parse and clean the URL or ID object provided.
199222
# ! url_or_id -> the block ID or URL : ``str``
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
require_relative "template"
2+
3+
module NotionAPI
4+
# Bullet list block: best for an unordered list
5+
class BulletedBlock < BlockTemplate
6+
@notion_type = "bulleted_list"
7+
@type = "bulleted_list"
8+
9+
def type
10+
NotionAPI::BulletedBlock.notion_type
11+
end
12+
13+
class << self
14+
attr_reader :notion_type, :type
15+
end
16+
end
17+
end
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module NotionAPI
2+
3+
# same as quote... works similarly to page block
4+
class CalloutBlock < BlockTemplate
5+
@notion_type = 'callout'
6+
@type = 'callout'
7+
8+
def type
9+
NotionAPI::CalloutBlock.notion_type
10+
end
11+
12+
class << self
13+
attr_reader :notion_type, :type
14+
end
15+
end
16+
end
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module NotionAPI
2+
3+
# Code block: used to store code, should be assigned a coding language.
4+
class CodeBlock < BlockTemplate
5+
@notion_type = 'code'
6+
@type = 'code'
7+
8+
def type
9+
NotionAPI::CodeBlock.notion_type
10+
end
11+
12+
class << self
13+
attr_reader :notion_type, :type
14+
end
15+
end
16+
end
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
module NotionAPI
2+
# collection views such as tables and timelines.
3+
class CollectionView < Core
4+
attr_reader :id, :title, :parent_id, :collection_id, :view_id
5+
6+
@notion_type = 'collection_view'
7+
@type = 'collection_view'
8+
9+
def type
10+
NotionAPI::CollectionView.notion_type
11+
end
12+
13+
class << self
14+
attr_reader :notion_type, :type
15+
end
16+
17+
def initialize(id, title, parent_id, collection_id, view_id)
18+
@id = id
19+
@title = title
20+
@parent_id = parent_id
21+
@collection_id = collection_id
22+
@view_id = view_id
23+
end
24+
25+
def add_row(data)
26+
# ! add new row to Collection View table.
27+
# ! data -> data to add to table : ``hash``
28+
29+
cookies = Core.options['cookies']
30+
headers = Core.options['headers']
31+
32+
request_id = extract_id(SecureRandom.hex(16))
33+
transaction_id = extract_id(SecureRandom.hex(16))
34+
space_id = extract_id(SecureRandom.hex(16))
35+
new_block_id = extract_id(SecureRandom.hex(16))
36+
schema = extract_collection_schema(@collection_id, @view_id)
37+
keys = schema.keys
38+
col_map = {}
39+
keys.map { |key| col_map[schema[key]['name']] = key }
40+
41+
request_ids = {
42+
request_id: request_id,
43+
transaction_id: transaction_id,
44+
space_id: space_id
45+
}
46+
47+
instantiate_row = Utils::CollectionViewComponents.add_new_row(new_block_id)
48+
set_block_alive = Utils::CollectionViewComponents.set_collection_blocks_alive(new_block_id, @collection_id)
49+
new_block_edited_time = Utils::BlockComponents.last_edited_time(new_block_id)
50+
parent_edited_time = Utils::BlockComponents.last_edited_time(@parent_id)
51+
52+
operations = [
53+
instantiate_row,
54+
set_block_alive,
55+
new_block_edited_time,
56+
parent_edited_time
57+
]
58+
59+
data.keys.each_with_index do |col_name, j|
60+
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'])
61+
operations.push(child_component)
62+
end
63+
64+
request_url = URLS[:UPDATE_BLOCK]
65+
request_body = build_payload(operations, request_ids)
66+
response = HTTParty.post(
67+
request_url,
68+
body: request_body.to_json,
69+
cookies: cookies,
70+
headers: headers
71+
)
72+
73+
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}.
74+
Please try again, and if issues persist open an issue in GitHub."; end
75+
76+
NotionAPI::CollectionViewRow.new(new_block_id, @parent_id, @collection_id, @view_id)
77+
end
78+
79+
def add_property(name, type)
80+
# ! add a property (column) to the table.
81+
# ! name -> name of the property : ``str``
82+
# ! type -> type of the property : ``str``
83+
cookies = Core.options['cookies']
84+
headers = Core.options['headers']
85+
86+
request_id = extract_id(SecureRandom.hex(16))
87+
transaction_id = extract_id(SecureRandom.hex(16))
88+
space_id = extract_id(SecureRandom.hex(16))
89+
90+
request_ids = {
91+
request_id: request_id,
92+
transaction_id: transaction_id,
93+
space_id: space_id
94+
}
95+
96+
# create updated schema
97+
schema = extract_collection_schema(@collection_id, @view_id)
98+
schema[name] = {
99+
name: name,
100+
type: type
101+
}
102+
new_schema = {
103+
schema: schema
104+
}
105+
106+
add_collection_property = Utils::CollectionViewComponents.add_collection_property(@collection_id, new_schema)
107+
108+
operations = [
109+
add_collection_property
110+
]
111+
112+
request_url = URLS[:UPDATE_BLOCK]
113+
request_body = build_payload(operations, request_ids)
114+
response = HTTParty.post(
115+
request_url,
116+
body: request_body.to_json,
117+
cookies: cookies,
118+
headers: headers
119+
)
120+
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}.
121+
Please try again, and if issues persist open an issue in GitHub."; end
122+
123+
true
124+
end
125+
126+
def row(row_id)
127+
# ! retrieve a row from a CollectionView Table.
128+
# ! row_id -> the ID for the row to retrieve: ``str``
129+
clean_id = extract_id(row_id)
130+
131+
request_body = {
132+
pageId: clean_id,
133+
chunkNumber: 0,
134+
limit: 100,
135+
verticalColumns: false
136+
}
137+
jsonified_record_response = get_all_block_info(clean_id, request_body)
138+
schema = extract_collection_schema(@collection_id, @view_id)
139+
keys = schema.keys
140+
column_names = keys.map { |key| schema[key]['name'] }
141+
i = 0
142+
while jsonified_record_response.empty? || jsonified_record_response['block'].empty?
143+
return {} if i >= 10
144+
145+
jsonified_record_response = get_all_block_info(clean_id, request_body)
146+
i += 1
147+
end
148+
row_jsonified_response = jsonified_record_response['block'][clean_id]['value']['properties']
149+
row_data = {}
150+
keys.each_with_index { |key, idx| row_data[column_names[idx]] = row_jsonified_response[key] ? row_jsonified_response[key].flatten : [] }
151+
row_data
152+
end
153+
154+
def row_ids
155+
# ! retrieve all Collection View table rows.
156+
clean_id = extract_id(@id)
157+
158+
request_body = {
159+
pageId: clean_id,
160+
chunkNumber: 0,
161+
limit: 100,
162+
verticalColumns: false
163+
}
164+
165+
jsonified_record_response = get_all_block_info(clean_id, request_body)
166+
i = 0
167+
while jsonified_record_response.empty? || jsonified_record_response['block'].empty?
168+
return {} if i >= 10
169+
170+
jsonified_record_response = get_all_block_info(clean_id, request_body)
171+
i += 1
172+
end
173+
174+
jsonified_record_response['collection_view'][@view_id]['value']['page_sort']
175+
end
176+
177+
def rows
178+
# ! returns all rows as instantiated class instances.
179+
row_id_array = row_ids
180+
parent_id = @parent_id
181+
collection_id = @collection_id
182+
view_id = @view_id
183+
184+
row_id_array.map { |row_id| NotionAPI::CollectionViewRow.new(row_id, parent_id, collection_id, view_id) }
185+
end
186+
187+
private
188+
189+
def extract_collection_schema(collection_id, view_id)
190+
# ! retrieve the collection scehma. Useful for 'building' the backbone for a table.
191+
# ! collection_id -> the collection ID : ``str``
192+
# ! view_id -> the view ID : ``str``
193+
cookies = Core.options['cookies']
194+
headers = Core.options['headers']
195+
196+
query_collection_hash = Utils::CollectionViewComponents.query_collection(collection_id, view_id, '')
197+
198+
request_url = URLS[:GET_COLLECTION]
199+
response = HTTParty.post(
200+
request_url,
201+
body: query_collection_hash.to_json,
202+
cookies: cookies,
203+
headers: headers
204+
)
205+
response['recordMap']['collection'][collection_id]['value']['schema']
206+
end
207+
end
208+
class CollectionViewRow < Core
209+
@notion_type = 'table_row'
210+
@type = 'table_row'
211+
212+
def type
213+
NotionAPI::CollectionViewRow.notion_type
214+
end
215+
216+
class << self
217+
attr_reader :notion_type, :type, :parent_id
218+
end
219+
220+
attr_reader :parent_id, :id
221+
def initialize(id, parent_id, collection_id, view_id)
222+
@id = id
223+
@parent_id = parent_id
224+
@collection_id = collection_id
225+
@view_id = view_id
226+
end
227+
end
228+
end
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module NotionAPI
2+
3+
# no use case for this yet.
4+
class ColumnListBlock < BlockTemplate
5+
@notion_type = 'column_list'
6+
@type = 'column_list'
7+
8+
def type
9+
NotionAPI::ColumnListBlock.notion_type
10+
end
11+
12+
class << self
13+
attr_reader :notion_type, :type
14+
end
15+
end
16+
end
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module NotionAPI
2+
# divider block: ---------
3+
class DividerBlock < BlockTemplate
4+
@notion_type = 'divider'
5+
@type = 'divider'
6+
7+
def type
8+
NotionAPI::DividerBlock.notion_type
9+
end
10+
11+
class << self
12+
attr_reader :notion_type, :type
13+
end
14+
end
15+
end
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module NotionAPI
2+
3+
# Header block: H1
4+
class HeaderBlock < BlockTemplate
5+
@notion_type = 'header'
6+
@type = 'header'
7+
8+
def type
9+
NotionAPI::HeaderBlock.notion_type
10+
end
11+
12+
class << self
13+
attr_reader :notion_type, :type
14+
end
15+
end
16+
end
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module NotionAPI
2+
3+
# good for visual information
4+
class ImageBlock < BlockTemplate
5+
@notion_type = 'image'
6+
@type = 'image'
7+
8+
def type
9+
NotionAPI::ImageBlock.notion_type
10+
end
11+
12+
class << self
13+
attr_reader :notion_type, :type
14+
end
15+
end
16+
end

0 commit comments

Comments
 (0)