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.
- checksums.yaml +4 -4
- data/README.md +8 -4
- data/lib/notion_api/blocks.rb +1 -0
- data/lib/notion_api/client.rb +2 -2
- data/lib/notion_api/core.rb +169 -111
- data/lib/notion_api/notion_types/code_block.rb +13 -13
- data/lib/notion_api/notion_types/collection_view_blocks.rb +66 -39
- data/lib/notion_api/notion_types/column_list_block.rb +13 -13
- data/lib/notion_api/notion_types/divider_block.rb +13 -13
- data/lib/notion_api/notion_types/header_block.rb +13 -13
- data/lib/notion_api/notion_types/image_block.rb +59 -12
- data/lib/notion_api/notion_types/latex_block.rb +13 -13
- data/lib/notion_api/notion_types/link_block.rb +51 -0
- data/lib/notion_api/notion_types/numbered_block.rb +13 -13
- data/lib/notion_api/notion_types/page_block.rb +117 -124
- data/lib/notion_api/notion_types/quote_block.rb +13 -13
- data/lib/notion_api/notion_types/sub_header_block.rb +13 -13
- data/lib/notion_api/notion_types/sub_sub_header.rb +13 -13
- data/lib/notion_api/notion_types/table_of_contents_block.rb +3 -3
- data/lib/notion_api/notion_types/template.rb +325 -328
- data/lib/notion_api/notion_types/text_block.rb +13 -13
- data/lib/notion_api/notion_types/todo_block.rb +56 -56
- data/lib/notion_api/notion_types/toggle_block.rb +13 -13
- data/lib/notion_api/utils.rb +100 -63
- data/lib/notion_api/version.rb +1 -1
- metadata +11 -10
@@ -1,16 +1,16 @@
|
|
1
1
|
module NotionAPI
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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[
|
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
|
-
|
66
|
-
|
67
|
-
|
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(
|
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
|
-
|
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(
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
+
|