notion-ruby-client 0.0.8 → 0.1.0.pre.beta1

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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +1 -0
  3. data/.gitignore +7 -0
  4. data/.rubocop.yml +9 -0
  5. data/CHANGELOG.md +19 -0
  6. data/Gemfile.lock +29 -7
  7. data/README.md +245 -55
  8. data/bin/console +31 -0
  9. data/lib/notion/api/endpoints/blocks.rb +35 -7
  10. data/lib/notion/api/endpoints/databases.rb +65 -37
  11. data/lib/notion/api/endpoints/pages.rb +6 -6
  12. data/lib/notion/api/endpoints/search.rb +41 -0
  13. data/lib/notion/api/endpoints/users.rb +6 -3
  14. data/lib/notion/api/endpoints.rb +3 -1
  15. data/lib/notion/api/errors/too_many_requests.rb +15 -0
  16. data/lib/notion/api/errors.rb +0 -2
  17. data/lib/notion/config.rb +2 -0
  18. data/lib/notion/pagination/cursor.rb +5 -2
  19. data/lib/notion/version.rb +2 -2
  20. data/lib/notion-ruby-client.rb +2 -0
  21. data/notion-ruby-client.gemspec +3 -1
  22. data/spec/fixtures/notion/block.yml +146 -0
  23. data/spec/fixtures/notion/block_append_children.yml +76 -62
  24. data/spec/fixtures/notion/block_children.yml +80 -65
  25. data/spec/fixtures/notion/create_database.yml +67 -58
  26. data/spec/fixtures/notion/create_page.yml +68 -59
  27. data/spec/fixtures/notion/database.yml +78 -61
  28. data/spec/fixtures/notion/database_query.yml +81 -62
  29. data/spec/fixtures/notion/databases_list.yml +77 -60
  30. data/spec/fixtures/notion/page.yml +70 -57
  31. data/spec/fixtures/notion/paginated_block_children.yml +296 -242
  32. data/spec/fixtures/notion/paginated_database_query.yml +79 -62
  33. data/spec/fixtures/notion/paginated_databases_list.yml +78 -61
  34. data/spec/fixtures/notion/paginated_search.yml +301 -0
  35. data/spec/fixtures/notion/paginated_users_list.yml +143 -130
  36. data/spec/fixtures/notion/search.yml +160 -0
  37. data/spec/fixtures/notion/search_with_query.yml +152 -0
  38. data/spec/fixtures/notion/update_block.yml +148 -0
  39. data/spec/fixtures/notion/update_database.yml +152 -0
  40. data/spec/fixtures/notion/update_page.yml +71 -59
  41. data/spec/fixtures/notion/users.yml +69 -56
  42. data/spec/fixtures/notion/users_list.yml +143 -130
  43. data/spec/notion/api/endpoints/blocks_spec.rb +37 -11
  44. data/spec/notion/api/endpoints/databases_spec.rb +25 -17
  45. data/spec/notion/api/endpoints/pages_spec.rb +7 -16
  46. data/spec/notion/api/endpoints/search_spec.rb +26 -0
  47. data/spec/notion/api/endpoints/users_spec.rb +4 -4
  48. data/spec/notion/pagination/cursor_spec.rb +126 -0
  49. metadata +52 -8
  50. data/.rspec_status +0 -19
  51. data/notion-ruby-client-0.0.4.gem +0 -0
  52. data/scratchpad.rb +0 -22
  53. data/screenshots/create_notion_bot.png +0 -0
data/bin/console ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "dotenv/load"
6
+ require "notion-ruby-client"
7
+
8
+ # You can add fixtures and/or initialization code here to make experimenting
9
+ # with your gem easier. You can also use a different console, if you like.
10
+
11
+ # (If you use this, don't forget to add pry to your Gemfile!)
12
+ # require "pry"
13
+ # Pry.start
14
+
15
+ require "irb"
16
+
17
+ def reload!(print = true)
18
+ puts 'Reloading ...' if print
19
+ # Main project directory.
20
+ root_dir = File.expand_path('..', __dir__)
21
+ # Directories within the project that should be reloaded.
22
+ reload_dirs = %w{lib}
23
+ # Loop through and reload every file in all relevant project directories.
24
+ reload_dirs.each do |dir|
25
+ Dir.glob("#{root_dir}/#{dir}/**/*.rb").each { |f| load(f) }
26
+ end
27
+ # Return true when complete.
28
+ true
29
+ end
30
+
31
+ IRB.start(__FILE__)
@@ -4,6 +4,34 @@ module Notion
4
4
  module Api
5
5
  module Endpoints
6
6
  module Blocks
7
+ #
8
+ # Retrieves a Block object using the ID specified.
9
+ #
10
+ # @option options [id] :block_id
11
+ # Block to get children info on.
12
+ def block(options = {})
13
+ throw ArgumentError.new('Required arguments :block_id missing') if options[:block_id].nil?
14
+ get("blocks/#{options[:block_id]}")
15
+ end
16
+
17
+ #
18
+ # Updates the content for the specified block_id based on
19
+ # the block type. Supported fields based on the block object
20
+ # type (see Block object for available fields and the
21
+ # expected input for each field).
22
+ #
23
+ # @option options [id] :block_id
24
+ # Block to get children info on.
25
+ #
26
+ # @option options [string] {type}
27
+ # The block object type value with the properties to be
28
+ # updated. Currently only text (for supported block types)
29
+ # and checked (for to_do blocks) fields can be updated.
30
+ def update_block(options = {})
31
+ throw ArgumentError.new('Required arguments :block_id missing') if options[:block_id].nil?
32
+ patch("blocks/#{options[:block_id]}", options.except(:block_id))
33
+ end
34
+
7
35
  #
8
36
  # Returns a paginated array of Block objects contained in the
9
37
  # block of the requested path using the ID specified.
@@ -14,16 +42,16 @@ module Notion
14
42
  #
15
43
  # Returns a 400 or 429 HTTP response if the request exceeds Notion's Request limits.
16
44
  #
17
- # @option options [id] :id
45
+ # @option options [id] :block_id
18
46
  # Block to get children info on.
19
47
  def block_children(options = {})
20
- throw ArgumentError.new('Required arguments :id missing') if options[:id].nil?
48
+ throw ArgumentError.new('Required arguments :block_id missing') if options[:block_id].nil?
21
49
  if block_given?
22
50
  Pagination::Cursor.new(self, :block_children, options).each do |page|
23
51
  yield page
24
52
  end
25
53
  else
26
- get("blocks/#{options[:id]}/children", options)
54
+ get("blocks/#{options[:block_id]}/children", options.except(:block_id))
27
55
  end
28
56
  end
29
57
 
@@ -38,14 +66,14 @@ module Notion
38
66
  #
39
67
  # Returns a 400 or 429 HTTP response if the request exceeds Notion's Request limits.
40
68
  #
41
- # @option options [id] :id
42
- # Block to get children info on.
69
+ # @option options [id] :block_id
70
+ # Block to append children to.
43
71
  #
44
72
  # @option options [[Object]] :children
45
73
  # Children blocks to append
46
74
  def block_append_children(options = {})
47
- throw ArgumentError.new('Required arguments :id missing') if options[:id].nil?
48
- patch("blocks/#{options[:id]}/children", options)
75
+ throw ArgumentError.new('Required arguments :block_id missing') if options[:block_id].nil?
76
+ patch("blocks/#{options[:block_id]}/children", options.except(:block_id))
49
77
  end
50
78
  end
51
79
  end
@@ -5,17 +5,43 @@ module Notion
5
5
  module Endpoints
6
6
  module Databases
7
7
  #
8
- # Retrieves a Database object using the ID specified in the request.
8
+ # Gets a paginated array of Page object s contained in the requested database,
9
+ # filtered and ordered according to the filter and sort objects provided in the request.
9
10
  #
10
- # Returns a 404 HTTP response if the database doesn't exist, or if the bot
11
- # doesn't have access to the database. Returns a 429 HTTP response if the
12
- # request exceeds Notion's Request limits.
11
+ # Filters are similar to the filters provided in the Notion UI. Filters operate
12
+ # on database properties and can be combined. If no filter is provided, all the
13
+ # pages in the database will be returned with pagination.
13
14
  #
14
- # @option options [id] :id
15
- # Database to get info on.
16
- def database(options = {})
17
- throw ArgumentError.new('Required arguments :id missing') if options[:id].nil?
18
- get("databases/#{options[:id]}")
15
+ # Sorts are similar to the sorts provided in the Notion UI. Sorts operate on
16
+ # database properties and can be combined. The order of the sorts in the request
17
+ # matter, with earlier sorts taking precedence over later ones.
18
+ #
19
+ # @option options [id] :database_id
20
+ # Database to query.
21
+ #
22
+ # @option options [Object] :filter
23
+ # When supplied, limits which pages are returned based on the provided criteria.
24
+ #
25
+ # @option options [[Object]] :sorts
26
+ # When supplied, sorts the results based on the provided criteria.
27
+ #
28
+ # @option options [UUID] :start_cursor
29
+ # Paginate through collections of data by setting the cursor parameter
30
+ # to a start_cursor attribute returned by a previous request's next_cursor.
31
+ # Default value fetches the first "page" of the collection.
32
+ # See pagination for more detail.
33
+ #
34
+ # @option options [integer] :page_size
35
+ # The number of items from the full list desired in the response. Maximum: 100
36
+ def database_query(options = {})
37
+ throw ArgumentError.new('Required arguments :database_id missing') if options[:database_id].nil?
38
+ if block_given?
39
+ Pagination::Cursor.new(self, :database_query, options).each do |page|
40
+ yield page
41
+ end
42
+ else
43
+ post("databases/#{options[:database_id]}/query", options.except(:database_id))
44
+ end
19
45
  end
20
46
 
21
47
  #
@@ -41,40 +67,39 @@ module Notion
41
67
  end
42
68
 
43
69
  #
44
- # Gets a paginated array of Page object s contained in the requested database,
45
- # filtered and ordered according to the filter and sort objects provided in the request.
70
+ # Updates an existing database as specified by the parameters.
46
71
  #
47
- # Filters are similar to the filters provided in the Notion UI. Filters operate
48
- # on database properties and can be combined. If no filter is provided, all the
49
- # pages in the database will be returned with pagination.
72
+ # @option options [id] :database_id
73
+ # Database to update.
50
74
  #
51
- # Sorts are similar to the sorts provided in the Notion UI. Sorts operate on
52
- # database properties and can be combined. The order of the sorts in the request
53
- # matter, with earlier sorts taking precedence over later ones.
75
+ # @option options [Object] :title
76
+ # Title of database as it appears in Notion. An array of rich text objects.
77
+ # If omitted, the database title will remain unchanged.
54
78
  #
55
- # @option options [id] :id
56
- # Database to query.
79
+ # @option options [Object] :properties
80
+ # Updates to the property schema of a database.
81
+ # If updating an existing property, the keys are the names or IDs
82
+ # of the properties as they appear in Notion and the values
83
+ # are property schema objects. If adding a new property, the key is
84
+ # the name of the database property and the value is a property schema object.
85
+ #
86
+ def update_database(options = {})
87
+ throw ArgumentError.new('Required arguments :database_id missing') if options.dig(:database_id).nil?
88
+ patch("databases/#{options[:database_id]}", options.except(:database_id))
89
+ end
90
+
57
91
  #
58
- # @option options [Object] :filter
59
- # When supplied, limits which pages are returned based on the provided criteria.
92
+ # Retrieves a Database object using the ID specified in the request.
60
93
  #
61
- # @option options [[Object]] :sorts
62
- # When supplied, sorts the results based on the provided criteria.
94
+ # Returns a 404 HTTP response if the database doesn't exist, or if the bot
95
+ # doesn't have access to the database. Returns a 429 HTTP response if the
96
+ # request exceeds Notion's Request limits.
63
97
  #
64
- # @option options [UUID] :start_cursor
65
- # Paginate through collections of data by setting the cursor parameter
66
- # to a start_cursor attribute returned by a previous request's next_cursor.
67
- # Default value fetches the first "page" of the collection.
68
- # See pagination for more detail.
69
- def database_query(options = {})
70
- throw ArgumentError.new('Required arguments :id missing') if options[:id].nil?
71
- if block_given?
72
- Pagination::Cursor.new(self, :database_query, options).each do |page|
73
- yield page
74
- end
75
- else
76
- post("databases/#{options[:id]}/query", options)
77
- end
98
+ # @option options [id] :database_id
99
+ # Database to get info on.
100
+ def database(options = {})
101
+ throw ArgumentError.new('Required arguments :database_id missing') if options[:database_id].nil?
102
+ get("databases/#{options[:database_id]}")
78
103
  end
79
104
 
80
105
  #
@@ -85,6 +110,9 @@ module Notion
85
110
  # to a start_cursor attribute returned by a previous request's next_cursor.
86
111
  # Default value fetches the first "page" of the collection.
87
112
  # See pagination for more detail.
113
+ #
114
+ # @option options [integer] :page_size
115
+ # The number of items from the full list desired in the response. Maximum: 100
88
116
  def databases_list(options = {})
89
117
  if block_given?
90
118
  Pagination::Cursor.new(self, :databases_list, options).each do |page|
@@ -8,15 +8,15 @@ module Notion
8
8
  # Retrieves a 📄Page object using the ID specified in the request path.
9
9
  # Note that this version of the API only exposes page properties, not page content
10
10
  #
11
- # @option options [id] :id
11
+ # @option options [id] :page_id
12
12
  # Page to get info on.
13
13
  #
14
14
  # @option options [bool] :archived
15
15
  # Set to true to retrieve an archived page; must be false or omitted to
16
16
  # retrieve a page that has not been archived. Defaults to false.
17
17
  def page(options = {})
18
- throw ArgumentError.new('Required arguments :id missing') if options[:id].nil?
19
- get("pages/#{options[:id]}")
18
+ throw ArgumentError.new('Required arguments :page_id missing') if options[:page_id].nil?
19
+ get("pages/#{options[:page_id]}")
20
20
  end
21
21
 
22
22
  #
@@ -50,7 +50,7 @@ module Notion
50
50
  # Note that this iteration of the API will only expose page properties, not page
51
51
  # content, as described in the data model.
52
52
  #
53
- # @option options [id] :id
53
+ # @option options [id] :page_id
54
54
  # Page to get info on.
55
55
  #
56
56
  # @option options [Object] :properties
@@ -60,8 +60,8 @@ module Notion
60
60
  # appears in Notion, or property ID. value object Object containing a value
61
61
  # specific to the property type, e.g. {"checkbox": true}.
62
62
  def update_page(options = {})
63
- throw ArgumentError.new('Required arguments :id missing') if options[:id].nil?
64
- patch("pages/#{options[:id]}", options)
63
+ throw ArgumentError.new('Required arguments :page_id missing') if options[:page_id].nil?
64
+ patch("pages/#{options[:page_id]}", options.except(:page_id))
65
65
  end
66
66
  end
67
67
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Notion
4
+ module Api
5
+ module Endpoints
6
+ module Search
7
+ #
8
+ # Searches all pages and child pages that are shared with the integration.
9
+ # The results may include databases.
10
+ #
11
+ # @option options [string] :query
12
+ # When supplied, limits which pages are returned by comparing the query to the page title.
13
+ #
14
+ # @option options [Object] :filter
15
+ # When supplied, filters the results based on the provided criteria.
16
+ #
17
+ # @option options [[Object]] :sorts
18
+ # When supplied, sorts the results based on the provided criteria.
19
+ # Limitation: Currently only a single sort is allowed and is limited to last_edited_time.
20
+ #
21
+ # @option options [UUID] :start_cursor
22
+ # Paginate through collections of data by setting the cursor parameter
23
+ # to a start_cursor attribute returned by a previous request's next_cursor.
24
+ # Default value fetches the first "page" of the collection.
25
+ # See pagination for more detail.
26
+ #
27
+ # @option options [integer] :page_size
28
+ # The number of items from the full list desired in the response. Maximum: 100
29
+ def search(options = {})
30
+ if block_given?
31
+ Pagination::Cursor.new(self, :search, options).each do |page|
32
+ yield page
33
+ end
34
+ else
35
+ post('search', options)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -7,11 +7,11 @@ module Notion
7
7
  #
8
8
  # Retrieves a User object using the ID specified in the request.
9
9
  #
10
- # @option options [id] :id
10
+ # @option options [id] :user_id
11
11
  # User to get info on.
12
12
  def user(options = {})
13
- throw ArgumentError.new('Required arguments :id missing') if options[:id].nil?
14
- get("users/#{options[:id]}")
13
+ throw ArgumentError.new('Required arguments :user_id missing') if options[:user_id].nil?
14
+ get("users/#{options[:user_id]}")
15
15
  end
16
16
 
17
17
  #
@@ -22,6 +22,9 @@ module Notion
22
22
  # to a start_cursor attribute returned by a previous request's next_cursor.
23
23
  # Default value fetches the first "page" of the collection.
24
24
  # See pagination for more detail.
25
+ #
26
+ # @option options [integer] :page_size
27
+ # The number of items from the full list desired in the response. Maximum: 100
25
28
  def users_list(options = {})
26
29
  if block_given?
27
30
  Pagination::Cursor.new(self, :users_list, options).each do |page|
@@ -4,6 +4,7 @@ require_relative 'endpoints/blocks'
4
4
  require_relative 'endpoints/databases'
5
5
  require_relative 'endpoints/pages'
6
6
  require_relative 'endpoints/users'
7
+ require_relative 'endpoints/search'
7
8
 
8
9
  module Notion
9
10
  module Api
@@ -12,6 +13,7 @@ module Notion
12
13
  include Databases
13
14
  include Pages
14
15
  include Users
16
+ include Search
15
17
  end
16
18
  end
17
- end
19
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ module Notion
3
+ module Api
4
+ module Errors
5
+ class TooManyRequests < ::Faraday::Error
6
+ attr_reader :response
7
+
8
+ def initialize(response)
9
+ @response = response
10
+ super 'Too many requests'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -8,7 +8,6 @@ module Notion
8
8
  class InternalError < NotionError; end
9
9
  class InvalidRequest < NotionError; end
10
10
  class ObjectNotFound < NotionError; end
11
- class TooManyRequests < NotionError; end
12
11
  class Unauthorized < NotionError; end
13
12
 
14
13
  ERROR_CLASSES = {
@@ -17,7 +16,6 @@ module Notion
17
16
  'internal_error' => InternalError,
18
17
  'invalid_request' => InvalidRequest,
19
18
  'object_not_found' => ObjectNotFound,
20
- 'rate_limited' => TooManyRequests,
21
19
  'unauthorized' => Unauthorized
22
20
  }.freeze
23
21
  end
data/lib/notion/config.rb CHANGED
@@ -15,6 +15,7 @@ module Notion
15
15
  open_timeout
16
16
  default_page_size
17
17
  default_max_retries
18
+ default_retry_after
18
19
  adapter
19
20
  ].freeze
20
21
 
@@ -32,6 +33,7 @@ module Notion
32
33
  self.open_timeout = nil
33
34
  self.default_page_size = 100
34
35
  self.default_max_retries = 100
36
+ self.default_retry_after = 10
35
37
  self.adapter = ::Faraday.default_adapter
36
38
  end
37
39
 
@@ -9,6 +9,7 @@ module Notion
9
9
  attr_reader :verb
10
10
  attr_reader :sleep_interval
11
11
  attr_reader :max_retries
12
+ attr_reader :retry_after
12
13
  attr_reader :params
13
14
 
14
15
  def initialize(client, verb, params = {})
@@ -17,13 +18,15 @@ module Notion
17
18
  @params = params.dup
18
19
  @sleep_interval = @params.delete(:sleep_interval)
19
20
  @max_retries = @params.delete(:max_retries) || client.default_max_retries
21
+ @retry_after = @params.delete(:retry_after) || client.default_retry_after
20
22
  end
21
23
 
22
24
  def each
23
25
  next_cursor = nil
24
26
  retry_count = 0
25
27
  loop do
26
- query = next_cursor.nil? ? params : params.merge(start_cursor: next_cursor)
28
+ query = { page_size: client.default_page_size }.merge(params)
29
+ query = query.merge(start_cursor: next_cursor) unless next_cursor.nil?
27
30
  begin
28
31
  response = client.send(verb, query)
29
32
  rescue Notion::Api::Errors::TooManyRequests => e
@@ -31,7 +34,7 @@ module Notion
31
34
 
32
35
  client.logger.debug("#{self.class}##{__method__}") { e.to_s }
33
36
  retry_count += 1
34
- sleep(e.retry_after)
37
+ sleep(retry_after)
35
38
  next
36
39
  end
37
40
  yield response
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module Notion
3
- VERSION = '0.0.8'
4
- NOTION_REQUEST_VERSION = '2021-05-13'
3
+ VERSION = '0.1.0-beta1'
4
+ NOTION_REQUEST_VERSION = '2021-08-16'
5
5
  end