notion_orbit 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.env.sample +5 -0
- data/.github/CODE_OF_CONDUCT.md +134 -0
- data/.github/CONTRIBUTING.md +69 -0
- data/.github/workflows/CI.yml +25 -0
- data/.gitignore +34 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +115 -0
- data/LICENSE +21 -0
- data/README.md +108 -0
- data/bin/console +16 -0
- data/bin/notion_orbit +28 -0
- data/bin/setup +8 -0
- data/docs/database-id-location.png +0 -0
- data/docs/new-note-screenshot.png +0 -0
- data/docs/setup-table-for-orbit.png +0 -0
- data/docs/setup.md +17 -0
- data/docs/ways-to-use.png +0 -0
- data/lib/notion_orbit.rb +12 -0
- data/lib/notion_orbit/client.rb +55 -0
- data/lib/notion_orbit/interactions/note.rb +37 -0
- data/lib/notion_orbit/notion.rb +42 -0
- data/lib/notion_orbit/notion_objects/block.rb +60 -0
- data/lib/notion_orbit/notion_objects/block_types/bulleted_list_item.rb +15 -0
- data/lib/notion_orbit/notion_objects/block_types/heading_1.rb +11 -0
- data/lib/notion_orbit/notion_objects/block_types/heading_2.rb +11 -0
- data/lib/notion_orbit/notion_objects/block_types/heading_3.rb +11 -0
- data/lib/notion_orbit/notion_objects/block_types/numbered_list_item.rb +15 -0
- data/lib/notion_orbit/notion_objects/block_types/paragraph.rb +15 -0
- data/lib/notion_orbit/notion_objects/block_types/to_do.rb +11 -0
- data/lib/notion_orbit/notion_objects/block_types/unsupported.rb +11 -0
- data/lib/notion_orbit/notion_objects/blocks.rb +18 -0
- data/lib/notion_orbit/notion_objects/rich_text.rb +36 -0
- data/lib/notion_orbit/orbit.rb +16 -0
- data/lib/notion_orbit/services/notion.rb +57 -0
- data/lib/notion_orbit/services/orbit.rb +73 -0
- data/lib/notion_orbit/version.rb +5 -0
- data/notion_orbit.gemspec +43 -0
- data/scripts/check_notes.rb +17 -0
- metadata +201 -0
data/bin/console
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "dotenv/load"
|
6
|
+
require "notion_orbit"
|
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
|
+
IRB.start(__FILE__)
|
data/bin/notion_orbit
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
#!/usr/bin/env ruby
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
check_notes = false
|
6
|
+
|
7
|
+
options = {}
|
8
|
+
choices = OptionParser.new do |opts|
|
9
|
+
opts.banner = "Usage: notion_orbit --check-notes"
|
10
|
+
opts.on("-h", "--help", "Prints help instructions") do
|
11
|
+
puts opts
|
12
|
+
exit
|
13
|
+
end
|
14
|
+
opts.on("--check-notes", "Check for new notes") do
|
15
|
+
check_notes = true
|
16
|
+
end
|
17
|
+
end.parse!
|
18
|
+
|
19
|
+
$LOAD_PATH.unshift(File.expand_path('../lib/notion_orbit', __dir__))
|
20
|
+
|
21
|
+
require_relative '../lib/notion_orbit'
|
22
|
+
require_relative '../scripts/check_notes'
|
23
|
+
|
24
|
+
if check_notes
|
25
|
+
puts "Checking for new notes and posting them to your Orbit workspace..."
|
26
|
+
ARGV[0] = 'render'
|
27
|
+
NotionOrbit::Scripts::CheckNotes.start(ARGV)
|
28
|
+
end
|
data/bin/setup
ADDED
Binary file
|
Binary file
|
Binary file
|
data/docs/setup.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
<small><a href="../README.md">Back to README</a></small>
|
2
|
+
|
3
|
+
# First Time Setup
|
4
|
+
|
5
|
+
During the setup, we will need to create a new Notion integration which will allow this library to interact with the platform. This process takes about 2 minutes to finish. The application will contain an API secret which we should take note of for later.
|
6
|
+
|
7
|
+
1. Head to [Notion Integrations](https://www.notion.so/my-integrations) and login in to your account.
|
8
|
+
2. Click on the "+ New Integration" button on the left-hand side of the page. *Note: You must have admin access to your Notion workspace.*
|
9
|
+
3. Fill out the details in the request form and press the "Submit" button.
|
10
|
+
4. Save the "Internal Integration Token" from Notion. You will use it in this application. Do not share it with others and keep it in a secure location.
|
11
|
+
5. Make sure that the "Integration Type" is set to "Internal Integration".
|
12
|
+
6. Click "Save changes".
|
13
|
+
7. You must add your integration to the database in your Notion workspace that you wish to fetch notes from.
|
14
|
+
* From the top navigation bar in your Notion database view press the "Share" button
|
15
|
+
* Find your integration by the name you gave it in the request form
|
16
|
+
* Select the integration and click "Invite"<br/>
|
17
|
+
![](https://files.readme.io/0a267dd-share-database-with-integration.gif)
|
Binary file
|
data/lib/notion_orbit.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "zeitwerk"
|
4
|
+
require_relative "notion_orbit/version"
|
5
|
+
require "notion-ruby-client"
|
6
|
+
|
7
|
+
module NotionOrbit
|
8
|
+
loader = Zeitwerk::Loader.new
|
9
|
+
loader.tag = File.basename(__FILE__, ".rb")
|
10
|
+
loader.push_dir(__dir__)
|
11
|
+
loader.setup
|
12
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dotenv/load"
|
4
|
+
require "net/http"
|
5
|
+
require "json"
|
6
|
+
|
7
|
+
# Create a client to log Notion database activities in your Orbit workspace
|
8
|
+
# Credentials can either be passed in to the instance or be loaded
|
9
|
+
# from environment variables
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# client = NotionOrbit::Client.new
|
13
|
+
#
|
14
|
+
# @option params [String] :orbit_api_key
|
15
|
+
# The API key for the Orbit API
|
16
|
+
#
|
17
|
+
# @option params [String] :orbit_workspace
|
18
|
+
# The workspace ID for the Orbit workspace
|
19
|
+
#
|
20
|
+
# @option params [String] :notion_api_key
|
21
|
+
# The API key for Notion
|
22
|
+
#
|
23
|
+
# @option params [String] :notion_workspace_slug
|
24
|
+
# The Notion workspace slug
|
25
|
+
#
|
26
|
+
# @option params [String] :notion_database_id
|
27
|
+
# The Notion database ID
|
28
|
+
#
|
29
|
+
# @param [Hash] params
|
30
|
+
#
|
31
|
+
# @return [NotionOrbit::Client]
|
32
|
+
#
|
33
|
+
module NotionOrbit
|
34
|
+
class Client
|
35
|
+
attr_accessor :orbit_api_key, :orbit_workspace, :notion_database_id, :notion_api_key, :notion_workspace_slug
|
36
|
+
|
37
|
+
def initialize(params = {})
|
38
|
+
@orbit_api_key = params.fetch(:orbit_api_key, ENV["ORBIT_API_KEY"])
|
39
|
+
@orbit_workspace = params.fetch(:orbit_workspace, ENV["ORBIT_WORKSPACE_ID"])
|
40
|
+
@notion_api_key = params.fetch(:notion_api_key, ENV["NOTION_API_KEY"])
|
41
|
+
@notion_database_id = params.fetch(:notion_database_id, ENV["NOTION_DATABASE_ID"])
|
42
|
+
@notion_workspace_slug = params.fetch(:notion_workspace_slug, ENV["NOTION_WORKSPACE_SLUG"])
|
43
|
+
end
|
44
|
+
|
45
|
+
def notes
|
46
|
+
NotionOrbit::Notion.new(
|
47
|
+
orbit_api_key: @orbit_api_key,
|
48
|
+
orbit_workspace: @orbit_workspace,
|
49
|
+
notion_api_key: @notion_api_key,
|
50
|
+
notion_database_id: @notion_database_id,
|
51
|
+
notion_workspace_slug: @notion_workspace_slug
|
52
|
+
).process_notes
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
module NotionOrbit
|
6
|
+
module Interactions
|
7
|
+
class Note
|
8
|
+
def initialize(note:, orbit_api_key:, orbit_workspace:, notion_api_key:)
|
9
|
+
@note = note
|
10
|
+
@orbit_workspace = orbit_workspace
|
11
|
+
@orbit_api_key = orbit_api_key
|
12
|
+
@notion_api_key = notion_api_key
|
13
|
+
|
14
|
+
after_initialize!
|
15
|
+
end
|
16
|
+
|
17
|
+
def after_initialize!
|
18
|
+
orbit_service = NotionOrbit::Services::Orbit.new(orbit_workspace: @orbit_workspace, orbit_api_key: @orbit_api_key)
|
19
|
+
notion_service = NotionOrbit::Services::Notion.new(token: @notion_api_key)
|
20
|
+
|
21
|
+
orbit_service.send_note(
|
22
|
+
member_slug: @note[:member_slug],
|
23
|
+
api_key: @orbit_api_key,
|
24
|
+
content: @note[:content]
|
25
|
+
)
|
26
|
+
|
27
|
+
notion_service.mark_note_as_synced(@note[:page_id], orbit_note_url(@note[:member_slug]))
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def orbit_note_url(member_slug)
|
33
|
+
"https://app.orbit.love/#{@orbit_workspace}/members/#{member_slug}?type=notes"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NotionOrbit
|
4
|
+
class Notion
|
5
|
+
def initialize(params = {})
|
6
|
+
@orbit_api_key = params.fetch(:orbit_api_key)
|
7
|
+
@orbit_workspace = params.fetch(:orbit_workspace)
|
8
|
+
@notion_api_key = params.fetch(:notion_api_key)
|
9
|
+
@notion_database_id = params.fetch(:notion_database_id)
|
10
|
+
@notion_workspace_slug = params.fetch(:notion_workspace_slug)
|
11
|
+
end
|
12
|
+
|
13
|
+
def process_notes
|
14
|
+
notion_service = NotionOrbit::Services::Notion.new(token: @notion_api_key)
|
15
|
+
orbit_service = NotionOrbit::Services::Orbit.new(orbit_workspace: @orbit_workspace, orbit_api_key: @orbit_api_key)
|
16
|
+
|
17
|
+
notes = notion_service.notes(database_id: @notion_database_id)
|
18
|
+
|
19
|
+
notes.each do |note|
|
20
|
+
next if note[:properties][:email].nil? || note[:properties][:email] == ""
|
21
|
+
|
22
|
+
member_slug = orbit_service.member_slug(email: note[:properties][:email])
|
23
|
+
next if member_slug == "" || member_slug.nil?
|
24
|
+
|
25
|
+
NotionOrbit::Orbit.call(
|
26
|
+
type: "note",
|
27
|
+
data: {
|
28
|
+
note: {
|
29
|
+
email: note[:properties][:email],
|
30
|
+
member_slug: member_slug,
|
31
|
+
page_id: note[:properties][:page_id],
|
32
|
+
content: note[:content]
|
33
|
+
}
|
34
|
+
},
|
35
|
+
orbit_workspace: @orbit_workspace,
|
36
|
+
orbit_api_key: @orbit_api_key,
|
37
|
+
notion_api_key: @notion_api_key
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module NotionOrbit
|
2
|
+
module NotionObjects
|
3
|
+
class Block
|
4
|
+
class << self
|
5
|
+
def new_from_raw_block(raw_block, indentation: 0)
|
6
|
+
klass = case raw_block.type
|
7
|
+
when 'bulleted_list_item'
|
8
|
+
NotionOrbit::NotionObjects::BlockTypes::BulletedListItem
|
9
|
+
when 'heading_1'
|
10
|
+
NotionOrbit::NotionObjects::BlockTypes::Heading1
|
11
|
+
when 'heading_2'
|
12
|
+
NotionOrbit::NotionObjects::BlockTypes::Heading2
|
13
|
+
when 'heading_3'
|
14
|
+
NotionOrbit::NotionObjects::BlockTypes::Heading3
|
15
|
+
when 'numbered_list_item'
|
16
|
+
NotionOrbit::NotionObjects::BlockTypes::NumberedListItem
|
17
|
+
when 'paragraph'
|
18
|
+
NotionOrbit::NotionObjects::BlockTypes::Paragraph
|
19
|
+
when 'to_do'
|
20
|
+
NotionOrbit::NotionObjects::BlockTypes::ToDo
|
21
|
+
else
|
22
|
+
NotionOrbit::NotionObjects::BlockTypes::Unsupported
|
23
|
+
end
|
24
|
+
klass.new(raw_block, indentation)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(raw_block, indentation)
|
29
|
+
@raw_block = raw_block
|
30
|
+
@id = raw_block.id
|
31
|
+
@type = raw_block.type
|
32
|
+
@has_children = raw_block.has_children
|
33
|
+
@indentation = indentation
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_markdown
|
37
|
+
markdown = @raw_block[@type].text.map do |rich_text|
|
38
|
+
NotionOrbit::NotionObjects::RichText.new(rich_text).to_markdown
|
39
|
+
end.join
|
40
|
+
|
41
|
+
if @has_children
|
42
|
+
raw_children = notion_service.client.block_children(id: @id).results
|
43
|
+
children_indentation = indent_children? ? @indentation + 2 : @indentation
|
44
|
+
children_blocks = Blocks.new(raw_children, indentation: children_indentation)
|
45
|
+
markdown += "\n\n" + children_blocks.to_markdown
|
46
|
+
end
|
47
|
+
|
48
|
+
markdown
|
49
|
+
end
|
50
|
+
|
51
|
+
def indent_children?
|
52
|
+
false
|
53
|
+
end
|
54
|
+
|
55
|
+
def notion_service
|
56
|
+
@notion_service ||= NotionOrbit::Services::Notion.new
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module NotionOrbit
|
2
|
+
module NotionObjects
|
3
|
+
class Blocks
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
attr_accessor :blocks
|
7
|
+
|
8
|
+
def initialize(raw_blocks, indentation: 0)
|
9
|
+
@blocks = raw_blocks.map{ |raw_block| Block.new_from_raw_block(raw_block, indentation: indentation) }
|
10
|
+
@indentation = indentation
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_markdown
|
14
|
+
@blocks.map { |block| " " * @indentation + block.to_markdown }.join("\n").rstrip.gsub("\n","\\n")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module NotionOrbit
|
2
|
+
module NotionObjects
|
3
|
+
class RichText
|
4
|
+
def initialize(raw_rich_text)
|
5
|
+
@raw_rich_text = raw_rich_text
|
6
|
+
@type = raw_rich_text.type
|
7
|
+
@annotations = raw_rich_text.annotations
|
8
|
+
@text = raw_rich_text.text
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_markdown
|
12
|
+
return "" unless @type == 'text'
|
13
|
+
markdown = @text.content
|
14
|
+
markdown = apply_link(markdown) unless @text.link.nil?
|
15
|
+
markdown = apply_annotations(markdown)
|
16
|
+
markdown
|
17
|
+
end
|
18
|
+
|
19
|
+
def apply_link(content)
|
20
|
+
@text.link.nil? ? content : "[#{content}](#{@text.link.url})"
|
21
|
+
end
|
22
|
+
|
23
|
+
def apply_annotations(content)
|
24
|
+
annotation_symbols = []
|
25
|
+
annotation_symbols << '**' if @annotations.bold
|
26
|
+
annotation_symbols << '_' if @annotations.italic
|
27
|
+
annotation_symbols << '`' if @annotations.code
|
28
|
+
wrap_with(content, annotation_symbols)
|
29
|
+
end
|
30
|
+
|
31
|
+
def wrap_with(string, wrappers)
|
32
|
+
"#{wrappers.join}#{string}#{wrappers.reverse.join}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|