attio 0.4.0 → 0.5.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +53 -5
- data/Gemfile.lock +1 -1
- data/META_IMPLEMENTATION_PLAN.md +205 -0
- data/README.md +159 -38
- data/lib/attio/client.rb +9 -0
- data/lib/attio/enhanced_client.rb +1 -1
- data/lib/attio/resources/attributes.rb +244 -0
- data/lib/attio/resources/lists.rb +195 -0
- data/lib/attio/resources/meta.rb +133 -0
- data/lib/attio/resources/objects.rb +104 -0
- data/lib/attio/resources/records.rb +68 -0
- data/lib/attio/resources/workspaces.rb +11 -2
- data/lib/attio/version.rb +1 -1
- data/lib/attio.rb +1 -0
- metadata +3 -1
@@ -9,6 +9,20 @@ module Attio
|
|
9
9
|
#
|
10
10
|
# @example Listing attributes
|
11
11
|
# client.attributes.list(object: "people")
|
12
|
+
#
|
13
|
+
# @example Creating a custom attribute
|
14
|
+
# client.attributes.create(
|
15
|
+
# object: "deals",
|
16
|
+
# data: {
|
17
|
+
# title: "Deal Stage",
|
18
|
+
# api_slug: "deal_stage",
|
19
|
+
# type: "select",
|
20
|
+
# options: [
|
21
|
+
# { title: "Lead", value: "lead" },
|
22
|
+
# { title: "Qualified", value: "qualified" }
|
23
|
+
# ]
|
24
|
+
# }
|
25
|
+
# )
|
12
26
|
class Attributes < Base
|
13
27
|
def list(object:, **params)
|
14
28
|
validate_object!(object)
|
@@ -21,6 +35,228 @@ module Attio
|
|
21
35
|
request(:get, "objects/#{object}/attributes/#{id_or_slug}")
|
22
36
|
end
|
23
37
|
|
38
|
+
# Create a custom attribute for an object
|
39
|
+
#
|
40
|
+
# @param object [String] The object type or slug
|
41
|
+
# @param data [Hash] The attribute configuration
|
42
|
+
# @option data [String] :title The display title of the attribute
|
43
|
+
# @option data [String] :api_slug The API slug for the attribute
|
44
|
+
# @option data [String] :type The attribute type (text, number, select, date, etc.)
|
45
|
+
# @option data [String] :description Optional description
|
46
|
+
# @option data [Boolean] :is_required Whether the attribute is required
|
47
|
+
# @option data [Boolean] :is_unique Whether the attribute must be unique
|
48
|
+
# @option data [Boolean] :is_multiselect For select types, whether multiple values are allowed
|
49
|
+
# @option data [Array<Hash>] :options For select types, the available options
|
50
|
+
# @return [Hash] The created attribute
|
51
|
+
# @example Create a select attribute
|
52
|
+
# client.attributes.create(
|
53
|
+
# object: "trips",
|
54
|
+
# data: {
|
55
|
+
# title: "Status",
|
56
|
+
# api_slug: "status",
|
57
|
+
# type: "select",
|
58
|
+
# options: [
|
59
|
+
# { title: "Pending", value: "pending" },
|
60
|
+
# { title: "Active", value: "active" }
|
61
|
+
# ]
|
62
|
+
# }
|
63
|
+
# )
|
64
|
+
def create(object:, data:)
|
65
|
+
validate_object!(object)
|
66
|
+
validate_required_hash!(data, "Attribute data")
|
67
|
+
|
68
|
+
# Wrap data in the expected format
|
69
|
+
payload = { data: data }
|
70
|
+
|
71
|
+
request(:post, "objects/#{object}/attributes", payload)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Update an existing attribute
|
75
|
+
#
|
76
|
+
# @param object [String] The object type or slug
|
77
|
+
# @param id_or_slug [String] The attribute ID or API slug
|
78
|
+
# @param data [Hash] The attribute configuration updates
|
79
|
+
# @option data [String] :title The display title of the attribute
|
80
|
+
# @option data [String] :api_slug The API slug for the attribute
|
81
|
+
# @option data [String] :description Optional description
|
82
|
+
# @option data [Boolean] :is_required Whether the attribute is required
|
83
|
+
# @option data [Boolean] :is_unique Whether the attribute must be unique
|
84
|
+
# @option data [Boolean] :is_multiselect For select types, whether multiple values are allowed
|
85
|
+
# @return [Hash] The updated attribute
|
86
|
+
# @example Update an attribute's title
|
87
|
+
# client.attributes.update(
|
88
|
+
# object: "contacts",
|
89
|
+
# id_or_slug: "status",
|
90
|
+
# data: {
|
91
|
+
# title: "Contact Status",
|
92
|
+
# description: "The current status of the contact"
|
93
|
+
# }
|
94
|
+
# )
|
95
|
+
def update(object:, id_or_slug:, data:)
|
96
|
+
validate_object!(object)
|
97
|
+
validate_id_or_slug!(id_or_slug)
|
98
|
+
validate_required_hash!(data, "Attribute data")
|
99
|
+
|
100
|
+
# Wrap data in the expected format
|
101
|
+
payload = { data: data }
|
102
|
+
|
103
|
+
request(:patch, "objects/#{object}/attributes/#{id_or_slug}", payload)
|
104
|
+
end
|
105
|
+
|
106
|
+
# List options for a select attribute
|
107
|
+
#
|
108
|
+
# @param object [String] The object type or slug
|
109
|
+
# @param id_or_slug [String] The attribute ID or API slug
|
110
|
+
# @param params [Hash] Additional query parameters
|
111
|
+
# @option params [Integer] :limit Number of results to return
|
112
|
+
# @option params [Integer] :offset Number of results to skip
|
113
|
+
# @return [Hash] The list of attribute options
|
114
|
+
# @example List options for a select attribute
|
115
|
+
# client.attributes.list_options(
|
116
|
+
# object: "deals",
|
117
|
+
# id_or_slug: "deal_stage"
|
118
|
+
# )
|
119
|
+
def list_options(object:, id_or_slug:, **params)
|
120
|
+
validate_object!(object)
|
121
|
+
validate_id_or_slug!(id_or_slug)
|
122
|
+
request(:get, "objects/#{object}/attributes/#{id_or_slug}/options", params)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Create a new option for a select attribute
|
126
|
+
#
|
127
|
+
# @param object [String] The object type or slug
|
128
|
+
# @param id_or_slug [String] The attribute ID or API slug
|
129
|
+
# @param data [Hash] The option configuration
|
130
|
+
# @option data [String] :title The display title of the option
|
131
|
+
# @option data [String] :value The value of the option
|
132
|
+
# @option data [String] :color Optional color for the option
|
133
|
+
# @option data [Integer] :order Optional order for the option
|
134
|
+
# @return [Hash] The created option
|
135
|
+
# @example Create a new option
|
136
|
+
# client.attributes.create_option(
|
137
|
+
# object: "deals",
|
138
|
+
# id_or_slug: "deal_stage",
|
139
|
+
# data: {
|
140
|
+
# title: "Negotiation",
|
141
|
+
# value: "negotiation",
|
142
|
+
# color: "blue"
|
143
|
+
# }
|
144
|
+
# )
|
145
|
+
def create_option(object:, id_or_slug:, data:)
|
146
|
+
validate_object!(object)
|
147
|
+
validate_id_or_slug!(id_or_slug)
|
148
|
+
validate_required_hash!(data, "Option data")
|
149
|
+
|
150
|
+
request(:post, "objects/#{object}/attributes/#{id_or_slug}/options", data)
|
151
|
+
end
|
152
|
+
|
153
|
+
# Update an option for a select attribute
|
154
|
+
#
|
155
|
+
# @param object [String] The object type or slug
|
156
|
+
# @param id_or_slug [String] The attribute ID or API slug
|
157
|
+
# @param option [String] The option ID or value
|
158
|
+
# @param data [Hash] The option configuration updates
|
159
|
+
# @option data [String] :title The display title of the option
|
160
|
+
# @option data [String] :value The value of the option
|
161
|
+
# @option data [String] :color Optional color for the option
|
162
|
+
# @option data [Integer] :order Optional order for the option
|
163
|
+
# @return [Hash] The updated option
|
164
|
+
# @example Update an option's title
|
165
|
+
# client.attributes.update_option(
|
166
|
+
# object: "deals",
|
167
|
+
# id_or_slug: "deal_stage",
|
168
|
+
# option: "negotiation",
|
169
|
+
# data: {
|
170
|
+
# title: "In Negotiation",
|
171
|
+
# color: "orange"
|
172
|
+
# }
|
173
|
+
# )
|
174
|
+
def update_option(object:, id_or_slug:, option:, data:)
|
175
|
+
validate_object!(object)
|
176
|
+
validate_id_or_slug!(id_or_slug)
|
177
|
+
validate_option_id!(option)
|
178
|
+
validate_required_hash!(data, "Option data")
|
179
|
+
|
180
|
+
request(:patch, "objects/#{object}/attributes/#{id_or_slug}/options/#{option}", data)
|
181
|
+
end
|
182
|
+
|
183
|
+
# List statuses for a status attribute
|
184
|
+
#
|
185
|
+
# @param object [String] The object type or slug
|
186
|
+
# @param id_or_slug [String] The attribute ID or API slug
|
187
|
+
# @param params [Hash] Additional query parameters
|
188
|
+
# @option params [Integer] :limit Number of results to return
|
189
|
+
# @option params [Integer] :offset Number of results to skip
|
190
|
+
# @return [Hash] The list of attribute statuses
|
191
|
+
# @example List statuses for a status attribute
|
192
|
+
# client.attributes.list_statuses(
|
193
|
+
# object: "deals",
|
194
|
+
# id_or_slug: "deal_status"
|
195
|
+
# )
|
196
|
+
def list_statuses(object:, id_or_slug:, **params)
|
197
|
+
validate_object!(object)
|
198
|
+
validate_id_or_slug!(id_or_slug)
|
199
|
+
request(:get, "objects/#{object}/attributes/#{id_or_slug}/statuses", params)
|
200
|
+
end
|
201
|
+
|
202
|
+
# Create a new status for a status attribute
|
203
|
+
#
|
204
|
+
# @param object [String] The object type or slug
|
205
|
+
# @param id_or_slug [String] The attribute ID or API slug
|
206
|
+
# @param data [Hash] The status configuration
|
207
|
+
# @option data [String] :title The display title of the status
|
208
|
+
# @option data [String] :value The value of the status
|
209
|
+
# @option data [String] :color Optional color for the status
|
210
|
+
# @option data [Integer] :order Optional order for the status
|
211
|
+
# @return [Hash] The created status
|
212
|
+
# @example Create a new status
|
213
|
+
# client.attributes.create_status(
|
214
|
+
# object: "deals",
|
215
|
+
# id_or_slug: "deal_status",
|
216
|
+
# data: {
|
217
|
+
# title: "Under Review",
|
218
|
+
# value: "under_review",
|
219
|
+
# color: "yellow"
|
220
|
+
# }
|
221
|
+
# )
|
222
|
+
def create_status(object:, id_or_slug:, data:)
|
223
|
+
validate_object!(object)
|
224
|
+
validate_id_or_slug!(id_or_slug)
|
225
|
+
validate_required_hash!(data, "Status data")
|
226
|
+
|
227
|
+
request(:post, "objects/#{object}/attributes/#{id_or_slug}/statuses", data)
|
228
|
+
end
|
229
|
+
|
230
|
+
# Update a status for a status attribute
|
231
|
+
#
|
232
|
+
# @param object [String] The object type or slug
|
233
|
+
# @param id_or_slug [String] The attribute ID or API slug
|
234
|
+
# @param status [String] The status ID or value
|
235
|
+
# @param data [Hash] The status configuration updates
|
236
|
+
# @option data [String] :title The display title of the status
|
237
|
+
# @option data [String] :value The value of the status
|
238
|
+
# @option data [String] :color Optional color for the status
|
239
|
+
# @option data [Integer] :order Optional order for the status
|
240
|
+
# @return [Hash] The updated status
|
241
|
+
# @example Update a status's title
|
242
|
+
# client.attributes.update_status(
|
243
|
+
# object: "deals",
|
244
|
+
# id_or_slug: "deal_status",
|
245
|
+
# status: "under_review",
|
246
|
+
# data: {
|
247
|
+
# title: "Pending Review",
|
248
|
+
# color: "orange"
|
249
|
+
# }
|
250
|
+
# )
|
251
|
+
def update_status(object:, id_or_slug:, status:, data:)
|
252
|
+
validate_object!(object)
|
253
|
+
validate_id_or_slug!(id_or_slug)
|
254
|
+
validate_status_id!(status)
|
255
|
+
validate_required_hash!(data, "Status data")
|
256
|
+
|
257
|
+
request(:patch, "objects/#{object}/attributes/#{id_or_slug}/statuses/#{status}", data)
|
258
|
+
end
|
259
|
+
|
24
260
|
private def validate_object!(object)
|
25
261
|
raise ArgumentError, "Object type is required" if object.nil? || object.to_s.strip.empty?
|
26
262
|
end
|
@@ -28,6 +264,14 @@ module Attio
|
|
28
264
|
private def validate_id_or_slug!(id_or_slug)
|
29
265
|
raise ArgumentError, "Attribute ID or slug is required" if id_or_slug.nil? || id_or_slug.to_s.strip.empty?
|
30
266
|
end
|
267
|
+
|
268
|
+
private def validate_option_id!(option)
|
269
|
+
raise ArgumentError, "Option ID is required" if option.nil? || option.to_s.strip.empty?
|
270
|
+
end
|
271
|
+
|
272
|
+
private def validate_status_id!(status)
|
273
|
+
raise ArgumentError, "Status ID is required" if status.nil? || status.to_s.strip.empty?
|
274
|
+
end
|
31
275
|
end
|
32
276
|
end
|
33
277
|
end
|
@@ -44,10 +44,205 @@ module Attio
|
|
44
44
|
request(:delete, "lists/#{list_id}/entries/#{entry_id}")
|
45
45
|
end
|
46
46
|
|
47
|
+
# Create a new list.
|
48
|
+
#
|
49
|
+
# Creates a new list with the specified configuration. The list can be
|
50
|
+
# associated with a parent object type and configured with various options.
|
51
|
+
#
|
52
|
+
# @param data [Hash] The list configuration data
|
53
|
+
# @option data [String] :name The name of the list (required)
|
54
|
+
# @option data [String] :parent_object The parent object type for the list
|
55
|
+
# @option data [Boolean] :is_public Whether the list is publicly accessible
|
56
|
+
# @option data [String] :description Optional description for the list
|
57
|
+
#
|
58
|
+
# @return [Hash] The created list data
|
59
|
+
# @raise [ArgumentError] if data is invalid
|
60
|
+
#
|
61
|
+
# @example Create a simple list
|
62
|
+
# list = client.lists.create(
|
63
|
+
# data: {
|
64
|
+
# name: "VIP Customers",
|
65
|
+
# parent_object: "people",
|
66
|
+
# is_public: true
|
67
|
+
# }
|
68
|
+
# )
|
69
|
+
def create(data:)
|
70
|
+
validate_list_data!(data)
|
71
|
+
request(:post, "lists", { data: data })
|
72
|
+
end
|
73
|
+
|
74
|
+
# Update an existing list.
|
75
|
+
#
|
76
|
+
# Updates the configuration of an existing list. You can modify the name,
|
77
|
+
# description, visibility, and other list properties.
|
78
|
+
#
|
79
|
+
# @param id_or_slug [String] The list ID or slug
|
80
|
+
# @param data [Hash] The list configuration updates
|
81
|
+
# @option data [String] :name New name for the list
|
82
|
+
# @option data [Boolean] :is_public New visibility setting
|
83
|
+
# @option data [String] :description New description for the list
|
84
|
+
#
|
85
|
+
# @return [Hash] The updated list data
|
86
|
+
# @raise [ArgumentError] if id_or_slug or data is invalid
|
87
|
+
#
|
88
|
+
# @example Update list name and visibility
|
89
|
+
# list = client.lists.update(
|
90
|
+
# id_or_slug: "list_123",
|
91
|
+
# data: {
|
92
|
+
# name: "Premium Customers",
|
93
|
+
# is_public: false
|
94
|
+
# }
|
95
|
+
# )
|
96
|
+
def update(id_or_slug:, data:)
|
97
|
+
validate_id!(id_or_slug, "List")
|
98
|
+
validate_list_data!(data)
|
99
|
+
request(:patch, "lists/#{id_or_slug}", { data: data })
|
100
|
+
end
|
101
|
+
|
102
|
+
# Query list entries with advanced filtering and sorting.
|
103
|
+
#
|
104
|
+
# Provides advanced querying capabilities for list entries, supporting
|
105
|
+
# complex filters, sorting, and pagination. This is more powerful than
|
106
|
+
# the basic entries method as it supports structured queries.
|
107
|
+
#
|
108
|
+
# @param id_or_slug [String] The list ID or slug
|
109
|
+
# @param filter [Hash, String, nil] Optional filter criteria for querying entries
|
110
|
+
# @param sort [Hash, Array, String, nil] Optional sorting configuration
|
111
|
+
# @param limit [Integer, nil] Maximum number of entries to return
|
112
|
+
# @param offset [Integer, nil] Number of entries to skip for pagination
|
113
|
+
#
|
114
|
+
# @return [Hash] Query results with entries and pagination info
|
115
|
+
# @raise [ArgumentError] if id_or_slug is invalid
|
116
|
+
#
|
117
|
+
# @example Query with filters
|
118
|
+
# entries = client.lists.query_entries(
|
119
|
+
# id_or_slug: "vip_customers",
|
120
|
+
# filter: { created_at: { gte: "2023-01-01" } },
|
121
|
+
# sort: { created_at: "desc" },
|
122
|
+
# limit: 50
|
123
|
+
# )
|
124
|
+
#
|
125
|
+
# @example Query all entries without filters
|
126
|
+
# entries = client.lists.query_entries(id_or_slug: "list_123")
|
127
|
+
def query_entries(id_or_slug:, filter: nil, sort: nil, limit: nil, offset: nil)
|
128
|
+
validate_id!(id_or_slug, "List")
|
129
|
+
|
130
|
+
query_params = build_query_params({
|
131
|
+
filter: filter,
|
132
|
+
sort: sort,
|
133
|
+
limit: limit,
|
134
|
+
offset: offset,
|
135
|
+
})
|
136
|
+
|
137
|
+
request(:post, "lists/#{id_or_slug}/entries/query", query_params)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Assert (upsert) a list entry.
|
141
|
+
#
|
142
|
+
# Creates or updates a list entry based on a matching attribute. This is an
|
143
|
+
# upsert operation that will create a new entry if no match is found, or update
|
144
|
+
# an existing entry if a match is found based on the specified matching attribute.
|
145
|
+
#
|
146
|
+
# Required scopes: list_entry:read-write, list_configuration:read
|
147
|
+
#
|
148
|
+
# @param id_or_slug [String] The list ID or slug
|
149
|
+
# @param matching_attribute [String] The attribute to match against for upsert
|
150
|
+
# @param data [Hash] The entry data to create or update
|
151
|
+
# @option data [String] :record_id The ID of the record to add to the list
|
152
|
+
# @option data [Hash] :values Optional field values for the entry
|
153
|
+
# @option data [String] :notes Optional notes for the entry
|
154
|
+
#
|
155
|
+
# @return [Hash] The created or updated entry data
|
156
|
+
# @raise [ArgumentError] if parameters are invalid
|
157
|
+
#
|
158
|
+
# @example Assert entry with record ID
|
159
|
+
# entry = client.lists.assert_entry(
|
160
|
+
# id_or_slug: "vip_customers",
|
161
|
+
# matching_attribute: "record_id",
|
162
|
+
# data: {
|
163
|
+
# record_id: "rec_123",
|
164
|
+
# values: { priority: "high" },
|
165
|
+
# notes: "Premium customer"
|
166
|
+
# }
|
167
|
+
# )
|
168
|
+
#
|
169
|
+
# @example Assert entry with custom matching
|
170
|
+
# entry = client.lists.assert_entry(
|
171
|
+
# id_or_slug: "lead_list",
|
172
|
+
# matching_attribute: "email",
|
173
|
+
# data: {
|
174
|
+
# email: "john@example.com",
|
175
|
+
# values: { status: "qualified" }
|
176
|
+
# }
|
177
|
+
# )
|
178
|
+
def assert_entry(id_or_slug:, matching_attribute:, data:)
|
179
|
+
validate_id!(id_or_slug, "List")
|
180
|
+
validate_required_string!(matching_attribute, "Matching attribute")
|
181
|
+
validate_list_entry_data!(data)
|
182
|
+
|
183
|
+
request_body = {
|
184
|
+
data: data,
|
185
|
+
matching_attribute: matching_attribute,
|
186
|
+
}
|
187
|
+
|
188
|
+
request(:put, "lists/#{id_or_slug}/entries", request_body)
|
189
|
+
end
|
190
|
+
|
191
|
+
# Update an existing list entry.
|
192
|
+
#
|
193
|
+
# Updates the data for an existing list entry. This method requires the
|
194
|
+
# entry ID and will update only the provided fields, leaving other fields
|
195
|
+
# unchanged.
|
196
|
+
#
|
197
|
+
# @param id_or_slug [String] The list ID or slug
|
198
|
+
# @param entry_id [String] The entry ID to update
|
199
|
+
# @param data [Hash] The entry data to update
|
200
|
+
# @option data [Hash] :values Field values to update
|
201
|
+
# @option data [String] :notes Updated notes for the entry
|
202
|
+
#
|
203
|
+
# @return [Hash] The updated entry data
|
204
|
+
# @raise [ArgumentError] if parameters are invalid
|
205
|
+
#
|
206
|
+
# @example Update entry values
|
207
|
+
# entry = client.lists.update_entry(
|
208
|
+
# id_or_slug: "vip_customers",
|
209
|
+
# entry_id: "ent_456",
|
210
|
+
# data: {
|
211
|
+
# values: { priority: "medium", last_contacted: "2024-01-15" },
|
212
|
+
# notes: "Updated contact information"
|
213
|
+
# }
|
214
|
+
# )
|
215
|
+
#
|
216
|
+
# @example Update only notes
|
217
|
+
# entry = client.lists.update_entry(
|
218
|
+
# id_or_slug: "lead_list",
|
219
|
+
# entry_id: "ent_789",
|
220
|
+
# data: { notes: "Follow up scheduled" }
|
221
|
+
# )
|
222
|
+
def update_entry(id_or_slug:, entry_id:, data:)
|
223
|
+
validate_id!(id_or_slug, "List")
|
224
|
+
validate_id!(entry_id, "Entry")
|
225
|
+
validate_list_entry_data!(data)
|
226
|
+
|
227
|
+
request_body = { data: data }
|
228
|
+
|
229
|
+
request(:patch, "lists/#{id_or_slug}/entries/#{entry_id}", request_body)
|
230
|
+
end
|
231
|
+
|
47
232
|
private def validate_list_entry_data!(data)
|
48
233
|
raise ArgumentError, "Data is required" if data.nil?
|
49
234
|
raise ArgumentError, "Data must be a hash" unless data.is_a?(Hash)
|
50
235
|
end
|
236
|
+
|
237
|
+
# Validates that the list data parameter is present and valid.
|
238
|
+
#
|
239
|
+
# @param data [Hash, nil] The data to validate
|
240
|
+
# @raise [ArgumentError] if data is nil or not a hash
|
241
|
+
# @api private
|
242
|
+
private def validate_list_data!(data)
|
243
|
+
raise ArgumentError, "Data is required" if data.nil?
|
244
|
+
raise ArgumentError, "Data must be a hash" unless data.is_a?(Hash)
|
245
|
+
end
|
51
246
|
end
|
52
247
|
end
|
53
248
|
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Attio
|
4
|
+
module Resources
|
5
|
+
# Meta resource for getting information about the API token and workspace
|
6
|
+
#
|
7
|
+
# The Meta resource provides a single endpoint (/v2/self) that returns
|
8
|
+
# information about the current access token, workspace, and permissions.
|
9
|
+
#
|
10
|
+
# @example Get token and workspace information
|
11
|
+
# meta_info = client.meta.identify
|
12
|
+
# puts "Workspace: #{meta_info['data']['workspace_name']}"
|
13
|
+
# puts "Token active: #{meta_info['data']['active']}"
|
14
|
+
#
|
15
|
+
# @example Check if token is active
|
16
|
+
# if client.meta.active?
|
17
|
+
# puts "Token is valid and active"
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# @example Get workspace details
|
21
|
+
# workspace = client.meta.workspace
|
22
|
+
# puts "Working in: #{workspace['name']} (#{workspace['id']})"
|
23
|
+
#
|
24
|
+
# @example Check permissions
|
25
|
+
# if client.meta.permission?("record_permission:read-write")
|
26
|
+
# # Can read and write records
|
27
|
+
# end
|
28
|
+
class Meta < Base
|
29
|
+
# Get information about the current access token and workspace
|
30
|
+
#
|
31
|
+
# This is the primary method that calls the /v2/self endpoint.
|
32
|
+
# Returns full token metadata including workspace info and permissions.
|
33
|
+
#
|
34
|
+
# @return [Hash] Token and workspace information
|
35
|
+
# @example
|
36
|
+
# info = client.meta.identify
|
37
|
+
# # => { "data" => { "active" => true, "workspace_name" => "My Workspace", ... } }
|
38
|
+
def identify
|
39
|
+
request(:get, "self")
|
40
|
+
end
|
41
|
+
|
42
|
+
# Alias methods for convenience and clarity
|
43
|
+
alias self identify
|
44
|
+
alias get identify
|
45
|
+
|
46
|
+
# Check if the current token is active
|
47
|
+
#
|
48
|
+
# @return [Boolean] true if token is active, false otherwise
|
49
|
+
# @example
|
50
|
+
# if client.meta.active?
|
51
|
+
# # Proceed with API calls
|
52
|
+
# else
|
53
|
+
# # Token is inactive or invalid
|
54
|
+
# end
|
55
|
+
def active?
|
56
|
+
response = identify
|
57
|
+
response.dig("data", "active") || false
|
58
|
+
end
|
59
|
+
|
60
|
+
# Get the workspace information
|
61
|
+
#
|
62
|
+
# Returns workspace details if token is active, nil otherwise.
|
63
|
+
#
|
64
|
+
# @return [Hash, nil] Workspace details or nil if token inactive
|
65
|
+
# @example
|
66
|
+
# workspace = client.meta.workspace
|
67
|
+
# # => { "id" => "uuid", "name" => "My Workspace", "slug" => "my-workspace", "logo_url" => nil }
|
68
|
+
def workspace
|
69
|
+
response = identify
|
70
|
+
return nil unless response.dig("data", "active")
|
71
|
+
|
72
|
+
{
|
73
|
+
"id" => response.dig("data", "workspace_id"),
|
74
|
+
"name" => response.dig("data", "workspace_name"),
|
75
|
+
"slug" => response.dig("data", "workspace_slug"),
|
76
|
+
"logo_url" => response.dig("data", "workspace_logo_url"),
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
# Get the token's permissions/scopes
|
81
|
+
#
|
82
|
+
# Parses the space-separated scope string into an array.
|
83
|
+
#
|
84
|
+
# @return [Array<String>] List of permission scopes
|
85
|
+
# @example
|
86
|
+
# permissions = client.meta.permissions
|
87
|
+
# # => ["comment:read-write", "list_configuration:read", "note:read-write"]
|
88
|
+
def permissions
|
89
|
+
response = identify
|
90
|
+
scope = response.dig("data", "scope") || ""
|
91
|
+
scope.split
|
92
|
+
end
|
93
|
+
|
94
|
+
# Check if token has a specific permission
|
95
|
+
#
|
96
|
+
# @param permission [String] The permission to check (e.g., "comment:read-write")
|
97
|
+
# @return [Boolean] true if permission is granted
|
98
|
+
# @example
|
99
|
+
# if client.meta.permission?("record_permission:read-write")
|
100
|
+
# # Can manage records
|
101
|
+
# end
|
102
|
+
def permission?(permission)
|
103
|
+
permissions.include?(permission)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Alias for backward compatibility
|
107
|
+
alias has_permission? permission?
|
108
|
+
|
109
|
+
# Get token expiration and metadata
|
110
|
+
#
|
111
|
+
# Returns detailed token information including expiration,
|
112
|
+
# issue time, client ID, and who authorized it.
|
113
|
+
#
|
114
|
+
# @return [Hash] Token metadata
|
115
|
+
# @example
|
116
|
+
# info = client.meta.token_info
|
117
|
+
# # => { "active" => true, "type" => "Bearer", "expires_at" => nil, ... }
|
118
|
+
def token_info
|
119
|
+
response = identify
|
120
|
+
return { "active" => false } unless response.dig("data", "active")
|
121
|
+
|
122
|
+
{
|
123
|
+
"active" => true,
|
124
|
+
"type" => response.dig("data", "token_type"),
|
125
|
+
"expires_at" => response.dig("data", "exp"),
|
126
|
+
"issued_at" => response.dig("data", "iat"),
|
127
|
+
"client_id" => response.dig("data", "client_id"),
|
128
|
+
"authorized_by" => response.dig("data", "authorized_by_workspace_member_id"),
|
129
|
+
}
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|