notion 1.0.7 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+