basecamp-sdk 0.2.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.
- checksums.yaml +7 -0
- data/.rubocop.yml +14 -0
- data/.yardopts +6 -0
- data/README.md +293 -0
- data/Rakefile +26 -0
- data/basecamp-sdk.gemspec +46 -0
- data/lib/basecamp/auth_strategy.rb +38 -0
- data/lib/basecamp/chain_hooks.rb +45 -0
- data/lib/basecamp/client.rb +428 -0
- data/lib/basecamp/config.rb +143 -0
- data/lib/basecamp/errors.rb +289 -0
- data/lib/basecamp/generated/metadata.json +2281 -0
- data/lib/basecamp/generated/services/attachments_service.rb +24 -0
- data/lib/basecamp/generated/services/boosts_service.rb +70 -0
- data/lib/basecamp/generated/services/campfires_service.rb +122 -0
- data/lib/basecamp/generated/services/card_columns_service.rb +103 -0
- data/lib/basecamp/generated/services/card_steps_service.rb +57 -0
- data/lib/basecamp/generated/services/card_tables_service.rb +20 -0
- data/lib/basecamp/generated/services/cards_service.rb +66 -0
- data/lib/basecamp/generated/services/checkins_service.rb +157 -0
- data/lib/basecamp/generated/services/client_approvals_service.rb +28 -0
- data/lib/basecamp/generated/services/client_correspondences_service.rb +28 -0
- data/lib/basecamp/generated/services/client_replies_service.rb +30 -0
- data/lib/basecamp/generated/services/client_visibility_service.rb +21 -0
- data/lib/basecamp/generated/services/comments_service.rb +49 -0
- data/lib/basecamp/generated/services/documents_service.rb +52 -0
- data/lib/basecamp/generated/services/events_service.rb +20 -0
- data/lib/basecamp/generated/services/forwards_service.rb +67 -0
- data/lib/basecamp/generated/services/lineup_service.rb +44 -0
- data/lib/basecamp/generated/services/message_boards_service.rb +20 -0
- data/lib/basecamp/generated/services/message_types_service.rb +59 -0
- data/lib/basecamp/generated/services/messages_service.rb +75 -0
- data/lib/basecamp/generated/services/people_service.rb +73 -0
- data/lib/basecamp/generated/services/projects_service.rb +63 -0
- data/lib/basecamp/generated/services/recordings_service.rb +64 -0
- data/lib/basecamp/generated/services/reports_service.rb +56 -0
- data/lib/basecamp/generated/services/schedules_service.rb +92 -0
- data/lib/basecamp/generated/services/search_service.rb +31 -0
- data/lib/basecamp/generated/services/subscriptions_service.rb +50 -0
- data/lib/basecamp/generated/services/templates_service.rb +82 -0
- data/lib/basecamp/generated/services/timeline_service.rb +20 -0
- data/lib/basecamp/generated/services/timesheets_service.rb +81 -0
- data/lib/basecamp/generated/services/todolist_groups_service.rb +41 -0
- data/lib/basecamp/generated/services/todolists_service.rb +53 -0
- data/lib/basecamp/generated/services/todos_service.rb +106 -0
- data/lib/basecamp/generated/services/todosets_service.rb +20 -0
- data/lib/basecamp/generated/services/tools_service.rb +80 -0
- data/lib/basecamp/generated/services/uploads_service.rb +61 -0
- data/lib/basecamp/generated/services/vaults_service.rb +49 -0
- data/lib/basecamp/generated/services/webhooks_service.rb +63 -0
- data/lib/basecamp/generated/types.rb +3196 -0
- data/lib/basecamp/hooks.rb +70 -0
- data/lib/basecamp/http.rb +440 -0
- data/lib/basecamp/logger_hooks.rb +46 -0
- data/lib/basecamp/noop_hooks.rb +9 -0
- data/lib/basecamp/oauth/discovery.rb +123 -0
- data/lib/basecamp/oauth/errors.rb +35 -0
- data/lib/basecamp/oauth/exchange.rb +291 -0
- data/lib/basecamp/oauth/pkce.rb +68 -0
- data/lib/basecamp/oauth/types.rb +133 -0
- data/lib/basecamp/oauth.rb +56 -0
- data/lib/basecamp/oauth_token_provider.rb +108 -0
- data/lib/basecamp/operation_info.rb +17 -0
- data/lib/basecamp/request_info.rb +10 -0
- data/lib/basecamp/request_result.rb +14 -0
- data/lib/basecamp/security.rb +112 -0
- data/lib/basecamp/services/attachments_service.rb +33 -0
- data/lib/basecamp/services/authorization_service.rb +47 -0
- data/lib/basecamp/services/base_service.rb +146 -0
- data/lib/basecamp/services/campfires_service.rb +141 -0
- data/lib/basecamp/services/card_columns_service.rb +106 -0
- data/lib/basecamp/services/card_steps_service.rb +86 -0
- data/lib/basecamp/services/card_tables_service.rb +23 -0
- data/lib/basecamp/services/cards_service.rb +93 -0
- data/lib/basecamp/services/checkins_service.rb +127 -0
- data/lib/basecamp/services/client_approvals_service.rb +33 -0
- data/lib/basecamp/services/client_correspondences_service.rb +33 -0
- data/lib/basecamp/services/client_replies_service.rb +35 -0
- data/lib/basecamp/services/comments_service.rb +63 -0
- data/lib/basecamp/services/documents_service.rb +74 -0
- data/lib/basecamp/services/events_service.rb +27 -0
- data/lib/basecamp/services/forwards_service.rb +80 -0
- data/lib/basecamp/services/lineup_service.rb +67 -0
- data/lib/basecamp/services/message_boards_service.rb +24 -0
- data/lib/basecamp/services/message_types_service.rb +79 -0
- data/lib/basecamp/services/messages_service.rb +133 -0
- data/lib/basecamp/services/people_service.rb +73 -0
- data/lib/basecamp/services/projects_service.rb +67 -0
- data/lib/basecamp/services/recordings_service.rb +127 -0
- data/lib/basecamp/services/reports_service.rb +80 -0
- data/lib/basecamp/services/schedules_service.rb +156 -0
- data/lib/basecamp/services/search_service.rb +36 -0
- data/lib/basecamp/services/subscriptions_service.rb +67 -0
- data/lib/basecamp/services/templates_service.rb +96 -0
- data/lib/basecamp/services/timeline_service.rb +62 -0
- data/lib/basecamp/services/timesheet_service.rb +68 -0
- data/lib/basecamp/services/todolist_groups_service.rb +100 -0
- data/lib/basecamp/services/todolists_service.rb +104 -0
- data/lib/basecamp/services/todos_service.rb +156 -0
- data/lib/basecamp/services/todosets_service.rb +23 -0
- data/lib/basecamp/services/tools_service.rb +89 -0
- data/lib/basecamp/services/uploads_service.rb +84 -0
- data/lib/basecamp/services/vaults_service.rb +84 -0
- data/lib/basecamp/services/webhooks_service.rb +88 -0
- data/lib/basecamp/static_token_provider.rb +24 -0
- data/lib/basecamp/token_provider.rb +42 -0
- data/lib/basecamp/version.rb +6 -0
- data/lib/basecamp/webhooks/event.rb +52 -0
- data/lib/basecamp/webhooks/rack_middleware.rb +49 -0
- data/lib/basecamp/webhooks/receiver.rb +161 -0
- data/lib/basecamp/webhooks/verify.rb +36 -0
- data/lib/basecamp.rb +107 -0
- data/scripts/generate-metadata.rb +106 -0
- data/scripts/generate-services.rb +778 -0
- data/scripts/generate-types.rb +191 -0
- metadata +316 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for card step (checklist item) operations.
|
|
6
|
+
#
|
|
7
|
+
# Steps are checklist items on cards in card tables.
|
|
8
|
+
#
|
|
9
|
+
# @example Create a step
|
|
10
|
+
# step = account.card_steps.create(
|
|
11
|
+
# project_id: 123,
|
|
12
|
+
# card_id: 456,
|
|
13
|
+
# title: "Review code",
|
|
14
|
+
# due_on: "2024-12-15"
|
|
15
|
+
# )
|
|
16
|
+
#
|
|
17
|
+
# @example Complete a step
|
|
18
|
+
# account.card_steps.complete(project_id: 123, step_id: 789)
|
|
19
|
+
class CardStepsService < BaseService
|
|
20
|
+
# Creates a new step on a card.
|
|
21
|
+
#
|
|
22
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
23
|
+
# @param card_id [Integer, String] card ID
|
|
24
|
+
# @param title [String] step title
|
|
25
|
+
# @param due_on [String, nil] due date (YYYY-MM-DD)
|
|
26
|
+
# @param assignees [Array<Integer>, nil] person IDs to assign
|
|
27
|
+
# @return [Hash] created step
|
|
28
|
+
def create(project_id:, card_id:, title:, due_on: nil, assignees: nil)
|
|
29
|
+
body = compact_params(
|
|
30
|
+
title: title,
|
|
31
|
+
due_on: due_on,
|
|
32
|
+
assignees: assignees
|
|
33
|
+
)
|
|
34
|
+
http_post(bucket_path(project_id, "/card_tables/cards/#{card_id}/steps.json"), body: body).json
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Updates an existing step.
|
|
38
|
+
#
|
|
39
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
40
|
+
# @param step_id [Integer, String] step ID
|
|
41
|
+
# @param title [String, nil] new title
|
|
42
|
+
# @param due_on [String, nil] new due date (YYYY-MM-DD)
|
|
43
|
+
# @param assignees [Array<Integer>, nil] person IDs to assign
|
|
44
|
+
# @return [Hash] updated step
|
|
45
|
+
def update(project_id:, step_id:, title: nil, due_on: nil, assignees: nil)
|
|
46
|
+
body = compact_params(
|
|
47
|
+
title: title,
|
|
48
|
+
due_on: due_on,
|
|
49
|
+
assignees: assignees
|
|
50
|
+
)
|
|
51
|
+
http_put(bucket_path(project_id, "/card_tables/steps/#{step_id}.json"), body: body).json
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Marks a step as completed.
|
|
55
|
+
#
|
|
56
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
57
|
+
# @param step_id [Integer, String] step ID
|
|
58
|
+
# @return [Hash] updated step
|
|
59
|
+
def complete(project_id:, step_id:)
|
|
60
|
+
http_put(bucket_path(project_id, "/card_tables/steps/#{step_id}/completions.json")).json
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Marks a step as incomplete.
|
|
64
|
+
#
|
|
65
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
66
|
+
# @param step_id [Integer, String] step ID
|
|
67
|
+
# @return [Hash] updated step
|
|
68
|
+
def uncomplete(project_id:, step_id:)
|
|
69
|
+
http_delete(bucket_path(project_id, "/card_tables/steps/#{step_id}/completions.json")).json
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Changes the position of a step within a card.
|
|
73
|
+
#
|
|
74
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
75
|
+
# @param card_id [Integer, String] card ID
|
|
76
|
+
# @param step_id [Integer, String] step ID
|
|
77
|
+
# @param position [Integer] new position (0-indexed)
|
|
78
|
+
# @return [void]
|
|
79
|
+
def reposition(project_id:, card_id:, step_id:, position:)
|
|
80
|
+
http_post(bucket_path(project_id, "/card_tables/cards/#{card_id}/positions.json"),
|
|
81
|
+
body: { source_id: step_id, position: position })
|
|
82
|
+
nil
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for card table (kanban board) operations.
|
|
6
|
+
#
|
|
7
|
+
# Card Tables are kanban-style boards with columns containing cards.
|
|
8
|
+
#
|
|
9
|
+
# @example Get a card table
|
|
10
|
+
# table = account.card_tables.get(project_id: 123, card_table_id: 456)
|
|
11
|
+
# puts "#{table["title"]} - #{table["lists"].length} columns"
|
|
12
|
+
class CardTablesService < BaseService
|
|
13
|
+
# Gets a card table by ID.
|
|
14
|
+
#
|
|
15
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
16
|
+
# @param card_table_id [Integer, String] card table ID
|
|
17
|
+
# @return [Hash] card table with its columns
|
|
18
|
+
def get(project_id:, card_table_id:)
|
|
19
|
+
http_get(bucket_path(project_id, "/card_tables/#{card_table_id}.json")).json
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for card operations within card tables.
|
|
6
|
+
#
|
|
7
|
+
# Cards are items in card table columns. They can have steps (checklist items),
|
|
8
|
+
# assignees, and due dates.
|
|
9
|
+
#
|
|
10
|
+
# @example List cards in a column
|
|
11
|
+
# account.cards.list(project_id: 123, column_id: 456).each do |card|
|
|
12
|
+
# puts "#{card["title"]} - #{card["completed"] ? "done" : "pending"}"
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# @example Create a card
|
|
16
|
+
# card = account.cards.create(
|
|
17
|
+
# project_id: 123,
|
|
18
|
+
# column_id: 456,
|
|
19
|
+
# title: "New Feature",
|
|
20
|
+
# content: "<p>Feature description</p>",
|
|
21
|
+
# due_on: "2024-12-31"
|
|
22
|
+
# )
|
|
23
|
+
class CardsService < BaseService
|
|
24
|
+
# Lists all cards in a column.
|
|
25
|
+
#
|
|
26
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
27
|
+
# @param column_id [Integer, String] column ID
|
|
28
|
+
# @return [Enumerator<Hash>] cards
|
|
29
|
+
def list(project_id:, column_id:)
|
|
30
|
+
paginate(bucket_path(project_id, "/card_tables/lists/#{column_id}/cards.json"))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Gets a card by ID.
|
|
34
|
+
#
|
|
35
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
36
|
+
# @param card_id [Integer, String] card ID
|
|
37
|
+
# @return [Hash] card data
|
|
38
|
+
def get(project_id:, card_id:)
|
|
39
|
+
http_get(bucket_path(project_id, "/card_tables/cards/#{card_id}.json")).json
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Creates a new card in a column.
|
|
43
|
+
#
|
|
44
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
45
|
+
# @param column_id [Integer, String] column ID
|
|
46
|
+
# @param title [String] card title
|
|
47
|
+
# @param content [String, nil] card body in HTML
|
|
48
|
+
# @param due_on [String, nil] due date (YYYY-MM-DD)
|
|
49
|
+
# @param notify [Boolean, nil] notify assignees
|
|
50
|
+
# @return [Hash] created card
|
|
51
|
+
def create(project_id:, column_id:, title:, content: nil, due_on: nil, notify: nil)
|
|
52
|
+
body = compact_params(
|
|
53
|
+
title: title,
|
|
54
|
+
content: content,
|
|
55
|
+
due_on: due_on,
|
|
56
|
+
notify: notify
|
|
57
|
+
)
|
|
58
|
+
http_post(bucket_path(project_id, "/card_tables/lists/#{column_id}/cards.json"), body: body).json
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Updates an existing card.
|
|
62
|
+
#
|
|
63
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
64
|
+
# @param card_id [Integer, String] card ID
|
|
65
|
+
# @param title [String, nil] new title
|
|
66
|
+
# @param content [String, nil] new content
|
|
67
|
+
# @param due_on [String, nil] new due date (YYYY-MM-DD)
|
|
68
|
+
# @param assignee_ids [Array<Integer>, nil] person IDs to assign
|
|
69
|
+
# @return [Hash] updated card
|
|
70
|
+
def update(project_id:, card_id:, title: nil, content: nil, due_on: nil, assignee_ids: nil)
|
|
71
|
+
body = compact_params(
|
|
72
|
+
title: title,
|
|
73
|
+
content: content,
|
|
74
|
+
due_on: due_on,
|
|
75
|
+
assignee_ids: assignee_ids
|
|
76
|
+
)
|
|
77
|
+
http_put(bucket_path(project_id, "/card_tables/cards/#{card_id}.json"), body: body).json
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Moves a card to a different column.
|
|
81
|
+
#
|
|
82
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
83
|
+
# @param card_id [Integer, String] card ID
|
|
84
|
+
# @param column_id [Integer, String] destination column ID
|
|
85
|
+
# @return [void]
|
|
86
|
+
def move(project_id:, card_id:, column_id:)
|
|
87
|
+
http_post(bucket_path(project_id, "/card_tables/cards/#{card_id}/moves.json"),
|
|
88
|
+
body: { column_id: column_id })
|
|
89
|
+
nil
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for automatic check-in operations.
|
|
6
|
+
#
|
|
7
|
+
# Checkins (also called Automatic Check-ins) are scheduled questions
|
|
8
|
+
# that get sent to team members. The questionnaire contains questions,
|
|
9
|
+
# and each question can have multiple answers from different people.
|
|
10
|
+
#
|
|
11
|
+
# @example List questions
|
|
12
|
+
# account.checkins.list_questions(project_id: 123, questionnaire_id: 456).each do |q|
|
|
13
|
+
# puts "#{q["title"]} - #{q["paused"] ? "(paused)" : ""}"
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# @example Create an answer
|
|
17
|
+
# answer = account.checkins.create_answer(
|
|
18
|
+
# project_id: 123,
|
|
19
|
+
# question_id: 456,
|
|
20
|
+
# content: "<p>Making great progress!</p>"
|
|
21
|
+
# )
|
|
22
|
+
class CheckinsService < BaseService
|
|
23
|
+
# Gets a questionnaire by ID.
|
|
24
|
+
#
|
|
25
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
26
|
+
# @param questionnaire_id [Integer, String] questionnaire ID
|
|
27
|
+
# @return [Hash] questionnaire data
|
|
28
|
+
def get_questionnaire(project_id:, questionnaire_id:)
|
|
29
|
+
http_get(bucket_path(project_id, "/questionnaires/#{questionnaire_id}.json")).json
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Lists all questions in a questionnaire.
|
|
33
|
+
#
|
|
34
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
35
|
+
# @param questionnaire_id [Integer, String] questionnaire ID
|
|
36
|
+
# @return [Enumerator<Hash>] questions
|
|
37
|
+
def list_questions(project_id:, questionnaire_id:)
|
|
38
|
+
paginate(bucket_path(project_id, "/questionnaires/#{questionnaire_id}/questions.json"))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Gets a question by ID.
|
|
42
|
+
#
|
|
43
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
44
|
+
# @param question_id [Integer, String] question ID
|
|
45
|
+
# @return [Hash] question data
|
|
46
|
+
def get_question(project_id:, question_id:)
|
|
47
|
+
http_get(bucket_path(project_id, "/questions/#{question_id}.json")).json
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Creates a new question in a questionnaire.
|
|
51
|
+
#
|
|
52
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
53
|
+
# @param questionnaire_id [Integer, String] questionnaire ID
|
|
54
|
+
# @param title [String] question text
|
|
55
|
+
# @param schedule [Hash] schedule configuration with frequency, days, hour, minute
|
|
56
|
+
# @return [Hash] created question
|
|
57
|
+
def create_question(project_id:, questionnaire_id:, title:, schedule:)
|
|
58
|
+
body = {
|
|
59
|
+
title: title,
|
|
60
|
+
schedule: schedule
|
|
61
|
+
}
|
|
62
|
+
http_post(bucket_path(project_id, "/questionnaires/#{questionnaire_id}/questions.json"), body: body).json
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Updates an existing question.
|
|
66
|
+
#
|
|
67
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
68
|
+
# @param question_id [Integer, String] question ID
|
|
69
|
+
# @param title [String, nil] new question text
|
|
70
|
+
# @param schedule [Hash, nil] new schedule configuration
|
|
71
|
+
# @param paused [Boolean, nil] whether the question is paused
|
|
72
|
+
# @return [Hash] updated question
|
|
73
|
+
def update_question(project_id:, question_id:, title: nil, schedule: nil, paused: nil)
|
|
74
|
+
body = compact_params(
|
|
75
|
+
title: title,
|
|
76
|
+
schedule: schedule,
|
|
77
|
+
paused: paused
|
|
78
|
+
)
|
|
79
|
+
http_put(bucket_path(project_id, "/questions/#{question_id}.json"), body: body).json
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Lists all answers for a question.
|
|
83
|
+
#
|
|
84
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
85
|
+
# @param question_id [Integer, String] question ID
|
|
86
|
+
# @return [Enumerator<Hash>] answers
|
|
87
|
+
def list_answers(project_id:, question_id:)
|
|
88
|
+
paginate(bucket_path(project_id, "/questions/#{question_id}/answers.json"))
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Gets an answer by ID.
|
|
92
|
+
#
|
|
93
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
94
|
+
# @param answer_id [Integer, String] answer ID
|
|
95
|
+
# @return [Hash] answer data
|
|
96
|
+
def get_answer(project_id:, answer_id:)
|
|
97
|
+
http_get(bucket_path(project_id, "/question_answers/#{answer_id}.json")).json
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Creates a new answer for a question.
|
|
101
|
+
#
|
|
102
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
103
|
+
# @param question_id [Integer, String] question ID
|
|
104
|
+
# @param content [String] answer content in HTML
|
|
105
|
+
# @param group_on [String, nil] date to group the answer with (ISO 8601)
|
|
106
|
+
# @return [Hash] created answer
|
|
107
|
+
def create_answer(project_id:, question_id:, content:, group_on: nil)
|
|
108
|
+
body = compact_params(
|
|
109
|
+
content: content,
|
|
110
|
+
group_on: group_on
|
|
111
|
+
)
|
|
112
|
+
http_post(bucket_path(project_id, "/questions/#{question_id}/answers.json"), body: body).json
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Updates an existing answer.
|
|
116
|
+
#
|
|
117
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
118
|
+
# @param answer_id [Integer, String] answer ID
|
|
119
|
+
# @param content [String] updated answer content in HTML
|
|
120
|
+
# @return [void]
|
|
121
|
+
def update_answer(project_id:, answer_id:, content:)
|
|
122
|
+
http_put(bucket_path(project_id, "/question_answers/#{answer_id}.json"), body: { content: content })
|
|
123
|
+
nil
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for client approval operations.
|
|
6
|
+
#
|
|
7
|
+
# Client approvals allow you to request approval from clients
|
|
8
|
+
# on specific deliverables or decisions within a project.
|
|
9
|
+
#
|
|
10
|
+
# @example List client approvals
|
|
11
|
+
# account.client_approvals.list(project_id: 123).each do |approval|
|
|
12
|
+
# puts "#{approval["subject"]} - #{approval["approval_status"]}"
|
|
13
|
+
# end
|
|
14
|
+
class ClientApprovalsService < BaseService
|
|
15
|
+
# Lists all client approvals in a project.
|
|
16
|
+
#
|
|
17
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
18
|
+
# @return [Enumerator<Hash>] client approvals
|
|
19
|
+
def list(project_id:)
|
|
20
|
+
paginate(bucket_path(project_id, "/client/approvals.json"))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Gets a client approval by ID.
|
|
24
|
+
#
|
|
25
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
26
|
+
# @param approval_id [Integer, String] client approval ID
|
|
27
|
+
# @return [Hash] client approval data
|
|
28
|
+
def get(project_id:, approval_id:)
|
|
29
|
+
http_get(bucket_path(project_id, "/client/approvals/#{approval_id}.json")).json
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for client correspondence operations.
|
|
6
|
+
#
|
|
7
|
+
# Client correspondences are messages sent to and from clients
|
|
8
|
+
# within a project's client portal.
|
|
9
|
+
#
|
|
10
|
+
# @example List client correspondences
|
|
11
|
+
# account.client_correspondences.list(project_id: 123).each do |c|
|
|
12
|
+
# puts "#{c["subject"]} - #{c["replies_count"]} replies"
|
|
13
|
+
# end
|
|
14
|
+
class ClientCorrespondencesService < BaseService
|
|
15
|
+
# Lists all client correspondences in a project.
|
|
16
|
+
#
|
|
17
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
18
|
+
# @return [Enumerator<Hash>] client correspondences
|
|
19
|
+
def list(project_id:)
|
|
20
|
+
paginate(bucket_path(project_id, "/client/correspondences.json"))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Gets a client correspondence by ID.
|
|
24
|
+
#
|
|
25
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
26
|
+
# @param correspondence_id [Integer, String] client correspondence ID
|
|
27
|
+
# @return [Hash] client correspondence data
|
|
28
|
+
def get(project_id:, correspondence_id:)
|
|
29
|
+
http_get(bucket_path(project_id, "/client/correspondences/#{correspondence_id}.json")).json
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for client reply operations.
|
|
6
|
+
#
|
|
7
|
+
# Client replies are responses to client correspondences or approvals
|
|
8
|
+
# within a project's client portal.
|
|
9
|
+
#
|
|
10
|
+
# @example List client replies
|
|
11
|
+
# account.client_replies.list(project_id: 123, recording_id: 456).each do |r|
|
|
12
|
+
# puts "#{r["creator"]["name"]}: #{r["content"]}"
|
|
13
|
+
# end
|
|
14
|
+
class ClientRepliesService < BaseService
|
|
15
|
+
# Lists all replies for a client recording (correspondence or approval).
|
|
16
|
+
#
|
|
17
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
18
|
+
# @param recording_id [Integer, String] parent correspondence/approval ID
|
|
19
|
+
# @return [Enumerator<Hash>] client replies
|
|
20
|
+
def list(project_id:, recording_id:)
|
|
21
|
+
paginate(bucket_path(project_id, "/client/recordings/#{recording_id}/replies.json"))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Gets a specific client reply.
|
|
25
|
+
#
|
|
26
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
27
|
+
# @param recording_id [Integer, String] parent correspondence/approval ID
|
|
28
|
+
# @param reply_id [Integer, String] client reply ID
|
|
29
|
+
# @return [Hash] client reply data
|
|
30
|
+
def get(project_id:, recording_id:, reply_id:)
|
|
31
|
+
http_get(bucket_path(project_id, "/client/recordings/#{recording_id}/replies/#{reply_id}.json")).json
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for comment operations.
|
|
6
|
+
#
|
|
7
|
+
# Comments can be added to most recordings (todos, messages, etc.)
|
|
8
|
+
# in Basecamp. They support HTML content.
|
|
9
|
+
#
|
|
10
|
+
# @example List comments on a todo
|
|
11
|
+
# account.comments.list(project_id: 123, recording_id: 456).each do |comment|
|
|
12
|
+
# puts "#{comment["creator"]["name"]}: #{comment["content"]}"
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# @example Create a comment
|
|
16
|
+
# comment = account.comments.create(
|
|
17
|
+
# project_id: 123,
|
|
18
|
+
# recording_id: 456,
|
|
19
|
+
# content: "<p>Great work on this!</p>"
|
|
20
|
+
# )
|
|
21
|
+
class CommentsService < BaseService
|
|
22
|
+
# Lists all comments on a recording.
|
|
23
|
+
#
|
|
24
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
25
|
+
# @param recording_id [Integer, String] recording ID (todo, message, etc.)
|
|
26
|
+
# @return [Enumerator<Hash>] comments
|
|
27
|
+
def list(project_id:, recording_id:)
|
|
28
|
+
paginate(bucket_path(project_id, "/recordings/#{recording_id}/comments.json"))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Gets a specific comment.
|
|
32
|
+
#
|
|
33
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
34
|
+
# @param comment_id [Integer, String] comment ID
|
|
35
|
+
# @return [Hash] comment data
|
|
36
|
+
def get(project_id:, comment_id:)
|
|
37
|
+
http_get(bucket_path(project_id, "/comments/#{comment_id}.json")).json
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Creates a new comment on a recording.
|
|
41
|
+
#
|
|
42
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
43
|
+
# @param recording_id [Integer, String] recording ID to comment on
|
|
44
|
+
# @param content [String] comment content in HTML
|
|
45
|
+
# @return [Hash] created comment
|
|
46
|
+
def create(project_id:, recording_id:, content:)
|
|
47
|
+
body = { content: content }
|
|
48
|
+
http_post(bucket_path(project_id, "/recordings/#{recording_id}/comments.json"), body: body).json
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Updates an existing comment.
|
|
52
|
+
#
|
|
53
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
54
|
+
# @param comment_id [Integer, String] comment ID
|
|
55
|
+
# @param content [String] new comment content in HTML
|
|
56
|
+
# @return [Hash] updated comment
|
|
57
|
+
def update(project_id:, comment_id:, content:)
|
|
58
|
+
body = { content: content }
|
|
59
|
+
http_put(bucket_path(project_id, "/comments/#{comment_id}.json"), body: body).json
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for document operations.
|
|
6
|
+
#
|
|
7
|
+
# Documents are rich text files stored within vaults. They support
|
|
8
|
+
# HTML content and can be in draft or active status.
|
|
9
|
+
#
|
|
10
|
+
# @example List documents in a vault
|
|
11
|
+
# account.documents.list(project_id: 123, vault_id: 456).each do |doc|
|
|
12
|
+
# puts "#{doc["title"]} - #{doc["comments_count"]} comments"
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# @example Create a document
|
|
16
|
+
# doc = account.documents.create(
|
|
17
|
+
# project_id: 123,
|
|
18
|
+
# vault_id: 456,
|
|
19
|
+
# title: "Meeting Notes",
|
|
20
|
+
# content: "<p>Notes from today's meeting...</p>"
|
|
21
|
+
# )
|
|
22
|
+
class DocumentsService < BaseService
|
|
23
|
+
# Lists all documents in a vault.
|
|
24
|
+
#
|
|
25
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
26
|
+
# @param vault_id [Integer, String] vault ID
|
|
27
|
+
# @return [Enumerator<Hash>] documents
|
|
28
|
+
def list(project_id:, vault_id:)
|
|
29
|
+
paginate(bucket_path(project_id, "/vaults/#{vault_id}/documents.json"))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Gets a specific document.
|
|
33
|
+
#
|
|
34
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
35
|
+
# @param document_id [Integer, String] document ID
|
|
36
|
+
# @return [Hash] document data
|
|
37
|
+
def get(project_id:, document_id:)
|
|
38
|
+
http_get(bucket_path(project_id, "/documents/#{document_id}.json")).json
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Creates a new document in a vault.
|
|
42
|
+
#
|
|
43
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
44
|
+
# @param vault_id [Integer, String] vault ID
|
|
45
|
+
# @param title [String] document title
|
|
46
|
+
# @param content [String, nil] document body in HTML
|
|
47
|
+
# @param status [String, nil] status ("drafted" or "active")
|
|
48
|
+
# @return [Hash] created document
|
|
49
|
+
def create(project_id:, vault_id:, title:, content: nil, status: nil)
|
|
50
|
+
body = compact_params(
|
|
51
|
+
title: title,
|
|
52
|
+
content: content,
|
|
53
|
+
status: status
|
|
54
|
+
)
|
|
55
|
+
http_post(bucket_path(project_id, "/vaults/#{vault_id}/documents.json"), body: body).json
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Updates an existing document.
|
|
59
|
+
#
|
|
60
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
61
|
+
# @param document_id [Integer, String] document ID
|
|
62
|
+
# @param title [String, nil] new title
|
|
63
|
+
# @param content [String, nil] new content
|
|
64
|
+
# @return [Hash] updated document
|
|
65
|
+
def update(project_id:, document_id:, title: nil, content: nil)
|
|
66
|
+
body = compact_params(
|
|
67
|
+
title: title,
|
|
68
|
+
content: content
|
|
69
|
+
)
|
|
70
|
+
http_put(bucket_path(project_id, "/documents/#{document_id}.json"), body: body).json
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for event operations.
|
|
6
|
+
#
|
|
7
|
+
# Events are activity records that track changes to recordings.
|
|
8
|
+
# An event is created any time a recording is modified (created,
|
|
9
|
+
# updated, completed, etc.).
|
|
10
|
+
#
|
|
11
|
+
# @example List events for a recording
|
|
12
|
+
# account.events.list(project_id: 123, recording_id: 456).each do |event|
|
|
13
|
+
# puts "#{event["action"]} by #{event["creator"]["name"]} at #{event["created_at"]}"
|
|
14
|
+
# end
|
|
15
|
+
class EventsService < BaseService
|
|
16
|
+
# Lists all events for a recording.
|
|
17
|
+
# Events track all changes made to a recording over time.
|
|
18
|
+
#
|
|
19
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
20
|
+
# @param recording_id [Integer, String] recording ID
|
|
21
|
+
# @return [Enumerator<Hash>] events
|
|
22
|
+
def list(project_id:, recording_id:)
|
|
23
|
+
paginate(bucket_path(project_id, "/recordings/#{recording_id}/events.json"))
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for email forward operations.
|
|
6
|
+
#
|
|
7
|
+
# Forwards are emails that have been forwarded to a project's inbox.
|
|
8
|
+
# Team members can reply to forwarded emails from within Basecamp.
|
|
9
|
+
#
|
|
10
|
+
# @example List forwards in an inbox
|
|
11
|
+
# account.forwards.list(project_id: 123, inbox_id: 456).each do |f|
|
|
12
|
+
# puts "#{f["subject"]} - from #{f["from"]}"
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# @example Create a reply
|
|
16
|
+
# reply = account.forwards.create_reply(
|
|
17
|
+
# project_id: 123,
|
|
18
|
+
# forward_id: 456,
|
|
19
|
+
# content: "<p>Thanks for reaching out!</p>"
|
|
20
|
+
# )
|
|
21
|
+
class ForwardsService < BaseService
|
|
22
|
+
# Gets an inbox by ID.
|
|
23
|
+
#
|
|
24
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
25
|
+
# @param inbox_id [Integer, String] inbox ID
|
|
26
|
+
# @return [Hash] inbox data
|
|
27
|
+
def get_inbox(project_id:, inbox_id:)
|
|
28
|
+
http_get(bucket_path(project_id, "/inboxes/#{inbox_id}.json")).json
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Lists all forwards in an inbox.
|
|
32
|
+
#
|
|
33
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
34
|
+
# @param inbox_id [Integer, String] inbox ID
|
|
35
|
+
# @return [Enumerator<Hash>] forwards
|
|
36
|
+
def list(project_id:, inbox_id:)
|
|
37
|
+
paginate(bucket_path(project_id, "/inboxes/#{inbox_id}/forwards.json"))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Gets a forward by ID.
|
|
41
|
+
#
|
|
42
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
43
|
+
# @param forward_id [Integer, String] forward ID
|
|
44
|
+
# @return [Hash] forward data
|
|
45
|
+
def get(project_id:, forward_id:)
|
|
46
|
+
http_get(bucket_path(project_id, "/inbox_forwards/#{forward_id}.json")).json
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Lists all replies to a forward.
|
|
50
|
+
#
|
|
51
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
52
|
+
# @param forward_id [Integer, String] forward ID
|
|
53
|
+
# @return [Enumerator<Hash>] replies
|
|
54
|
+
def list_replies(project_id:, forward_id:)
|
|
55
|
+
paginate(bucket_path(project_id, "/inbox_forwards/#{forward_id}/replies.json"))
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Gets a specific reply.
|
|
59
|
+
#
|
|
60
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
61
|
+
# @param forward_id [Integer, String] forward ID
|
|
62
|
+
# @param reply_id [Integer, String] reply ID
|
|
63
|
+
# @return [Hash] reply data
|
|
64
|
+
def get_reply(project_id:, forward_id:, reply_id:)
|
|
65
|
+
http_get(bucket_path(project_id, "/inbox_forwards/#{forward_id}/replies/#{reply_id}.json")).json
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Creates a reply to a forwarded email.
|
|
69
|
+
#
|
|
70
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
71
|
+
# @param forward_id [Integer, String] forward ID
|
|
72
|
+
# @param content [String] reply body in HTML
|
|
73
|
+
# @return [Hash] created reply
|
|
74
|
+
def create_reply(project_id:, forward_id:, content:)
|
|
75
|
+
body = { content: content }
|
|
76
|
+
http_post(bucket_path(project_id, "/inbox_forwards/#{forward_id}/replies.json"), body: body).json
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|