notion 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Notion
4
+ class Markdown
5
+ # ! convert user input formatted with markdown (**hi** is bold, *hi* is italic, etc.) -> notion-understood stylings.
6
+ end
7
+ 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