attio 0.1.3 → 0.3.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/.github/workflows/release.yml +3 -51
- data/CHANGELOG.md +62 -1
- data/CLAUDE.md +360 -0
- data/CONCEPTS.md +428 -0
- data/Gemfile.lock +3 -1
- data/README.md +304 -7
- data/examples/advanced_filtering.rb +178 -0
- data/examples/basic_usage.rb +110 -0
- data/examples/collaboration_example.rb +173 -0
- data/examples/full_workflow.rb +348 -0
- data/examples/notes_and_tasks.rb +200 -0
- data/lib/attio/client.rb +86 -0
- data/lib/attio/errors.rb +30 -2
- data/lib/attio/http_client.rb +16 -4
- data/lib/attio/rate_limiter.rb +212 -0
- data/lib/attio/resources/base.rb +70 -6
- data/lib/attio/resources/bulk.rb +290 -0
- data/lib/attio/resources/comments.rb +147 -0
- data/lib/attio/resources/deals.rb +183 -0
- data/lib/attio/resources/lists.rb +9 -21
- data/lib/attio/resources/meta.rb +72 -0
- data/lib/attio/resources/notes.rb +110 -0
- data/lib/attio/resources/records.rb +11 -24
- data/lib/attio/resources/tasks.rb +131 -0
- data/lib/attio/resources/threads.rb +154 -0
- data/lib/attio/resources/workspace_members.rb +103 -0
- data/lib/attio/version.rb +1 -1
- data/lib/attio.rb +9 -0
- metadata +17 -1
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Attio
|
4
|
+
module Resources
|
5
|
+
# Meta resource for API metadata and identification
|
6
|
+
#
|
7
|
+
# @example Identify the current API key
|
8
|
+
# client.meta.identify
|
9
|
+
# # => { "workspace" => { "id" => "...", "name" => "..." }, "user" => { ... } }
|
10
|
+
#
|
11
|
+
# @example Get API status
|
12
|
+
# client.meta.status
|
13
|
+
# # => { "status" => "operational", "version" => "v2" }
|
14
|
+
class Meta < Base
|
15
|
+
# Identify the current API key and get workspace/user information
|
16
|
+
#
|
17
|
+
# @return [Hash] Information about the authenticated workspace and user
|
18
|
+
def identify
|
19
|
+
request(:get, "meta/identify")
|
20
|
+
end
|
21
|
+
|
22
|
+
# Get API status and version information
|
23
|
+
#
|
24
|
+
# @return [Hash] API status and version details
|
25
|
+
def status
|
26
|
+
request(:get, "meta/status")
|
27
|
+
end
|
28
|
+
|
29
|
+
# Get rate limit information for the current API key
|
30
|
+
#
|
31
|
+
# @return [Hash] Current rate limit status
|
32
|
+
def rate_limits
|
33
|
+
request(:get, "meta/rate_limits")
|
34
|
+
end
|
35
|
+
|
36
|
+
# Get workspace configuration and settings
|
37
|
+
#
|
38
|
+
# @return [Hash] Workspace configuration details
|
39
|
+
def workspace_config
|
40
|
+
request(:get, "meta/workspace_config")
|
41
|
+
end
|
42
|
+
|
43
|
+
# Validate an API key without making changes
|
44
|
+
#
|
45
|
+
# @return [Hash] Validation result with key permissions
|
46
|
+
def validate_key
|
47
|
+
request(:post, "meta/validate", {})
|
48
|
+
end
|
49
|
+
|
50
|
+
# Get available API endpoints and their documentation
|
51
|
+
#
|
52
|
+
# @return [Hash] List of available endpoints with descriptions
|
53
|
+
def endpoints
|
54
|
+
request(:get, "meta/endpoints")
|
55
|
+
end
|
56
|
+
|
57
|
+
# Get workspace usage statistics
|
58
|
+
#
|
59
|
+
# @return [Hash] Usage statistics including record counts, API calls, etc.
|
60
|
+
def usage_stats
|
61
|
+
request(:get, "meta/usage")
|
62
|
+
end
|
63
|
+
|
64
|
+
# Get feature flags and capabilities for the workspace
|
65
|
+
#
|
66
|
+
# @return [Hash] Enabled features and capabilities
|
67
|
+
def features
|
68
|
+
request(:get, "meta/features")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Attio
|
4
|
+
module Resources
|
5
|
+
# API resource for managing notes in Attio
|
6
|
+
#
|
7
|
+
# Notes can be attached to records to track important information,
|
8
|
+
# meeting notes, or any other textual data.
|
9
|
+
#
|
10
|
+
# @example Creating a note on a person
|
11
|
+
# client.notes.create(
|
12
|
+
# parent_object: "people",
|
13
|
+
# parent_record_id: "person_123",
|
14
|
+
# title: "Meeting Notes",
|
15
|
+
# content: "Discussed Q4 goals..."
|
16
|
+
# )
|
17
|
+
#
|
18
|
+
# @example Listing notes for a record
|
19
|
+
# client.notes.list(
|
20
|
+
# parent_object: "companies",
|
21
|
+
# parent_record_id: "company_456"
|
22
|
+
# )
|
23
|
+
class Notes < Base
|
24
|
+
# List notes for a specific parent record
|
25
|
+
#
|
26
|
+
# @param parent_object [String] The parent object type (e.g., "people", "companies")
|
27
|
+
# @param parent_record_id [String] The ID of the parent record
|
28
|
+
# @param params [Hash] Additional query parameters
|
29
|
+
# @option params [Integer] :limit Number of notes to return
|
30
|
+
# @option params [String] :cursor Pagination cursor
|
31
|
+
#
|
32
|
+
# @return [Hash] API response containing notes
|
33
|
+
# @raise [ArgumentError] if parent_object or parent_record_id is nil
|
34
|
+
def list(parent_object:, parent_record_id:, **params)
|
35
|
+
validate_parent!(parent_object, parent_record_id)
|
36
|
+
request(:get, "notes", params.merge(
|
37
|
+
parent_object: parent_object,
|
38
|
+
parent_record_id: parent_record_id
|
39
|
+
))
|
40
|
+
end
|
41
|
+
|
42
|
+
# Get a specific note by ID
|
43
|
+
#
|
44
|
+
# @param id [String] The note ID
|
45
|
+
#
|
46
|
+
# @return [Hash] The note data
|
47
|
+
# @raise [ArgumentError] if id is nil or empty
|
48
|
+
def get(id:)
|
49
|
+
validate_id!(id, "Note")
|
50
|
+
request(:get, "notes/#{id}")
|
51
|
+
end
|
52
|
+
|
53
|
+
# Create a new note
|
54
|
+
#
|
55
|
+
# @param parent_object [String] The parent object type
|
56
|
+
# @param parent_record_id [String] The ID of the parent record
|
57
|
+
# @param title [String] The note title
|
58
|
+
# @param content [String] The note content (supports markdown)
|
59
|
+
# @param data [Hash] Additional note data
|
60
|
+
#
|
61
|
+
# @return [Hash] The created note
|
62
|
+
# @raise [ArgumentError] if required parameters are missing
|
63
|
+
def create(parent_object:, parent_record_id:, title:, content:, **data)
|
64
|
+
validate_parent!(parent_object, parent_record_id)
|
65
|
+
validate_required_string!(title, "Note title")
|
66
|
+
validate_required_string!(content, "Note content")
|
67
|
+
|
68
|
+
request(:post, "notes", data.merge(
|
69
|
+
parent_object: parent_object,
|
70
|
+
parent_record_id: parent_record_id,
|
71
|
+
title: title,
|
72
|
+
content: content
|
73
|
+
))
|
74
|
+
end
|
75
|
+
|
76
|
+
# Update an existing note
|
77
|
+
#
|
78
|
+
# @param id [String] The note ID
|
79
|
+
# @param data [Hash] The fields to update
|
80
|
+
# @option data [String] :title New title
|
81
|
+
# @option data [String] :content New content
|
82
|
+
#
|
83
|
+
# @return [Hash] The updated note
|
84
|
+
# @raise [ArgumentError] if id or data is invalid
|
85
|
+
def update(id:, **data)
|
86
|
+
validate_id!(id, "Note")
|
87
|
+
validate_note_update_data!(data)
|
88
|
+
request(:patch, "notes/#{id}", data)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Delete a note
|
92
|
+
#
|
93
|
+
# @param id [String] The note ID to delete
|
94
|
+
#
|
95
|
+
# @return [Hash] Deletion confirmation
|
96
|
+
# @raise [ArgumentError] if id is nil or empty
|
97
|
+
def delete(id:)
|
98
|
+
validate_id!(id, "Note")
|
99
|
+
request(:delete, "notes/#{id}")
|
100
|
+
end
|
101
|
+
|
102
|
+
private def validate_note_update_data!(data)
|
103
|
+
raise ArgumentError, "Update data is required" if data.empty?
|
104
|
+
return if data.key?(:title) || data.key?(:content)
|
105
|
+
|
106
|
+
raise ArgumentError, "Must provide title or content to update"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -45,7 +45,7 @@ module Attio
|
|
45
45
|
# limit: 50
|
46
46
|
# )
|
47
47
|
def list(object:, **params)
|
48
|
-
|
48
|
+
validate_required_string!(object, "Object type")
|
49
49
|
request(:post, "objects/#{object}/records/query", params)
|
50
50
|
end
|
51
51
|
|
@@ -60,8 +60,8 @@ module Attio
|
|
60
60
|
# @example
|
61
61
|
# record = client.records.get(object: 'people', id: 'abc123')
|
62
62
|
def get(object:, id:)
|
63
|
-
|
64
|
-
validate_id!(id)
|
63
|
+
validate_required_string!(object, "Object type")
|
64
|
+
validate_id!(id, "Record")
|
65
65
|
request(:get, "objects/#{object}/records/#{id}")
|
66
66
|
end
|
67
67
|
|
@@ -83,8 +83,8 @@ module Attio
|
|
83
83
|
# }
|
84
84
|
# )
|
85
85
|
def create(object:, data:)
|
86
|
-
|
87
|
-
|
86
|
+
validate_required_string!(object, "Object type")
|
87
|
+
validate_record_data!(data)
|
88
88
|
request(:post, "objects/#{object}/records", data)
|
89
89
|
end
|
90
90
|
|
@@ -104,9 +104,9 @@ module Attio
|
|
104
104
|
# data: { name: 'Jane Smith' }
|
105
105
|
# )
|
106
106
|
def update(object:, id:, data:)
|
107
|
-
|
108
|
-
validate_id!(id)
|
109
|
-
|
107
|
+
validate_required_string!(object, "Object type")
|
108
|
+
validate_id!(id, "Record")
|
109
|
+
validate_record_data!(data)
|
110
110
|
request(:patch, "objects/#{object}/records/#{id}", data)
|
111
111
|
end
|
112
112
|
|
@@ -121,30 +121,17 @@ module Attio
|
|
121
121
|
# @example
|
122
122
|
# client.records.delete(object: 'people', id: 'abc123')
|
123
123
|
def delete(object:, id:)
|
124
|
-
|
125
|
-
validate_id!(id)
|
124
|
+
validate_required_string!(object, "Object type")
|
125
|
+
validate_id!(id, "Record")
|
126
126
|
request(:delete, "objects/#{object}/records/#{id}")
|
127
127
|
end
|
128
128
|
|
129
|
-
private def validate_object!(object)
|
130
|
-
raise ArgumentError, "Object type is required" if object.nil? || object.to_s.strip.empty?
|
131
|
-
end
|
132
|
-
|
133
|
-
# Validates that the ID parameter is present and not empty.
|
134
|
-
#
|
135
|
-
# @param id [String, nil] The record ID to validate
|
136
|
-
# @raise [ArgumentError] if id is nil or empty
|
137
|
-
# @api private
|
138
|
-
private def validate_id!(id)
|
139
|
-
raise ArgumentError, "Record ID is required" if id.nil? || id.to_s.strip.empty?
|
140
|
-
end
|
141
|
-
|
142
129
|
# Validates that the data parameter is present and is a hash.
|
143
130
|
#
|
144
131
|
# @param data [Hash, nil] The data to validate
|
145
132
|
# @raise [ArgumentError] if data is nil or not a hash
|
146
133
|
# @api private
|
147
|
-
private def
|
134
|
+
private def validate_record_data!(data)
|
148
135
|
raise ArgumentError, "Data is required" if data.nil?
|
149
136
|
raise ArgumentError, "Data must be a hash" unless data.is_a?(Hash)
|
150
137
|
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Attio
|
4
|
+
module Resources
|
5
|
+
# API resource for managing tasks in Attio
|
6
|
+
#
|
7
|
+
# Tasks help track action items and to-dos associated with records.
|
8
|
+
#
|
9
|
+
# @example Creating a task
|
10
|
+
# client.tasks.create(
|
11
|
+
# parent_object: "people",
|
12
|
+
# parent_record_id: "person_123",
|
13
|
+
# title: "Follow up on proposal",
|
14
|
+
# due_date: "2025-02-01",
|
15
|
+
# assignee_id: "user_456"
|
16
|
+
# )
|
17
|
+
#
|
18
|
+
# @example Listing tasks with filters
|
19
|
+
# client.tasks.list(
|
20
|
+
# status: "pending",
|
21
|
+
# assignee_id: "user_456"
|
22
|
+
# )
|
23
|
+
class Tasks < Base
|
24
|
+
# List tasks with optional filters
|
25
|
+
#
|
26
|
+
# @param params [Hash] Query parameters
|
27
|
+
# @option params [String] :parent_object Filter by parent object type
|
28
|
+
# @option params [String] :parent_record_id Filter by parent record
|
29
|
+
# @option params [String] :status Filter by status (pending, completed)
|
30
|
+
# @option params [String] :assignee_id Filter by assignee
|
31
|
+
# @option params [Integer] :limit Number of tasks to return
|
32
|
+
# @option params [String] :cursor Pagination cursor
|
33
|
+
#
|
34
|
+
# @return [Hash] API response containing tasks
|
35
|
+
def list(**params)
|
36
|
+
request(:get, "tasks", params)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Get a specific task by ID
|
40
|
+
#
|
41
|
+
# @param id [String] The task ID
|
42
|
+
#
|
43
|
+
# @return [Hash] The task data
|
44
|
+
# @raise [ArgumentError] if id is nil or empty
|
45
|
+
def get(id:)
|
46
|
+
validate_id!(id, "Task")
|
47
|
+
request(:get, "tasks/#{id}")
|
48
|
+
end
|
49
|
+
|
50
|
+
# Create a new task
|
51
|
+
#
|
52
|
+
# @param parent_object [String] The parent object type
|
53
|
+
# @param parent_record_id [String] The ID of the parent record
|
54
|
+
# @param title [String] The task title
|
55
|
+
# @param data [Hash] Additional task data
|
56
|
+
# @option data [String] :description Task description
|
57
|
+
# @option data [String] :due_date Due date (ISO 8601 format)
|
58
|
+
# @option data [String] :assignee_id User ID to assign the task to
|
59
|
+
# @option data [String] :status Task status (pending, completed)
|
60
|
+
# @option data [Integer] :priority Task priority (1-5)
|
61
|
+
#
|
62
|
+
# @return [Hash] The created task
|
63
|
+
# @raise [ArgumentError] if required parameters are missing
|
64
|
+
def create(parent_object:, parent_record_id:, title:, **data)
|
65
|
+
validate_parent!(parent_object, parent_record_id)
|
66
|
+
validate_required_string!(title, "Task title")
|
67
|
+
|
68
|
+
request(:post, "tasks", data.merge(
|
69
|
+
parent_object: parent_object,
|
70
|
+
parent_record_id: parent_record_id,
|
71
|
+
title: title
|
72
|
+
))
|
73
|
+
end
|
74
|
+
|
75
|
+
# Update an existing task
|
76
|
+
#
|
77
|
+
# @param id [String] The task ID
|
78
|
+
# @param data [Hash] The fields to update
|
79
|
+
# @option data [String] :title New title
|
80
|
+
# @option data [String] :description New description
|
81
|
+
# @option data [String] :due_date New due date
|
82
|
+
# @option data [String] :assignee_id New assignee
|
83
|
+
# @option data [String] :status New status
|
84
|
+
# @option data [Integer] :priority New priority
|
85
|
+
#
|
86
|
+
# @return [Hash] The updated task
|
87
|
+
# @raise [ArgumentError] if id is invalid
|
88
|
+
def update(id:, **data)
|
89
|
+
validate_id!(id, "Task")
|
90
|
+
validate_data!(data, "Update")
|
91
|
+
request(:patch, "tasks/#{id}", data)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Mark a task as completed
|
95
|
+
#
|
96
|
+
# @param id [String] The task ID
|
97
|
+
# @param completed_at [String] Optional completion timestamp (defaults to now)
|
98
|
+
#
|
99
|
+
# @return [Hash] The updated task
|
100
|
+
# @raise [ArgumentError] if id is nil or empty
|
101
|
+
def complete(id:, completed_at: nil)
|
102
|
+
validate_id!(id, "Task")
|
103
|
+
data = { status: "completed" }
|
104
|
+
data[:completed_at] = completed_at if completed_at
|
105
|
+
request(:patch, "tasks/#{id}", data)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Reopen a completed task
|
109
|
+
#
|
110
|
+
# @param id [String] The task ID
|
111
|
+
#
|
112
|
+
# @return [Hash] The updated task
|
113
|
+
# @raise [ArgumentError] if id is nil or empty
|
114
|
+
def reopen(id:)
|
115
|
+
validate_id!(id, "Task")
|
116
|
+
request(:patch, "tasks/#{id}", { status: "pending", completed_at: nil })
|
117
|
+
end
|
118
|
+
|
119
|
+
# Delete a task
|
120
|
+
#
|
121
|
+
# @param id [String] The task ID to delete
|
122
|
+
#
|
123
|
+
# @return [Hash] Deletion confirmation
|
124
|
+
# @raise [ArgumentError] if id is nil or empty
|
125
|
+
def delete(id:)
|
126
|
+
validate_id!(id, "Task")
|
127
|
+
request(:delete, "tasks/#{id}")
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Attio
|
4
|
+
module Resources
|
5
|
+
# API resource for managing threads in Attio
|
6
|
+
#
|
7
|
+
# Threads represent conversations or discussion topics related to records.
|
8
|
+
#
|
9
|
+
# @example Listing threads for a record
|
10
|
+
# client.threads.list(
|
11
|
+
# parent_object: "companies",
|
12
|
+
# parent_record_id: "company_123"
|
13
|
+
# )
|
14
|
+
#
|
15
|
+
# @example Getting a specific thread
|
16
|
+
# client.threads.get(id: "thread_456")
|
17
|
+
class Threads < Base
|
18
|
+
# List threads for a parent record
|
19
|
+
#
|
20
|
+
# @param parent_object [String] The parent object type
|
21
|
+
# @param parent_record_id [String] The parent record ID
|
22
|
+
# @param params [Hash] Additional query parameters
|
23
|
+
# @option params [Integer] :limit Number of threads to return
|
24
|
+
# @option params [String] :cursor Pagination cursor
|
25
|
+
# @option params [String] :status Filter by status (open, closed)
|
26
|
+
#
|
27
|
+
# @return [Hash] API response containing threads
|
28
|
+
# @raise [ArgumentError] if parent_object or parent_record_id is missing
|
29
|
+
def list(parent_object:, parent_record_id:, **params)
|
30
|
+
validate_parent!(parent_object, parent_record_id)
|
31
|
+
request(:get, "threads", params.merge(
|
32
|
+
parent_object: parent_object,
|
33
|
+
parent_record_id: parent_record_id
|
34
|
+
))
|
35
|
+
end
|
36
|
+
|
37
|
+
# Get a specific thread by ID
|
38
|
+
#
|
39
|
+
# @param id [String] The thread ID
|
40
|
+
# @param include_comments [Boolean] Whether to include comments in the response
|
41
|
+
#
|
42
|
+
# @return [Hash] The thread data
|
43
|
+
# @raise [ArgumentError] if id is nil or empty
|
44
|
+
def get(id:, include_comments: false)
|
45
|
+
validate_id!(id, "Thread")
|
46
|
+
params = include_comments ? { include: "comments" } : {}
|
47
|
+
request(:get, "threads/#{id}", params)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Create a new thread
|
51
|
+
#
|
52
|
+
# @param parent_object [String] The parent object type
|
53
|
+
# @param parent_record_id [String] The parent record ID
|
54
|
+
# @param title [String] The thread title
|
55
|
+
# @param data [Hash] Additional thread data
|
56
|
+
# @option data [String] :description Thread description
|
57
|
+
# @option data [String] :status Thread status (open, closed)
|
58
|
+
# @option data [Array<String>] :participant_ids User IDs of participants
|
59
|
+
#
|
60
|
+
# @return [Hash] The created thread
|
61
|
+
# @raise [ArgumentError] if required parameters are missing
|
62
|
+
def create(parent_object:, parent_record_id:, title:, **data)
|
63
|
+
validate_parent!(parent_object, parent_record_id)
|
64
|
+
validate_required_string!(title, "Thread title")
|
65
|
+
|
66
|
+
request(:post, "threads", data.merge(
|
67
|
+
parent_object: parent_object,
|
68
|
+
parent_record_id: parent_record_id,
|
69
|
+
title: title
|
70
|
+
))
|
71
|
+
end
|
72
|
+
|
73
|
+
# Update an existing thread
|
74
|
+
#
|
75
|
+
# @param id [String] The thread ID
|
76
|
+
# @param data [Hash] The fields to update
|
77
|
+
# @option data [String] :title New title
|
78
|
+
# @option data [String] :description New description
|
79
|
+
# @option data [String] :status New status (open, closed)
|
80
|
+
#
|
81
|
+
# @return [Hash] The updated thread
|
82
|
+
# @raise [ArgumentError] if id is invalid
|
83
|
+
def update(id:, **data)
|
84
|
+
validate_id!(id, "Thread")
|
85
|
+
validate_data!(data, "Update")
|
86
|
+
request(:patch, "threads/#{id}", data)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Close a thread
|
90
|
+
#
|
91
|
+
# @param id [String] The thread ID
|
92
|
+
#
|
93
|
+
# @return [Hash] The updated thread
|
94
|
+
# @raise [ArgumentError] if id is nil or empty
|
95
|
+
def close(id:)
|
96
|
+
validate_id!(id, "Thread")
|
97
|
+
request(:patch, "threads/#{id}", { status: "closed" })
|
98
|
+
end
|
99
|
+
|
100
|
+
# Reopen a closed thread
|
101
|
+
#
|
102
|
+
# @param id [String] The thread ID
|
103
|
+
#
|
104
|
+
# @return [Hash] The updated thread
|
105
|
+
# @raise [ArgumentError] if id is nil or empty
|
106
|
+
def reopen(id:)
|
107
|
+
validate_id!(id, "Thread")
|
108
|
+
request(:patch, "threads/#{id}", { status: "open" })
|
109
|
+
end
|
110
|
+
|
111
|
+
# Delete a thread
|
112
|
+
#
|
113
|
+
# @param id [String] The thread ID to delete
|
114
|
+
#
|
115
|
+
# @return [Hash] Deletion confirmation
|
116
|
+
# @raise [ArgumentError] if id is nil or empty
|
117
|
+
def delete(id:)
|
118
|
+
validate_id!(id, "Thread")
|
119
|
+
request(:delete, "threads/#{id}")
|
120
|
+
end
|
121
|
+
|
122
|
+
# Add participants to a thread
|
123
|
+
#
|
124
|
+
# @param id [String] The thread ID
|
125
|
+
# @param user_ids [Array<String>] User IDs to add as participants
|
126
|
+
#
|
127
|
+
# @return [Hash] The updated thread
|
128
|
+
# @raise [ArgumentError] if id or user_ids is invalid
|
129
|
+
def add_participants(id:, user_ids:)
|
130
|
+
validate_id!(id, "Thread")
|
131
|
+
validate_user_ids!(user_ids)
|
132
|
+
request(:post, "threads/#{id}/participants", { user_ids: user_ids })
|
133
|
+
end
|
134
|
+
|
135
|
+
# Remove participants from a thread
|
136
|
+
#
|
137
|
+
# @param id [String] The thread ID
|
138
|
+
# @param user_ids [Array<String>] User IDs to remove
|
139
|
+
#
|
140
|
+
# @return [Hash] The updated thread
|
141
|
+
# @raise [ArgumentError] if id or user_ids is invalid
|
142
|
+
def remove_participants(id:, user_ids:)
|
143
|
+
validate_id!(id, "Thread")
|
144
|
+
validate_user_ids!(user_ids)
|
145
|
+
request(:delete, "threads/#{id}/participants", { user_ids: user_ids })
|
146
|
+
end
|
147
|
+
|
148
|
+
private def validate_user_ids!(user_ids)
|
149
|
+
raise ArgumentError, "User IDs are required" if user_ids.nil? || user_ids.empty?
|
150
|
+
raise ArgumentError, "User IDs must be an array" unless user_ids.is_a?(Array)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Attio
|
4
|
+
module Resources
|
5
|
+
# Workspace Members resource for managing workspace member access
|
6
|
+
#
|
7
|
+
# @example List all workspace members
|
8
|
+
# client.workspace_members.list
|
9
|
+
#
|
10
|
+
# @example Get a specific member
|
11
|
+
# client.workspace_members.get(member_id: "user_123")
|
12
|
+
#
|
13
|
+
# @example Invite a new member
|
14
|
+
# client.workspace_members.invite(
|
15
|
+
# email: "new.member@example.com",
|
16
|
+
# role: "member"
|
17
|
+
# )
|
18
|
+
class WorkspaceMembers < Base
|
19
|
+
# List all workspace members
|
20
|
+
#
|
21
|
+
# @param params [Hash] Optional query parameters
|
22
|
+
# @option params [Integer] :limit Maximum number of results
|
23
|
+
# @option params [String] :offset Pagination offset
|
24
|
+
# @return [Hash] The API response
|
25
|
+
def list(params = {})
|
26
|
+
request(:get, "workspace_members", params)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Get a specific workspace member
|
30
|
+
#
|
31
|
+
# @param member_id [String] The member ID
|
32
|
+
# @return [Hash] The member data
|
33
|
+
def get(member_id:)
|
34
|
+
validate_id!(member_id, "Member")
|
35
|
+
request(:get, "workspace_members/#{member_id}")
|
36
|
+
end
|
37
|
+
|
38
|
+
# Invite a new member to the workspace
|
39
|
+
#
|
40
|
+
# @param email [String] The email address to invite
|
41
|
+
# @param role [String] The role to assign (admin, member, guest)
|
42
|
+
# @param data [Hash] Additional member data
|
43
|
+
# @return [Hash] The created invitation
|
44
|
+
def invite(email:, role: "member", data: {})
|
45
|
+
validate_required_string!(email, "Email")
|
46
|
+
validate_required_string!(role, "Role")
|
47
|
+
|
48
|
+
raise ArgumentError, "Role must be one of: admin, member, guest" unless %w[admin member guest].include?(role)
|
49
|
+
|
50
|
+
body = data.merge(email: email, role: role)
|
51
|
+
request(:post, "workspace_members/invitations", body)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Update a workspace member's role or permissions
|
55
|
+
#
|
56
|
+
# @param member_id [String] The member ID to update
|
57
|
+
# @param data [Hash] The data to update
|
58
|
+
# @option data [String] :role The new role
|
59
|
+
# @option data [Hash] :permissions Custom permissions
|
60
|
+
# @return [Hash] The updated member
|
61
|
+
def update(member_id:, data:)
|
62
|
+
validate_id!(member_id, "Member")
|
63
|
+
validate_required_hash!(data, "Data")
|
64
|
+
|
65
|
+
request(:patch, "workspace_members/#{member_id}", data)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Remove a member from the workspace
|
69
|
+
#
|
70
|
+
# @param member_id [String] The member ID to remove
|
71
|
+
# @return [Hash] Confirmation of removal
|
72
|
+
def remove(member_id:)
|
73
|
+
validate_id!(member_id, "Member")
|
74
|
+
request(:delete, "workspace_members/#{member_id}")
|
75
|
+
end
|
76
|
+
|
77
|
+
# Accept a workspace invitation
|
78
|
+
#
|
79
|
+
# @param invitation_token [String] The invitation token
|
80
|
+
# @return [Hash] The workspace member data
|
81
|
+
def accept_invitation(invitation_token:)
|
82
|
+
validate_required_string!(invitation_token, "Invitation token")
|
83
|
+
request(:post, "workspace_members/invitations/#{invitation_token}/accept")
|
84
|
+
end
|
85
|
+
|
86
|
+
# Resend an invitation
|
87
|
+
#
|
88
|
+
# @param member_id [String] The member ID with pending invitation
|
89
|
+
# @return [Hash] Confirmation of resent invitation
|
90
|
+
def resend_invitation(member_id:)
|
91
|
+
validate_id!(member_id, "Member")
|
92
|
+
request(:post, "workspace_members/#{member_id}/resend_invitation")
|
93
|
+
end
|
94
|
+
|
95
|
+
# Get current member (self)
|
96
|
+
#
|
97
|
+
# @return [Hash] The current authenticated member's data
|
98
|
+
def me
|
99
|
+
request(:get, "workspace_members/me")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/attio/version.rb
CHANGED
data/lib/attio.rb
CHANGED
@@ -14,6 +14,15 @@ require "attio/resources/lists"
|
|
14
14
|
require "attio/resources/workspaces"
|
15
15
|
require "attio/resources/attributes"
|
16
16
|
require "attio/resources/users"
|
17
|
+
require "attio/resources/notes"
|
18
|
+
require "attio/resources/tasks"
|
19
|
+
require "attio/resources/comments"
|
20
|
+
require "attio/resources/threads"
|
21
|
+
require "attio/resources/workspace_members"
|
22
|
+
require "attio/resources/deals"
|
23
|
+
require "attio/resources/meta"
|
24
|
+
require "attio/resources/bulk"
|
25
|
+
require "attio/rate_limiter"
|
17
26
|
|
18
27
|
# The main Attio module provides access to the Attio API client.
|
19
28
|
#
|