attio 0.1.3 → 0.2.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 +2 -6
- data/CHANGELOG.md +26 -1
- data/CONCEPTS.md +428 -0
- data/Gemfile.lock +3 -1
- data/README.md +157 -3
- 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 +36 -0
- data/lib/attio/http_client.rb +12 -4
- data/lib/attio/resources/base.rb +54 -5
- data/lib/attio/resources/comments.rb +147 -0
- data/lib/attio/resources/lists.rb +9 -21
- 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/version.rb +1 -1
- data/lib/attio.rb +4 -0
- metadata +11 -1
@@ -0,0 +1,147 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Attio
|
4
|
+
module Resources
|
5
|
+
# API resource for managing comments in Attio
|
6
|
+
#
|
7
|
+
# Comments can be added to records and threads for collaboration.
|
8
|
+
#
|
9
|
+
# @example Creating a comment on a record
|
10
|
+
# client.comments.create(
|
11
|
+
# parent_object: "people",
|
12
|
+
# parent_record_id: "person_123",
|
13
|
+
# content: "Just had a great call with this lead!"
|
14
|
+
# )
|
15
|
+
#
|
16
|
+
# @example Creating a comment in a thread
|
17
|
+
# client.comments.create(
|
18
|
+
# thread_id: "thread_456",
|
19
|
+
# content: "Following up on our discussion..."
|
20
|
+
# )
|
21
|
+
class Comments < Base
|
22
|
+
# List comments for a parent record or thread
|
23
|
+
#
|
24
|
+
# @param params [Hash] Query parameters
|
25
|
+
# @option params [String] :parent_object Parent object type
|
26
|
+
# @option params [String] :parent_record_id Parent record ID
|
27
|
+
# @option params [String] :thread_id Thread ID
|
28
|
+
# @option params [Integer] :limit Number of comments to return
|
29
|
+
# @option params [String] :cursor Pagination cursor
|
30
|
+
#
|
31
|
+
# @return [Hash] API response containing comments
|
32
|
+
def list(**params)
|
33
|
+
validate_list_params!(params)
|
34
|
+
request(:get, "comments", params)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Get a specific comment by ID
|
38
|
+
#
|
39
|
+
# @param id [String] The comment ID
|
40
|
+
#
|
41
|
+
# @return [Hash] The comment data
|
42
|
+
# @raise [ArgumentError] if id is nil or empty
|
43
|
+
def get(id:)
|
44
|
+
validate_id!(id, "Comment")
|
45
|
+
request(:get, "comments/#{id}")
|
46
|
+
end
|
47
|
+
|
48
|
+
# Create a new comment
|
49
|
+
#
|
50
|
+
# @param content [String] The comment content (supports markdown)
|
51
|
+
# @param parent_object [String] Parent object type (required if no thread_id)
|
52
|
+
# @param parent_record_id [String] Parent record ID (required if no thread_id)
|
53
|
+
# @param thread_id [String] Thread ID (required if no parent_object/parent_record_id)
|
54
|
+
# @param data [Hash] Additional comment data
|
55
|
+
#
|
56
|
+
# @return [Hash] The created comment
|
57
|
+
# @raise [ArgumentError] if required parameters are missing
|
58
|
+
def create(content:, parent_object: nil, parent_record_id: nil, thread_id: nil, **data)
|
59
|
+
validate_required_string!(content, "Comment content")
|
60
|
+
validate_create_params!(parent_object, parent_record_id, thread_id)
|
61
|
+
|
62
|
+
params = data.merge(content: content)
|
63
|
+
|
64
|
+
if thread_id
|
65
|
+
params[:thread_id] = thread_id
|
66
|
+
else
|
67
|
+
params[:parent_object] = parent_object
|
68
|
+
params[:parent_record_id] = parent_record_id
|
69
|
+
end
|
70
|
+
|
71
|
+
request(:post, "comments", params)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Update an existing comment
|
75
|
+
#
|
76
|
+
# @param id [String] The comment ID
|
77
|
+
# @param content [String] The new content
|
78
|
+
#
|
79
|
+
# @return [Hash] The updated comment
|
80
|
+
# @raise [ArgumentError] if id or content is invalid
|
81
|
+
def update(id:, content:)
|
82
|
+
validate_id!(id, "Comment")
|
83
|
+
validate_required_string!(content, "Comment content")
|
84
|
+
request(:patch, "comments/#{id}", { content: content })
|
85
|
+
end
|
86
|
+
|
87
|
+
# Delete a comment
|
88
|
+
#
|
89
|
+
# @param id [String] The comment ID to delete
|
90
|
+
#
|
91
|
+
# @return [Hash] Deletion confirmation
|
92
|
+
# @raise [ArgumentError] if id is nil or empty
|
93
|
+
def delete(id:)
|
94
|
+
validate_id!(id, "Comment")
|
95
|
+
request(:delete, "comments/#{id}")
|
96
|
+
end
|
97
|
+
|
98
|
+
# React to a comment with an emoji
|
99
|
+
#
|
100
|
+
# @param id [String] The comment ID
|
101
|
+
# @param emoji [String] The emoji reaction (e.g., "👍", "❤️")
|
102
|
+
#
|
103
|
+
# @return [Hash] The updated comment with reaction
|
104
|
+
# @raise [ArgumentError] if id or emoji is invalid
|
105
|
+
def react(id:, emoji:)
|
106
|
+
validate_id!(id, "Comment")
|
107
|
+
validate_required_string!(emoji, "Emoji")
|
108
|
+
request(:post, "comments/#{id}/reactions", { emoji: emoji })
|
109
|
+
end
|
110
|
+
|
111
|
+
# Remove a reaction from a comment
|
112
|
+
#
|
113
|
+
# @param id [String] The comment ID
|
114
|
+
# @param emoji [String] The emoji reaction to remove
|
115
|
+
#
|
116
|
+
# @return [Hash] The updated comment
|
117
|
+
# @raise [ArgumentError] if id or emoji is invalid
|
118
|
+
def unreact(id:, emoji:)
|
119
|
+
validate_id!(id, "Comment")
|
120
|
+
validate_required_string!(emoji, "Emoji")
|
121
|
+
request(:delete, "comments/#{id}/reactions/#{CGI.escape(emoji)}")
|
122
|
+
end
|
123
|
+
|
124
|
+
private def validate_list_params!(params)
|
125
|
+
has_parent = params[:parent_object] && params[:parent_record_id]
|
126
|
+
has_thread = params[:thread_id]
|
127
|
+
|
128
|
+
return if has_parent || has_thread
|
129
|
+
|
130
|
+
raise ArgumentError, "Must provide either parent_object/parent_record_id or thread_id"
|
131
|
+
end
|
132
|
+
|
133
|
+
private def validate_create_params!(parent_object, parent_record_id, thread_id)
|
134
|
+
has_parent = parent_object && parent_record_id
|
135
|
+
has_thread = thread_id
|
136
|
+
|
137
|
+
unless has_parent || has_thread
|
138
|
+
raise ArgumentError, "Must provide either parent_object/parent_record_id or thread_id"
|
139
|
+
end
|
140
|
+
|
141
|
+
return unless has_parent && has_thread
|
142
|
+
|
143
|
+
raise ArgumentError, "Cannot provide both parent and thread parameters"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -17,46 +17,34 @@ module Attio
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def get(id:)
|
20
|
-
validate_id!(id)
|
20
|
+
validate_id!(id, "List")
|
21
21
|
request(:get, "lists/#{id}")
|
22
22
|
end
|
23
23
|
|
24
24
|
def entries(id:, **params)
|
25
|
-
validate_id!(id)
|
25
|
+
validate_id!(id, "List")
|
26
26
|
request(:get, "lists/#{id}/entries", params)
|
27
27
|
end
|
28
28
|
|
29
29
|
def create_entry(id:, data:)
|
30
|
-
validate_id!(id)
|
31
|
-
|
30
|
+
validate_id!(id, "List")
|
31
|
+
validate_list_entry_data!(data)
|
32
32
|
request(:post, "lists/#{id}/entries", data)
|
33
33
|
end
|
34
34
|
|
35
35
|
def get_entry(list_id:, entry_id:)
|
36
|
-
|
37
|
-
|
36
|
+
validate_id!(list_id, "List")
|
37
|
+
validate_id!(entry_id, "Entry")
|
38
38
|
request(:get, "lists/#{list_id}/entries/#{entry_id}")
|
39
39
|
end
|
40
40
|
|
41
41
|
def delete_entry(list_id:, entry_id:)
|
42
|
-
|
43
|
-
|
42
|
+
validate_id!(list_id, "List")
|
43
|
+
validate_id!(entry_id, "Entry")
|
44
44
|
request(:delete, "lists/#{list_id}/entries/#{entry_id}")
|
45
45
|
end
|
46
46
|
|
47
|
-
private def
|
48
|
-
raise ArgumentError, "List ID is required" if id.nil? || id.to_s.strip.empty?
|
49
|
-
end
|
50
|
-
|
51
|
-
private def validate_list_id!(list_id)
|
52
|
-
raise ArgumentError, "List ID is required" if list_id.nil? || list_id.to_s.strip.empty?
|
53
|
-
end
|
54
|
-
|
55
|
-
private def validate_entry_id!(entry_id)
|
56
|
-
raise ArgumentError, "Entry ID is required" if entry_id.nil? || entry_id.to_s.strip.empty?
|
57
|
-
end
|
58
|
-
|
59
|
-
private def validate_data!(data)
|
47
|
+
private def validate_list_entry_data!(data)
|
60
48
|
raise ArgumentError, "Data is required" if data.nil?
|
61
49
|
raise ArgumentError, "Data must be a hash" unless data.is_a?(Hash)
|
62
50
|
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
|
data/lib/attio/version.rb
CHANGED
data/lib/attio.rb
CHANGED
@@ -14,6 +14,10 @@ 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"
|
17
21
|
|
18
22
|
# The main Attio module provides access to the Attio API client.
|
19
23
|
#
|