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.
@@ -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