notion 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.md +21 -0
- data/README.md +196 -0
- data/lib/notion_api.rb +5 -0
- data/lib/notion_api/blocks.rb +984 -0
- data/lib/notion_api/client.rb +16 -0
- data/lib/notion_api/core.rb +217 -0
- data/lib/notion_api/markdown.rb +7 -0
- data/lib/notion_api/utils.rb +518 -0
- data/lib/notion_api/version.rb +3 -0
- metadata +143 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'core'
|
4
|
+
|
5
|
+
module NotionAPI
|
6
|
+
# acts as the 'main interface' to the methods of this package.
|
7
|
+
class Client < Core
|
8
|
+
attr_reader :token_v2, :active_user_header
|
9
|
+
|
10
|
+
def initialize(token_v2, active_user_header = nil)
|
11
|
+
@token_v2 = token_v2
|
12
|
+
@active_user_header = active_user_header
|
13
|
+
super(token_v2, active_user_header)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'utils'
|
4
|
+
require 'httparty'
|
5
|
+
|
6
|
+
module NotionAPI
|
7
|
+
# the initial methods available to an instantiated Cloent object are defined
|
8
|
+
class Core
|
9
|
+
include Utils
|
10
|
+
@options = { 'cookies' => { :token_v2 => nil, 'x-active-user-header' => nil }, 'headers' => { 'Content-Type' => 'application/json' } }
|
11
|
+
@type_whitelist = 'divider'
|
12
|
+
|
13
|
+
class << self
|
14
|
+
attr_reader :options, :type_whitelist, :token_v2, :active_user_header
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :clean_id, :cookies, :headers
|
18
|
+
|
19
|
+
def initialize(token_v2, active_user_header)
|
20
|
+
@@token_v2 = token_v2
|
21
|
+
@@active_user_header = active_user_header
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_page(url_or_id)
|
25
|
+
# ! retrieve a Notion Page Block and return its instantiated class object.
|
26
|
+
# ! url_or_id -> the block ID or URL : ``str``
|
27
|
+
clean_id = extract_id(url_or_id)
|
28
|
+
|
29
|
+
request_body = {
|
30
|
+
pageId: clean_id,
|
31
|
+
chunkNumber: 0,
|
32
|
+
limit: 100,
|
33
|
+
verticalColumns: false
|
34
|
+
}
|
35
|
+
jsonified_record_response = get_all_block_info(clean_id, request_body)
|
36
|
+
i = 0
|
37
|
+
while jsonified_record_response.empty? || jsonified_record_response['block'].empty?
|
38
|
+
return {} if i >= 10
|
39
|
+
|
40
|
+
jsonified_record_response = get_all_block_info(clean_id, request_body)
|
41
|
+
i += 1
|
42
|
+
end
|
43
|
+
|
44
|
+
block_id = clean_id
|
45
|
+
block_title = extract_title(clean_id, jsonified_record_response)
|
46
|
+
block_type = extract_type(clean_id, jsonified_record_response)
|
47
|
+
block_parent_id = extract_parent_id(clean_id, jsonified_record_response)
|
48
|
+
|
49
|
+
raise 'the URL or ID passed to the get_page method must be that of a Page Block.' if block_type != 'page'
|
50
|
+
|
51
|
+
PageBlock.new(block_id, block_title, block_parent_id)
|
52
|
+
end
|
53
|
+
|
54
|
+
def children(url_or_id = @id)
|
55
|
+
# ! retrieve the children of a block. If the block has no children, return []. If it does, return the instantiated class objects associated with each child.
|
56
|
+
# ! url_or_id -> the block ID or URL : ``str``
|
57
|
+
|
58
|
+
children_ids = children_ids(url_or_id)
|
59
|
+
if children_ids.empty?
|
60
|
+
[]
|
61
|
+
else
|
62
|
+
children_class_instances = []
|
63
|
+
children_ids.each { |child| children_class_instances.push(get(child)) }
|
64
|
+
children_class_instances
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def children_ids(url_or_id = @id)
|
69
|
+
# ! retrieve the children IDs of a block.
|
70
|
+
# ! url_or_id -> the block ID or URL : ``str``
|
71
|
+
clean_id = extract_id(url_or_id)
|
72
|
+
request_body = {
|
73
|
+
pageId: clean_id,
|
74
|
+
chunkNumber: 0,
|
75
|
+
limit: 100,
|
76
|
+
verticalColumns: false
|
77
|
+
}
|
78
|
+
jsonified_record_response = get_all_block_info(clean_id, request_body)
|
79
|
+
i = 0
|
80
|
+
while jsonified_record_response.empty?
|
81
|
+
return {} if i >= 10
|
82
|
+
|
83
|
+
jsonified_record_response = get_all_block_info(clean_id, request_body)
|
84
|
+
i += 1
|
85
|
+
end
|
86
|
+
|
87
|
+
jsonified_record_response['block'][clean_id]['value']['content'] || []
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def get_notion_id(body)
|
93
|
+
# ! retrieves a users ID from the headers of a Notion response object.
|
94
|
+
# ! body -> the body to send in the request : ``Hash``
|
95
|
+
Core.options['cookies'][:token_v2] = @@token_v2
|
96
|
+
Core.options['headers']['x-notion-active-user-header'] = @@active_user_header
|
97
|
+
cookies = Core.options['cookies']
|
98
|
+
headers = Core.options['headers']
|
99
|
+
request_url = URLS[:GET_BLOCK]
|
100
|
+
|
101
|
+
response = HTTParty.post(
|
102
|
+
request_url,
|
103
|
+
body: body.to_json,
|
104
|
+
cookies: cookies,
|
105
|
+
headers: headers
|
106
|
+
)
|
107
|
+
response.headers['x-notion-user-id']
|
108
|
+
end
|
109
|
+
|
110
|
+
def get_last_page_block_id(url_or_id)
|
111
|
+
# ! retrieve and return the last child ID of a block.
|
112
|
+
# ! url_or_id -> the block ID or URL : ``str``
|
113
|
+
children_ids(url_or_id).empty? ? [] : children_ids(url_or_id)[-1]
|
114
|
+
end
|
115
|
+
|
116
|
+
def get_all_block_info(_clean_id, body)
|
117
|
+
# ! retrieves all info pertaining to a block Id.
|
118
|
+
# ! clean_id -> the block ID or URL cleaned : ``str``
|
119
|
+
Core.options['cookies'][:token_v2] = @@token_v2
|
120
|
+
Core.options['headers']['x-notion-active-user-header'] = @active_user_header
|
121
|
+
cookies = Core.options['cookies']
|
122
|
+
headers = Core.options['headers']
|
123
|
+
|
124
|
+
request_url = URLS[:GET_BLOCK]
|
125
|
+
|
126
|
+
response = HTTParty.post(
|
127
|
+
request_url,
|
128
|
+
body: body.to_json,
|
129
|
+
cookies: cookies,
|
130
|
+
headers: headers
|
131
|
+
)
|
132
|
+
|
133
|
+
JSON.parse(response.body)['recordMap']
|
134
|
+
end
|
135
|
+
|
136
|
+
def filter_nil_blocks(jsonified_record_response)
|
137
|
+
# ! removes any blocks that are empty [i.e. have no title / content]
|
138
|
+
# ! jsonified_record_responses -> parsed JSON representation of a notion response object : ``Json``
|
139
|
+
jsonified_record_response.empty? || jsonified_record_response['block'].empty? ? nil : jsonified_record_response['block']
|
140
|
+
end
|
141
|
+
|
142
|
+
def extract_title(clean_id, jsonified_record_response)
|
143
|
+
# ! extract title from core JSON Notion response object.
|
144
|
+
# ! clean_id -> the cleaned block ID: ``str``
|
145
|
+
# ! jsonified_record_response -> parsed JSON representation of a notion response object : ``Json``
|
146
|
+
filter_nil_blocks = filter_nil_blocks(jsonified_record_response)
|
147
|
+
if filter_nil_blocks.nil? || filter_nil_blocks[clean_id].nil? || filter_nil_blocks[clean_id]['value']['properties'].nil?
|
148
|
+
nil
|
149
|
+
else
|
150
|
+
# titles for images are called source, while titles for text-based blocks are called title, so lets dynamically grab it
|
151
|
+
# https://stackoverflow.com/questions/23765996/get-all-keys-from-ruby-hash/23766007
|
152
|
+
title_value = filter_nil_blocks[clean_id]['value']['properties'].keys[0]
|
153
|
+
Core.type_whitelist.include?(filter_nil_blocks[clean_id]['value']['type']) ? nil : jsonified_record_response['block'][clean_id]['value']['properties'][title_value].flatten[0]
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def extract_collection_title(_clean_id, collection_id, jsonified_record_response)
|
159
|
+
# ! extract title from core JSON Notion response object.
|
160
|
+
# ! clean_id -> the cleaned block ID: ``str``
|
161
|
+
# ! collection_id -> the collection ID: ``str``
|
162
|
+
# ! jsonified_record_response -> parsed JSON representation of a notion response object : ``Json``
|
163
|
+
jsonified_record_response['collection'][collection_id]['value']['name'].flatten.join if jsonified_record_response['collection']
|
164
|
+
end
|
165
|
+
|
166
|
+
def extract_type(clean_id, jsonified_record_response)
|
167
|
+
# ! extract type from core JSON response object.
|
168
|
+
# ! clean_id -> the block ID or URL cleaned : ``str``
|
169
|
+
# ! jsonified_record_response -> parsed JSON representation of a notion response object : ``Json``
|
170
|
+
filter_nil_blocks = filter_nil_blocks(jsonified_record_response)
|
171
|
+
if filter_nil_blocks.nil?
|
172
|
+
nil
|
173
|
+
else
|
174
|
+
filter_nil_blocks[clean_id]['value']['type']
|
175
|
+
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def extract_parent_id(clean_id, jsonified_record_response)
|
180
|
+
# ! extract parent ID from core JSON response object.
|
181
|
+
# ! clean_id -> the block ID or URL cleaned : ``str``
|
182
|
+
# ! jsonified_record_response -> parsed JSON representation of a notion response object : ``Json``
|
183
|
+
jsonified_record_response.empty? || jsonified_record_response['block'].empty? ? {} : jsonified_record_response['block'][clean_id]['value']['parent_id']
|
184
|
+
end
|
185
|
+
|
186
|
+
def extract_collection_id(clean_id, jsonified_record_response)
|
187
|
+
# ! extract the collection ID
|
188
|
+
# ! clean_id -> the block ID or URL cleaned : ``str``
|
189
|
+
# ! jsonified_record_response -> parsed JSON representation of a notion response object : ``Json``
|
190
|
+
jsonified_record_response['block'][clean_id]['value']['collection_id']
|
191
|
+
end
|
192
|
+
|
193
|
+
def extract_view_ids(clean_id, jsonified_record_response)
|
194
|
+
jsonified_record_response['block'][clean_id]['value']['view_ids'] || []
|
195
|
+
end
|
196
|
+
|
197
|
+
def extract_id(url_or_id)
|
198
|
+
# ! parse and clean the URL or ID object provided.
|
199
|
+
# ! url_or_id -> the block ID or URL : ``str``
|
200
|
+
http_or_https = url_or_id.match(/^(http|https)/) # true if http or https in url_or_id...
|
201
|
+
if (url_or_id.length == 36) && ((url_or_id.split('-').length == 5) && !http_or_https)
|
202
|
+
# passes if url_or_id is perfectly formatted already...
|
203
|
+
url_or_id
|
204
|
+
elsif (http_or_https && (url_or_id.split('-').last.length == 32)) || (!http_or_https && (url_or_id.length == 32))
|
205
|
+
# passes if either:
|
206
|
+
# 1. a URL is passed as url_or_id and the ID at the end is 32 characters long or
|
207
|
+
# 2. a URL is not passed and the ID length is 32 [aka unformatted]
|
208
|
+
pattern = [8, 13, 18, 23]
|
209
|
+
id = url_or_id.split('-').last
|
210
|
+
pattern.each { |index| id.insert(index, '-') }
|
211
|
+
id
|
212
|
+
else
|
213
|
+
raise ArgumentError, 'Expected a Notion page URL or a page ID. Please consult the documentation for further information.'
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
@@ -0,0 +1,518 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Utils
|
4
|
+
# ! defines utility functions and static variables for this application.
|
5
|
+
URLS = {
|
6
|
+
GET_BLOCK: 'https://www.notion.so/api/v3/loadPageChunk',
|
7
|
+
UPDATE_BLOCK: 'https://www.notion.so/api/v3/saveTransactions',
|
8
|
+
GET_COLLECTION: 'https://www.notion.so/api/v3/queryCollection'
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
class BlockComponents
|
12
|
+
# ! Each function defined here builds one component that is included in each request sent to Notions backend.
|
13
|
+
# ! Each request sent will contain multiple components.
|
14
|
+
def self.create(block_id, block_type)
|
15
|
+
# ! payload for creating a block.
|
16
|
+
# ! block_id -> id of the new block : ``str``
|
17
|
+
# ! block_type -> type of block to create : ``cls``
|
18
|
+
table = 'block'
|
19
|
+
path = []
|
20
|
+
command = 'update'
|
21
|
+
timestamp = DateTime.now.strftime('%Q')
|
22
|
+
{
|
23
|
+
id: block_id,
|
24
|
+
table: table,
|
25
|
+
path: path,
|
26
|
+
command: command,
|
27
|
+
args: {
|
28
|
+
id: block_id,
|
29
|
+
type: block_type,
|
30
|
+
properties: {},
|
31
|
+
created_time: timestamp,
|
32
|
+
last_edited_time: timestamp
|
33
|
+
}
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.title(id, title)
|
38
|
+
# ! payload for updating the title of a block
|
39
|
+
# ! id -> the ID to update the title of : ``str``
|
40
|
+
table = 'block'
|
41
|
+
path = %w[properties title]
|
42
|
+
command = 'set'
|
43
|
+
|
44
|
+
{
|
45
|
+
id: id,
|
46
|
+
table: table,
|
47
|
+
path: path,
|
48
|
+
command: command,
|
49
|
+
args: [[title]]
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.last_edited_time(id)
|
54
|
+
# ! payload for updating the last edited time
|
55
|
+
# ! id -> either the block ID or parent ID : ``str``
|
56
|
+
timestamp = DateTime.now.strftime('%Q')
|
57
|
+
table = 'block'
|
58
|
+
path = ['last_edited_time']
|
59
|
+
command = 'set'
|
60
|
+
|
61
|
+
{
|
62
|
+
table: table,
|
63
|
+
id: id,
|
64
|
+
path: path,
|
65
|
+
command: command,
|
66
|
+
args: timestamp
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.convert_type(id, block_class_to_convert_to)
|
71
|
+
# ! payload for converting a block to a different type.
|
72
|
+
# ! id -> id of the block to convert : ``str``
|
73
|
+
# ! block_class_to_convert_to -> type to convert to block to: ``NotionAPI::<Block_Type>``
|
74
|
+
table = 'block'
|
75
|
+
path = []
|
76
|
+
command = 'update'
|
77
|
+
|
78
|
+
{
|
79
|
+
id: id,
|
80
|
+
table: table,
|
81
|
+
path: path,
|
82
|
+
command: command,
|
83
|
+
args: {
|
84
|
+
type: block_class_to_convert_to.notion_type
|
85
|
+
}
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.set_parent_to_alive(block_parent_id, new_block_id)
|
90
|
+
# ! payload for setting a blocks parent ID to 'alive'
|
91
|
+
# ! block_parent_id -> the blocks parent ID : ``str``
|
92
|
+
# ! new_block_id -> the new block ID, who is a child of the parent : ``str``
|
93
|
+
table = 'block'
|
94
|
+
path = []
|
95
|
+
command = 'update'
|
96
|
+
parent_table = 'block'
|
97
|
+
alive = true
|
98
|
+
{
|
99
|
+
id: new_block_id,
|
100
|
+
table: table,
|
101
|
+
path: path,
|
102
|
+
command: command,
|
103
|
+
args: {
|
104
|
+
parent_id: block_parent_id,
|
105
|
+
parent_table: parent_table,
|
106
|
+
alive: alive
|
107
|
+
}
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.set_block_to_dead(block_id)
|
112
|
+
# ! payload for setting a block to dead (alive == true)
|
113
|
+
# ! block_id -> the block ID to 'kill' : ``str``
|
114
|
+
table = 'block'
|
115
|
+
path = []
|
116
|
+
command = 'update'
|
117
|
+
alive = false
|
118
|
+
|
119
|
+
{
|
120
|
+
id: block_id,
|
121
|
+
table: table,
|
122
|
+
path: path,
|
123
|
+
command: command,
|
124
|
+
args: {
|
125
|
+
alive: alive
|
126
|
+
}
|
127
|
+
}
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.duplicate(block_type, block_title, block_id, new_block_id, user_notion_id, contents)
|
131
|
+
# ! payload for duplicating a block. Most properties should be
|
132
|
+
# ! inherited from the block class the method is invoked on.
|
133
|
+
# ! block_type -> type of block that is being duplicated : ``cls``
|
134
|
+
# ! block_title -> title of block : ``str``
|
135
|
+
# ! block_id -> id of block: ``str``
|
136
|
+
# ! new_block_id -> id of new block : ``str``
|
137
|
+
# ! user_notion_id -> ID of notion user : ``str``
|
138
|
+
# ! contents -> The children of the block
|
139
|
+
timestamp = DateTime.now.strftime('%Q')
|
140
|
+
table = 'block'
|
141
|
+
path = []
|
142
|
+
command = 'update'
|
143
|
+
|
144
|
+
{
|
145
|
+
id: new_block_id,
|
146
|
+
table: table,
|
147
|
+
path: path,
|
148
|
+
command: command,
|
149
|
+
args: {
|
150
|
+
id: new_block_id,
|
151
|
+
version: 10,
|
152
|
+
type: block_type,
|
153
|
+
properties: {
|
154
|
+
title: [[block_title]]
|
155
|
+
},
|
156
|
+
content: contents, # root-level blocks
|
157
|
+
created_time: timestamp,
|
158
|
+
last_edited_time: timestamp,
|
159
|
+
created_by_table: 'notion_user',
|
160
|
+
created_by_id: user_notion_id,
|
161
|
+
last_edited_by_table: 'notion_user',
|
162
|
+
last_edited_by_id: user_notion_id,
|
163
|
+
copied_from: block_id
|
164
|
+
}
|
165
|
+
}
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.parent_location_add(block_parent_id, block_id)
|
169
|
+
# ! payload for adding a parent
|
170
|
+
# ! block_parent_id -> the parent id of the block : ``str``
|
171
|
+
# ! block_id -> the id of the block : ``str``
|
172
|
+
table = 'block'
|
173
|
+
path = []
|
174
|
+
command = 'update'
|
175
|
+
parent_table = 'block'
|
176
|
+
alive = true
|
177
|
+
|
178
|
+
{
|
179
|
+
id: block_id,
|
180
|
+
table: table,
|
181
|
+
path: path,
|
182
|
+
command: command,
|
183
|
+
args: {
|
184
|
+
parent_id: block_parent_id,
|
185
|
+
parent_table: parent_table,
|
186
|
+
alive: alive
|
187
|
+
}
|
188
|
+
}
|
189
|
+
end
|
190
|
+
|
191
|
+
def self.block_location_add(block_parent_id, block_id, new_block_id = nil, target, command)
|
192
|
+
# ! payload for duplicating a block. Most properties should be
|
193
|
+
# ! inherited from the block class the method is invoked on.
|
194
|
+
# ! block_parent_id -> id of parent block : ``str``
|
195
|
+
# ! block_id -> id of block: ``str``
|
196
|
+
# ! new_block_id -> id of the new block: ``str``
|
197
|
+
# ! target -> the ID of the target block : ``str``
|
198
|
+
# ! command -> the position of the block, before or after, in relation to the target : ``str``
|
199
|
+
table = 'block'
|
200
|
+
path = ['content']
|
201
|
+
|
202
|
+
args = if command == 'listAfter'
|
203
|
+
{
|
204
|
+
after: target || block_id,
|
205
|
+
id: new_block_id || block_id
|
206
|
+
}
|
207
|
+
else
|
208
|
+
{
|
209
|
+
before: target || block_id,
|
210
|
+
id: new_block_id || block_id
|
211
|
+
}
|
212
|
+
end
|
213
|
+
|
214
|
+
{
|
215
|
+
table: table,
|
216
|
+
id: block_parent_id, # ID of the parent for the new block. It should be the block that the method is invoked on.
|
217
|
+
path: path,
|
218
|
+
command: command,
|
219
|
+
args: args
|
220
|
+
}
|
221
|
+
end
|
222
|
+
|
223
|
+
def self.block_location_remove(block_parent_id, block_id)
|
224
|
+
# ! removes a notion block
|
225
|
+
# ! block_parent_id -> the parent ID of the block to remove : ``str``
|
226
|
+
# ! block_id -> the ID of the block to remove : ``str``
|
227
|
+
table = 'block'
|
228
|
+
path = ['content']
|
229
|
+
command = 'listRemove'
|
230
|
+
{
|
231
|
+
table: table,
|
232
|
+
id: block_parent_id, # ID of the parent for the new block. It should be the block that the method is invoked on.
|
233
|
+
path: path,
|
234
|
+
command: command,
|
235
|
+
args: {
|
236
|
+
id: block_id
|
237
|
+
}
|
238
|
+
}
|
239
|
+
end
|
240
|
+
|
241
|
+
def self.checked_todo(block_id, standardized_check_val)
|
242
|
+
# ! payload for setting a "checked" value for TodoBlock.
|
243
|
+
# ! block_id -> the ID of the block to remove : ``str``
|
244
|
+
# ! standardized_check_val -> tyes/no value, determines the checked property of the block : ``str``
|
245
|
+
table = 'block'
|
246
|
+
path = ['properties']
|
247
|
+
command = 'update'
|
248
|
+
{
|
249
|
+
id: block_id,
|
250
|
+
table: table,
|
251
|
+
path: path,
|
252
|
+
command: command,
|
253
|
+
args: {
|
254
|
+
checked: [[standardized_check_val]]
|
255
|
+
}
|
256
|
+
}
|
257
|
+
end
|
258
|
+
|
259
|
+
def self.update_codeblock_language(block_id, coding_language)
|
260
|
+
# ! update the language for a codeblock
|
261
|
+
# ! block_id -> id of the code block
|
262
|
+
# ! coding_language -> language to change the block to.
|
263
|
+
table = 'block'
|
264
|
+
path = ['properties']
|
265
|
+
command = 'update'
|
266
|
+
|
267
|
+
{
|
268
|
+
id: block_id,
|
269
|
+
table: table,
|
270
|
+
path: path,
|
271
|
+
command: command,
|
272
|
+
args: {
|
273
|
+
language: [[coding_language]]
|
274
|
+
}
|
275
|
+
}
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
class CollectionViewComponents
|
280
|
+
def self.create_collection_view(new_block_id, collection_id, view_ids)
|
281
|
+
# ! payload for creating a collection view
|
282
|
+
# ! new_block_id -> id of the new block
|
283
|
+
# ! collection_id -> ID of the collection.
|
284
|
+
# ! view_ids -> id of the view
|
285
|
+
table = 'block'
|
286
|
+
command = 'update'
|
287
|
+
path = []
|
288
|
+
type = 'collection_view'
|
289
|
+
properties = {}
|
290
|
+
timestamp = DateTime.now.strftime('%Q')
|
291
|
+
|
292
|
+
{
|
293
|
+
id: new_block_id,
|
294
|
+
table: table,
|
295
|
+
path: path,
|
296
|
+
command: command,
|
297
|
+
args: {
|
298
|
+
id: new_block_id,
|
299
|
+
type: type,
|
300
|
+
collection_id: collection_id,
|
301
|
+
view_ids: [
|
302
|
+
view_ids
|
303
|
+
],
|
304
|
+
properties: properties,
|
305
|
+
created_time: timestamp,
|
306
|
+
last_edited_time: timestamp
|
307
|
+
}
|
308
|
+
}
|
309
|
+
end
|
310
|
+
|
311
|
+
def self.set_collection_blocks_alive(new_block_id, collection_id)
|
312
|
+
# ! payload for setting the collection blocks to alive.
|
313
|
+
# ! new_block_id -> id of the new block
|
314
|
+
# ! collection_id -> ID of the collection.
|
315
|
+
table = 'block'
|
316
|
+
path = []
|
317
|
+
command = 'update'
|
318
|
+
parent_table = 'collection'
|
319
|
+
alive = true
|
320
|
+
type = 'page'
|
321
|
+
properties = {}
|
322
|
+
timestamp = DateTime.now.strftime('%Q')
|
323
|
+
|
324
|
+
{
|
325
|
+
id: new_block_id,
|
326
|
+
table: table,
|
327
|
+
path: path,
|
328
|
+
command: command,
|
329
|
+
args: {
|
330
|
+
id: new_block_id,
|
331
|
+
type: type,
|
332
|
+
parent_id: collection_id,
|
333
|
+
parent_table: parent_table,
|
334
|
+
alive: alive,
|
335
|
+
properties: properties,
|
336
|
+
created_time: timestamp,
|
337
|
+
last_edited_time: timestamp
|
338
|
+
}
|
339
|
+
}
|
340
|
+
end
|
341
|
+
|
342
|
+
def self.set_view_config(new_block_id, view_id, children_ids)
|
343
|
+
# ! payload for setting the configurations of the view.
|
344
|
+
# ! new_block_id -> id of the new block
|
345
|
+
# ! view_id -> id of the view
|
346
|
+
# ! children_ids -> IDs for the children of the collection.
|
347
|
+
table = 'collection_view'
|
348
|
+
path = []
|
349
|
+
command = 'update'
|
350
|
+
version = 0
|
351
|
+
type = 'table'
|
352
|
+
name = 'Default View'
|
353
|
+
parent_table = 'block'
|
354
|
+
alive = true
|
355
|
+
|
356
|
+
{
|
357
|
+
id: view_id,
|
358
|
+
table: table,
|
359
|
+
path: path,
|
360
|
+
command: command,
|
361
|
+
args: {
|
362
|
+
id: view_id,
|
363
|
+
version: version,
|
364
|
+
type: type,
|
365
|
+
name: name,
|
366
|
+
page_sort: children_ids,
|
367
|
+
parent_id: new_block_id,
|
368
|
+
parent_table: parent_table,
|
369
|
+
alive: alive
|
370
|
+
}
|
371
|
+
}
|
372
|
+
end
|
373
|
+
|
374
|
+
def self.set_collection_columns(collection_id, new_block_id, data)
|
375
|
+
# ! payload for setting the columns of the table.
|
376
|
+
# ! collection_id -> ID of the collection.
|
377
|
+
# ! new_block_id -> id of the new block
|
378
|
+
# ! data -> json data to insert into table.
|
379
|
+
col_names = data[0].keys
|
380
|
+
|
381
|
+
schema_conf = {}
|
382
|
+
col_names.each_with_index do |_name, i|
|
383
|
+
if i.zero?
|
384
|
+
schema_conf[:title] = { name: col_names[i], type: 'title' }
|
385
|
+
else
|
386
|
+
schema_conf[col_names[i]] = { name: col_names[i], type: 'text' }
|
387
|
+
end
|
388
|
+
end
|
389
|
+
{
|
390
|
+
id: collection_id,
|
391
|
+
table: 'collection',
|
392
|
+
path: [],
|
393
|
+
command: 'update',
|
394
|
+
args: {
|
395
|
+
id: collection_id,
|
396
|
+
schema: schema_conf,
|
397
|
+
parent_id: new_block_id,
|
398
|
+
parent_table: 'block',
|
399
|
+
alive: true
|
400
|
+
}
|
401
|
+
}
|
402
|
+
end
|
403
|
+
|
404
|
+
def self.set_collection_title(collection_title, collection_id)
|
405
|
+
# ! payload for setting the title of the collection.
|
406
|
+
# ! collection_title -> title of the collection.
|
407
|
+
# ! collection_id -> ID of the collection.
|
408
|
+
table = 'collection'
|
409
|
+
path = ['name']
|
410
|
+
command = 'set'
|
411
|
+
|
412
|
+
{
|
413
|
+
id: collection_id,
|
414
|
+
table: table,
|
415
|
+
path: path,
|
416
|
+
command: command,
|
417
|
+
args: [[collection_title]]
|
418
|
+
}
|
419
|
+
end
|
420
|
+
|
421
|
+
def self.insert_data(block_id, column, value)
|
422
|
+
# ! payload for inserting data into the table.
|
423
|
+
# ! block_id -> the ID of the block : ``str``
|
424
|
+
# ! column -> the name of the column to insert data into.
|
425
|
+
# ! value -> the value to insert into the column.
|
426
|
+
table = 'block'
|
427
|
+
path = [
|
428
|
+
'properties',
|
429
|
+
column
|
430
|
+
]
|
431
|
+
command = 'set'
|
432
|
+
|
433
|
+
{
|
434
|
+
id: block_id,
|
435
|
+
table: table,
|
436
|
+
path: path,
|
437
|
+
command: command,
|
438
|
+
args: [[value]]
|
439
|
+
}
|
440
|
+
end
|
441
|
+
|
442
|
+
def self.add_new_row(new_block_id)
|
443
|
+
# ! payload for adding a new row to the table.
|
444
|
+
# ! new_block_id -> the ID of the new row : ``str``
|
445
|
+
table = 'block'
|
446
|
+
path = []
|
447
|
+
command = 'set'
|
448
|
+
type = 'page'
|
449
|
+
|
450
|
+
{
|
451
|
+
id: new_block_id,
|
452
|
+
table: table,
|
453
|
+
path: path,
|
454
|
+
command: command,
|
455
|
+
args: {
|
456
|
+
type: type,
|
457
|
+
id: new_block_id,
|
458
|
+
version: 1
|
459
|
+
}
|
460
|
+
}
|
461
|
+
end
|
462
|
+
|
463
|
+
def self.query_collection(collection_id, view_id, search_query = '')
|
464
|
+
# ! payload for querying the table for data.
|
465
|
+
# ! collection_id -> the collection ID : ``str``
|
466
|
+
# ! view_id -> the view ID : ``str``
|
467
|
+
# ! search_query -> the query for searching the table : ``str``
|
468
|
+
query = {}
|
469
|
+
loader = {
|
470
|
+
type: 'table',
|
471
|
+
limit: 100,
|
472
|
+
searchQuery: search_query,
|
473
|
+
loadContentCover: true
|
474
|
+
}
|
475
|
+
|
476
|
+
{
|
477
|
+
collectionId: collection_id,
|
478
|
+
collectionViewId: view_id,
|
479
|
+
query: query,
|
480
|
+
loader: loader
|
481
|
+
}
|
482
|
+
end
|
483
|
+
|
484
|
+
def self.add_collection_property(collection_id, args)
|
485
|
+
# ! payload for adding a column to the table.
|
486
|
+
# ! collection_id -> the collection ID : ``str``
|
487
|
+
# ! args -> the definition of the column : ``str``
|
488
|
+
{
|
489
|
+
id: collection_id,
|
490
|
+
table: 'collection',
|
491
|
+
path: [],
|
492
|
+
command: 'update',
|
493
|
+
args: args
|
494
|
+
}
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
def build_payload(operations, request_ids)
|
499
|
+
# ! properly formats the payload for Notions backend.
|
500
|
+
# ! operations -> an array of hashes that define the operations to perform : ``Array[Hash]``
|
501
|
+
# ! request_ids -> the unique IDs for the request : ``str``
|
502
|
+
request_id = request_ids[:request_id]
|
503
|
+
transaction_id = request_ids[:transaction_id]
|
504
|
+
space_id = request_ids[:space_id]
|
505
|
+
payload = {
|
506
|
+
requestId: request_id,
|
507
|
+
transactions: [
|
508
|
+
{
|
509
|
+
id: transaction_id,
|
510
|
+
shardId: 955_090,
|
511
|
+
spaceId: space_id,
|
512
|
+
operations: operations
|
513
|
+
}
|
514
|
+
]
|
515
|
+
}
|
516
|
+
payload
|
517
|
+
end
|
518
|
+
end
|