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

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