basecamp-sdk 0.11.0 → 0.13.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 +127 -8
- data/lib/basecamp/client.rb +55 -11
- data/lib/basecamp/config.rb +69 -0
- data/lib/basecamp/generated/metadata.json +443 -133
- data/lib/basecamp/generated/services/base_service.rb +37 -16
- data/lib/basecamp/generated/services/bookmarks_service.rb +50 -0
- data/lib/basecamp/generated/services/boosts_service.rb +12 -6
- data/lib/basecamp/generated/services/calendars_service.rb +30 -0
- data/lib/basecamp/generated/services/campfires_service.rb +54 -41
- data/lib/basecamp/generated/services/cards_service.rb +6 -3
- data/lib/basecamp/generated/services/checkins_service.rb +28 -15
- data/lib/basecamp/generated/services/client_approvals_service.rb +8 -5
- data/lib/basecamp/generated/services/client_correspondences_service.rb +8 -5
- data/lib/basecamp/generated/services/client_replies_service.rb +12 -7
- data/lib/basecamp/generated/services/cloud_files_service.rb +57 -0
- data/lib/basecamp/generated/services/comments_service.rb +6 -3
- data/lib/basecamp/generated/services/documents_service.rb +9 -6
- data/lib/basecamp/generated/services/drafts_service.rb +22 -0
- data/lib/basecamp/generated/services/events_service.rb +6 -3
- data/lib/basecamp/generated/services/everything_service.rb +116 -69
- data/lib/basecamp/generated/services/folders_service.rb +62 -0
- data/lib/basecamp/generated/services/forwards_service.rb +12 -17
- data/lib/basecamp/generated/services/gauges_service.rb +12 -7
- data/lib/basecamp/generated/services/google_documents_service.rb +61 -0
- data/lib/basecamp/generated/services/message_types_service.rb +4 -3
- data/lib/basecamp/generated/services/messages_service.rb +6 -4
- data/lib/basecamp/generated/services/my_assignments_service.rb +31 -0
- data/lib/basecamp/generated/services/my_notes_service.rb +28 -0
- data/lib/basecamp/generated/services/my_notifications_service.rb +8 -5
- data/lib/basecamp/generated/services/people_service.rb +17 -10
- data/lib/basecamp/generated/services/projects_service.rb +26 -4
- data/lib/basecamp/generated/services/recordings_service.rb +6 -13
- data/lib/basecamp/generated/services/reports_service.rb +15 -9
- data/lib/basecamp/generated/services/schedules_service.rb +90 -16
- data/lib/basecamp/generated/services/search_service.rb +6 -4
- data/lib/basecamp/generated/services/templates_service.rb +6 -4
- data/lib/basecamp/generated/services/timeline_service.rb +6 -3
- data/lib/basecamp/generated/services/timesheets_service.rb +22 -8
- data/lib/basecamp/generated/services/todolist_groups_service.rb +7 -4
- data/lib/basecamp/generated/services/todolists_service.rb +11 -9
- data/lib/basecamp/generated/services/todos_service.rb +23 -14
- data/lib/basecamp/generated/services/uploads_service.rb +10 -6
- data/lib/basecamp/generated/services/vaults_service.rb +6 -3
- data/lib/basecamp/generated/services/webhooks_service.rb +4 -3
- data/lib/basecamp/generated/types.rb +847 -147
- data/lib/basecamp/http.rb +346 -163
- data/lib/basecamp/list_enumerator.rb +29 -0
- data/lib/basecamp/list_meta.rb +44 -0
- data/lib/basecamp/services/cards_extensions.rb +35 -27
- data/lib/basecamp/services/documents_extensions.rb +136 -0
- data/lib/basecamp/services/merge_safe.rb +255 -0
- data/lib/basecamp/services/schedules_extensions.rb +354 -0
- data/lib/basecamp/services/todolists_extensions.rb +274 -0
- data/lib/basecamp/services/todos_extensions.rb +22 -6
- data/lib/basecamp/validation_error.rb +11 -1
- data/lib/basecamp/version.rb +2 -2
- data/lib/basecamp.rb +94 -4
- data/scripts/generate-services.rb +74 -25
- data/scripts/generate-types.rb +2 -1
- data/scripts/go_type_spellings.rb +26 -0
- metadata +16 -2
|
@@ -32,6 +32,37 @@ module Basecamp
|
|
|
32
32
|
http_get("/my/assignments/due.json", params: compact_query_params(scope: scope), operation: "GetMyDueAssignments").json
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
|
+
|
|
36
|
+
# Add a recording to Up Next — the current user's ordered list of prioritized
|
|
37
|
+
# @param id [Integer] The recording id to prioritize.
|
|
38
|
+
# @return [void]
|
|
39
|
+
def prioritize_assignment(id:)
|
|
40
|
+
with_operation(service: "myassignments", operation: "prioritize_assignment", is_mutation: true) do
|
|
41
|
+
http_post("/my/priorities.json", body: compact_params(id: id))
|
|
42
|
+
nil
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Remove a recording from Up Next (returns 204 No Content). Exact-target:
|
|
47
|
+
# @param recording_id [Integer] recording id ID
|
|
48
|
+
# @return [void]
|
|
49
|
+
def deprioritize_assignment(recording_id:)
|
|
50
|
+
with_operation(service: "myassignments", operation: "deprioritize_assignment", is_mutation: true, resource_id: recording_id) do
|
|
51
|
+
http_delete("/my/priorities/#{recording_id}")
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Move an already-prioritized recording to a new 1-based position in Up Next
|
|
57
|
+
# @param source_id [Integer] The recording id to move, chosen the same way as when prioritizing.
|
|
58
|
+
# @param position [Integer] The 1-based position to move it to.
|
|
59
|
+
# @return [void]
|
|
60
|
+
def reorder_up_next(source_id:, position:)
|
|
61
|
+
with_operation(service: "myassignments", operation: "reorder_up_next", is_mutation: true) do
|
|
62
|
+
http_post("/my/priority_moves.json", body: compact_params(source_id: source_id, position: position))
|
|
63
|
+
nil
|
|
64
|
+
end
|
|
65
|
+
end
|
|
35
66
|
end
|
|
36
67
|
end
|
|
37
68
|
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Service for MyNotes operations
|
|
6
|
+
#
|
|
7
|
+
# @generated from OpenAPI spec
|
|
8
|
+
class MyNotesService < BaseService
|
|
9
|
+
|
|
10
|
+
# Get the authenticated user's note — a per-person notebook singleton at
|
|
11
|
+
# @return [Hash] response data
|
|
12
|
+
def get_my_note()
|
|
13
|
+
with_operation(service: "mynotes", operation: "get_my_note", is_mutation: false) do
|
|
14
|
+
http_get("/my/notes.json", operation: "GetMyNote").json
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Replace the note's content, recording a new revision server-side.
|
|
19
|
+
# @param note [Hash] note
|
|
20
|
+
# @return [Hash] response data
|
|
21
|
+
def update_my_note(note:)
|
|
22
|
+
with_operation(service: "mynotes", operation: "update_my_note", is_mutation: true) do
|
|
23
|
+
http_put("/my/notes.json", body: compact_params(note: note)).json
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -8,7 +8,9 @@ module Basecamp
|
|
|
8
8
|
class MyNotificationsService < BaseService
|
|
9
9
|
|
|
10
10
|
# Get the current user's notification inbox (the "Hey!" menu).
|
|
11
|
-
# @param page [Integer, nil] Page number for paginating through read items. Defaults to 1.
|
|
11
|
+
# @param page [Integer, nil] Page number for paginating through read items. Defaults to 1. This
|
|
12
|
+
# operation is not auto-paginated in any SDK, so a page is returned as
|
|
13
|
+
# asked for and later pages are not followed.
|
|
12
14
|
# @param limit_bubble_ups [Boolean, nil] Set to true to cap `bubble_ups` at 2 current bubble-ups and omit the
|
|
13
15
|
# `scheduled_bubble_ups` key entirely. Defaults to false. Use the dedicated
|
|
14
16
|
# bubble-ups endpoint (GetBubbleUps) to page through all current and
|
|
@@ -21,12 +23,13 @@ module Basecamp
|
|
|
21
23
|
end
|
|
22
24
|
|
|
23
25
|
# Get the current user's current and scheduled bubble-ups (paginated, 50 per page).
|
|
24
|
-
# @param page [Integer, nil] Page number. Defaults to 1.
|
|
25
|
-
# @
|
|
26
|
-
|
|
26
|
+
# @param page [Integer, nil] Page number. Defaults to 1. A positive value selects exactly that page, not a starting offset; see SPEC section 8.
|
|
27
|
+
# @param max_items [Integer, nil] cap on items yielded across pages; nil or non-positive means no cap
|
|
28
|
+
# @return [ListEnumerator<Hash>] lazily paginated results (#meta carries pagination metadata)
|
|
29
|
+
def get_bubble_ups(page: nil, max_items: nil)
|
|
27
30
|
wrap_paginated(service: "mynotifications", operation: "get_bubble_ups", is_mutation: false) do
|
|
28
31
|
params = compact_query_params(page: page)
|
|
29
|
-
paginate("/my/readings/bubble_ups.json", params: params, operation: "GetBubbleUps")
|
|
32
|
+
paginate("/my/readings/bubble_ups.json", params: params, operation: "GetBubbleUps", max_items: max_items)
|
|
30
33
|
end
|
|
31
34
|
end
|
|
32
35
|
|
|
@@ -8,10 +8,11 @@ module Basecamp
|
|
|
8
8
|
class PeopleService < BaseService
|
|
9
9
|
|
|
10
10
|
# List all account users who can be pinged
|
|
11
|
-
# @
|
|
12
|
-
|
|
11
|
+
# @param max_items [Integer, nil] cap on items yielded across pages; nil or non-positive means no cap
|
|
12
|
+
# @return [ListEnumerator<Hash>] lazily paginated results (#meta carries pagination metadata)
|
|
13
|
+
def list_pingable(max_items: nil)
|
|
13
14
|
wrap_paginated(service: "people", operation: "list_pingable", is_mutation: false) do
|
|
14
|
-
paginate("/circles/people.json", operation: "ListPingablePeople")
|
|
15
|
+
paginate("/circles/people.json", operation: "ListPingablePeople", max_items: max_items)
|
|
15
16
|
end
|
|
16
17
|
end
|
|
17
18
|
|
|
@@ -23,7 +24,7 @@ module Basecamp
|
|
|
23
24
|
end
|
|
24
25
|
end
|
|
25
26
|
|
|
26
|
-
# Update the current user's preferences
|
|
27
|
+
# Update the current user's preferences.
|
|
27
28
|
# @param person [Hash] person
|
|
28
29
|
# @return [Hash] response data
|
|
29
30
|
def update_my_preferences(person:)
|
|
@@ -58,10 +59,13 @@ module Basecamp
|
|
|
58
59
|
end
|
|
59
60
|
|
|
60
61
|
# List all people visible to the current user
|
|
61
|
-
# @
|
|
62
|
-
|
|
62
|
+
# @param page [Integer, nil] Page number for paginating through results. Defaults to 1. A positive value selects exactly that page, not a starting offset; see SPEC section 8.
|
|
63
|
+
# @param max_items [Integer, nil] cap on items yielded across pages; nil or non-positive means no cap
|
|
64
|
+
# @return [ListEnumerator<Hash>] lazily paginated results (#meta carries pagination metadata)
|
|
65
|
+
def list(page: nil, max_items: nil)
|
|
63
66
|
wrap_paginated(service: "people", operation: "list", is_mutation: false) do
|
|
64
|
-
|
|
67
|
+
params = compact_query_params(page: page)
|
|
68
|
+
paginate("/people.json", params: params, operation: "ListPeople", max_items: max_items)
|
|
65
69
|
end
|
|
66
70
|
end
|
|
67
71
|
|
|
@@ -105,10 +109,13 @@ module Basecamp
|
|
|
105
109
|
|
|
106
110
|
# List all active people on a project
|
|
107
111
|
# @param project_id [Integer] project id ID
|
|
108
|
-
# @
|
|
109
|
-
|
|
112
|
+
# @param page [Integer, nil] Page number for paginating through results. Defaults to 1. A positive value selects exactly that page, not a starting offset; see SPEC section 8.
|
|
113
|
+
# @param max_items [Integer, nil] cap on items yielded across pages; nil or non-positive means no cap
|
|
114
|
+
# @return [ListEnumerator<Hash>] lazily paginated results (#meta carries pagination metadata)
|
|
115
|
+
def list_for_project(project_id:, page: nil, max_items: nil)
|
|
110
116
|
wrap_paginated(service: "people", operation: "list_for_project", is_mutation: false, project_id: project_id) do
|
|
111
|
-
|
|
117
|
+
params = compact_query_params(page: page)
|
|
118
|
+
paginate("/projects/#{project_id}/people.json", params: params, operation: "ListProjectPeople", max_items: max_items)
|
|
112
119
|
end
|
|
113
120
|
end
|
|
114
121
|
|
|
@@ -9,11 +9,13 @@ module Basecamp
|
|
|
9
9
|
|
|
10
10
|
# List projects (active by default; optionally archived/trashed)
|
|
11
11
|
# @param status [String, nil] active|archived|trashed
|
|
12
|
-
# @
|
|
13
|
-
|
|
12
|
+
# @param page [Integer, nil] Page number for paginating through results. Defaults to 1. A positive value selects exactly that page, not a starting offset; see SPEC section 8.
|
|
13
|
+
# @param max_items [Integer, nil] cap on items yielded across pages; nil or non-positive means no cap
|
|
14
|
+
# @return [ListEnumerator<Hash>] lazily paginated results (#meta carries pagination metadata)
|
|
15
|
+
def list(status: nil, page: nil, max_items: nil)
|
|
14
16
|
wrap_paginated(service: "projects", operation: "list", is_mutation: false) do
|
|
15
|
-
params = compact_query_params(status: status)
|
|
16
|
-
paginate("/projects.json", params: params, operation: "ListProjects")
|
|
17
|
+
params = compact_query_params(status: status, page: page)
|
|
18
|
+
paginate("/projects.json", params: params, operation: "ListProjects", max_items: max_items)
|
|
17
19
|
end
|
|
18
20
|
end
|
|
19
21
|
|
|
@@ -58,6 +60,26 @@ module Basecamp
|
|
|
58
60
|
nil
|
|
59
61
|
end
|
|
60
62
|
end
|
|
63
|
+
|
|
64
|
+
# Restore a project to active status from trash as well as from the archive (returns 204 No Content).
|
|
65
|
+
# @param project_id [Integer] project id ID
|
|
66
|
+
# @return [void]
|
|
67
|
+
def unarchive(project_id:)
|
|
68
|
+
with_operation(service: "projects", operation: "unarchive", is_mutation: true, project_id: project_id) do
|
|
69
|
+
http_put("/projects/#{project_id}/status/active.json")
|
|
70
|
+
nil
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Archive a project, removing it from the active project list (returns 204 No Content).
|
|
75
|
+
# @param project_id [Integer] project id ID
|
|
76
|
+
# @return [void]
|
|
77
|
+
def archive(project_id:)
|
|
78
|
+
with_operation(service: "projects", operation: "archive", is_mutation: true, project_id: project_id) do
|
|
79
|
+
http_put("/projects/#{project_id}/status/archived.json")
|
|
80
|
+
nil
|
|
81
|
+
end
|
|
82
|
+
end
|
|
61
83
|
end
|
|
62
84
|
end
|
|
63
85
|
end
|
|
@@ -13,20 +13,13 @@ module Basecamp
|
|
|
13
13
|
# @param status [String, nil] active|archived|trashed
|
|
14
14
|
# @param sort [String, nil] created_at|updated_at
|
|
15
15
|
# @param direction [String, nil] asc|desc
|
|
16
|
-
# @
|
|
17
|
-
|
|
16
|
+
# @param page [Integer, nil] Page number for paginating through results. Defaults to 1. A positive value selects exactly that page, not a starting offset; see SPEC section 8.
|
|
17
|
+
# @param max_items [Integer, nil] cap on items yielded across pages; nil or non-positive means no cap
|
|
18
|
+
# @return [ListEnumerator<Hash>] lazily paginated results (#meta carries pagination metadata)
|
|
19
|
+
def list(type:, bucket: nil, status: nil, sort: nil, direction: nil, page: nil, max_items: nil)
|
|
18
20
|
wrap_paginated(service: "recordings", operation: "list", is_mutation: false) do
|
|
19
|
-
params = compact_query_params(type: type, bucket: bucket, status: status, sort: sort, direction: direction)
|
|
20
|
-
paginate("/projects/recordings.json", params: params, operation: "ListRecordings")
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# Get a single recording by id
|
|
25
|
-
# @param recording_id [Integer] recording id ID
|
|
26
|
-
# @return [Hash] response data
|
|
27
|
-
def get(recording_id:)
|
|
28
|
-
with_operation(service: "recordings", operation: "get", is_mutation: false, resource_id: recording_id) do
|
|
29
|
-
http_get("/recordings/#{recording_id}", operation: "GetRecording").json
|
|
21
|
+
params = compact_query_params(type: type, bucket: bucket, status: status, sort: sort, direction: direction, page: page)
|
|
22
|
+
paginate("/projects/recordings.json", params: params, operation: "ListRecordings", max_items: max_items)
|
|
30
23
|
end
|
|
31
24
|
end
|
|
32
25
|
|
|
@@ -8,18 +8,21 @@ module Basecamp
|
|
|
8
8
|
class ReportsService < BaseService
|
|
9
9
|
|
|
10
10
|
# Get account-wide activity feed (progress report)
|
|
11
|
-
# @
|
|
12
|
-
|
|
11
|
+
# @param page [Integer, nil] Page number for paginating through results. Defaults to 1. A positive value selects exactly that page, not a starting offset; see SPEC section 8.
|
|
12
|
+
# @param max_items [Integer, nil] cap on items yielded across pages; nil or non-positive means no cap
|
|
13
|
+
# @return [ListEnumerator<Hash>] lazily paginated results (#meta carries pagination metadata)
|
|
14
|
+
def progress(page: nil, max_items: nil)
|
|
13
15
|
wrap_paginated(service: "reports", operation: "progress", is_mutation: false) do
|
|
14
|
-
|
|
16
|
+
params = compact_query_params(page: page)
|
|
17
|
+
paginate("/reports/progress.json", params: params, operation: "GetProgressReport", max_items: max_items)
|
|
15
18
|
end
|
|
16
19
|
end
|
|
17
20
|
|
|
18
21
|
# Get upcoming schedule entries and assignable items within a date window.
|
|
19
|
-
# @param window_starts_on [String
|
|
20
|
-
# @param window_ends_on [String
|
|
22
|
+
# @param window_starts_on [String] Inclusive first day of the window, `YYYY-MM-DD`. Required — BC3 answers 400 without it.
|
|
23
|
+
# @param window_ends_on [String] Inclusive last day of the window, `YYYY-MM-DD`. Required — BC3 answers 400 without it.
|
|
21
24
|
# @return [Hash] response data
|
|
22
|
-
def upcoming(window_starts_on
|
|
25
|
+
def upcoming(window_starts_on:, window_ends_on:)
|
|
23
26
|
with_operation(service: "reports", operation: "upcoming", is_mutation: false) do
|
|
24
27
|
http_get("/reports/schedules/upcoming.json", params: compact_query_params(window_starts_on: window_starts_on, window_ends_on: window_ends_on), operation: "GetUpcomingSchedule").json
|
|
25
28
|
end
|
|
@@ -45,10 +48,13 @@ module Basecamp
|
|
|
45
48
|
|
|
46
49
|
# Get a person's activity timeline
|
|
47
50
|
# @param person_id [Integer] person id ID
|
|
48
|
-
# @
|
|
49
|
-
|
|
51
|
+
# @param page [Integer, nil] Page number for paginating through results. Defaults to 1. A positive value selects exactly that page, not a starting offset; see SPEC section 8.
|
|
52
|
+
# @param max_items [Integer, nil] cap on items yielded across pages; nil or non-positive means no cap
|
|
53
|
+
# @return [Hash] wrapper fields merged with a ListEnumerator of the paginated items
|
|
54
|
+
def person_progress(person_id:, page: nil, max_items: nil)
|
|
50
55
|
wrap_paginated_wrapped(key: "events", service: "reports", operation: "person_progress", is_mutation: false, resource_id: person_id) do
|
|
51
|
-
|
|
56
|
+
params = compact_query_params(page: page)
|
|
57
|
+
paginate_wrapped("/reports/users/progress/#{person_id}.json", key: "events", params: params, operation: "GetPersonProgress", max_items: max_items)
|
|
52
58
|
end
|
|
53
59
|
end
|
|
54
60
|
end
|
|
@@ -16,14 +16,16 @@ module Basecamp
|
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
#
|
|
19
|
+
# Replace a schedule entry with a new complete representation.
|
|
20
20
|
# @param entry_id [Integer] entry id ID
|
|
21
21
|
# @param summary [String, nil] summary
|
|
22
|
-
# @param starts_at [String,
|
|
23
|
-
#
|
|
22
|
+
# @param starts_at [String] The entry's start, as a bare date ("2026-06-01") for an all-day entry or a
|
|
23
|
+
# full timestamp otherwise. Same rule as CreateScheduleEntry: send it
|
|
24
|
+
# verbatim, never parsed and re-rendered.
|
|
25
|
+
# @param ends_at [String] The entry's end. See starts_at for the date-vs-timestamp rule.
|
|
24
26
|
# @param description [String, nil] description
|
|
25
27
|
# @param participant_ids [Array, nil] Replaces the entry's participants.
|
|
26
|
-
#
|
|
28
|
+
#
|
|
27
29
|
# Omitting this member preserves the current participants; sending an empty
|
|
28
30
|
# array clears them. That guarantee is BC3-side and recent: until
|
|
29
31
|
# basecamp/bc3#12425, `Schedules::EntriesController#update` called
|
|
@@ -31,12 +33,36 @@ module Basecamp
|
|
|
31
33
|
# including the shape in BC3's own "Update a schedule entry" doc example —
|
|
32
34
|
# silently removed every participant and notified each one. The controller
|
|
33
35
|
# now guards on the request actually addressing participants.
|
|
34
|
-
# @param all_day [Boolean, nil]
|
|
36
|
+
# @param all_day [Boolean, nil] Whether the entry occupies whole days rather than a time range.
|
|
37
|
+
#
|
|
38
|
+
# Not carved out, and the carve-out list is what makes that dangerous to
|
|
39
|
+
# forget: `schedule_entries.all_day` is NOT NULL with a `false` default, so
|
|
40
|
+
# omitting this member on a replace resets it — silently converting an
|
|
41
|
+
# all-day entry into a midnight-to-midnight timed one. The SDK's merge-safe
|
|
42
|
+
# update and edit resend it from the read-back for exactly this reason.
|
|
43
|
+
#
|
|
44
|
+
# Sending an explicit null is worse than omitting it: the column rejects
|
|
45
|
+
# NULL, so BC3 raises rather than falling back to the default. The same is
|
|
46
|
+
# true of highlighted.
|
|
35
47
|
# @param notify [Boolean, nil] notify
|
|
48
|
+
# @param url [String, nil] The entry's join link — a video-call URL or similar, up to 2500
|
|
49
|
+
# characters, validated as a URL when present.
|
|
50
|
+
#
|
|
51
|
+
# Omitting this member preserves the current join link; sending an empty
|
|
52
|
+
# string clears it. Read it back as `join_url`, never as `url`: the entry's
|
|
53
|
+
# `url` is its own Basecamp API URL, written by a partial that renders
|
|
54
|
+
# before this one, so BC3 emits the join link under a non-colliding key.
|
|
55
|
+
# Echoing the response's `url` into this member would write the API URL into
|
|
56
|
+
# the join link.
|
|
57
|
+
# @param highlighted [Boolean, nil] Whether the entry is highlighted on the schedule.
|
|
58
|
+
#
|
|
59
|
+
# Omitting this member preserves the current highlight; sending false
|
|
60
|
+
# removes it. Preserved on omission because until basecamp/bc3#12502 the
|
|
61
|
+
# field was writable but never returned, so no caller could resend it.
|
|
36
62
|
# @return [Hash] response data
|
|
37
|
-
def
|
|
38
|
-
with_operation(service: "schedules", operation: "
|
|
39
|
-
http_put("/schedule_entries/#{entry_id}", body: compact_params(summary: summary, starts_at: starts_at, ends_at: ends_at, description: description, participant_ids: participant_ids, all_day: all_day, notify: notify)).json
|
|
63
|
+
def replace_entry(entry_id:, starts_at:, ends_at:, summary: nil, description: nil, participant_ids: nil, all_day: nil, notify: nil, url: nil, highlighted: nil)
|
|
64
|
+
with_operation(service: "schedules", operation: "replace_entry", is_mutation: true, resource_id: entry_id) do
|
|
65
|
+
http_put("/schedule_entries/#{entry_id}", body: compact_params(summary: summary, starts_at: starts_at, ends_at: ends_at, description: description, participant_ids: participant_ids, all_day: all_day, notify: notify, url: url, highlighted: highlighted)).json
|
|
40
66
|
end
|
|
41
67
|
end
|
|
42
68
|
|
|
@@ -72,29 +98,77 @@ module Basecamp
|
|
|
72
98
|
# List entries on a schedule
|
|
73
99
|
# @param schedule_id [Integer] schedule id ID
|
|
74
100
|
# @param status [String, nil] active|archived|trashed
|
|
75
|
-
# @
|
|
76
|
-
|
|
101
|
+
# @param page [Integer, nil] Page number for paginating through results. Defaults to 1. A positive value selects exactly that page, not a starting offset; see SPEC section 8.
|
|
102
|
+
# @param max_items [Integer, nil] cap on items yielded across pages; nil or non-positive means no cap
|
|
103
|
+
# @return [ListEnumerator<Hash>] lazily paginated results (#meta carries pagination metadata)
|
|
104
|
+
def list_entries(schedule_id:, status: nil, page: nil, max_items: nil)
|
|
77
105
|
wrap_paginated(service: "schedules", operation: "list_entries", is_mutation: false, resource_id: schedule_id) do
|
|
78
|
-
params = compact_query_params(status: status)
|
|
79
|
-
paginate("/schedules/#{schedule_id}/entries.json", params: params, operation: "ListScheduleEntries")
|
|
106
|
+
params = compact_query_params(status: status, page: page)
|
|
107
|
+
paginate("/schedules/#{schedule_id}/entries.json", params: params, operation: "ListScheduleEntries", max_items: max_items)
|
|
80
108
|
end
|
|
81
109
|
end
|
|
82
110
|
|
|
83
111
|
# Create a new schedule entry
|
|
84
112
|
# @param schedule_id [Integer] schedule id ID
|
|
85
113
|
# @param summary [String] summary
|
|
86
|
-
# @param starts_at [String]
|
|
87
|
-
#
|
|
114
|
+
# @param starts_at [String] The entry's start, as a bare date ("2026-06-01") for an all-day entry or a
|
|
115
|
+
# full timestamp ("2026-06-01T09:00:00Z") otherwise — the same two forms the
|
|
116
|
+
# response renders, and the same two ReplaceScheduleEntry accepts.
|
|
117
|
+
#
|
|
118
|
+
# Create and replace share one permit list:
|
|
119
|
+
# `Schedules::Entries::BaseController#base_schedule_entry_params` is what
|
|
120
|
+
# both `new_schedule_entry_params` and `update_schedule_entry_params` call,
|
|
121
|
+
# and Schedule::Entry does no format-specific parsing of either bound, so
|
|
122
|
+
# whatever one operation takes the other takes too.
|
|
123
|
+
#
|
|
124
|
+
# Treat the value as opaque and send it verbatim. Parsing it into a
|
|
125
|
+
# date-time type and re-rendering rewrites an all-day entry's bounds into
|
|
126
|
+
# midnight timestamps, which is why every SDK models it as a string.
|
|
127
|
+
# @param ends_at [String] The entry's end. See starts_at for the date-vs-timestamp rule.
|
|
88
128
|
# @param description [String, nil] description
|
|
89
129
|
# @param participant_ids [Array, nil] participant ids
|
|
90
130
|
# @param all_day [Boolean, nil] all day
|
|
91
131
|
# @param notify [Boolean, nil] notify
|
|
132
|
+
# @param url [String, nil] The entry's join link — a video-call URL or similar, up to 2500
|
|
133
|
+
# characters, validated as a URL when present. A scheme-less value is
|
|
134
|
+
# normalized to `https://`.
|
|
135
|
+
#
|
|
136
|
+
# Spell it `url` on the way in and read it back as `join_url`: the response
|
|
137
|
+
# key `url` is the entry's own Basecamp API URL, written by a partial that
|
|
138
|
+
# renders before this field, so BC3 emits the join link under a
|
|
139
|
+
# non-colliding name. Sending `join_url` instead is silently dropped by
|
|
140
|
+
# strong parameters — the create succeeds with no join link.
|
|
141
|
+
#
|
|
142
|
+
# Accepted on create since long before it was documented:
|
|
143
|
+
# `Schedules::Entries::BaseController#base_schedule_entry_params` permits it
|
|
144
|
+
# and `new_schedule_entry_params` passes it through unchanged for API
|
|
145
|
+
# requests. Modeling it only on ReplaceScheduleEntry forced callers into a
|
|
146
|
+
# three-request read-modify-write for a field the create already took — and
|
|
147
|
+
# create is the notifying write, so participants learned about a video call
|
|
148
|
+
# before its link existed.
|
|
149
|
+
# @param highlighted [Boolean, nil] Whether the entry is highlighted on the schedule. Defaults to false.
|
|
150
|
+
#
|
|
151
|
+
# Do not send an explicit null: `schedule_entries.highlighted` is NOT NULL,
|
|
152
|
+
# so BC3 raises rather than falling back to the default. Omit it instead —
|
|
153
|
+
# every SDK's request compactor already drops unset members.
|
|
154
|
+
# @param status [String, nil] Publication state at creation — `active|drafted`, defaulting to `active`
|
|
155
|
+
# for an API create.
|
|
156
|
+
#
|
|
157
|
+
# A top-level parameter, not part of the entry's attributes: `status` is a
|
|
158
|
+
# Recording column, so `wrap_parameters` leaves it outside the
|
|
159
|
+
# `schedule_entry` envelope and `Recording::StatusParam#status_param` reads
|
|
160
|
+
# it directly. On create it accepts `drafted`, `active`, `archived` or
|
|
161
|
+
# `trashed` and raises `ActionController::BadRequest` — a 400, not a 422 —
|
|
162
|
+
# for anything else; the two documented values are the two worth sending.
|
|
163
|
+
#
|
|
164
|
+
# Unlike messages and documents, schedule-entry drafts are not listed by
|
|
165
|
+
# GetMyDrafts.
|
|
92
166
|
# @param subscriptions [Array, nil] subscriptions
|
|
93
167
|
# @param visible_to_clients [Boolean, nil] visible to clients
|
|
94
168
|
# @return [Hash] response data
|
|
95
|
-
def create_entry(schedule_id:, summary:, starts_at:, ends_at:, description: nil, participant_ids: nil, all_day: nil, notify: nil, subscriptions: nil, visible_to_clients: nil)
|
|
169
|
+
def create_entry(schedule_id:, summary:, starts_at:, ends_at:, description: nil, participant_ids: nil, all_day: nil, notify: nil, url: nil, highlighted: nil, status: nil, subscriptions: nil, visible_to_clients: nil)
|
|
96
170
|
with_operation(service: "schedules", operation: "create_entry", is_mutation: true, resource_id: schedule_id) do
|
|
97
|
-
http_post("/schedules/#{schedule_id}/entries.json", body: compact_params(summary: summary, starts_at: starts_at, ends_at: ends_at, description: description, participant_ids: participant_ids, all_day: all_day, notify: notify, subscriptions: subscriptions, visible_to_clients: visible_to_clients)).json
|
|
171
|
+
http_post("/schedules/#{schedule_id}/entries.json", body: compact_params(summary: summary, starts_at: starts_at, ends_at: ends_at, description: description, participant_ids: participant_ids, all_day: all_day, notify: notify, url: url, highlighted: highlighted, status: status, subscriptions: subscriptions, visible_to_clients: visible_to_clients)).json
|
|
98
172
|
end
|
|
99
173
|
end
|
|
100
174
|
end
|
|
@@ -21,11 +21,13 @@ module Basecamp
|
|
|
21
21
|
# @param type [String, nil] Deprecated: prefer type_names[].
|
|
22
22
|
# @param bucket_id [Integer, nil] Deprecated: prefer bucket_ids[].
|
|
23
23
|
# @param creator_id [Integer, nil] Deprecated: prefer creator_ids[].
|
|
24
|
-
# @
|
|
25
|
-
|
|
24
|
+
# @param page [Integer, nil] Page number for paginating through results. Defaults to 1. A positive value selects exactly that page, not a starting offset; see SPEC section 8.
|
|
25
|
+
# @param max_items [Integer, nil] cap on items yielded across pages; nil or non-positive means no cap
|
|
26
|
+
# @return [ListEnumerator<Hash>] lazily paginated results (#meta carries pagination metadata)
|
|
27
|
+
def search(q:, type_names: nil, bucket_ids: nil, creator_ids: nil, file_type: nil, exclude_chat: nil, since: nil, sort: nil, type: nil, bucket_id: nil, creator_id: nil, page: nil, max_items: nil)
|
|
26
28
|
wrap_paginated(service: "search", operation: "search", is_mutation: false) do
|
|
27
|
-
params = compact_query_params(q: q, type_names: type_names, bucket_ids: bucket_ids, creator_ids: creator_ids, file_type: file_type, exclude_chat: exclude_chat, since: since, sort: sort, type: type, bucket_id: bucket_id, creator_id: creator_id)
|
|
28
|
-
paginate("/search.json", params: params, operation: "Search")
|
|
29
|
+
params = compact_query_params(q: q, type_names: type_names, bucket_ids: bucket_ids, creator_ids: creator_ids, file_type: file_type, exclude_chat: exclude_chat, since: since, sort: sort, type: type, bucket_id: bucket_id, creator_id: creator_id, page: page)
|
|
30
|
+
paginate("/search.json", params: params, operation: "Search", max_items: max_items)
|
|
29
31
|
end
|
|
30
32
|
end
|
|
31
33
|
|
|
@@ -9,11 +9,13 @@ module Basecamp
|
|
|
9
9
|
|
|
10
10
|
# List all templates visible to the current user
|
|
11
11
|
# @param status [String, nil] active|archived|trashed
|
|
12
|
-
# @
|
|
13
|
-
|
|
12
|
+
# @param page [Integer, nil] Page number for paginating through results. Defaults to 1. A positive value selects exactly that page, not a starting offset; see SPEC section 8.
|
|
13
|
+
# @param max_items [Integer, nil] cap on items yielded across pages; nil or non-positive means no cap
|
|
14
|
+
# @return [ListEnumerator<Hash>] lazily paginated results (#meta carries pagination metadata)
|
|
15
|
+
def list(status: nil, page: nil, max_items: nil)
|
|
14
16
|
wrap_paginated(service: "templates", operation: "list", is_mutation: false) do
|
|
15
|
-
params = compact_query_params(status: status)
|
|
16
|
-
paginate("/templates.json", params: params, operation: "ListTemplates")
|
|
17
|
+
params = compact_query_params(status: status, page: page)
|
|
18
|
+
paginate("/templates.json", params: params, operation: "ListTemplates", max_items: max_items)
|
|
17
19
|
end
|
|
18
20
|
end
|
|
19
21
|
|
|
@@ -9,10 +9,13 @@ module Basecamp
|
|
|
9
9
|
|
|
10
10
|
# Get project timeline
|
|
11
11
|
# @param project_id [Integer] project id ID
|
|
12
|
-
# @
|
|
13
|
-
|
|
12
|
+
# @param page [Integer, nil] Page number for paginating through results. Defaults to 1. A positive value selects exactly that page, not a starting offset; see SPEC section 8.
|
|
13
|
+
# @param max_items [Integer, nil] cap on items yielded across pages; nil or non-positive means no cap
|
|
14
|
+
# @return [ListEnumerator<Hash>] lazily paginated results (#meta carries pagination metadata)
|
|
15
|
+
def get_project_timeline(project_id:, page: nil, max_items: nil)
|
|
14
16
|
wrap_paginated(service: "timeline", operation: "get_project_timeline", is_mutation: false, project_id: project_id) do
|
|
15
|
-
|
|
17
|
+
params = compact_query_params(page: page)
|
|
18
|
+
paginate("/projects/#{project_id}/timeline.json", params: params, operation: "GetProjectTimeline", max_items: max_items)
|
|
16
19
|
end
|
|
17
20
|
end
|
|
18
21
|
end
|
|
@@ -12,11 +12,13 @@ module Basecamp
|
|
|
12
12
|
# @param from [String, nil] from
|
|
13
13
|
# @param to [String, nil] to
|
|
14
14
|
# @param person_id [Integer, nil] person id
|
|
15
|
-
# @
|
|
16
|
-
|
|
15
|
+
# @param page [Integer, nil] Page number for paginating through results. Defaults to 1. A positive value selects exactly that page, not a starting offset; see SPEC section 8.
|
|
16
|
+
# @param max_items [Integer, nil] cap on items yielded across pages; nil or non-positive means no cap
|
|
17
|
+
# @return [ListEnumerator<Hash>] lazily paginated results (#meta carries pagination metadata)
|
|
18
|
+
def for_project(project_id:, from: nil, to: nil, person_id: nil, page: nil, max_items: nil)
|
|
17
19
|
wrap_paginated(service: "timesheets", operation: "for_project", is_mutation: false, project_id: project_id) do
|
|
18
|
-
params = compact_query_params(from: from, to: to, person_id: person_id)
|
|
19
|
-
paginate("/projects/#{project_id}/timesheet.json", params: params, operation: "GetProjectTimesheet")
|
|
20
|
+
params = compact_query_params(from: from, to: to, person_id: person_id, page: page)
|
|
21
|
+
paginate("/projects/#{project_id}/timesheet.json", params: params, operation: "GetProjectTimesheet", max_items: max_items)
|
|
20
22
|
end
|
|
21
23
|
end
|
|
22
24
|
|
|
@@ -25,11 +27,13 @@ module Basecamp
|
|
|
25
27
|
# @param from [String, nil] from
|
|
26
28
|
# @param to [String, nil] to
|
|
27
29
|
# @param person_id [Integer, nil] person id
|
|
28
|
-
# @
|
|
29
|
-
|
|
30
|
+
# @param page [Integer, nil] Page number for paginating through results. Defaults to 1. A positive value selects exactly that page, not a starting offset; see SPEC section 8.
|
|
31
|
+
# @param max_items [Integer, nil] cap on items yielded across pages; nil or non-positive means no cap
|
|
32
|
+
# @return [ListEnumerator<Hash>] lazily paginated results (#meta carries pagination metadata)
|
|
33
|
+
def for_recording(recording_id:, from: nil, to: nil, person_id: nil, page: nil, max_items: nil)
|
|
30
34
|
wrap_paginated(service: "timesheets", operation: "for_recording", is_mutation: false, resource_id: recording_id) do
|
|
31
|
-
params = compact_query_params(from: from, to: to, person_id: person_id)
|
|
32
|
-
paginate("/recordings/#{recording_id}/timesheet.json", params: params, operation: "GetRecordingTimesheet")
|
|
35
|
+
params = compact_query_params(from: from, to: to, person_id: person_id, page: page)
|
|
36
|
+
paginate("/recordings/#{recording_id}/timesheet.json", params: params, operation: "GetRecordingTimesheet", max_items: max_items)
|
|
33
37
|
end
|
|
34
38
|
end
|
|
35
39
|
|
|
@@ -78,6 +82,16 @@ module Basecamp
|
|
|
78
82
|
http_put("/timesheet_entries/#{entry_id}", body: compact_params(date: date, hours: hours, description: description, person_id: person_id)).json
|
|
79
83
|
end
|
|
80
84
|
end
|
|
85
|
+
|
|
86
|
+
# Permanently delete a timesheet entry; answers 403 when the caller may not archive or trash it.
|
|
87
|
+
# @param entry_id [Integer] entry id ID
|
|
88
|
+
# @return [void]
|
|
89
|
+
def destroy(entry_id:)
|
|
90
|
+
with_operation(service: "timesheets", operation: "destroy", is_mutation: true, resource_id: entry_id) do
|
|
91
|
+
http_delete("/timesheet_entries/#{entry_id}")
|
|
92
|
+
nil
|
|
93
|
+
end
|
|
94
|
+
end
|
|
81
95
|
end
|
|
82
96
|
end
|
|
83
97
|
end
|
|
@@ -13,17 +13,20 @@ module Basecamp
|
|
|
13
13
|
# @return [void]
|
|
14
14
|
def reposition(group_id:, position:)
|
|
15
15
|
with_operation(service: "todolistgroups", operation: "reposition", is_mutation: true, resource_id: group_id) do
|
|
16
|
-
http_put("/todolists/#{group_id}/position.json", body: compact_params(position: position))
|
|
16
|
+
http_put("/todolists/groups/#{group_id}/position.json", body: compact_params(position: position))
|
|
17
17
|
nil
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
# List groups in a todolist
|
|
22
22
|
# @param todolist_id [Integer] todolist id ID
|
|
23
|
-
# @
|
|
24
|
-
|
|
23
|
+
# @param page [Integer, nil] Page number for paginating through results. Defaults to 1. A positive value selects exactly that page, not a starting offset; see SPEC section 8.
|
|
24
|
+
# @param max_items [Integer, nil] cap on items yielded across pages; nil or non-positive means no cap
|
|
25
|
+
# @return [ListEnumerator<Hash>] lazily paginated results (#meta carries pagination metadata)
|
|
26
|
+
def list(todolist_id:, page: nil, max_items: nil)
|
|
25
27
|
wrap_paginated(service: "todolistgroups", operation: "list", is_mutation: false, resource_id: todolist_id) do
|
|
26
|
-
|
|
28
|
+
params = compact_query_params(page: page)
|
|
29
|
+
paginate("/todolists/#{todolist_id}/groups.json", params: params, operation: "ListTodolistGroups", max_items: max_items)
|
|
27
30
|
end
|
|
28
31
|
end
|
|
29
32
|
|
|
@@ -16,13 +16,13 @@ module Basecamp
|
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
#
|
|
19
|
+
# Replace a todolist (or todolist group) with a new complete representation.
|
|
20
20
|
# @param id [Integer] id ID
|
|
21
|
-
# @param name [String
|
|
22
|
-
# @param description [String, nil] Description (
|
|
21
|
+
# @param name [String] Name (required for a to-do list and for a group alike) - presence-validated server-side, so omitting it is a 422, not a preserve
|
|
22
|
+
# @param description [String, nil] Description (rich text HTML) - writable for a todolist group as well as a todolist, and omitting it clears it either way
|
|
23
23
|
# @return [Hash] response data
|
|
24
|
-
def
|
|
25
|
-
with_operation(service: "todolists", operation: "
|
|
24
|
+
def replace(id:, name:, description: nil)
|
|
25
|
+
with_operation(service: "todolists", operation: "replace", is_mutation: true, resource_id: id) do
|
|
26
26
|
http_put("/todolists/#{id}", body: compact_params(name: name, description: description)).json
|
|
27
27
|
end
|
|
28
28
|
end
|
|
@@ -41,11 +41,13 @@ module Basecamp
|
|
|
41
41
|
# List todolists in a todoset
|
|
42
42
|
# @param todoset_id [Integer] todoset id ID
|
|
43
43
|
# @param status [String, nil] active|archived|trashed
|
|
44
|
-
# @
|
|
45
|
-
|
|
44
|
+
# @param page [Integer, nil] Page number for paginating through results. Defaults to 1. A positive value selects exactly that page, not a starting offset; see SPEC section 8.
|
|
45
|
+
# @param max_items [Integer, nil] cap on items yielded across pages; nil or non-positive means no cap
|
|
46
|
+
# @return [ListEnumerator<Hash>] lazily paginated results (#meta carries pagination metadata)
|
|
47
|
+
def list(todoset_id:, status: nil, page: nil, max_items: nil)
|
|
46
48
|
wrap_paginated(service: "todolists", operation: "list", is_mutation: false, resource_id: todoset_id) do
|
|
47
|
-
params = compact_query_params(status: status)
|
|
48
|
-
paginate("/todosets/#{todoset_id}/todolists.json", params: params, operation: "ListTodolists")
|
|
49
|
+
params = compact_query_params(status: status, page: page)
|
|
50
|
+
paginate("/todosets/#{todoset_id}/todolists.json", params: params, operation: "ListTodolists", max_items: max_items)
|
|
49
51
|
end
|
|
50
52
|
end
|
|
51
53
|
|