notion_rb 0.1.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/.gitignore +12 -0
- data/.rspec +3 -0
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +14 -0
- data/.ruby-version +1 -0
- data/.travis.yml +14 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +115 -0
- data/LICENSE.txt +21 -0
- data/README.md +92 -0
- data/Rakefile +8 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/notion_rb.rb +31 -0
- data/lib/notion_rb/api/base.rb +56 -0
- data/lib/notion_rb/api/create.rb +74 -0
- data/lib/notion_rb/api/destroy.rb +41 -0
- data/lib/notion_rb/api/get.rb +58 -0
- data/lib/notion_rb/api/query_collection.rb +30 -0
- data/lib/notion_rb/api/restore.rb +42 -0
- data/lib/notion_rb/api/update.rb +45 -0
- data/lib/notion_rb/block.rb +97 -0
- data/lib/notion_rb/utils/block_cache.rb +58 -0
- data/lib/notion_rb/utils/converter.rb +23 -0
- data/lib/notion_rb/utils/parser.rb +100 -0
- data/lib/notion_rb/utils/types.rb +44 -0
- data/lib/notion_rb/utils/uuid_validator.rb +32 -0
- data/lib/notion_rb/version.rb +5 -0
- data/notion_rb.gemspec +41 -0
- metadata +216 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NotionRb
|
4
|
+
module Api
|
5
|
+
class Base
|
6
|
+
BASE_URL = 'https://www.notion.so/'
|
7
|
+
API_BASE_URL = BASE_URL + 'api/v3/'
|
8
|
+
SIGNED_URL_PREFIX = 'https://www.notion.so/signed/'
|
9
|
+
S3_URL_PREFIX = 'https://s3-us-west-2.amazonaws.com/secure.notion-static.com/'
|
10
|
+
S3_URL_PREFIX_ENCODED = 'https://s3.us-west-2.amazonaws.com/secure.notion-static.com/'
|
11
|
+
REDEFINE_EXCEPTION = 'Define methods on subclass'
|
12
|
+
|
13
|
+
def initialize(params)
|
14
|
+
@notion_id = params[:notion_id]
|
15
|
+
@token_v2 = NotionRb.config[:token_v2]
|
16
|
+
@converter = NotionRb::Utils::Converter.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def call
|
20
|
+
response
|
21
|
+
end
|
22
|
+
|
23
|
+
def success?
|
24
|
+
response.code == '200'
|
25
|
+
rescue Mechanize::ResponseCodeError
|
26
|
+
false
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def agent
|
32
|
+
return @agent if @agent
|
33
|
+
|
34
|
+
@agent = Mechanize.new
|
35
|
+
cookie = Mechanize::Cookie.new(domain: 'www.notion.so',
|
36
|
+
name: 'token_v2',
|
37
|
+
value: @token_v2,
|
38
|
+
path: '/',
|
39
|
+
expires: (Date.today + 1).to_s)
|
40
|
+
@agent.tap { |agent| agent.cookie_jar << cookie }
|
41
|
+
end
|
42
|
+
|
43
|
+
def response
|
44
|
+
@response ||= agent.post("#{API_BASE_URL}#{url}", params.to_json, 'Content-Type' => 'application/json')
|
45
|
+
end
|
46
|
+
|
47
|
+
def url
|
48
|
+
raise REDEFINE_EXCEPTION
|
49
|
+
end
|
50
|
+
|
51
|
+
def params
|
52
|
+
raise REDEFINE_EXCEPTION
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NotionRb
|
4
|
+
module Api
|
5
|
+
class Create < Base
|
6
|
+
def initialize(params)
|
7
|
+
super
|
8
|
+
|
9
|
+
@parent_id = params[:parent_id]
|
10
|
+
@notion_id = SecureRandom.uuid
|
11
|
+
@created_at = (Time.now.to_i / 100) * 100_000
|
12
|
+
end
|
13
|
+
|
14
|
+
def block_uuid
|
15
|
+
success? && @notion_id
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def url
|
21
|
+
'submitTransaction'
|
22
|
+
end
|
23
|
+
|
24
|
+
def params
|
25
|
+
{
|
26
|
+
requestId: SecureRandom.uuid,
|
27
|
+
transactions: [{
|
28
|
+
id: SecureRandom.uuid,
|
29
|
+
operations: [{
|
30
|
+
id: @notion_id,
|
31
|
+
table: 'block',
|
32
|
+
path: [],
|
33
|
+
command: 'set',
|
34
|
+
args: { type: 'text', id: @notion_id, version: 1 }
|
35
|
+
}, {
|
36
|
+
id: @notion_id,
|
37
|
+
table: 'block',
|
38
|
+
path: [],
|
39
|
+
command: 'update',
|
40
|
+
args: { parent_id: @parent_id, parent_table: 'block', alive: true }
|
41
|
+
}, {
|
42
|
+
id: @parent_id,
|
43
|
+
table: 'block',
|
44
|
+
path: ['content'],
|
45
|
+
command: 'listAfter',
|
46
|
+
args: { id: @notion_id }
|
47
|
+
}, {
|
48
|
+
id: @notion_id,
|
49
|
+
table: 'block',
|
50
|
+
path: %w[
|
51
|
+
properties
|
52
|
+
title
|
53
|
+
],
|
54
|
+
command: 'set',
|
55
|
+
args: []
|
56
|
+
}, {
|
57
|
+
id: @notion_id,
|
58
|
+
table: 'block',
|
59
|
+
path: ['created_time'],
|
60
|
+
command: 'set',
|
61
|
+
args: @created_at
|
62
|
+
}, {
|
63
|
+
id: @notion_id,
|
64
|
+
table: 'block',
|
65
|
+
path: ['last_edited_time'],
|
66
|
+
command: 'set',
|
67
|
+
args: @created_at
|
68
|
+
}]
|
69
|
+
}]
|
70
|
+
}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NotionRb
|
4
|
+
module Api
|
5
|
+
class Destroy < Base
|
6
|
+
def initialize(params)
|
7
|
+
super
|
8
|
+
|
9
|
+
@parent_id = params[:parent_id]
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def url
|
15
|
+
'submitTransaction'
|
16
|
+
end
|
17
|
+
|
18
|
+
def params
|
19
|
+
{
|
20
|
+
requestId: SecureRandom.uuid,
|
21
|
+
transactions: [{
|
22
|
+
id: SecureRandom.uuid,
|
23
|
+
operations: [{
|
24
|
+
id: @notion_id,
|
25
|
+
table: 'block',
|
26
|
+
path: [],
|
27
|
+
command: 'update',
|
28
|
+
args: { alive: false }
|
29
|
+
}, {
|
30
|
+
id: @parent_id,
|
31
|
+
table: 'block',
|
32
|
+
path: ['content'],
|
33
|
+
command: 'listRemove',
|
34
|
+
args: { id: @notion_id }
|
35
|
+
}]
|
36
|
+
}]
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NotionRb
|
4
|
+
module Api
|
5
|
+
class Get < Base
|
6
|
+
def initialize(_params)
|
7
|
+
super
|
8
|
+
|
9
|
+
@blocks = []
|
10
|
+
@data = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def blocks
|
14
|
+
return @blocks if @blocks.any?
|
15
|
+
|
16
|
+
call
|
17
|
+
@blocks
|
18
|
+
end
|
19
|
+
|
20
|
+
def call
|
21
|
+
body = JSON.parse(response.body)
|
22
|
+
@collection_rows = body.dig('result', 'blockIds')
|
23
|
+
data = body.dig('recordMap', 'block').merge(body.dig('recordMap', 'collection') || {})
|
24
|
+
data.values.each do |value|
|
25
|
+
convert_values(value.dig('value'))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def url
|
32
|
+
'loadPageChunk'
|
33
|
+
end
|
34
|
+
|
35
|
+
def params
|
36
|
+
{
|
37
|
+
chunkNumber: 0,
|
38
|
+
cursor: { stack: [] },
|
39
|
+
limit: 50,
|
40
|
+
pageId: @notion_id,
|
41
|
+
verticalColumns: false
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def convert_values(value)
|
46
|
+
add_collection_data(value)
|
47
|
+
@blocks << @converter.convert(value)
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_collection_data(value)
|
51
|
+
return unless value.key? 'schema'
|
52
|
+
|
53
|
+
value['content'] = @collection_rows if @collection_rows
|
54
|
+
value['type'] = 'collection'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NotionRb
|
4
|
+
module Api
|
5
|
+
class QueryCollection < Get
|
6
|
+
def initialize(params)
|
7
|
+
super
|
8
|
+
|
9
|
+
@collection_id = params[:collection_id]
|
10
|
+
@view_id = params[:view_id]
|
11
|
+
@schema = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def url
|
17
|
+
'queryCollection'
|
18
|
+
end
|
19
|
+
|
20
|
+
def params
|
21
|
+
{
|
22
|
+
collectionId: @collection_id,
|
23
|
+
collectionViewId: @view_id,
|
24
|
+
query: { agregrate: [{}], filter: [], sort: [], filter_operation: 'and' },
|
25
|
+
loader: { type: 'table', limit: 70, userTimeZone: 'America/Santiago', userLocale: 'en', loadContentCover: true }
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NotionRb
|
4
|
+
module Api
|
5
|
+
class Restore < Base
|
6
|
+
def initialize(params)
|
7
|
+
super
|
8
|
+
|
9
|
+
@parent_id = params[:parent_id]
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def url
|
16
|
+
'submitTransaction'
|
17
|
+
end
|
18
|
+
|
19
|
+
def params
|
20
|
+
{
|
21
|
+
requestId: SecureRandom.uuid,
|
22
|
+
transactions: [{
|
23
|
+
id: SecureRandom.uuid,
|
24
|
+
operations: [{
|
25
|
+
id: @notion_id,
|
26
|
+
table: 'block',
|
27
|
+
path: [],
|
28
|
+
command: 'update',
|
29
|
+
args: { parent_id: @parent_id, parent_table: 'block', alive: true }
|
30
|
+
}, {
|
31
|
+
id: @parent_id,
|
32
|
+
table: 'block',
|
33
|
+
path: ['content'],
|
34
|
+
command: 'listAfter',
|
35
|
+
args: { id: @notion_id }
|
36
|
+
}]
|
37
|
+
}]
|
38
|
+
}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NotionRb
|
4
|
+
module Api
|
5
|
+
class Update < Base
|
6
|
+
def initialize(params)
|
7
|
+
super
|
8
|
+
|
9
|
+
@title = params[:title]
|
10
|
+
@block_type = params[:block_type]
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def url
|
16
|
+
'submitTransaction'
|
17
|
+
end
|
18
|
+
|
19
|
+
def params
|
20
|
+
{
|
21
|
+
requestId: SecureRandom.uuid,
|
22
|
+
transactions: [{
|
23
|
+
id: SecureRandom.uuid,
|
24
|
+
operations: [{
|
25
|
+
id: @notion_id,
|
26
|
+
table: 'block',
|
27
|
+
path: %w[properties title],
|
28
|
+
command: 'set',
|
29
|
+
args: [[@title]]
|
30
|
+
}]
|
31
|
+
}, {
|
32
|
+
id: SecureRandom.uuid,
|
33
|
+
operations: [{
|
34
|
+
id: @notion_id,
|
35
|
+
table: 'block',
|
36
|
+
path: [],
|
37
|
+
command: 'update',
|
38
|
+
args: { type: @block_type }
|
39
|
+
}]
|
40
|
+
}]
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NotionRb
|
4
|
+
class Block
|
5
|
+
include NotionRb::Utils::UuidValidator
|
6
|
+
include NotionRb::Utils::Types
|
7
|
+
|
8
|
+
attr_accessor :uuid
|
9
|
+
|
10
|
+
def initialize(url_or_uuid)
|
11
|
+
@block_container = NotionRb::Utils::BlockCache.instance
|
12
|
+
@uuid = parse_uuid url_or_uuid
|
13
|
+
get_resource
|
14
|
+
end
|
15
|
+
|
16
|
+
def title
|
17
|
+
@block[:title]
|
18
|
+
end
|
19
|
+
|
20
|
+
def title=(title)
|
21
|
+
@block[:title] = title
|
22
|
+
save
|
23
|
+
end
|
24
|
+
|
25
|
+
def type
|
26
|
+
@block[:block_type]
|
27
|
+
end
|
28
|
+
|
29
|
+
def type=(type)
|
30
|
+
return unless valid_block_type?(type)
|
31
|
+
|
32
|
+
@block[:block_type] = type
|
33
|
+
save
|
34
|
+
end
|
35
|
+
|
36
|
+
def metadata
|
37
|
+
metadata = @block[:metadata].except(:properties)
|
38
|
+
add_parent_metadata(metadata)
|
39
|
+
end
|
40
|
+
|
41
|
+
def parent
|
42
|
+
@parent ||= self.class.new(@block[:parent_id])
|
43
|
+
end
|
44
|
+
|
45
|
+
def children
|
46
|
+
if type == 'collection_view_page'
|
47
|
+
@children ||= [self.class.new(metadata[:collection_id])]
|
48
|
+
else
|
49
|
+
@children ||= @block_container.children(@uuid).map { |child_uuid| self.class.new(child_uuid) }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def create_child
|
54
|
+
creator = NotionRb::Api::Create.new(parent_id: @uuid)
|
55
|
+
return nil unless creator.success?
|
56
|
+
|
57
|
+
@block[:children] << creator.block_uuid
|
58
|
+
self.class.new(creator.block_uuid)
|
59
|
+
end
|
60
|
+
|
61
|
+
def save
|
62
|
+
# TODO: add validations if needed
|
63
|
+
post_resource
|
64
|
+
end
|
65
|
+
|
66
|
+
def destroy
|
67
|
+
NotionRb::Api::Destroy.new(notion_id: @uuid, parent_id: @block[:parent_id]).success?
|
68
|
+
end
|
69
|
+
|
70
|
+
def restore
|
71
|
+
NotionRb::Api::Restore.new(notion_id: @uuid, parent_id: @block[:parent_id]).success?
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def get_resource
|
77
|
+
@block = @block_container.find(@uuid)
|
78
|
+
@block_container.add_collection_view_blocks(@block)
|
79
|
+
end
|
80
|
+
|
81
|
+
def post_resource
|
82
|
+
# TODO: detect changes if any before post
|
83
|
+
NotionRb::Api::Update.new(notion_id: @uuid, title: @block[:title], block_type: @block[:block_type]).success?
|
84
|
+
end
|
85
|
+
|
86
|
+
def add_parent_metadata(metadata)
|
87
|
+
return metadata unless parent.type == 'collection'
|
88
|
+
|
89
|
+
parent_schema = parent.metadata[:schema]
|
90
|
+
@block.dig(:metadata, :properties).each do |key, value|
|
91
|
+
schema = parent_schema[key]
|
92
|
+
metadata.merge!(schema['name'] => value[0][0])
|
93
|
+
end
|
94
|
+
metadata
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|