notion_rb 0.1.0

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