basecamp-sdk 0.7.3 → 0.9.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/README.md +65 -1
- data/basecamp-sdk.gemspec +2 -3
- data/lib/basecamp/client.rb +5 -0
- data/lib/basecamp/generated/metadata.json +100 -33
- data/lib/basecamp/generated/services/base_service.rb +13 -0
- data/lib/basecamp/generated/services/campfires_service.rb +15 -3
- data/lib/basecamp/generated/services/card_columns_service.rb +26 -23
- data/lib/basecamp/generated/services/checkins_service.rb +5 -4
- data/lib/basecamp/generated/services/client_approvals_service.rb +1 -1
- data/lib/basecamp/generated/services/client_correspondences_service.rb +1 -1
- data/lib/basecamp/generated/services/documents_service.rb +3 -2
- data/lib/basecamp/generated/services/forwards_service.rb +1 -1
- data/lib/basecamp/generated/services/gauges_service.rb +4 -4
- data/lib/basecamp/generated/services/messages_service.rb +4 -3
- data/lib/basecamp/generated/services/my_assignments_service.rb +1 -1
- data/lib/basecamp/generated/services/my_notifications_service.rb +1 -1
- data/lib/basecamp/generated/services/people_service.rb +2 -2
- data/lib/basecamp/generated/services/projects_service.rb +2 -2
- data/lib/basecamp/generated/services/recordings_service.rb +1 -1
- data/lib/basecamp/generated/services/reports_service.rb +3 -3
- data/lib/basecamp/generated/services/schedules_service.rb +5 -4
- data/lib/basecamp/generated/services/search_service.rb +14 -3
- data/lib/basecamp/generated/services/templates_service.rb +4 -5
- data/lib/basecamp/generated/services/timesheets_service.rb +3 -3
- data/lib/basecamp/generated/services/todolists_service.rb +15 -3
- data/lib/basecamp/generated/services/todos_service.rb +5 -5
- data/lib/basecamp/generated/services/tools_service.rb +7 -6
- data/lib/basecamp/generated/services/uploads_service.rb +20 -2
- data/lib/basecamp/generated/services/webhooks_service.rb +2 -2
- data/lib/basecamp/generated/services/wormholes_service.rb +44 -0
- data/lib/basecamp/generated/types.rb +284 -64
- data/lib/basecamp/http.rb +86 -15
- data/lib/basecamp/oauth/config.rb +20 -5
- data/lib/basecamp/oauth/discovery.rb +134 -64
- data/lib/basecamp/oauth/discovery_result.rb +33 -0
- data/lib/basecamp/oauth/discovery_selection_error.rb +30 -0
- data/lib/basecamp/oauth/fetcher.rb +204 -0
- data/lib/basecamp/oauth/protected_resource_metadata.rb +22 -0
- data/lib/basecamp/oauth/resource.rb +95 -0
- data/lib/basecamp/oauth.rb +173 -0
- data/lib/basecamp/security.rb +83 -0
- data/lib/basecamp/services/authorization_service.rb +45 -0
- data/lib/basecamp/services/todos_extensions.rb +121 -0
- data/lib/basecamp/version.rb +2 -2
- data/lib/basecamp.rb +6 -0
- data/scripts/generate-services.rb +61 -13
- data/scripts/generate-types.rb +33 -1
- metadata +14 -21
- data/lib/basecamp/generated/services/authorization_service.rb +0 -47
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e872009b6b4862fca29c9f3d432d1b60c6629b77d6f3a293983b56bb0afc249a
|
|
4
|
+
data.tar.gz: 3aa007580b800dde800072fb5b13ef21cc619800194f1a0c1d34f3d76db85ba8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e229aad8ab09a80b14abf54abce5d4d205c71b3b2ad2105cd03a3a152ba4d6ee5eefc5d5538bbd6ebf4dda0892fb9073a92e9cd4334d76521533f08c2e47320f
|
|
7
|
+
data.tar.gz: ac047d82d5997039b26db6b1848cd151bb662c96837210c233614fdb4e170ee65daad81cf6048d5f3656468bafacad4327f2117c6556c3629973b0470c420087
|
data/README.md
CHANGED
|
@@ -133,9 +133,53 @@ if token.expired?
|
|
|
133
133
|
end
|
|
134
134
|
```
|
|
135
135
|
|
|
136
|
+
### Resource-First Discovery (RFC 9728 + RFC 8414)
|
|
137
|
+
|
|
138
|
+
BC5's Authorization Server (AS) metadata lives only at the canonical issuer (the
|
|
139
|
+
web host), so discovery starts from the **resource** (the API host) rather than
|
|
140
|
+
probing the API host for AS metadata. Three composable operations are provided:
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
# RFC 8414 — AS metadata for a known issuer, bound to the requested issuer by
|
|
144
|
+
# code-point. token_endpoint is required; authorization_endpoint is OPTIONAL
|
|
145
|
+
# (device-only servers omit it) — authorization-code consumers must assert it.
|
|
146
|
+
config = Basecamp::Oauth.discover("https://launchpad.37signals.com")
|
|
147
|
+
|
|
148
|
+
# RFC 9728 — protected-resource metadata for a resource origin. resource is
|
|
149
|
+
# bound by code-point; authorization_servers preserves absent (nil) vs [].
|
|
150
|
+
resource = Basecamp::Oauth.discover_protected_resource("https://3.basecampapi.com")
|
|
151
|
+
|
|
152
|
+
# Orchestrator — resource-first selection + stage-sensitive fallback.
|
|
153
|
+
result = Basecamp::Oauth.discover_from_resource(
|
|
154
|
+
"https://3.basecampapi.com",
|
|
155
|
+
expected_issuer: nil # optional: authoritative issuer selection
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
if result.selected?
|
|
159
|
+
config = result.config # bound AS config for the selected issuer
|
|
160
|
+
else
|
|
161
|
+
# Only two SOFT reasons ever yield a fallback (→ Launchpad):
|
|
162
|
+
# "resource_discovery_failed" | "no_as_advertised"
|
|
163
|
+
result.reason
|
|
164
|
+
end
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
`discover_from_resource` returns a `DiscoveryResult` that is either **selected**
|
|
168
|
+
or a **soft fallback**. Every *hard* failure — an ambiguous advertised set, an
|
|
169
|
+
unavailable `expected_issuer`, an invalid advertised issuer origin, an AS-metadata
|
|
170
|
+
fetch failure, or an issuer-binding mismatch after a BC5 issuer was selected —
|
|
171
|
+
raises `Basecamp::Oauth::DiscoverySelectionError` (carrying a `reason`). A hard
|
|
172
|
+
failure is **never** silently converted into a Launchpad request.
|
|
173
|
+
|
|
174
|
+
All discovery fetches are SSRF-hardened: origins are validated against the
|
|
175
|
+
origin-root profile (HTTPS-only, localhost exempt) with Ruby's `URI` parser before
|
|
176
|
+
any socket opens, redirects are not followed, timeouts are bounded, non-2xx maps
|
|
177
|
+
to `api_error`, and the response body is read under a genuine streaming cap that
|
|
178
|
+
aborts before an oversized body is buffered.
|
|
179
|
+
|
|
136
180
|
## Services
|
|
137
181
|
|
|
138
|
-
The SDK provides
|
|
182
|
+
The SDK provides 45 account-scoped services. The table below covers the common ones; see `lib/basecamp/generated/services/` for the authoritative, complete set:
|
|
139
183
|
|
|
140
184
|
| Service | Description |
|
|
141
185
|
|---------|-------------|
|
|
@@ -166,6 +210,7 @@ The SDK provides 37 services covering the complete Basecamp API:
|
|
|
166
210
|
| `card_tables` | Card tables (kanban) |
|
|
167
211
|
| `card_columns` | Card table columns |
|
|
168
212
|
| `card_steps` | Card workflow steps |
|
|
213
|
+
| `wormholes` | Card table wormholes (cross-project moves) |
|
|
169
214
|
| `lineup` | Card lineup view |
|
|
170
215
|
| `tools` | Project dock tools |
|
|
171
216
|
| `search` | Full-text search |
|
|
@@ -194,6 +239,25 @@ first_10 = account.todos.list(todolist_id: 456).take(10)
|
|
|
194
239
|
all_projects = account.projects.list.to_a
|
|
195
240
|
```
|
|
196
241
|
|
|
242
|
+
## Downloading Files
|
|
243
|
+
|
|
244
|
+
Fetch an upload's file content in one call. The SDK fetches the upload
|
|
245
|
+
metadata, then follows the authenticated-hop + 302 flow against the
|
|
246
|
+
signed storage URL.
|
|
247
|
+
|
|
248
|
+
```ruby
|
|
249
|
+
result = account.uploads.download(upload_id: 1069479400)
|
|
250
|
+
File.binwrite("uploaded.bin", result.body)
|
|
251
|
+
# result.content_type, result.content_length, result.filename are also available
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
For any authenticated download URL (e.g. a `download_url` you already
|
|
255
|
+
have in hand), use `AccountClient#download_url`:
|
|
256
|
+
|
|
257
|
+
```ruby
|
|
258
|
+
result = account.download_url(url)
|
|
259
|
+
```
|
|
260
|
+
|
|
197
261
|
## Retry Behavior
|
|
198
262
|
|
|
199
263
|
GET requests automatically retry on transient failures with exponential backoff:
|
data/basecamp-sdk.gemspec
CHANGED
|
@@ -37,10 +37,9 @@ Gem::Specification.new do |spec|
|
|
|
37
37
|
spec.add_development_dependency 'minitest', '~> 6.0'
|
|
38
38
|
spec.add_development_dependency 'rake', '~> 13.0'
|
|
39
39
|
spec.add_development_dependency 'rubocop-37signals'
|
|
40
|
-
spec.add_development_dependency 'simplecov', '~> 0
|
|
40
|
+
spec.add_development_dependency 'simplecov', '~> 1.0'
|
|
41
41
|
spec.add_development_dependency 'webmock', '~> 3.24'
|
|
42
42
|
spec.add_development_dependency 'irb', '~> 1.15'
|
|
43
|
-
spec.add_development_dependency 'rdoc', '~>
|
|
44
|
-
spec.add_development_dependency 'webrick', '~> 1.9'
|
|
43
|
+
spec.add_development_dependency 'rdoc', '~> 8.0'
|
|
45
44
|
spec.add_development_dependency 'yard', '~> 0.9'
|
|
46
45
|
end
|
data/lib/basecamp/client.rb
CHANGED
|
@@ -431,6 +431,11 @@ module Basecamp
|
|
|
431
431
|
service(:card_steps) { Services::CardStepsService.new(self) }
|
|
432
432
|
end
|
|
433
433
|
|
|
434
|
+
# @return [Services::WormholesService]
|
|
435
|
+
def wormholes
|
|
436
|
+
service(:wormholes) { Services::WormholesService.new(self) }
|
|
437
|
+
end
|
|
438
|
+
|
|
434
439
|
# @return [Services::TemplatesService]
|
|
435
440
|
def templates
|
|
436
441
|
service(:templates) { Services::TemplatesService.new(self) }
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://basecamp.com/schemas/sdk-metadata.json",
|
|
3
3
|
"version": "1.0.0",
|
|
4
|
-
"generated": "2026-
|
|
4
|
+
"generated": "2026-07-23T19:34:23Z",
|
|
5
5
|
"operations": {
|
|
6
6
|
"GetAccount": {
|
|
7
7
|
"retry": {
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"natural": true
|
|
93
93
|
}
|
|
94
94
|
},
|
|
95
|
-
"
|
|
95
|
+
"SetCardColumnColor": {
|
|
96
96
|
"retry": {
|
|
97
97
|
"maxAttempts": 3,
|
|
98
98
|
"baseDelayMs": 1000,
|
|
@@ -102,13 +102,11 @@
|
|
|
102
102
|
503
|
|
103
103
|
]
|
|
104
104
|
},
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
"totalCountHeader": "X-Total-Count",
|
|
108
|
-
"maxPageSize": 50
|
|
105
|
+
"idempotent": {
|
|
106
|
+
"natural": true
|
|
109
107
|
}
|
|
110
108
|
},
|
|
111
|
-
"
|
|
109
|
+
"EnableCardColumnOnHold": {
|
|
112
110
|
"retry": {
|
|
113
111
|
"maxAttempts": 2,
|
|
114
112
|
"baseDelayMs": 1000,
|
|
@@ -119,7 +117,7 @@
|
|
|
119
117
|
]
|
|
120
118
|
}
|
|
121
119
|
},
|
|
122
|
-
"
|
|
120
|
+
"DisableCardColumnOnHold": {
|
|
123
121
|
"retry": {
|
|
124
122
|
"maxAttempts": 3,
|
|
125
123
|
"baseDelayMs": 1000,
|
|
@@ -128,9 +126,12 @@
|
|
|
128
126
|
429,
|
|
129
127
|
503
|
|
130
128
|
]
|
|
129
|
+
},
|
|
130
|
+
"idempotent": {
|
|
131
|
+
"natural": true
|
|
131
132
|
}
|
|
132
133
|
},
|
|
133
|
-
"
|
|
134
|
+
"UpdateWormhole": {
|
|
134
135
|
"retry": {
|
|
135
136
|
"maxAttempts": 3,
|
|
136
137
|
"baseDelayMs": 1000,
|
|
@@ -144,18 +145,21 @@
|
|
|
144
145
|
"natural": true
|
|
145
146
|
}
|
|
146
147
|
},
|
|
147
|
-
"
|
|
148
|
+
"DeleteWormhole": {
|
|
148
149
|
"retry": {
|
|
149
|
-
"maxAttempts":
|
|
150
|
+
"maxAttempts": 3,
|
|
150
151
|
"baseDelayMs": 1000,
|
|
151
152
|
"backoff": "exponential",
|
|
152
153
|
"retryOn": [
|
|
153
154
|
429,
|
|
154
155
|
503
|
|
155
156
|
]
|
|
157
|
+
},
|
|
158
|
+
"idempotent": {
|
|
159
|
+
"natural": true
|
|
156
160
|
}
|
|
157
161
|
},
|
|
158
|
-
"
|
|
162
|
+
"CreateWormhole": {
|
|
159
163
|
"retry": {
|
|
160
164
|
"maxAttempts": 2,
|
|
161
165
|
"baseDelayMs": 1000,
|
|
@@ -166,7 +170,7 @@
|
|
|
166
170
|
]
|
|
167
171
|
}
|
|
168
172
|
},
|
|
169
|
-
"
|
|
173
|
+
"CreateTool": {
|
|
170
174
|
"retry": {
|
|
171
175
|
"maxAttempts": 2,
|
|
172
176
|
"baseDelayMs": 1000,
|
|
@@ -177,7 +181,7 @@
|
|
|
177
181
|
]
|
|
178
182
|
}
|
|
179
183
|
},
|
|
180
|
-
"
|
|
184
|
+
"ListWebhooks": {
|
|
181
185
|
"retry": {
|
|
182
186
|
"maxAttempts": 3,
|
|
183
187
|
"baseDelayMs": 1000,
|
|
@@ -186,9 +190,25 @@
|
|
|
186
190
|
429,
|
|
187
191
|
503
|
|
188
192
|
]
|
|
193
|
+
},
|
|
194
|
+
"pagination": {
|
|
195
|
+
"style": "link",
|
|
196
|
+
"totalCountHeader": "X-Total-Count",
|
|
197
|
+
"maxPageSize": 50
|
|
189
198
|
}
|
|
190
199
|
},
|
|
191
|
-
"
|
|
200
|
+
"CreateWebhook": {
|
|
201
|
+
"retry": {
|
|
202
|
+
"maxAttempts": 2,
|
|
203
|
+
"baseDelayMs": 1000,
|
|
204
|
+
"backoff": "exponential",
|
|
205
|
+
"retryOn": [
|
|
206
|
+
429,
|
|
207
|
+
503
|
|
208
|
+
]
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
"GetCard": {
|
|
192
212
|
"retry": {
|
|
193
213
|
"maxAttempts": 3,
|
|
194
214
|
"baseDelayMs": 1000,
|
|
@@ -197,12 +217,9 @@
|
|
|
197
217
|
429,
|
|
198
218
|
503
|
|
199
219
|
]
|
|
200
|
-
},
|
|
201
|
-
"idempotent": {
|
|
202
|
-
"natural": true
|
|
203
220
|
}
|
|
204
221
|
},
|
|
205
|
-
"
|
|
222
|
+
"UpdateCard": {
|
|
206
223
|
"retry": {
|
|
207
224
|
"maxAttempts": 3,
|
|
208
225
|
"baseDelayMs": 1000,
|
|
@@ -216,7 +233,7 @@
|
|
|
216
233
|
"natural": true
|
|
217
234
|
}
|
|
218
235
|
},
|
|
219
|
-
"
|
|
236
|
+
"MoveCard": {
|
|
220
237
|
"retry": {
|
|
221
238
|
"maxAttempts": 2,
|
|
222
239
|
"baseDelayMs": 1000,
|
|
@@ -227,7 +244,40 @@
|
|
|
227
244
|
]
|
|
228
245
|
}
|
|
229
246
|
},
|
|
230
|
-
"
|
|
247
|
+
"RepositionCardStep": {
|
|
248
|
+
"retry": {
|
|
249
|
+
"maxAttempts": 2,
|
|
250
|
+
"baseDelayMs": 1000,
|
|
251
|
+
"backoff": "exponential",
|
|
252
|
+
"retryOn": [
|
|
253
|
+
429,
|
|
254
|
+
503
|
|
255
|
+
]
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
"CreateCardStep": {
|
|
259
|
+
"retry": {
|
|
260
|
+
"maxAttempts": 2,
|
|
261
|
+
"baseDelayMs": 1000,
|
|
262
|
+
"backoff": "exponential",
|
|
263
|
+
"retryOn": [
|
|
264
|
+
429,
|
|
265
|
+
503
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
"GetCardColumn": {
|
|
270
|
+
"retry": {
|
|
271
|
+
"maxAttempts": 3,
|
|
272
|
+
"baseDelayMs": 1000,
|
|
273
|
+
"backoff": "exponential",
|
|
274
|
+
"retryOn": [
|
|
275
|
+
429,
|
|
276
|
+
503
|
|
277
|
+
]
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
"UpdateCardColumn": {
|
|
231
281
|
"retry": {
|
|
232
282
|
"maxAttempts": 3,
|
|
233
283
|
"baseDelayMs": 1000,
|
|
@@ -565,6 +615,20 @@
|
|
|
565
615
|
]
|
|
566
616
|
}
|
|
567
617
|
},
|
|
618
|
+
"UpdateCampfireLine": {
|
|
619
|
+
"retry": {
|
|
620
|
+
"maxAttempts": 3,
|
|
621
|
+
"baseDelayMs": 1000,
|
|
622
|
+
"backoff": "exponential",
|
|
623
|
+
"retryOn": [
|
|
624
|
+
429,
|
|
625
|
+
503
|
|
626
|
+
]
|
|
627
|
+
},
|
|
628
|
+
"idempotent": {
|
|
629
|
+
"natural": true
|
|
630
|
+
}
|
|
631
|
+
},
|
|
568
632
|
"DeleteCampfireLine": {
|
|
569
633
|
"retry": {
|
|
570
634
|
"maxAttempts": 3,
|
|
@@ -728,17 +792,6 @@
|
|
|
728
792
|
"natural": true
|
|
729
793
|
}
|
|
730
794
|
},
|
|
731
|
-
"CloneTool": {
|
|
732
|
-
"retry": {
|
|
733
|
-
"maxAttempts": 2,
|
|
734
|
-
"baseDelayMs": 1000,
|
|
735
|
-
"backoff": "exponential",
|
|
736
|
-
"retryOn": [
|
|
737
|
-
429,
|
|
738
|
-
503
|
|
739
|
-
]
|
|
740
|
-
}
|
|
741
|
-
},
|
|
742
795
|
"GetTool": {
|
|
743
796
|
"retry": {
|
|
744
797
|
"maxAttempts": 3,
|
|
@@ -2329,7 +2382,7 @@
|
|
|
2329
2382
|
]
|
|
2330
2383
|
}
|
|
2331
2384
|
},
|
|
2332
|
-
"
|
|
2385
|
+
"ReplaceTodo": {
|
|
2333
2386
|
"retry": {
|
|
2334
2387
|
"maxAttempts": 3,
|
|
2335
2388
|
"baseDelayMs": 1000,
|
|
@@ -2399,6 +2452,20 @@
|
|
|
2399
2452
|
"natural": true
|
|
2400
2453
|
}
|
|
2401
2454
|
},
|
|
2455
|
+
"RepositionTodolist": {
|
|
2456
|
+
"retry": {
|
|
2457
|
+
"maxAttempts": 3,
|
|
2458
|
+
"baseDelayMs": 1000,
|
|
2459
|
+
"backoff": "exponential",
|
|
2460
|
+
"retryOn": [
|
|
2461
|
+
429,
|
|
2462
|
+
503
|
|
2463
|
+
]
|
|
2464
|
+
},
|
|
2465
|
+
"idempotent": {
|
|
2466
|
+
"natural": true
|
|
2467
|
+
}
|
|
2468
|
+
},
|
|
2402
2469
|
"GetTodoset": {
|
|
2403
2470
|
"retry": {
|
|
2404
2471
|
"maxAttempts": 3,
|
|
@@ -141,6 +141,19 @@ module Basecamp
|
|
|
141
141
|
kwargs.compact
|
|
142
142
|
end
|
|
143
143
|
|
|
144
|
+
# Like compact_params, but also drops empty arrays. For query filters an
|
|
145
|
+
# empty array means "no filter" and must be omitted entirely: Faraday's
|
|
146
|
+
# nested encoder would otherwise emit a bare `bucket_ids[]`, which Rails
|
|
147
|
+
# normalizes into a bogus `[0]` filter instead of the unfiltered request
|
|
148
|
+
# the caller intended. Not used for request bodies, where an explicit
|
|
149
|
+
# empty array (e.g. clearing a list) can be meaningful.
|
|
150
|
+
#
|
|
151
|
+
# @param hash [Hash] the input hash
|
|
152
|
+
# @return [Hash] hash with nil values and empty arrays removed
|
|
153
|
+
def compact_query_params(**kwargs)
|
|
154
|
+
kwargs.reject { |_, value| value.nil? || value == [] }
|
|
155
|
+
end
|
|
156
|
+
|
|
144
157
|
# Build a bucket (project) path.
|
|
145
158
|
# @param project_id [Integer, String] the project/bucket ID
|
|
146
159
|
# @param path [String] the path suffix
|
|
@@ -86,7 +86,7 @@ module Basecamp
|
|
|
86
86
|
# @return [Enumerator<Hash>] paginated results
|
|
87
87
|
def list_lines(campfire_id:, sort: nil, direction: nil)
|
|
88
88
|
wrap_paginated(service: "campfires", operation: "list_lines", is_mutation: false, resource_id: campfire_id) do
|
|
89
|
-
params =
|
|
89
|
+
params = compact_query_params(sort: sort, direction: direction)
|
|
90
90
|
paginate("/chats/#{campfire_id}/lines.json", params: params)
|
|
91
91
|
end
|
|
92
92
|
end
|
|
@@ -112,7 +112,19 @@ module Basecamp
|
|
|
112
112
|
end
|
|
113
113
|
end
|
|
114
114
|
|
|
115
|
-
#
|
|
115
|
+
# Update an existing campfire line; the content is always treated as rich text (HTML).
|
|
116
|
+
# @param campfire_id [Integer] campfire id ID
|
|
117
|
+
# @param line_id [Integer] line id ID
|
|
118
|
+
# @param content [String] The new line content, interpreted as rich text (HTML)
|
|
119
|
+
# @return [void]
|
|
120
|
+
def update_line(campfire_id:, line_id:, content:)
|
|
121
|
+
with_operation(service: "campfires", operation: "update_line", is_mutation: true, resource_id: line_id) do
|
|
122
|
+
http_put("/chats/#{campfire_id}/lines/#{line_id}", body: compact_params(content: content))
|
|
123
|
+
nil
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Delete a campfire line; allowed for the line's creator or an admin.
|
|
116
128
|
# @param campfire_id [Integer] campfire id ID
|
|
117
129
|
# @param line_id [Integer] line id ID
|
|
118
130
|
# @return [void]
|
|
@@ -130,7 +142,7 @@ module Basecamp
|
|
|
130
142
|
# @return [Enumerator<Hash>] paginated results
|
|
131
143
|
def list_uploads(campfire_id:, sort: nil, direction: nil)
|
|
132
144
|
wrap_paginated(service: "campfires", operation: "list_uploads", is_mutation: false, resource_id: campfire_id) do
|
|
133
|
-
params =
|
|
145
|
+
params = compact_query_params(sort: sort, direction: direction)
|
|
134
146
|
paginate("/chats/#{campfire_id}/uploads.json", params: params)
|
|
135
147
|
end
|
|
136
148
|
end
|
|
@@ -7,51 +7,54 @@ module Basecamp
|
|
|
7
7
|
# @generated from OpenAPI spec
|
|
8
8
|
class CardColumnsService < BaseService
|
|
9
9
|
|
|
10
|
-
#
|
|
10
|
+
# Set the color of a column
|
|
11
|
+
# @param bucket_id [Integer] bucket id ID
|
|
11
12
|
# @param column_id [Integer] column id ID
|
|
13
|
+
# @param color [String] Valid colors: white, red, orange, yellow, green, blue, aqua, purple, gray, pink, brown
|
|
12
14
|
# @return [Hash] response data
|
|
13
|
-
def
|
|
14
|
-
with_operation(service: "cardcolumns", operation: "
|
|
15
|
-
|
|
15
|
+
def set_color(bucket_id:, column_id:, color:)
|
|
16
|
+
with_operation(service: "cardcolumns", operation: "set_color", is_mutation: true, project_id: bucket_id, resource_id: column_id) do
|
|
17
|
+
http_put("/buckets/#{bucket_id}/card_tables/columns/#{column_id}/color.json", body: compact_params(color: color)).json
|
|
16
18
|
end
|
|
17
19
|
end
|
|
18
20
|
|
|
19
|
-
#
|
|
21
|
+
# Enable on-hold section in a column
|
|
22
|
+
# @param bucket_id [Integer] bucket id ID
|
|
20
23
|
# @param column_id [Integer] column id ID
|
|
21
|
-
# @param title [String, nil] title
|
|
22
|
-
# @param description [String, nil] description
|
|
23
24
|
# @return [Hash] response data
|
|
24
|
-
def
|
|
25
|
-
with_operation(service: "cardcolumns", operation: "
|
|
26
|
-
|
|
25
|
+
def enable_on_hold(bucket_id:, column_id:)
|
|
26
|
+
with_operation(service: "cardcolumns", operation: "enable_on_hold", is_mutation: true, project_id: bucket_id, resource_id: column_id) do
|
|
27
|
+
http_post("/buckets/#{bucket_id}/card_tables/columns/#{column_id}/on_hold.json").json
|
|
27
28
|
end
|
|
28
29
|
end
|
|
29
30
|
|
|
30
|
-
#
|
|
31
|
+
# Disable on-hold section in a column
|
|
32
|
+
# @param bucket_id [Integer] bucket id ID
|
|
31
33
|
# @param column_id [Integer] column id ID
|
|
32
|
-
# @param color [String] Valid colors: white, red, orange, yellow, green, blue, aqua, purple, gray, pink, brown
|
|
33
34
|
# @return [Hash] response data
|
|
34
|
-
def
|
|
35
|
-
with_operation(service: "cardcolumns", operation: "
|
|
36
|
-
|
|
35
|
+
def disable_on_hold(bucket_id:, column_id:)
|
|
36
|
+
with_operation(service: "cardcolumns", operation: "disable_on_hold", is_mutation: true, project_id: bucket_id, resource_id: column_id) do
|
|
37
|
+
http_delete("/buckets/#{bucket_id}/card_tables/columns/#{column_id}/on_hold.json").json
|
|
37
38
|
end
|
|
38
39
|
end
|
|
39
40
|
|
|
40
|
-
#
|
|
41
|
+
# Get a card column by ID
|
|
41
42
|
# @param column_id [Integer] column id ID
|
|
42
43
|
# @return [Hash] response data
|
|
43
|
-
def
|
|
44
|
-
with_operation(service: "cardcolumns", operation: "
|
|
45
|
-
|
|
44
|
+
def get(column_id:)
|
|
45
|
+
with_operation(service: "cardcolumns", operation: "get", is_mutation: false, resource_id: column_id) do
|
|
46
|
+
http_get("/card_tables/columns/#{column_id}").json
|
|
46
47
|
end
|
|
47
48
|
end
|
|
48
49
|
|
|
49
|
-
#
|
|
50
|
+
# Update an existing column
|
|
50
51
|
# @param column_id [Integer] column id ID
|
|
52
|
+
# @param title [String, nil] title
|
|
53
|
+
# @param description [String, nil] description
|
|
51
54
|
# @return [Hash] response data
|
|
52
|
-
def
|
|
53
|
-
with_operation(service: "cardcolumns", operation: "
|
|
54
|
-
|
|
55
|
+
def update(column_id:, title: nil, description: nil)
|
|
56
|
+
with_operation(service: "cardcolumns", operation: "update", is_mutation: true, resource_id: column_id) do
|
|
57
|
+
http_put("/card_tables/columns/#{column_id}", body: compact_params(title: title, description: description)).json
|
|
55
58
|
end
|
|
56
59
|
end
|
|
57
60
|
|
|
@@ -57,11 +57,12 @@ module Basecamp
|
|
|
57
57
|
# Create a new question in a questionnaire
|
|
58
58
|
# @param questionnaire_id [Integer] questionnaire id ID
|
|
59
59
|
# @param title [String] title
|
|
60
|
-
# @param schedule [
|
|
60
|
+
# @param schedule [Hash] schedule
|
|
61
|
+
# @param visible_to_clients [Boolean, nil] visible to clients
|
|
61
62
|
# @return [Hash] response data
|
|
62
|
-
def create_question(questionnaire_id:, title:, schedule:)
|
|
63
|
+
def create_question(questionnaire_id:, title:, schedule:, visible_to_clients: nil)
|
|
63
64
|
with_operation(service: "checkins", operation: "create_question", is_mutation: true, resource_id: questionnaire_id) do
|
|
64
|
-
http_post("/questionnaires/#{questionnaire_id}/questions.json", body: compact_params(title: title, schedule: schedule)).json
|
|
65
|
+
http_post("/questionnaires/#{questionnaire_id}/questions.json", body: compact_params(title: title, schedule: schedule, visible_to_clients: visible_to_clients)).json
|
|
65
66
|
end
|
|
66
67
|
end
|
|
67
68
|
|
|
@@ -77,7 +78,7 @@ module Basecamp
|
|
|
77
78
|
# Update an existing question
|
|
78
79
|
# @param question_id [Integer] question id ID
|
|
79
80
|
# @param title [String, nil] title
|
|
80
|
-
# @param schedule [
|
|
81
|
+
# @param schedule [Hash, nil] schedule
|
|
81
82
|
# @param paused [Boolean, nil] paused
|
|
82
83
|
# @return [Hash] response data
|
|
83
84
|
def update_question(question_id:, title: nil, schedule: nil, paused: nil)
|
|
@@ -13,7 +13,7 @@ module Basecamp
|
|
|
13
13
|
# @return [Enumerator<Hash>] paginated results
|
|
14
14
|
def list(sort: nil, direction: nil)
|
|
15
15
|
wrap_paginated(service: "clientapprovals", operation: "list", is_mutation: false) do
|
|
16
|
-
params =
|
|
16
|
+
params = compact_query_params(sort: sort, direction: direction)
|
|
17
17
|
paginate("/client/approvals.json", params: params)
|
|
18
18
|
end
|
|
19
19
|
end
|
|
@@ -13,7 +13,7 @@ module Basecamp
|
|
|
13
13
|
# @return [Enumerator<Hash>] paginated results
|
|
14
14
|
def list(sort: nil, direction: nil)
|
|
15
15
|
wrap_paginated(service: "clientcorrespondences", operation: "list", is_mutation: false) do
|
|
16
|
-
params =
|
|
16
|
+
params = compact_query_params(sort: sort, direction: direction)
|
|
17
17
|
paginate("/client/correspondences.json", params: params)
|
|
18
18
|
end
|
|
19
19
|
end
|
|
@@ -42,10 +42,11 @@ module Basecamp
|
|
|
42
42
|
# @param content [String, nil] content
|
|
43
43
|
# @param status [String, nil] active|drafted
|
|
44
44
|
# @param subscriptions [Array, nil] subscriptions
|
|
45
|
+
# @param visible_to_clients [Boolean, nil] visible to clients
|
|
45
46
|
# @return [Hash] response data
|
|
46
|
-
def create(vault_id:, title:, content: nil, status: nil, subscriptions: nil)
|
|
47
|
+
def create(vault_id:, title:, content: nil, status: nil, subscriptions: nil, visible_to_clients: nil)
|
|
47
48
|
with_operation(service: "documents", operation: "create", is_mutation: true, resource_id: vault_id) do
|
|
48
|
-
http_post("/vaults/#{vault_id}/documents.json", body: compact_params(title: title, content: content, status: status, subscriptions: subscriptions)).json
|
|
49
|
+
http_post("/vaults/#{vault_id}/documents.json", body: compact_params(title: title, content: content, status: status, subscriptions: subscriptions, visible_to_clients: visible_to_clients)).json
|
|
49
50
|
end
|
|
50
51
|
end
|
|
51
52
|
end
|
|
@@ -61,7 +61,7 @@ module Basecamp
|
|
|
61
61
|
# @return [Enumerator<Hash>] paginated results
|
|
62
62
|
def list(inbox_id:, sort: nil, direction: nil)
|
|
63
63
|
wrap_paginated(service: "forwards", operation: "list", is_mutation: false, resource_id: inbox_id) do
|
|
64
|
-
params =
|
|
64
|
+
params = compact_query_params(sort: sort, direction: direction)
|
|
65
65
|
paginate("/inboxes/#{inbox_id}/forwards.json", params: params)
|
|
66
66
|
end
|
|
67
67
|
end
|
|
@@ -18,7 +18,7 @@ module Basecamp
|
|
|
18
18
|
|
|
19
19
|
# Update a gauge needle's description. Position and color are immutable.
|
|
20
20
|
# @param needle_id [Integer] needle id ID
|
|
21
|
-
# @param gauge_needle [
|
|
21
|
+
# @param gauge_needle [Hash, nil] gauge needle
|
|
22
22
|
# @return [Hash] response data
|
|
23
23
|
def update_gauge_needle(needle_id:, gauge_needle: nil)
|
|
24
24
|
with_operation(service: "gauges", operation: "update_gauge_needle", is_mutation: true, resource_id: needle_id) do
|
|
@@ -38,7 +38,7 @@ module Basecamp
|
|
|
38
38
|
|
|
39
39
|
# Enable or disable the gauge for a project. Only project admins can toggle gauges.
|
|
40
40
|
# @param project_id [Integer] project id ID
|
|
41
|
-
# @param gauge [
|
|
41
|
+
# @param gauge [Hash] gauge
|
|
42
42
|
# @return [void]
|
|
43
43
|
def toggle_gauge(project_id:, gauge:)
|
|
44
44
|
with_operation(service: "gauges", operation: "toggle_gauge", is_mutation: true, project_id: project_id) do
|
|
@@ -58,7 +58,7 @@ module Basecamp
|
|
|
58
58
|
|
|
59
59
|
# Create a gauge needle (progress update) for a project
|
|
60
60
|
# @param project_id [Integer] project id ID
|
|
61
|
-
# @param gauge_needle [
|
|
61
|
+
# @param gauge_needle [Hash] gauge needle
|
|
62
62
|
# @param notify [String, nil] Who to notify: "everyone", "working_on", "custom", or omit for nobody
|
|
63
63
|
# @param subscriptions [Array, nil] Array of people IDs to notify (only used when notify is "custom")
|
|
64
64
|
# @return [Hash] response data
|
|
@@ -74,7 +74,7 @@ module Basecamp
|
|
|
74
74
|
# @return [Enumerator<Hash>] paginated results
|
|
75
75
|
def list_gauges(bucket_ids: nil)
|
|
76
76
|
wrap_paginated(service: "gauges", operation: "list_gauges", is_mutation: false) do
|
|
77
|
-
params =
|
|
77
|
+
params = compact_query_params(bucket_ids: bucket_ids)
|
|
78
78
|
paginate("/reports/gauges.json", params: params)
|
|
79
79
|
end
|
|
80
80
|
end
|
|
@@ -14,7 +14,7 @@ module Basecamp
|
|
|
14
14
|
# @return [Enumerator<Hash>] paginated results
|
|
15
15
|
def list(board_id:, sort: nil, direction: nil)
|
|
16
16
|
wrap_paginated(service: "messages", operation: "list", is_mutation: false, resource_id: board_id) do
|
|
17
|
-
params =
|
|
17
|
+
params = compact_query_params(sort: sort, direction: direction)
|
|
18
18
|
paginate("/message_boards/#{board_id}/messages.json", params: params)
|
|
19
19
|
end
|
|
20
20
|
end
|
|
@@ -26,10 +26,11 @@ module Basecamp
|
|
|
26
26
|
# @param status [String, nil] active|drafted
|
|
27
27
|
# @param category_id [Integer, nil] category id
|
|
28
28
|
# @param subscriptions [Array, nil] subscriptions
|
|
29
|
+
# @param visible_to_clients [Boolean, nil] visible to clients
|
|
29
30
|
# @return [Hash] response data
|
|
30
|
-
def create(board_id:, subject:, content: nil, status: nil, category_id: nil, subscriptions: nil)
|
|
31
|
+
def create(board_id:, subject:, content: nil, status: nil, category_id: nil, subscriptions: nil, visible_to_clients: nil)
|
|
31
32
|
with_operation(service: "messages", operation: "create", is_mutation: true, resource_id: board_id) do
|
|
32
|
-
http_post("/message_boards/#{board_id}/messages.json", body: compact_params(subject: subject, content: content, status: status, category_id: category_id, subscriptions: subscriptions)).json
|
|
33
|
+
http_post("/message_boards/#{board_id}/messages.json", body: compact_params(subject: subject, content: content, status: status, category_id: category_id, subscriptions: subscriptions, visible_to_clients: visible_to_clients)).json
|
|
33
34
|
end
|
|
34
35
|
end
|
|
35
36
|
|
|
@@ -29,7 +29,7 @@ module Basecamp
|
|
|
29
29
|
# @return [Hash] response data
|
|
30
30
|
def get_my_due_assignments(scope: nil)
|
|
31
31
|
with_operation(service: "myassignments", operation: "get_my_due_assignments", is_mutation: false) do
|
|
32
|
-
http_get("/my/assignments/due.json", params:
|
|
32
|
+
http_get("/my/assignments/due.json", params: compact_query_params(scope: scope)).json
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
end
|