grist-grist 0.1.1

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,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grist
4
+ module Type
5
+ # Defines a Grist Organization
6
+ class Access < Grist::Type::Base
7
+ PATH = "/access"
8
+ KEYS = %w[
9
+ id
10
+ email
11
+ name
12
+ picture
13
+ ref
14
+ access
15
+ isMember
16
+ ].freeze
17
+
18
+ attr_accessor(*KEYS)
19
+
20
+ # List all organizations
21
+ # @return [Array] Array of organizations
22
+ def self.all
23
+ grist_res = new.list
24
+ return [] unless grist_res&.data.is_a?(Array)
25
+
26
+ grist_res.data&.map { |org| Organization.new(org) }
27
+ end
28
+
29
+ # Finds an organization by ID
30
+ # @param id [Integer] The ID of the organization to find
31
+ # return [self | nil] The organization or nil if not found
32
+ def self.find(id)
33
+ grist_res = new.get(id)
34
+ return unless grist_res.success? && grist_res.data
35
+
36
+ new(grist_res.data)
37
+ end
38
+
39
+ # Updates the organization
40
+ # @param id [Integer] The ID of the organization to delete
41
+ # @param data [Hash] The data to update the organization with
42
+ # @return [self | nil] The updated organization or nil if not found
43
+ def self.update(id, data)
44
+ org = find(id)
45
+ return unless org
46
+
47
+ org.update(data)
48
+ end
49
+
50
+ # Deletes the organization
51
+ # @param id [Integer] The ID of the organization to delete
52
+ # @return [self | nil] The deleted organization or nil if not found
53
+ def self.delete(id)
54
+ org = find(id)
55
+ return unless org
56
+
57
+ org.delete
58
+ end
59
+
60
+ def self.access(id)
61
+ org = find(id)
62
+ grist_res = org.access
63
+ return unless grist_res.success? && grist_res.data
64
+
65
+ grist_res.data
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grist
4
+ module Type
5
+ class Base
6
+ include Rest
7
+ include Accessible
8
+ include Searchable
9
+
10
+ PATH = ""
11
+ KEYS = %w[].freeze
12
+ attr_accessor(*KEYS)
13
+
14
+ def initialize(params = {})
15
+ keys.each do |key|
16
+ instance_variable_set("@#{key}", params[key])
17
+ end
18
+ @deleted = params.delete(:deleted) || false
19
+ end
20
+
21
+ def keys
22
+ self.class::KEYS
23
+ end
24
+
25
+ def deleted?
26
+ !!@deleted
27
+ end
28
+
29
+ # List all items
30
+ # @return [Array] Array of items
31
+ def self.all
32
+ grist_res = new.list
33
+
34
+ return [] unless grist_res&.data.is_a?(Array)
35
+ return [] unless grist_res&.data&.any?
36
+
37
+ grist_res.data.map { |org| new(org) }
38
+ end
39
+
40
+ # Finds an item by ID
41
+ # @param id [Integer] The ID of the item to find
42
+ # return [Grist::Type::Base, nil] The item or nil if not found
43
+ def self.find(id)
44
+ grist_res = new.get(id)
45
+ return unless grist_res.success? && grist_res.data
46
+
47
+ new(grist_res.data)
48
+ end
49
+
50
+ # Updates the item
51
+ # @param id [Integer] The ID of the item to delete
52
+ # @param data [Hash] The data to update the item with
53
+ # @return [Grist::Type::Base, nil] The updated item or nil if not found
54
+ def self.update(id, data)
55
+ org = find(id)
56
+ return unless org
57
+
58
+ org.update(data)
59
+ end
60
+
61
+ # Deletes the item
62
+ # @param id [Integer] The ID of the item to delete
63
+ # @return [Grist::Type::Base, nil] The deleted item or nil if not found
64
+ def self.delete(id)
65
+ org = find(id)
66
+ return unless org
67
+
68
+ org.delete
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grist
4
+ module Type
5
+ # Defines a Grist Workspace
6
+ class Column
7
+ include Rest
8
+
9
+ PATH = "/docs"
10
+ KEYS = %w[
11
+ id
12
+ fields
13
+ ].freeze
14
+
15
+ attr_accessor(*KEYS)
16
+
17
+ def initialize(params = {})
18
+ @doc_id = params[:doc_id]
19
+ KEYS.each do |key|
20
+ instance_variable_set("@#{key}", params[key])
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grist
4
+ module Type
5
+ # Defines a Grist Workspace
6
+ class Doc < Grist::Type::Base
7
+ PATH = "/docs"
8
+ KEYS = %w[
9
+ name
10
+ createdAt
11
+ updatedAt
12
+ id
13
+ isPinned
14
+ urlId
15
+ trunkId
16
+ type
17
+ forks
18
+ access
19
+ ].freeze
20
+
21
+ attr_accessor(*KEYS)
22
+
23
+ def initialize(params = {})
24
+ super params
25
+ @ws_id = params[:ws_id]
26
+ @tables = []
27
+ end
28
+
29
+ def tables_path
30
+ "#{path}/#{@id}/tables"
31
+ end
32
+
33
+ def tables
34
+ grist_res = request(:get, tables_path)
35
+ return [] if grist_res&.error?
36
+
37
+ @tables = grist_res.data["tables"]&.map do |t|
38
+ Table.new(t.merge(doc_id: @id, ws_id: @ws_id))
39
+ end
40
+ end
41
+
42
+ def create_tables(data)
43
+ grist_res = request(:post, tables_path, data)
44
+
45
+ return [] unless grist_res&.data.is_a?(Array)
46
+
47
+ tables
48
+ end
49
+
50
+ def update_table(data)
51
+ grist_res = request(:patch, tables_path, data)
52
+
53
+ return [] unless grist_res&.data.is_a?(Array)
54
+
55
+ tables
56
+ end
57
+
58
+ # def base_api_url
59
+ # "#{ENV["GRIST_API_URL"]}/api/orgs/#{@org_id}"
60
+ # end
61
+
62
+ # Updates the workspace
63
+ # # @param id [Integer] The ID of the workspace to delete
64
+ # # # @param data [Hash] The data to update the workspace with
65
+ # # @return [self | nil] The updated workspace or nil if not found
66
+ def self.create(ws_id, data)
67
+ obj = new(ws_id: ws_id)
68
+ obj.create(data)
69
+ end
70
+
71
+ # List all workspaces
72
+ # # # @return [Array] Array of workspaces
73
+ def self.all(org_id)
74
+ grist_res = new(org_id: org_id).list
75
+ return [] unless grist_res&.data.is_a?(Array)
76
+
77
+ grist_res.data&.map { |org| Workspace.new(org) }
78
+ end
79
+
80
+ # Finds an workspace by ID
81
+ # # @param id [Integer] The ID of the workspace to find
82
+ # # # return [self | nil] The workspace or nil if not found
83
+ def self.find(id)
84
+ grist_res = new.get(id)
85
+ puts grist_res.inspect
86
+ return unless grist_res.success? && grist_res.data
87
+
88
+ new(grist_res.data)
89
+ end
90
+
91
+ def self.tables(doc_id)
92
+ org = find(doc_id)
93
+ return unless org
94
+
95
+ org.tables
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grist
4
+ module Type
5
+ # Defines a Grist Organization
6
+ class Organization < Grist::Type::Base
7
+ PATH = "/orgs"
8
+ KEYS = %w[
9
+ id
10
+ name
11
+ createdAt
12
+ updatedAt
13
+ domain
14
+ host
15
+ owner
16
+ ].freeze
17
+
18
+ attr_accessor(*KEYS)
19
+ attr_reader :workspaces
20
+
21
+ # Initialize a new Organization
22
+ # @param params [Hash] The parameters to initialize the organization with
23
+ # @return [Grist::Type::Organization] The organization
24
+ # @note API: https://support.getgrist.com/api/#tag/organizations
25
+ # @example
26
+ # org = Grist::Type::Organization.new(
27
+ # "id" => 1,
28
+ # "name" => "Grist Labs",
29
+ # "domain" => "gristlabs",
30
+ # "host" => "gristlabs.com",
31
+ # )
32
+ def initialize(params = {})
33
+ super params
34
+ @workspaces = []
35
+ end
36
+
37
+ # List Workspaces in the organization
38
+ # @return [Array] The array of Grist::Type::Workspace
39
+ # @note API: https://support.getgrist.com/api/#tag/workspaces
40
+ def workspaces
41
+ grist_res = request(:get, workspaces_path)
42
+
43
+ return [] unless grist_res.success? && grist_res.data
44
+
45
+ @workspaces = grist_res.data.map do |workspace|
46
+ Workspace.new(workspace)
47
+ end
48
+ end
49
+
50
+ # Create a new Workspace in the organization
51
+ # @param data [Hash] The data to create the workspace with
52
+ # @return [Decidim::Type::Workspace, nil] The organization or nil if not found
53
+ def create_workspace(data)
54
+ grist_res = request(:post, workspaces_path, data)
55
+
56
+ unless grist_res.success?
57
+ grist_res.print_error
58
+ return
59
+ end
60
+
61
+ data["id"] = grist_res.data
62
+ data.transform_keys!(&:to_s)
63
+
64
+ ws = Workspace.new(data)
65
+ @workspaces << ws
66
+
67
+ ws
68
+ end
69
+
70
+ # Get the path for the organization
71
+ # @return [String] The path for the organization
72
+ def workspaces_path
73
+ "#{path}/#{@id}/workspaces"
74
+ end
75
+
76
+ # Get users which can access to the organization
77
+ # @param id [Integer] The ID of the organization
78
+ # @return [Array, nil] An array of Grist::Type::Access or nil
79
+ def self.access(id)
80
+ org = find(id)
81
+ grist_res = org.access
82
+ return unless grist_res.success? && grist_res.data
83
+
84
+ grist_res.data["users"].map do |access|
85
+ Access.new(access)
86
+ end
87
+ end
88
+
89
+ # List workspaces in the organization
90
+ # @param id [Integer] The ID of the organization
91
+ # @return [Array] An array of Grist::Type::Workspace
92
+ def self.list_workspaces(id)
93
+ org = find(id)
94
+ return [] unless org
95
+
96
+ org.workspaces
97
+ end
98
+
99
+ # Create a new workspace in the organization
100
+ # @param org_id [Integer] The ID of the organization
101
+ # @param data [Hash] The data to create the workspace with
102
+ # @return [Grist::Type::Workspace, nil] The created workspace or nil if not found
103
+ def self.create_workspace(org_id, data)
104
+ org = find(org_id)
105
+ return unless org
106
+
107
+ org.create_workspace(data)
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grist
4
+ module Type
5
+ # Defines a Grist Workspace
6
+ class Record < Grist::Type::Base
7
+ PATH = "/records"
8
+ KEYS = %w[
9
+ id
10
+ fields
11
+ ].freeze
12
+
13
+ attr_accessor(*KEYS)
14
+
15
+ def initialize(params = {})
16
+ super params
17
+ @table_id = params[:table_id]
18
+ @doc_id = params[:doc_id]
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grist
4
+ module Type
5
+ # Defines a Grist Workspace
6
+ class Table < Grist::Type::Base
7
+ KEYS = %w[
8
+ id
9
+ fields
10
+ columns
11
+ ].freeze
12
+
13
+ attr_accessor(*KEYS)
14
+
15
+ def initialize(params = {})
16
+ @doc_id = params[:doc_id]
17
+ super params
18
+ end
19
+
20
+ def to_hash
21
+ {
22
+ "id" => @id,
23
+ "fields" => @fields,
24
+ "columns" => @columns
25
+ }
26
+ end
27
+
28
+ def columns_path
29
+ "/docs/#{@doc_id}/tables/#{@id}/columns"
30
+ end
31
+
32
+ def columns
33
+ grist_res = request(:get, columns_path)
34
+ return [] unless grist_res.success? && grist_res.data
35
+
36
+ grist_res.data.map do |column|
37
+ Column.new(column)
38
+ end
39
+ end
40
+
41
+ def records_path
42
+ "/docs/#{@doc_id}/tables/#{@id}/records"
43
+ end
44
+
45
+ def records(params = {})
46
+ grist_res = request(:get, records_path, params)
47
+
48
+ return [] unless grist_res.success? && grist_res.data
49
+
50
+ @records = grist_res.data["records"].map do |record|
51
+ Record.new(record.merge(doc_id: @doc_id, table_id: @id))
52
+ end
53
+
54
+ @records
55
+ end
56
+
57
+ def create_records(data)
58
+ grist_res = request(:post, records_path, data)
59
+ return [] unless grist_res.success? && grist_res.data
60
+
61
+ @records = grist_res.data["records"].map do |record|
62
+ Record.new(record.merge(doc_id: @doc_id, table_id: @id))
63
+ end
64
+
65
+ @records
66
+ end
67
+
68
+ # def base_api_url
69
+ # "#{ENV["GRIST_API_URL"]}/api/orgs/#{@org_id}"
70
+ # end
71
+
72
+ # Updates the workspace
73
+ # # @param id [Integer] The ID of the workspace to delete
74
+ # # # @param data [Hash] The data to update the workspace with
75
+ # # @return [self | nil] The updated workspace or nil if not found
76
+ def self.create(doc_id, data)
77
+ obj = new(doc_id: doc_id)
78
+ obj.create(data)
79
+ end
80
+
81
+ # List all workspaces
82
+ # # # @return [Array] Array of workspaces
83
+ def self.all(org_id)
84
+ grist_res = new(org_id: org_id).list
85
+ return [] unless grist_res&.data.is_a?(Array)
86
+
87
+ grist_res.data&.map { |org| Workspace.new(org) }
88
+ end
89
+
90
+ # Finds an workspace by ID
91
+ # # @param id [Integer] The ID of the workspace to find
92
+ # # # return [self | nil] The workspace or nil if not found
93
+ def self.find(id)
94
+ grist_res = new.get(id)
95
+ return unless grist_res.success? && grist_res.data
96
+
97
+ new(grist_res.data)
98
+ end
99
+
100
+ # Updates the workspace
101
+ # # @param id [Integer] The ID of the workspace to delete
102
+ # # # @param data [Hash] The data to update the workspace with
103
+ # # @return [self | nil] The updated workspace or nil if not found
104
+ def self.update(id, data)
105
+ org = find(id)
106
+ return unless org
107
+
108
+ org.update(data)
109
+ end
110
+
111
+ # Deletes the workspace
112
+ # # @param id [Integer] The ID of the workspace to delete
113
+ # # @return [self | nil] The deleted workspace or nil if not found
114
+ def self.delete(id)
115
+ org = find(id)
116
+ return unless org
117
+
118
+ org.delete
119
+ end
120
+
121
+ def self.access(id)
122
+ org = find(id)
123
+ grist_res = org.access
124
+ return unless grist_res.success? && grist_res.data
125
+
126
+ grist_res.data["users"].map do |access|
127
+ Access.new(access)
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grist
4
+ module Type
5
+ # Defines a Grist Workspace
6
+ class Workspace < Grist::Type::Base
7
+ PATH = "/workspaces"
8
+ KEYS = %w[
9
+ id
10
+ name
11
+ createdAt
12
+ updatedAt
13
+ isSupportWorkspace
14
+ docs
15
+ access
16
+ owner
17
+ orgDomain
18
+ ].freeze
19
+
20
+ attr_accessor(*KEYS)
21
+ attr_reader :org_id
22
+
23
+ def initialize(params = {})
24
+ @org_id = params[:org_id]
25
+ @docs = []
26
+ super params
27
+ end
28
+
29
+ def docs
30
+ return @docs if @docs&.any? && @docs.first.is_a?(Doc)
31
+
32
+ if @docs.any? && @docs.first.is_a?(Hash)
33
+ @docs = @docs.map do |doc|
34
+ Doc.new(doc.merge(ws_id: @id))
35
+ end
36
+ end
37
+
38
+ @docs
39
+ end
40
+
41
+ # Create a new Doc in the workspace
42
+ # @param data [Hash] The data to create the doc with
43
+ # @return [Grist::Type::Doc, nil] The created doc or nil if not found
44
+ def create_doc(data)
45
+ grist_res = request(:post, doc_path, data)
46
+
47
+ return unless grist_res.success?
48
+
49
+ data["id"] = grist_res.data
50
+ data.transform_keys!(&:to_s)
51
+ doc = Doc.new(data)
52
+ @docs ||= []
53
+ @docs << doc
54
+
55
+ doc
56
+ end
57
+
58
+ # Creates the workspace
59
+ # @param id [Integer] The ID of the workspace to create
60
+ # @param data [Hash] The data to create the workspace with
61
+ # @return [Grist::Type::Workspace, nil] The created workspace or nil if not found
62
+ def self.create(org_id, data)
63
+ org = Type::Organization.find(org_id)
64
+ org.create_workspace(data)
65
+ end
66
+
67
+ # List all workspaces
68
+ # @param org_id [Integer] The ID of the organization to list workspaces for
69
+ # @return [Array] Array of workspaces
70
+ def self.all(org_id)
71
+ grist_res = new(org_id: org_id).list
72
+
73
+ return [] unless grist_res&.data.is_a?(Array)
74
+ return [] unless grist_res&.data&.any?
75
+
76
+ grist_res.data.map { |org| Workspace.new(org) }
77
+ end
78
+
79
+ private
80
+
81
+ # @note Method to create a new doc in workspace
82
+ # @note API: https://support.getgrist.com/api/#tag/docs/operation/createDoc
83
+ def doc_path
84
+ "/workspaces/#{@id}/docs"
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grist
4
+ module Ruby
5
+ VERSION = "0.1.1"
6
+ end
7
+ end
data/lib/grist.rb ADDED
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "logger"
5
+ require "json"
6
+ require_relative "grist/version"
7
+ require_relative "grist/rest"
8
+ require_relative "grist/accessible"
9
+ require_relative "grist/searchable"
10
+ require_relative "grist/type/base"
11
+ require_relative "grist/type/table"
12
+ require_relative "grist/type/record"
13
+ require_relative "grist/type/doc"
14
+ require_relative "grist/type/access"
15
+ require_relative "grist/type/workspace"
16
+ require_relative "grist/type/organization"
17
+ require_relative "grist/response"
18
+
19
+ module Grist
20
+ class Error < StandardError
21
+ def self.help; end
22
+ end
23
+
24
+ class NetworkError < Error; end
25
+ class APIError < Error; end
26
+
27
+ class InvalidApiKey < APIError
28
+ def self.help
29
+ "help: Ensure the GRIST_API_KEY environment variable is set and valid."
30
+ end
31
+ end
32
+
33
+ class NotFound < APIError; end
34
+
35
+ def self.logger
36
+ @logger ||= Logger.new($stdout)
37
+ end
38
+
39
+ def self.logger=(logger)
40
+ @logger = logger
41
+ end
42
+
43
+ def self.api_key
44
+ ENV["GRIST_API_KEY"]
45
+ end
46
+
47
+ def self.token_auth
48
+ "Bearer #{Grist.api_key}"
49
+ end
50
+
51
+ def self.base_api_url
52
+ base_api_url = ENV["GRIST_API_URL"]
53
+ return base_api_url[0..-2] if !base_api_url.nil? && base_api_url != "" && base_api_url.end_with?("/")
54
+
55
+ base_api_url
56
+ end
57
+
58
+ def self.localhost?
59
+ base_api_url.include?("http://localhost")
60
+ end
61
+ end