notion 1.0.7 → 1.1.4

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.
@@ -1,16 +1,16 @@
1
1
  module NotionAPI
2
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
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
15
14
  end
16
- end
15
+ end
16
+ end
@@ -35,7 +35,7 @@ module NotionAPI
35
35
  new_block_id = extract_id(SecureRandom.hex(16))
36
36
  collection_data = extract_collection_data(collection_id, view_id)
37
37
  last_row_id = collection_data["collection_view"][@view_id]["value"]["page_sort"][-1]
38
- schema = collection_data['collection'][collection_id]['value']['schema']
38
+ schema = collection_data["collection"][collection_id]["value"]["schema"]
39
39
  keys = schema.keys
40
40
  col_map = {}
41
41
  keys.map { |key| col_map[schema[key]["name"]] = key }
@@ -55,16 +55,19 @@ module NotionAPI
55
55
  instantiate_row,
56
56
  set_block_alive,
57
57
  new_block_edited_time,
58
- page_sort
58
+ page_sort,
59
59
  ]
60
60
 
61
61
  data.keys.each_with_index do |col_name, j|
62
62
  unless col_map.keys.include?(col_name.to_s); raise ArgumentError, "Column '#{col_name.to_s}' does not exist." end
63
63
  if %q[select multi_select].include?(schema[col_map[col_name.to_s]]["type"])
64
- options = schema[col_map[col_name.to_s]]["options"].map {|option| option["value"]}
65
- if !options.include?(data[col_name])
66
- create_new_option = Utils::CollectionViewComponents.add_new_option(col_map[col_name.to_s], data[col_name], @collection_id)
67
- operations.push(create_new_option)
64
+ options = schema[col_map[col_name.to_s]]["options"].nil? ? [] : schema[col_map[col_name.to_s]]["options"].map { |option| option["value"] }
65
+ multi_select_multi_options = data[col_name].split(",")
66
+ multi_select_multi_options.each do |option|
67
+ if !options.include?(option.strip)
68
+ create_new_option = Utils::CollectionViewComponents.add_new_option(col_map[col_name.to_s], option.strip, @collection_id)
69
+ operations.push(create_new_option)
70
+ end
68
71
  end
69
72
  end
70
73
  child_component = Utils::CollectionViewComponents.insert_data(new_block_id, col_map[col_name.to_s], data[col_name], schema[col_map[col_name.to_s]]["type"])
@@ -83,7 +86,18 @@ module NotionAPI
83
86
  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}.
84
87
  Please try again, and if issues persist open an issue in GitHub."; end
85
88
 
86
- NotionAPI::CollectionViewRow.new(new_block_id, @parent_id, @collection_id, @view_id)
89
+ collection_row = NotionAPI::CollectionViewRow.new(new_block_id, @parent_id, @collection_id, @view_id)
90
+
91
+ properties = {}
92
+ data.keys.each do |col|
93
+ properties[col_map[col.to_s]] = [[data[col]]]
94
+ end
95
+
96
+ collection_data["block"][collection_row.id] = { "role" => "editor", "value" => { "id" => collection_row.id, "version" => 12, "type" => "page", "properties" => properties, "created_time" => 1607253360000, "last_edited_time" => 1607253360000, "parent_id" => "dde513c6-2428-4a5d-a830-7a67fdbf6b48", "parent_table" => "collection", "alive" => true, "created_by_table" => "notion_user", "created_by_id" => "0c5f02f3-495d-4b73-b1c5-9f6fe03a8c26", "last_edited_by_table" => "notion_user", "last_edited_by_id" => "0c5f02f3-495d-4b73-b1c5-9f6fe03a8c26", "shard_id" => 955090, "space_id" => "f687f7de-7f4c-4a86-b109-941a8dae92d2" } }
97
+ row_data = collection_data["block"][collection_row.id]
98
+ create_singleton_methods_and_instance_variables(collection_row, row_data)
99
+
100
+ collection_row
87
101
  end
88
102
 
89
103
  def add_property(name, type)
@@ -144,20 +158,11 @@ module NotionAPI
144
158
  limit: 100,
145
159
  verticalColumns: false,
146
160
  }
147
- jsonified_record_response = get_all_block_info(clean_id, request_body)
148
-
149
- i = 0
150
- while jsonified_record_response.empty? || jsonified_record_response["block"].empty?
151
- return {} if i >= 10
152
-
153
- jsonified_record_response = get_all_block_info(clean_id, request_body)
154
- i += 1
155
- end
161
+ jsonified_record_response = get_all_block_info(request_body)
156
162
 
157
163
  collection_data = extract_collection_data(@collection_id, @view_id)
158
164
  schema = collection_data["collection"][collection_id]["value"]["schema"]
159
- column_mappings = schema.keys
160
- column_names = column_mappings.map { |mapping| schema[mapping]["name"] }
165
+ column_names = NotionAPI::CollectionView.extract_collection_view_column_names(schema)
161
166
 
162
167
  collection_row = CollectionViewRow.new(row_id, @parent_id, @collection_id, @view_id)
163
168
  collection_row.instance_variable_set(:@column_names, column_names)
@@ -180,29 +185,20 @@ module NotionAPI
180
185
  verticalColumns: false,
181
186
  }
182
187
 
183
- jsonified_record_response = get_all_block_info(clean_id, request_body)
184
- i = 0
185
- while jsonified_record_response.empty? || jsonified_record_response["block"].empty?
186
- return {} if i >= 10
187
-
188
- jsonified_record_response = get_all_block_info(clean_id, request_body)
189
- i += 1
190
- end
188
+ jsonified_record_response = get_all_block_info(request_body)
191
189
 
192
190
  jsonified_record_response["collection_view"][@view_id]["value"]["page_sort"]
193
191
  end
194
192
 
195
193
  def rows
196
194
  # ! returns all rows as instantiated class instances.
197
- row_id_array = row_ids
195
+ row_id_array = row_ids()
198
196
  parent_id = @parent_id
199
197
  collection_id = @collection_id
200
198
  view_id = @view_id
201
199
  collection_data = extract_collection_data(@collection_id, @view_id)
202
200
  schema = collection_data["collection"][collection_id]["value"]["schema"]
203
- column_mappings = schema.keys
204
- column_names = column_mappings.map { |mapping| schema[mapping]["name"] }
205
-
201
+ column_names = NotionAPI::CollectionView.extract_collection_view_column_names(schema)
206
202
  row_instances = row_id_array.map { |row_id| NotionAPI::CollectionViewRow.new(row_id, parent_id, collection_id, view_id) }
207
203
  clean_row_instances = row_instances.filter { |row| collection_data["block"][row.id] }
208
204
  clean_row_instances.each { |row| row.instance_variable_set(:@column_names, column_names) }
@@ -214,6 +210,7 @@ module NotionAPI
214
210
  end
215
211
  clean_row_instances
216
212
  end
213
+
217
214
  def create_singleton_methods_and_instance_variables(row, row_data)
218
215
  # ! creates singleton methods for each property in a CollectionView.
219
216
  # ! row -> the block ID of the 'row' to retrieve: ``str``
@@ -223,22 +220,24 @@ module NotionAPI
223
220
  column_mappings = schema.keys
224
221
  column_hash = {}
225
222
  column_names = column_mappings.map { |mapping| column_hash[mapping] = schema[mapping]["name"].downcase }
226
-
223
+
227
224
  column_hash.keys.each_with_index do |column, i|
228
225
  # loop over the column names...
229
226
  # set instance variables for each column, allowing the dev to 'read' the column value
230
- cleaned_column = column_hash[column].split(" ").join("_").downcase.to_sym
227
+ cleaned_column = clean_property_names(column_hash, column)
231
228
 
232
- # p row_data["value"]["properties"][column_mappings[i]], !(row_data["value"]["properties"][column] or row_data["value"]["properties"][column_mappings[i]])
233
229
  if row_data["value"]["properties"].nil? or row_data["value"]["properties"][column].nil?
234
230
  value = ""
235
231
  else
236
- value = row_data["value"]["properties"][column][0][0]
232
+ value = row_data["value"]["properties"][column][0][0]
233
+ if ["‣"].include?(value.to_s)
234
+ value = row_data["value"]["properties"][column][0][1].flatten[-1]
235
+ end
237
236
  end
238
237
 
239
238
  row.instance_variable_set("@#{cleaned_column}", value)
240
239
  CollectionViewRow.class_eval { attr_reader cleaned_column }
241
- # then, define singleton methods for each column that are used to update the table cell
240
+ # then, define singleton methods for each column that are used to update the table cell
242
241
  row.define_singleton_method("#{cleaned_column}=") do |new_value|
243
242
  # neat way to get the name of the currently invoked method...
244
243
  parsed_method = __method__.to_s[0...-1].split("_").join(" ")
@@ -255,12 +254,23 @@ module NotionAPI
255
254
  space_id: space_id,
256
255
  }
257
256
 
258
- update_property_value = Utils::CollectionViewComponents.update_property_value(@id, column_hash.key(parsed_method), new_value)
257
+ update_property_value_hash = Utils::CollectionViewComponents.update_property_value(@id, column_hash.key(parsed_method), new_value, schema[column_hash.key(parsed_method)]["type"])
259
258
 
260
259
  operations = [
261
- update_property_value,
260
+ update_property_value_hash,
262
261
  ]
263
262
 
263
+ if %q[select multi_select].include?(schema[column_hash.key(parsed_method)]["type"])
264
+ options = schema[column_hash.key(parsed_method)]["options"].nil? ? [] : schema[column_hash.key(parsed_method)]["options"].map { |option| option["value"] }
265
+ multi_select_multi_options = new_value.split(",")
266
+ multi_select_multi_options.each do |option|
267
+ if !options.include?(option.strip)
268
+ create_new_option = Utils::CollectionViewComponents.add_new_option(column_hash.key(parsed_method), option.strip, @collection_id)
269
+ operations.push(create_new_option)
270
+ end
271
+ end
272
+ end
273
+
264
274
  request_url = URLS[:UPDATE_BLOCK]
265
275
  request_body = build_payload(operations, request_ids)
266
276
  response = HTTParty.post(
@@ -270,14 +280,31 @@ module NotionAPI
270
280
  headers: headers,
271
281
  )
272
282
  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}.
273
- Please try again, and if issues persist open an issue in GitHub.";end
274
-
283
+ Please try again, and if issues persist open an issue in GitHub."; end
284
+
275
285
  # set the instance variable to the updated value!
276
286
  _ = row.instance_variable_set("@#{__method__.to_s[0...-1]}", new_value)
277
287
  row
278
288
  end
279
289
  end
280
290
  end
291
+
292
+ def clean_property_names(prop_hash, prop_notion_name)
293
+ # ! standardize property names by splitting the words in the property name into an array, removing non-alphanumeric
294
+ # ! characters, downcasing, and then re-joining the array with underscores.
295
+ # ! prop_hash -> hash of property notion names and property textual names: ``str``
296
+ # ! prop_notion_name -> the four-character long name of the notion property: ``str``
297
+
298
+ prop_hash[prop_notion_name].split(" ").map { |word| word.gsub(/[^a-z0-9]/i, "").downcase }.join("_").to_sym
299
+ end
300
+
301
+ def self.extract_collection_view_column_names(schema)
302
+ # ! extract the column names of a Collection View
303
+ # ! schema: the schema of the collection view
304
+ column_mappings = column_mappings = schema.keys
305
+ column_names = column_mappings.map { |mapping| schema[mapping]["name"] }
306
+ column_names
307
+ end
281
308
  end
282
309
 
283
310
  # class that represents each row in a CollectionView
@@ -1,16 +1,16 @@
1
1
  module NotionAPI
2
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
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
15
14
  end
16
- end
15
+ end
16
+ end
@@ -1,15 +1,15 @@
1
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
2
+ # divider block: ---------
3
+ class DividerBlock < BlockTemplate
4
+ @notion_type = "divider"
5
+ @type = "divider"
6
+
7
+ def type
8
+ NotionAPI::DividerBlock.notion_type
14
9
  end
15
- end
10
+
11
+ class << self
12
+ attr_reader :notion_type, :type
13
+ end
14
+ end
15
+ end
@@ -1,16 +1,16 @@
1
1
  module NotionAPI
2
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
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
15
14
  end
16
- end
15
+ end
16
+ end
@@ -1,16 +1,63 @@
1
1
  module NotionAPI
2
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
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
+
16
+ private
17
+
18
+ def self.create(block_id, new_block_id, block_title, target, position_command, request_ids, options)
19
+ if !(options[:image])
20
+ raise ArgumentError, "Must specify image as an option. For example: .create(\"block type\", \"block title\", options: {image: \"https://image-domain.com\"})"
21
+ else
22
+ cookies = Core.options["cookies"]
23
+ headers = Core.options["headers"]
24
+ if options[:image].match(/^http:\/\/|^https:\/\//)
25
+ create_hash = Utils::BlockComponents.create(new_block_id, self.notion_type)
26
+ set_parent_alive_hash = Utils::BlockComponents.set_parent_to_alive(block_id, new_block_id)
27
+ block_location_hash = Utils::BlockComponents.block_location_add(block_id, block_id, new_block_id, target, position_command)
28
+ last_edited_time_parent_hash = Utils::BlockComponents.last_edited_time(block_id)
29
+ last_edited_time_child_hash = Utils::BlockComponents.last_edited_time(block_id)
30
+ title_hash = Utils::BlockComponents.title(new_block_id, block_title)
31
+ source_url_hash = Utils::BlockComponents.source(new_block_id, options[:image])
32
+ display_source_url_hash = Utils::BlockComponents.display_source(new_block_id, options[:image])
33
+
34
+ operations = [
35
+ create_hash,
36
+ set_parent_alive_hash,
37
+ block_location_hash,
38
+ last_edited_time_parent_hash,
39
+ last_edited_time_child_hash,
40
+ title_hash,
41
+ source_url_hash,
42
+ display_source_url_hash,
43
+ ]
44
+
45
+ request_url = URLS[:UPDATE_BLOCK]
46
+ request_body = Utils::BlockComponents.build_payload(operations, request_ids)
47
+ response = HTTParty.post(
48
+ request_url,
49
+ body: request_body.to_json,
50
+ cookies: cookies,
51
+ headers: headers,
52
+ )
53
+ 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}.
54
+ Please try again, and if issues persist open an issue in GitHub."; end
55
+
56
+ self.new(new_block_id, block_title, block_id)
57
+ else
58
+ raise ArgumentError, "Currently, images can only be created through a public image URL."
59
+ end
14
60
  end
15
61
  end
16
- end
62
+ end
63
+ end
@@ -1,16 +1,16 @@
1
1
  module NotionAPI
2
2
 
3
- # simiilar to code block but for mathematical functions.
4
- class LatexBlock < BlockTemplate
5
- @notion_type = 'equation'
6
- @type = 'equation'
7
-
8
- def type
9
- NotionAPI::LatexBlock.notion_type
10
- end
11
-
12
- class << self
13
- attr_reader :notion_type, :type
14
- end
3
+ # simiilar to code block but for mathematical functions.
4
+ class LatexBlock < BlockTemplate
5
+ @notion_type = "equation"
6
+ @type = "equation"
7
+
8
+ def type
9
+ NotionAPI::LatexBlock.notion_type
10
+ end
11
+
12
+ class << self
13
+ attr_reader :notion_type, :type
15
14
  end
16
- end
15
+ end
16
+ end
@@ -0,0 +1,51 @@
1
+ module NotionAPI
2
+
3
+ # simiilar to code block but for mathematical functions.
4
+ class LinkBlock < BlockTemplate
5
+ @notion_type = "link_to_page"
6
+ @type = "link_to_page"
7
+
8
+ def type
9
+ NotionAPI::LinkBlock.notion_type
10
+ end
11
+
12
+ class << self
13
+ attr_reader :notion_type, :type
14
+ end
15
+
16
+ def self.create(block_id, new_block_id, block_title, target, position_command, request_ids, options)
17
+ block_title = super.extract_id(block_title)
18
+
19
+ cookies = Core.options["cookies"]
20
+ headers = Core.options["headers"]
21
+
22
+ create_block_hash = Utils::BlockComponents.create(new_block_id, self.notion_type)
23
+ block_location_hash = Utils::BlockComponents.block_location_add(block_id, block_id, block_title, new_block_id, position_command)
24
+ last_edited_time_hash = Utils::BlockComponents.last_edited_time(block_id)
25
+ remove_item_hash = Utils::BlockComponents.block_location_remove( super.parent_id, new_block_id)
26
+
27
+ operations = [
28
+ create_block_hash,
29
+ block_location_hash,
30
+ last_edited_time_hash,
31
+ remove_item_hash
32
+ ]
33
+
34
+ request_url = URLS[:UPDATE_BLOCK]
35
+ request_body = Utils::BlockComponents.build_payload(operations, request_ids)
36
+
37
+ response = HTTParty.post(
38
+ request_url,
39
+ body: request_body.to_json,
40
+ cookies: cookies,
41
+ headers: headers,
42
+ )
43
+
44
+ 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}.
45
+ Please try again, and if issues persist open an issue in GitHub."; end
46
+
47
+ self.new(new_block_id, block_title, block_id)
48
+ end
49
+ end
50
+ end
51
+