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,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for lineup operations.
|
|
6
|
+
#
|
|
7
|
+
# The Lineup is Basecamp's visual timeline tool for tracking
|
|
8
|
+
# project schedules and milestones.
|
|
9
|
+
#
|
|
10
|
+
# @example Create a marker
|
|
11
|
+
# marker = account.lineup.create_marker(
|
|
12
|
+
# title: "Launch Day",
|
|
13
|
+
# starts_on: "2024-03-01",
|
|
14
|
+
# ends_on: "2024-03-01",
|
|
15
|
+
# color: "green"
|
|
16
|
+
# )
|
|
17
|
+
class LineupService < BaseService
|
|
18
|
+
# Creates a new marker on the lineup.
|
|
19
|
+
#
|
|
20
|
+
# @param title [String] marker title
|
|
21
|
+
# @param starts_on [String] start date (YYYY-MM-DD)
|
|
22
|
+
# @param ends_on [String] end date (YYYY-MM-DD)
|
|
23
|
+
# @param color [String, nil] marker color (white, red, orange, yellow, green, blue, aqua, purple, gray, pink, brown)
|
|
24
|
+
# @param description [String, nil] description in HTML
|
|
25
|
+
# @return [Hash] created marker
|
|
26
|
+
def create_marker(title:, starts_on:, ends_on:, color: nil, description: nil)
|
|
27
|
+
body = compact_params(
|
|
28
|
+
title: title,
|
|
29
|
+
starts_on: starts_on,
|
|
30
|
+
ends_on: ends_on,
|
|
31
|
+
color: color,
|
|
32
|
+
description: description
|
|
33
|
+
)
|
|
34
|
+
http_post("/lineup/markers.json", body: body).json
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Updates an existing marker.
|
|
38
|
+
#
|
|
39
|
+
# @param marker_id [Integer, String] marker ID
|
|
40
|
+
# @param title [String, nil] new title
|
|
41
|
+
# @param starts_on [String, nil] new start date (YYYY-MM-DD)
|
|
42
|
+
# @param ends_on [String, nil] new end date (YYYY-MM-DD)
|
|
43
|
+
# @param color [String, nil] new color
|
|
44
|
+
# @param description [String, nil] new description
|
|
45
|
+
# @return [Hash] updated marker
|
|
46
|
+
def update_marker(marker_id:, title: nil, starts_on: nil, ends_on: nil, color: nil, description: nil)
|
|
47
|
+
body = compact_params(
|
|
48
|
+
title: title,
|
|
49
|
+
starts_on: starts_on,
|
|
50
|
+
ends_on: ends_on,
|
|
51
|
+
color: color,
|
|
52
|
+
description: description
|
|
53
|
+
)
|
|
54
|
+
http_put("/lineup/markers/#{marker_id}", body: body).json
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Deletes a marker.
|
|
58
|
+
#
|
|
59
|
+
# @param marker_id [Integer, String] marker ID
|
|
60
|
+
# @return [void]
|
|
61
|
+
def delete_marker(marker_id:)
|
|
62
|
+
http_delete("/lineup/markers/#{marker_id}")
|
|
63
|
+
nil
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for message board operations.
|
|
6
|
+
#
|
|
7
|
+
# Each project has a message board where team members can post messages
|
|
8
|
+
# (announcements, updates, etc.).
|
|
9
|
+
#
|
|
10
|
+
# @example Get a message board
|
|
11
|
+
# board = account.message_boards.get(project_id: 123, board_id: 456)
|
|
12
|
+
# puts "#{board["title"]} - #{board["messages_count"]} messages"
|
|
13
|
+
class MessageBoardsService < BaseService
|
|
14
|
+
# Gets a specific message board.
|
|
15
|
+
#
|
|
16
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
17
|
+
# @param board_id [Integer, String] message board ID
|
|
18
|
+
# @return [Hash] message board data
|
|
19
|
+
def get(project_id:, board_id:)
|
|
20
|
+
http_get(bucket_path(project_id, "/message_boards/#{board_id}")).json
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for message type (category) operations.
|
|
6
|
+
#
|
|
7
|
+
# Message types (also called categories) are used to categorize messages
|
|
8
|
+
# on a message board. Each message type has a name and icon.
|
|
9
|
+
#
|
|
10
|
+
# @example List message types
|
|
11
|
+
# account.message_types.list(project_id: 123).each do |type|
|
|
12
|
+
# puts "#{type["icon"]} #{type["name"]}"
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# @example Create a message type
|
|
16
|
+
# type = account.message_types.create(
|
|
17
|
+
# project_id: 123,
|
|
18
|
+
# name: "Announcement",
|
|
19
|
+
# icon: "📢"
|
|
20
|
+
# )
|
|
21
|
+
class MessageTypesService < BaseService
|
|
22
|
+
# Lists all message types in a project.
|
|
23
|
+
#
|
|
24
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
25
|
+
# @return [Enumerator<Hash>] message types
|
|
26
|
+
def list(project_id:)
|
|
27
|
+
paginate(bucket_path(project_id, "/categories.json"))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Gets a message type by ID.
|
|
31
|
+
#
|
|
32
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
33
|
+
# @param type_id [Integer, String] message type ID
|
|
34
|
+
# @return [Hash] message type data
|
|
35
|
+
def get(project_id:, type_id:)
|
|
36
|
+
http_get(bucket_path(project_id, "/categories/#{type_id}")).json
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Creates a new message type in a project.
|
|
40
|
+
#
|
|
41
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
42
|
+
# @param name [String] message type name
|
|
43
|
+
# @param icon [String] message type icon
|
|
44
|
+
# @return [Hash] created message type
|
|
45
|
+
def create(project_id:, name:, icon:)
|
|
46
|
+
body = {
|
|
47
|
+
name: name,
|
|
48
|
+
icon: icon
|
|
49
|
+
}
|
|
50
|
+
http_post(bucket_path(project_id, "/categories.json"), body: body).json
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Updates an existing message type.
|
|
54
|
+
#
|
|
55
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
56
|
+
# @param type_id [Integer, String] message type ID
|
|
57
|
+
# @param name [String, nil] new name
|
|
58
|
+
# @param icon [String, nil] new icon
|
|
59
|
+
# @return [Hash] updated message type
|
|
60
|
+
def update(project_id:, type_id:, name: nil, icon: nil)
|
|
61
|
+
body = compact_params(
|
|
62
|
+
name: name,
|
|
63
|
+
icon: icon
|
|
64
|
+
)
|
|
65
|
+
http_put(bucket_path(project_id, "/categories/#{type_id}"), body: body).json
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Deletes a message type from a project.
|
|
69
|
+
#
|
|
70
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
71
|
+
# @param type_id [Integer, String] message type ID
|
|
72
|
+
# @return [void]
|
|
73
|
+
def delete(project_id:, type_id:)
|
|
74
|
+
http_delete(bucket_path(project_id, "/categories/#{type_id}"))
|
|
75
|
+
nil
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for message operations.
|
|
6
|
+
#
|
|
7
|
+
# Messages are posts on a project's message board. They have a subject,
|
|
8
|
+
# content, and can be categorized with message types.
|
|
9
|
+
#
|
|
10
|
+
# @example List messages
|
|
11
|
+
# account.messages.list(project_id: 123, board_id: 456).each do |message|
|
|
12
|
+
# puts "#{message["subject"]} by #{message["creator"]["name"]}"
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# @example Create a message
|
|
16
|
+
# message = account.messages.create(
|
|
17
|
+
# project_id: 123,
|
|
18
|
+
# board_id: 456,
|
|
19
|
+
# subject: "Project Update",
|
|
20
|
+
# content: "<p>Here's what happened this week...</p>"
|
|
21
|
+
# )
|
|
22
|
+
#
|
|
23
|
+
# @example Pin a message
|
|
24
|
+
# account.messages.pin(project_id: 123, message_id: 789)
|
|
25
|
+
class MessagesService < BaseService
|
|
26
|
+
# Lists all messages on a message board.
|
|
27
|
+
#
|
|
28
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
29
|
+
# @param board_id [Integer, String] message board ID
|
|
30
|
+
# @return [Enumerator<Hash>] messages
|
|
31
|
+
def list(project_id:, board_id:)
|
|
32
|
+
paginate(bucket_path(project_id, "/message_boards/#{board_id}/messages.json"))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Gets a specific message.
|
|
36
|
+
#
|
|
37
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
38
|
+
# @param message_id [Integer, String] message ID
|
|
39
|
+
# @return [Hash] message data
|
|
40
|
+
def get(project_id:, message_id:)
|
|
41
|
+
http_get(bucket_path(project_id, "/messages/#{message_id}")).json
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Creates a new message on a message board.
|
|
45
|
+
#
|
|
46
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
47
|
+
# @param board_id [Integer, String] message board ID
|
|
48
|
+
# @param subject [String] message title
|
|
49
|
+
# @param content [String, nil] message body in HTML
|
|
50
|
+
# @param status [String, nil] "drafted" or "active" (defaults to active)
|
|
51
|
+
# @param category_id [Integer, nil] message type ID
|
|
52
|
+
# @return [Hash] created message
|
|
53
|
+
def create(project_id:, board_id:, subject:, content: nil, status: nil, category_id: nil)
|
|
54
|
+
body = compact_params(
|
|
55
|
+
subject: subject,
|
|
56
|
+
content: content,
|
|
57
|
+
status: status,
|
|
58
|
+
category_id: category_id
|
|
59
|
+
)
|
|
60
|
+
http_post(bucket_path(project_id, "/message_boards/#{board_id}/messages.json"), body: body).json
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Updates an existing message.
|
|
64
|
+
#
|
|
65
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
66
|
+
# @param message_id [Integer, String] message ID
|
|
67
|
+
# @param subject [String, nil] new title
|
|
68
|
+
# @param content [String, nil] new content in HTML
|
|
69
|
+
# @param status [String, nil] "drafted" or "active"
|
|
70
|
+
# @param category_id [Integer, nil] message type ID
|
|
71
|
+
# @return [Hash] updated message
|
|
72
|
+
def update(project_id:, message_id:, subject: nil, content: nil, status: nil, category_id: nil)
|
|
73
|
+
body = compact_params(
|
|
74
|
+
subject: subject,
|
|
75
|
+
content: content,
|
|
76
|
+
status: status,
|
|
77
|
+
category_id: category_id
|
|
78
|
+
)
|
|
79
|
+
http_put(bucket_path(project_id, "/messages/#{message_id}"), body: body).json
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Pins a message to the top of the message board.
|
|
83
|
+
#
|
|
84
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
85
|
+
# @param message_id [Integer, String] message ID
|
|
86
|
+
# @return [void]
|
|
87
|
+
def pin(project_id:, message_id:)
|
|
88
|
+
http_post(bucket_path(project_id, "/recordings/#{message_id}/pin.json"))
|
|
89
|
+
nil
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Unpins a message from the top of the message board.
|
|
93
|
+
#
|
|
94
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
95
|
+
# @param message_id [Integer, String] message ID
|
|
96
|
+
# @return [void]
|
|
97
|
+
def unpin(project_id:, message_id:)
|
|
98
|
+
http_delete(bucket_path(project_id, "/recordings/#{message_id}/pin.json"))
|
|
99
|
+
nil
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Archives a message.
|
|
103
|
+
#
|
|
104
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
105
|
+
# @param message_id [Integer, String] message ID
|
|
106
|
+
# @return [void]
|
|
107
|
+
def archive(project_id:, message_id:)
|
|
108
|
+
http_put(bucket_path(project_id, "/recordings/#{message_id}/status/archived.json"))
|
|
109
|
+
nil
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Restores an archived message to active status.
|
|
113
|
+
#
|
|
114
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
115
|
+
# @param message_id [Integer, String] message ID
|
|
116
|
+
# @return [void]
|
|
117
|
+
def unarchive(project_id:, message_id:)
|
|
118
|
+
http_put(bucket_path(project_id, "/recordings/#{message_id}/status/active.json"))
|
|
119
|
+
nil
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Moves a message to the trash.
|
|
123
|
+
#
|
|
124
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
125
|
+
# @param message_id [Integer, String] message ID
|
|
126
|
+
# @return [void]
|
|
127
|
+
def trash(project_id:, message_id:)
|
|
128
|
+
http_put(bucket_path(project_id, "/recordings/#{message_id}/status/trashed.json"))
|
|
129
|
+
nil
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for people operations.
|
|
6
|
+
#
|
|
7
|
+
# People are the users in your Basecamp account.
|
|
8
|
+
#
|
|
9
|
+
# @example List all people
|
|
10
|
+
# account.people.list.each do |person|
|
|
11
|
+
# puts "#{person["name"]} <#{person["email_address"]}>"
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# @example Get current user's profile
|
|
15
|
+
# me = account.people.me
|
|
16
|
+
# puts "Logged in as #{me["name"]}"
|
|
17
|
+
class PeopleService < BaseService
|
|
18
|
+
# Lists all people in the account.
|
|
19
|
+
#
|
|
20
|
+
# @return [Enumerator<Hash>] people
|
|
21
|
+
def list
|
|
22
|
+
paginate("/people.json")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Gets a specific person.
|
|
26
|
+
#
|
|
27
|
+
# @param person_id [Integer, String] person ID
|
|
28
|
+
# @return [Hash] person data
|
|
29
|
+
def get(person_id:)
|
|
30
|
+
http_get("/people/#{person_id}").json
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Gets the current user's profile.
|
|
34
|
+
#
|
|
35
|
+
# @return [Hash] current user's profile
|
|
36
|
+
def me
|
|
37
|
+
http_get("/my/profile.json").json
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Lists all people who can be pinged (mentioned).
|
|
41
|
+
#
|
|
42
|
+
# @return [Enumerator<Hash>] pingable people
|
|
43
|
+
def list_pingable
|
|
44
|
+
paginate("/circles/people.json")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Lists all people in a project.
|
|
48
|
+
#
|
|
49
|
+
# @param project_id [Integer, String] project ID
|
|
50
|
+
# @return [Enumerator<Hash>] project members
|
|
51
|
+
def list_project_people(project_id:)
|
|
52
|
+
paginate("/projects/#{project_id}/people.json")
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Updates project access for users.
|
|
56
|
+
#
|
|
57
|
+
# @param project_id [Integer, String] project ID
|
|
58
|
+
# @param grant [Array<Integer>, nil] user IDs to grant access
|
|
59
|
+
# @param revoke [Array<Integer>, nil] user IDs to revoke access
|
|
60
|
+
# @param create [Array<Hash>, nil] new users to create and grant access
|
|
61
|
+
# @return [void]
|
|
62
|
+
def update_project_access(project_id:, grant: nil, revoke: nil, create: nil)
|
|
63
|
+
body = compact_params(
|
|
64
|
+
grant: grant,
|
|
65
|
+
revoke: revoke,
|
|
66
|
+
create: create
|
|
67
|
+
)
|
|
68
|
+
http_put("/projects/#{project_id}/people/users.json", body: body)
|
|
69
|
+
nil
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for project (Basecamp) operations.
|
|
6
|
+
#
|
|
7
|
+
# @example List all projects
|
|
8
|
+
# account.projects.list.each do |project|
|
|
9
|
+
# puts "#{project["name"]} (#{project["id"]})"
|
|
10
|
+
# end
|
|
11
|
+
#
|
|
12
|
+
# @example Get a specific project
|
|
13
|
+
# project = account.projects.get(123)
|
|
14
|
+
# puts project["name"]
|
|
15
|
+
#
|
|
16
|
+
# @example Create a project
|
|
17
|
+
# project = account.projects.create(name: "My Project", description: "A new project")
|
|
18
|
+
class ProjectsService < BaseService
|
|
19
|
+
# Lists all projects in the account.
|
|
20
|
+
#
|
|
21
|
+
# @param status [String, nil] filter by status ("active", "archived", "trashed")
|
|
22
|
+
# @return [Enumerator<Hash>] projects
|
|
23
|
+
def list(status: nil)
|
|
24
|
+
params = compact_params(status: status)
|
|
25
|
+
paginate("/projects.json", params: params)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Gets a specific project.
|
|
29
|
+
#
|
|
30
|
+
# @param project_id [Integer, String] project ID
|
|
31
|
+
# @return [Hash] project data
|
|
32
|
+
def get(project_id)
|
|
33
|
+
http_get("/projects/#{project_id}.json").json
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Creates a new project.
|
|
37
|
+
#
|
|
38
|
+
# @param name [String] project name
|
|
39
|
+
# @param description [String, nil] project description
|
|
40
|
+
# @return [Hash] created project
|
|
41
|
+
def create(name:, description: nil)
|
|
42
|
+
body = compact_params(name: name, description: description)
|
|
43
|
+
http_post("/projects.json", body: body).json
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Updates a project.
|
|
47
|
+
#
|
|
48
|
+
# @param project_id [Integer, String] project ID
|
|
49
|
+
# @param name [String, nil] new name
|
|
50
|
+
# @param description [String, nil] new description
|
|
51
|
+
# @return [Hash] updated project
|
|
52
|
+
def update(project_id, name: nil, description: nil)
|
|
53
|
+
body = compact_params(name: name, description: description)
|
|
54
|
+
http_put("/projects/#{project_id}.json", body: body).json
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Trashes a project.
|
|
58
|
+
#
|
|
59
|
+
# @param project_id [Integer, String] project ID
|
|
60
|
+
# @return [void]
|
|
61
|
+
def trash(project_id)
|
|
62
|
+
http_delete("/projects/#{project_id}.json")
|
|
63
|
+
nil
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for recording operations.
|
|
6
|
+
#
|
|
7
|
+
# Recordings are the base type for most content in Basecamp, including
|
|
8
|
+
# todos, messages, comments, documents, uploads, etc. This service
|
|
9
|
+
# provides common operations that work across all recording types.
|
|
10
|
+
#
|
|
11
|
+
# @example List all recordings in a project
|
|
12
|
+
# account.recordings.list(type: "Todo", bucket: 123).each do |recording|
|
|
13
|
+
# puts "#{recording["title"]} - #{recording["status"]}"
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# @example Archive a recording
|
|
17
|
+
# account.recordings.archive(project_id: 123, recording_id: 456)
|
|
18
|
+
class RecordingsService < BaseService
|
|
19
|
+
# Lists recordings across projects.
|
|
20
|
+
#
|
|
21
|
+
# @param type [String] recording type (e.g., "Todo", "Message", "Comment")
|
|
22
|
+
# @param bucket [Integer, nil] filter by project ID
|
|
23
|
+
# @param status [String, nil] filter by status ("active", "archived", "trashed")
|
|
24
|
+
# @param sort [String, nil] sort field ("created_at", "updated_at")
|
|
25
|
+
# @param direction [String, nil] sort direction ("asc", "desc")
|
|
26
|
+
# @return [Enumerator<Hash>] recordings
|
|
27
|
+
def list(type:, bucket: nil, status: nil, sort: nil, direction: nil)
|
|
28
|
+
params = compact_params(
|
|
29
|
+
type: type,
|
|
30
|
+
bucket: bucket,
|
|
31
|
+
status: status,
|
|
32
|
+
sort: sort,
|
|
33
|
+
direction: direction
|
|
34
|
+
)
|
|
35
|
+
paginate("/projects/recordings.json", params: params)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Gets a specific recording.
|
|
39
|
+
#
|
|
40
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
41
|
+
# @param recording_id [Integer, String] recording ID
|
|
42
|
+
# @return [Hash] recording data
|
|
43
|
+
def get(project_id:, recording_id:)
|
|
44
|
+
http_get(bucket_path(project_id, "/recordings/#{recording_id}")).json
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Archives a recording.
|
|
48
|
+
#
|
|
49
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
50
|
+
# @param recording_id [Integer, String] recording ID
|
|
51
|
+
# @return [void]
|
|
52
|
+
def archive(project_id:, recording_id:)
|
|
53
|
+
http_put(bucket_path(project_id, "/recordings/#{recording_id}/status/archived.json"))
|
|
54
|
+
nil
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Unarchives a recording (restores to active).
|
|
58
|
+
#
|
|
59
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
60
|
+
# @param recording_id [Integer, String] recording ID
|
|
61
|
+
# @return [void]
|
|
62
|
+
def unarchive(project_id:, recording_id:)
|
|
63
|
+
http_put(bucket_path(project_id, "/recordings/#{recording_id}/status/active.json"))
|
|
64
|
+
nil
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Moves a recording to the trash.
|
|
68
|
+
#
|
|
69
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
70
|
+
# @param recording_id [Integer, String] recording ID
|
|
71
|
+
# @return [void]
|
|
72
|
+
def trash(project_id:, recording_id:)
|
|
73
|
+
http_put(bucket_path(project_id, "/recordings/#{recording_id}/status/trashed.json"))
|
|
74
|
+
nil
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Lists events (change history) for a recording.
|
|
78
|
+
#
|
|
79
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
80
|
+
# @param recording_id [Integer, String] recording ID
|
|
81
|
+
# @return [Enumerator<Hash>] events
|
|
82
|
+
def list_events(project_id:, recording_id:)
|
|
83
|
+
paginate(bucket_path(project_id, "/recordings/#{recording_id}/events.json"))
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Gets the subscription status for a recording.
|
|
87
|
+
#
|
|
88
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
89
|
+
# @param recording_id [Integer, String] recording ID
|
|
90
|
+
# @return [Hash] subscription data
|
|
91
|
+
def get_subscription(project_id:, recording_id:)
|
|
92
|
+
http_get(bucket_path(project_id, "/recordings/#{recording_id}/subscription.json")).json
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Subscribes to a recording.
|
|
96
|
+
#
|
|
97
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
98
|
+
# @param recording_id [Integer, String] recording ID
|
|
99
|
+
# @return [Hash] subscription data
|
|
100
|
+
def subscribe(project_id:, recording_id:)
|
|
101
|
+
http_post(bucket_path(project_id, "/recordings/#{recording_id}/subscription.json")).json
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Unsubscribes from a recording.
|
|
105
|
+
#
|
|
106
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
107
|
+
# @param recording_id [Integer, String] recording ID
|
|
108
|
+
# @return [void]
|
|
109
|
+
def unsubscribe(project_id:, recording_id:)
|
|
110
|
+
http_delete(bucket_path(project_id, "/recordings/#{recording_id}/subscription.json"))
|
|
111
|
+
nil
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Sets client visibility for a recording.
|
|
115
|
+
#
|
|
116
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
117
|
+
# @param recording_id [Integer, String] recording ID
|
|
118
|
+
# @param visible [Boolean] whether clients can see this recording
|
|
119
|
+
# @return [void]
|
|
120
|
+
def set_client_visibility(project_id:, recording_id:, visible:)
|
|
121
|
+
http_put(bucket_path(project_id, "/recordings/#{recording_id}/client_visibility.json"),
|
|
122
|
+
body: { visible: visible })
|
|
123
|
+
nil
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for report operations.
|
|
6
|
+
#
|
|
7
|
+
# Provides access to various report types including timesheet and assigned todos reports.
|
|
8
|
+
#
|
|
9
|
+
# @example Get account-wide timesheet
|
|
10
|
+
# result = account.reports.timesheet
|
|
11
|
+
# result["entries"].each { |e| puts e["hours"] }
|
|
12
|
+
#
|
|
13
|
+
# @example Get list of people with assigned todos
|
|
14
|
+
# people = account.reports.assignable_people.to_a
|
|
15
|
+
#
|
|
16
|
+
# @example Get todos assigned to a specific person
|
|
17
|
+
# result = account.reports.assigned_todos(person_id: 123)
|
|
18
|
+
# result["todos"].each { |todo| puts todo["content"] }
|
|
19
|
+
class ReportsService < BaseService
|
|
20
|
+
# Returns the account-wide timesheet report.
|
|
21
|
+
# This includes time entries across all projects in the account.
|
|
22
|
+
#
|
|
23
|
+
# @param from [String, nil] filter entries on or after this date (ISO 8601)
|
|
24
|
+
# @param to [String, nil] filter entries on or before this date (ISO 8601)
|
|
25
|
+
# @param person_id [Integer, nil] filter entries by a specific person
|
|
26
|
+
# @return [Hash] timesheet report object with "entries" array
|
|
27
|
+
def timesheet(from: nil, to: nil, person_id: nil)
|
|
28
|
+
params = compact_params(from: from, to: to, person_id: person_id)
|
|
29
|
+
response = http_get("/reports/timesheet.json", params: params)
|
|
30
|
+
response.json
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns the timesheet report for a specific project.
|
|
34
|
+
#
|
|
35
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
36
|
+
# @param from [String, nil] filter entries on or after this date (ISO 8601)
|
|
37
|
+
# @param to [String, nil] filter entries on or before this date (ISO 8601)
|
|
38
|
+
# @param person_id [Integer, nil] filter entries by a specific person
|
|
39
|
+
# @return [Hash] timesheet report object with "entries" array
|
|
40
|
+
def project_timesheet(project_id:, from: nil, to: nil, person_id: nil)
|
|
41
|
+
params = compact_params(from: from, to: to, person_id: person_id)
|
|
42
|
+
response = http_get(bucket_path(project_id, "/timesheet.json"), params: params)
|
|
43
|
+
response.json
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns the timesheet report for a specific recording within a project.
|
|
47
|
+
#
|
|
48
|
+
# @param project_id [Integer, String] project (bucket) ID
|
|
49
|
+
# @param recording_id [Integer, String] recording ID (e.g., a todo or message)
|
|
50
|
+
# @param from [String, nil] filter entries on or after this date (ISO 8601)
|
|
51
|
+
# @param to [String, nil] filter entries on or before this date (ISO 8601)
|
|
52
|
+
# @param person_id [Integer, nil] filter entries by a specific person
|
|
53
|
+
# @return [Hash] timesheet report object with "entries" array
|
|
54
|
+
def recording_timesheet(project_id:, recording_id:, from: nil, to: nil, person_id: nil)
|
|
55
|
+
params = compact_params(from: from, to: to, person_id: person_id)
|
|
56
|
+
response = http_get(bucket_path(project_id, "/recordings/#{recording_id}/timesheet.json"), params: params)
|
|
57
|
+
response.json
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Returns the list of people who have assigned todos.
|
|
61
|
+
# Use assigned_todos(person_id:) to get the actual todos for a specific person.
|
|
62
|
+
#
|
|
63
|
+
# @return [Enumerator<Hash>] list of Person objects
|
|
64
|
+
def assignable_people
|
|
65
|
+
paginate("/reports/todos/assigned.json")
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Returns all todos assigned to a specific person.
|
|
69
|
+
#
|
|
70
|
+
# @param person_id [Integer, String] person ID
|
|
71
|
+
# @param group_by [String, nil] grouping method: "bucket" or "date"
|
|
72
|
+
# @return [Hash] object with "person", "grouped_by", and "todos" keys
|
|
73
|
+
def assigned_todos(person_id:, group_by: nil)
|
|
74
|
+
params = compact_params(group_by: group_by)
|
|
75
|
+
response = http_get("/reports/todos/assigned/#{person_id}", params: params)
|
|
76
|
+
response.json
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|