basecamp-sdk 0.18.0 → 0.20.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 +1 -1
- data/lib/basecamp/api_error.rb +5 -3
- data/lib/basecamp/bucket_mismatch_error.rb +41 -0
- data/lib/basecamp/campfire_discovery_incomplete_error.rb +57 -0
- data/lib/basecamp/campfire_index.rb +398 -0
- data/lib/basecamp/client.rb +47 -9
- data/lib/basecamp/generated/metadata.json +728 -1
- data/lib/basecamp/generated/services/account_service.rb +2 -2
- data/lib/basecamp/generated/services/attachments_service.rb +1 -1
- data/lib/basecamp/generated/services/bookmarks_service.rb +2 -2
- data/lib/basecamp/generated/services/boosts_service.rb +3 -3
- data/lib/basecamp/generated/services/calendars_service.rb +2 -2
- data/lib/basecamp/generated/services/campfires_service.rb +7 -7
- data/lib/basecamp/generated/services/card_columns_service.rb +6 -6
- data/lib/basecamp/generated/services/card_steps_service.rb +4 -4
- data/lib/basecamp/generated/services/card_tables_service.rb +1 -1
- data/lib/basecamp/generated/services/cards_service.rb +3 -3
- data/lib/basecamp/generated/services/checkins_service.rb +9 -9
- 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/client_replies_service.rb +1 -1
- data/lib/basecamp/generated/services/client_visibility_service.rb +1 -1
- data/lib/basecamp/generated/services/cloud_files_service.rb +3 -3
- data/lib/basecamp/generated/services/comments_service.rb +3 -3
- data/lib/basecamp/generated/services/documents_service.rb +3 -3
- data/lib/basecamp/generated/services/event_feed_service.rb +58 -0
- data/lib/basecamp/generated/services/everything_service.rb +2 -2
- data/lib/basecamp/generated/services/folders_service.rb +4 -4
- data/lib/basecamp/generated/services/forwards_service.rb +3 -3
- data/lib/basecamp/generated/services/gauges_service.rb +10 -6
- data/lib/basecamp/generated/services/google_documents_service.rb +3 -3
- data/lib/basecamp/generated/services/hill_charts_service.rb +2 -2
- data/lib/basecamp/generated/services/lineup_service.rb +8 -0
- data/lib/basecamp/generated/services/message_boards_service.rb +1 -1
- data/lib/basecamp/generated/services/message_types_service.rb +3 -3
- data/lib/basecamp/generated/services/messages_service.rb +3 -3
- data/lib/basecamp/generated/services/my_assignments_service.rb +3 -3
- data/lib/basecamp/generated/services/my_notes_service.rb +2 -2
- data/lib/basecamp/generated/services/my_notifications_service.rb +1 -1
- data/lib/basecamp/generated/services/people_service.rb +11 -11
- data/lib/basecamp/generated/services/projects_service.rb +4 -4
- 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 +6 -6
- data/lib/basecamp/generated/services/search_service.rb +1 -1
- data/lib/basecamp/generated/services/subscriptions_service.rb +3 -3
- data/lib/basecamp/generated/services/templates_service.rb +8 -8
- data/lib/basecamp/generated/services/timesheets_service.rb +4 -4
- data/lib/basecamp/generated/services/todolist_groups_service.rb +1 -1
- data/lib/basecamp/generated/services/todolists_service.rb +3 -3
- data/lib/basecamp/generated/services/todos_service.rb +4 -4
- data/lib/basecamp/generated/services/todosets_service.rb +1 -1
- data/lib/basecamp/generated/services/tools_service.rb +3 -3
- data/lib/basecamp/generated/services/uploads_service.rb +4 -4
- data/lib/basecamp/generated/services/vaults_service.rb +3 -3
- data/lib/basecamp/generated/services/webhooks_service.rb +3 -3
- data/lib/basecamp/generated/services/wormholes_service.rb +2 -2
- data/lib/basecamp/generated/types.rb +108 -6
- data/lib/basecamp/http.rb +383 -60
- data/lib/basecamp/ids.rb +277 -0
- data/lib/basecamp/mentions.rb +1119 -0
- data/lib/basecamp/person_id_sites.rb +184 -0
- data/lib/basecamp/recording_routing_error.rb +50 -0
- data/lib/basecamp/recording_summary_error.rb +33 -0
- data/lib/basecamp/services/comments_extensions.rb +121 -0
- data/lib/basecamp/services/merge_safe.rb +37 -13
- data/lib/basecamp/services/recordings_extensions.rb +1305 -0
- data/lib/basecamp/services/todolists_extensions.rb +4 -3
- data/lib/basecamp/text.rb +94 -0
- data/lib/basecamp/unresolved_recording_error.rb +68 -0
- data/lib/basecamp/version.rb +1 -1
- data/lib/basecamp/webhooks/event.rb +4 -1
- data/lib/basecamp.rb +22 -4
- data/scripts/generate-metadata.rb +165 -9
- data/scripts/generate-services.rb +156 -30
- data/scripts/generate-types.rb +19 -0
- metadata +15 -3
- data/lib/basecamp/generated/services/automation_service.rb +0 -19
|
@@ -17,7 +17,54 @@ require 'set'
|
|
|
17
17
|
|
|
18
18
|
# Service generator for Ruby SDK
|
|
19
19
|
class ServiceGenerator
|
|
20
|
-
|
|
20
|
+
# A Path Item Object is read by EXCLUSION. Its non-operation fields are a
|
|
21
|
+
# closed, spec-defined set and its extensions are `x-` prefixed, so every
|
|
22
|
+
# OTHER field is an operation. Enumerating the verbs instead is the defect
|
|
23
|
+
# this replaces (#925): Smithy's `@http` trait takes the method as a
|
|
24
|
+
# free-form string it "will use literally and will perform no validation
|
|
25
|
+
# on", so a model author writing `method: "HEAD"` produced a valid model, a
|
|
26
|
+
# valid openapi.json, and no method on any service — the verb was not in the
|
|
27
|
+
# list, so the operation was stepped over in silence.
|
|
28
|
+
NON_OPERATION_FIELDS = %w[summary description servers parameters].freeze
|
|
29
|
+
|
|
30
|
+
# Discovery above is total; emission is bounded by the ONE declaration every
|
|
31
|
+
# generator reads (spec/generated-verbs.json), whose header carries the
|
|
32
|
+
# reasoning. Each verb in it has an `Http` helper (`http_get`, `http_post`, …)
|
|
33
|
+
# the emitted method body calls. An operation on any other verb stops this
|
|
34
|
+
# generator by name instead of vanishing from the SDK — a loud refusal is the
|
|
35
|
+
# acceptable outcome, a silent drop never was.
|
|
36
|
+
#
|
|
37
|
+
# The declaration is ORDERED, and that order is emission order. Ordering is a
|
|
38
|
+
# different job from deciding membership and cannot reproduce #925: membership
|
|
39
|
+
# is decided by exclusion above, so a verb absent from the declaration is
|
|
40
|
+
# refused, never skipped.
|
|
41
|
+
# The self-test points this at a crafted declaration to prove the bound is
|
|
42
|
+
# sourced from the shared file rather than a private literal; production runs
|
|
43
|
+
# never set it.
|
|
44
|
+
GENERATED_VERBS_FILE = ENV.fetch(
|
|
45
|
+
'BASECAMP_GENERATED_VERBS', File.expand_path('../../spec/generated-verbs.json', __dir__)
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
EMITTABLE_METHODS = begin
|
|
49
|
+
verbs = JSON.parse(File.read(GENERATED_VERBS_FILE, encoding: 'UTF-8'))['verbs']
|
|
50
|
+
# An HTTP method is a TOKEN, so the rule is a positive character class rather
|
|
51
|
+
# than a blankness predicate: `[a-z]+`, identical in all six loaders. Two
|
|
52
|
+
# review rounds chased "blank" across languages — Kotlin and Rust rejected a
|
|
53
|
+
# space while the others accepted it, then Ruby's ASCII `strip` accepted a
|
|
54
|
+
# non-breaking space the Unicode-aware ones rejected — and the next
|
|
55
|
+
# disagreement was guaranteed, because every language defines whitespace
|
|
56
|
+
# differently (Java's Character.isWhitespace excludes U+00A0; Rust's
|
|
57
|
+
# char::is_whitespace includes it; Ruby's String#strip is ASCII-only). A
|
|
58
|
+
# closed positive rule has no such seam: "", " ", "\u00a0", "GET" and 1 are
|
|
59
|
+
# all rejected the same way everywhere.
|
|
60
|
+
unless verbs.is_a?(Array) && !verbs.empty? && verbs.all? { |v| v.is_a?(String) && v.match?(/\A[a-z]+\z/) }
|
|
61
|
+
abort "Error: #{GENERATED_VERBS_FILE} must declare a non-empty `verbs` array of lowercase " \
|
|
62
|
+
'ASCII method names (/\A[a-z]+\z/).'
|
|
63
|
+
end
|
|
64
|
+
verbs.freeze
|
|
65
|
+
rescue Errno::ENOENT, JSON::ParserError => e
|
|
66
|
+
abort "Error: cannot read the generated-verb declaration #{GENERATED_VERBS_FILE}: #{e.message}"
|
|
67
|
+
end
|
|
21
68
|
|
|
22
69
|
# Schema reference cache for resolving $ref
|
|
23
70
|
attr_reader :schemas
|
|
@@ -33,7 +80,6 @@ class ServiceGenerator
|
|
|
33
80
|
'Schedule' => 'Schedules',
|
|
34
81
|
'People' => 'People',
|
|
35
82
|
'Projects' => 'Projects',
|
|
36
|
-
'Automation' => 'Automation',
|
|
37
83
|
'ClientFeatures' => 'ClientFeatures',
|
|
38
84
|
'Boosts' => 'Boosts',
|
|
39
85
|
'Untagged' => 'Miscellaneous'
|
|
@@ -56,6 +102,7 @@ class ServiceGenerator
|
|
|
56
102
|
GetCardColumn UpdateCardColumn SetCardColumnColor
|
|
57
103
|
EnableCardColumnOnHold DisableCardColumnOnHold
|
|
58
104
|
CreateCardColumn MoveCardColumn
|
|
105
|
+
SubscribeToCardColumn UnsubscribeFromCardColumn
|
|
59
106
|
],
|
|
60
107
|
'CardSteps' => %w[
|
|
61
108
|
GetCardStep CreateCardStep UpdateCardStep SetCardStepCompletion
|
|
@@ -71,22 +118,11 @@ class ServiceGenerator
|
|
|
71
118
|
'CloudFiles' => %w[GetCloudFile CreateCloudFile UpdateCloudFile],
|
|
72
119
|
'GoogleDocuments' => %w[GetGoogleDocument CreateGoogleDocument UpdateGoogleDocument]
|
|
73
120
|
},
|
|
74
|
-
'
|
|
75
|
-
'Tools' => %w[GetTool UpdateTool DeleteTool CreateTool EnableTool DisableTool RepositionTool]
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
'Events' => %w[ListEvents]
|
|
79
|
-
'Lineup' => %w[CreateLineupMarker UpdateLineupMarker DeleteLineupMarker],
|
|
80
|
-
'Search' => %w[Search GetSearchMetadata],
|
|
81
|
-
'Templates' => %w[
|
|
82
|
-
ListTemplates CreateTemplate GetTemplate UpdateTemplate
|
|
83
|
-
DeleteTemplate CreateProjectFromTemplate GetProjectConstruction
|
|
84
|
-
GetTemplateLibrary CreateTemplateLibraryCopy GetTemplateLibraryCopy
|
|
85
|
-
],
|
|
86
|
-
'Checkins' => %w[
|
|
87
|
-
GetQuestionnaire ListQuestions CreateQuestion GetQuestion
|
|
88
|
-
UpdateQuestion ListAnswers CreateAnswer GetAnswer UpdateAnswer
|
|
89
|
-
]
|
|
121
|
+
'Dock' => {
|
|
122
|
+
'Tools' => %w[GetTool UpdateTool DeleteTool CreateTool EnableTool DisableTool RepositionTool]
|
|
123
|
+
},
|
|
124
|
+
'Recordings' => {
|
|
125
|
+
'Events' => %w[ListEvents]
|
|
90
126
|
},
|
|
91
127
|
'Messages' => {
|
|
92
128
|
'Messages' => %w[GetMessage UpdateMessage CreateMessage ListMessages PinMessage UnpinMessage],
|
|
@@ -365,14 +401,78 @@ class ServiceGenerator
|
|
|
365
401
|
|
|
366
402
|
private
|
|
367
403
|
|
|
404
|
+
# Yields [verb, operation] for every operation in a path item, identifying an
|
|
405
|
+
# operation by what it is NOT (see NON_OPERATION_FIELDS). Anything this
|
|
406
|
+
# generator cannot render aborts the run naming the operation.
|
|
407
|
+
def each_operation(path, path_item)
|
|
408
|
+
unless path_item.is_a?(Hash)
|
|
409
|
+
abort "Error: openapi.json path #{path} is a #{path_item.class}, not a path item object."
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
# A `$ref` path item points at operations this generator cannot see without
|
|
413
|
+
# resolving the reference. Skipping it is the same silent under-count the
|
|
414
|
+
# exclusion walk exists to prevent, so refuse until someone teaches it to
|
|
415
|
+
# follow one.
|
|
416
|
+
if path_item.key?('$ref')
|
|
417
|
+
abort "Error: openapi.json path #{path} is a $ref to #{path_item['$ref'].inspect}. " \
|
|
418
|
+
'This generator cannot resolve a path-item reference, and skipping it would hide ' \
|
|
419
|
+
'every operation behind it from the SDK. Inline the path item, or teach this ' \
|
|
420
|
+
'generator to resolve local references.'
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
# OpenAPI 3.2's `additionalOperations` is a MAP of method to Operation, not an
|
|
424
|
+
# operation. Read as one it carries no operationId, so it would drop every
|
|
425
|
+
# operation inside it without saying so. Refuse by name until the walk learns
|
|
426
|
+
# the map shape.
|
|
427
|
+
if path_item.key?('additionalOperations')
|
|
428
|
+
abort "Error: openapi.json path #{path} declares `additionalOperations`, which OpenAPI 3.2 " \
|
|
429
|
+
'defines as a map of method to Operation. This walk reads a path-item field as a ' \
|
|
430
|
+
'single operation, so it would drop every operation inside it. Teach the walk the map ' \
|
|
431
|
+
'shape, or take the field out of the spec.'
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
fields = path_item.keys.reject { |f| NON_OPERATION_FIELDS.include?(f) || f.start_with?('x-') }
|
|
435
|
+
fields.sort_by! { |f| [ EMITTABLE_METHODS.index(f) || EMITTABLE_METHODS.length, f ] }
|
|
436
|
+
|
|
437
|
+
fields.each do |field|
|
|
438
|
+
operation = path_item[field]
|
|
439
|
+
|
|
440
|
+
unless operation.is_a?(Hash)
|
|
441
|
+
abort "Error: openapi.json path #{path} field #{field.inspect} is a #{operation.class}, " \
|
|
442
|
+
'which is neither a known non-operation field nor an operation object. If a later ' \
|
|
443
|
+
'OpenAPI version added it, add it to NON_OPERATION_FIELDS with a reason.'
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
unless EMITTABLE_METHODS.include?(field)
|
|
447
|
+
op_id = operation['operationId'] || '(no operationId)'
|
|
448
|
+
abort "Error: openapi.json declares #{field.upcase} #{path} (#{op_id}), and this generator " \
|
|
449
|
+
"emits only #{EMITTABLE_METHODS.map(&:upcase).join('/')}. Generating the rest of the " \
|
|
450
|
+
'SDK without it would drop the operation from every Ruby client in silence, which is ' \
|
|
451
|
+
'the failure #925 closed. Give Basecamp::Http a ' \
|
|
452
|
+
"http_#{field} helper, add #{field.inspect} to spec/generated-verbs.json (read that " \
|
|
453
|
+
'file first — the other five SDKs need the same helper), or take the operation out ' \
|
|
454
|
+
'of the Smithy model.'
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
# An operation has to be IDENTIFIABLE. OpenAPI lets operationId be omitted,
|
|
458
|
+
# and every walker here used to step over one that was — a silent drop of a
|
|
459
|
+
# real operation, which is #925 wearing a different field.
|
|
460
|
+
op_id = operation['operationId']
|
|
461
|
+
unless op_id.is_a?(String) && !op_id.empty?
|
|
462
|
+
abort "Error: openapi.json declares #{field.upcase} #{path} with no operationId. " \
|
|
463
|
+
'Everything downstream is keyed by it, and skipping the operation would drop it ' \
|
|
464
|
+
'from the SDK in silence.'
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
yield field, operation
|
|
468
|
+
end
|
|
469
|
+
end
|
|
470
|
+
|
|
368
471
|
def group_operations
|
|
369
472
|
services = {}
|
|
370
473
|
|
|
371
474
|
@openapi['paths'].each do |path, path_item|
|
|
372
|
-
|
|
373
|
-
operation = path_item[method]
|
|
374
|
-
next unless operation
|
|
375
|
-
|
|
475
|
+
each_operation(path, path_item) do |method, operation|
|
|
376
476
|
tag = operation['tags']&.first || 'Untagged'
|
|
377
477
|
parsed = parse_operation(path, method, operation)
|
|
378
478
|
|
|
@@ -440,6 +540,14 @@ class ServiceGenerator
|
|
|
440
540
|
# Extract body parameters from schema
|
|
441
541
|
body_params = extract_body_params(body_schema_ref)
|
|
442
542
|
|
|
543
|
+
# Only "link" and "cursor" are implemented. Anything else -- a typo, or the
|
|
544
|
+
# "page" style the trait used to advertise -- must fail loudly: read as "not
|
|
545
|
+
# paginated" it would silently ship a method that never walks.
|
|
546
|
+
pagination_style = operation.dig('x-basecamp-pagination', 'style')
|
|
547
|
+
if operation['x-basecamp-pagination'] && !%w[ link cursor ].include?(pagination_style)
|
|
548
|
+
raise "#{operation_id}: unsupported pagination style #{pagination_style.inspect} (expected \"link\" or \"cursor\")"
|
|
549
|
+
end
|
|
550
|
+
|
|
443
551
|
# Check response
|
|
444
552
|
success_response = operation.dig('responses', '200') || operation.dig('responses', '201')
|
|
445
553
|
response_schema = success_response&.dig('content', 'application/json', 'schema')
|
|
@@ -470,8 +578,18 @@ class ServiceGenerator
|
|
|
470
578
|
returns_array: returns_array,
|
|
471
579
|
returns_bare_array: returns_bare_array,
|
|
472
580
|
is_mutation: http_method != 'GET',
|
|
473
|
-
|
|
474
|
-
|
|
581
|
+
# Auto-pagination is the "link" style alone: the generated method follows
|
|
582
|
+
# Link: rel="next" and flattens the walk into one array. The "cursor"
|
|
583
|
+
# style is declared for the catalogue and generates none -- each call
|
|
584
|
+
# returns one page carrying its own opaque position, and flattening would
|
|
585
|
+
# swallow every intermediate one.
|
|
586
|
+
has_pagination: pagination_style == 'link',
|
|
587
|
+
# Carried separately because has_pagination is false for cursor, and the
|
|
588
|
+
# bare-array gate below would otherwise walk it anyway.
|
|
589
|
+
cursor_pagination: pagination_style == 'cursor',
|
|
590
|
+
# Link-style only: the key drives envelope unwrapping, and a cursor
|
|
591
|
+
# operation must be typed as its envelope rather than the item under it.
|
|
592
|
+
pagination_key: (pagination_style == 'link' ? operation.dig('x-basecamp-pagination', 'key') : nil)
|
|
475
593
|
}
|
|
476
594
|
end
|
|
477
595
|
|
|
@@ -657,7 +775,10 @@ class ServiceGenerator
|
|
|
657
775
|
def generate_method(op, service_name:)
|
|
658
776
|
lines = []
|
|
659
777
|
|
|
660
|
-
|
|
778
|
+
# A cursor operation never walks, whatever its response shape: has_pagination
|
|
779
|
+
# is already false for it, but a bare-array response would otherwise send it
|
|
780
|
+
# down the Link-following path through returns_array.
|
|
781
|
+
is_paginated = !op[:cursor_pagination] && (op[:returns_array] || op[:has_pagination]) && !op[:pagination_key]
|
|
661
782
|
is_wrapped_paginated = op[:has_pagination] && op[:pagination_key]
|
|
662
783
|
|
|
663
784
|
# Method signature (paginated operations gain a trailing max_items: kwarg)
|
|
@@ -903,6 +1024,11 @@ class ServiceGenerator
|
|
|
903
1024
|
# Only GETs are retry-governed in Ruby, and only Http#get accepts the
|
|
904
1025
|
# operation keyword — mutations go through single_request with no retry.
|
|
905
1026
|
operation_arg = http_method == 'get' ? ", operation: \"#{op[:operation_id]}\"" : ''
|
|
1027
|
+
# Every verb names its operation to the body decode, which is a separate
|
|
1028
|
+
# channel from the retry keyword above: the typed person-id decode
|
|
1029
|
+
# (Basecamp::PersonIdSites) is keyed by operation id, and a mutation's
|
|
1030
|
+
# response carries people exactly as a read's does.
|
|
1031
|
+
json_call = ".json(operation: \"#{op[:operation_id]}\")"
|
|
906
1032
|
|
|
907
1033
|
if op[:has_binary_body]
|
|
908
1034
|
# Binary upload - use raw body and set Content-Type header
|
|
@@ -914,18 +1040,18 @@ class ServiceGenerator
|
|
|
914
1040
|
query_string = query_parts.join('&')
|
|
915
1041
|
# Modify path_expr to include query string
|
|
916
1042
|
path_expr_with_query = path_expr.sub(/"$/, "?#{query_string}\"")
|
|
917
|
-
lines << " http_#{http_method}_raw(#{path_expr_with_query}, body: data, content_type: content_type)
|
|
1043
|
+
lines << " http_#{http_method}_raw(#{path_expr_with_query}, body: data, content_type: content_type)#{json_call}"
|
|
918
1044
|
else
|
|
919
|
-
lines << " http_#{http_method}_raw(#{path_expr}, body: data, content_type: content_type)
|
|
1045
|
+
lines << " http_#{http_method}_raw(#{path_expr}, body: data, content_type: content_type)#{json_call}"
|
|
920
1046
|
end
|
|
921
1047
|
elsif op[:has_body]
|
|
922
1048
|
body_expr = build_body_expression(op)
|
|
923
|
-
lines << " http_#{http_method}(#{path_expr}, body: #{body_expr})
|
|
1049
|
+
lines << " http_#{http_method}(#{path_expr}, body: #{body_expr})#{json_call}"
|
|
924
1050
|
elsif op[:query_params].any?
|
|
925
1051
|
param_names = op[:query_params].map { |q| "#{to_snake_case(q[:name])}: #{to_snake_case(q[:name])}" }
|
|
926
|
-
lines << " http_#{http_method}(#{path_expr}, params: compact_query_params(#{param_names.join(', ')})#{operation_arg})
|
|
1052
|
+
lines << " http_#{http_method}(#{path_expr}, params: compact_query_params(#{param_names.join(', ')})#{operation_arg})#{json_call}"
|
|
927
1053
|
else
|
|
928
|
-
lines << " http_#{http_method}(#{path_expr}#{operation_arg})
|
|
1054
|
+
lines << " http_#{http_method}(#{path_expr}#{operation_arg})#{json_call}"
|
|
929
1055
|
end
|
|
930
1056
|
|
|
931
1057
|
lines
|
data/scripts/generate-types.rb
CHANGED
|
@@ -47,6 +47,23 @@ def generate_helpers
|
|
|
47
47
|
value.to_i
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
# A PERSON's id: the one field in this model the reference decodes
|
|
51
|
+
# flexibly (x-go-type: types.FlexibleInt64), and the only one that may
|
|
52
|
+
# arrive as a JSON string.
|
|
53
|
+
#
|
|
54
|
+
# Read with Basecamp::Ids.person_from_wire, which is Go's
|
|
55
|
+
# strconv.ParseInt(s, 10, 64) and is already the rule at the other two
|
|
56
|
+
# person-id sites (the pre-decode normalizer in Basecamp::Http and the
|
|
57
|
+
# flexible reader itself). NOT parse_integer, whose to_i answers 0 for
|
|
58
|
+
# "basecamp" without recording the label, 8 for "010", and — since the
|
|
59
|
+
# normalizer now leaves an out-of-range id as a String for the reader to
|
|
60
|
+
# refuse — a bignum for "18446744073709551616x", which is not an id any
|
|
61
|
+
# API can hold. A refused id is nil here, the same nil a malformed value
|
|
62
|
+
# of any other type gets.
|
|
63
|
+
def parse_flexible_person_id(value)
|
|
64
|
+
Basecamp::Ids.person_from_wire(value)
|
|
65
|
+
end
|
|
66
|
+
|
|
50
67
|
def parse_float(value)
|
|
51
68
|
return nil if value.nil?
|
|
52
69
|
value.to_f
|
|
@@ -203,6 +220,8 @@ if __FILE__ == $PROGRAM_NAME
|
|
|
203
220
|
elsif prop_schema['type'] == 'array' && prop_schema.dig('items', '$ref')
|
|
204
221
|
ref_name = prop_schema['items']['$ref'].split('/').last
|
|
205
222
|
"parse_array(data[\"#{prop_name}\"], \"#{ref_name}\")"
|
|
223
|
+
elsif prop_schema['x-go-type']&.include?('FlexibleInt64')
|
|
224
|
+
"parse_flexible_person_id(data[\"#{prop_name}\"])"
|
|
206
225
|
elsif prop_schema['type'] == 'integer'
|
|
207
226
|
"parse_integer(data[\"#{prop_name}\"])"
|
|
208
227
|
elsif prop_schema['type'] == 'number'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: basecamp-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.20.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Basecamp
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|
|
@@ -169,6 +169,9 @@ files:
|
|
|
169
169
|
- lib/basecamp/auth_error.rb
|
|
170
170
|
- lib/basecamp/auth_strategy.rb
|
|
171
171
|
- lib/basecamp/bearer_auth.rb
|
|
172
|
+
- lib/basecamp/bucket_mismatch_error.rb
|
|
173
|
+
- lib/basecamp/campfire_discovery_incomplete_error.rb
|
|
174
|
+
- lib/basecamp/campfire_index.rb
|
|
172
175
|
- lib/basecamp/chain_hooks.rb
|
|
173
176
|
- lib/basecamp/client.rb
|
|
174
177
|
- lib/basecamp/config.rb
|
|
@@ -180,7 +183,6 @@ files:
|
|
|
180
183
|
- lib/basecamp/generated/metadata.json
|
|
181
184
|
- lib/basecamp/generated/services/account_service.rb
|
|
182
185
|
- lib/basecamp/generated/services/attachments_service.rb
|
|
183
|
-
- lib/basecamp/generated/services/automation_service.rb
|
|
184
186
|
- lib/basecamp/generated/services/base_service.rb
|
|
185
187
|
- lib/basecamp/generated/services/bookmarks_service.rb
|
|
186
188
|
- lib/basecamp/generated/services/boosts_service.rb
|
|
@@ -200,6 +202,7 @@ files:
|
|
|
200
202
|
- lib/basecamp/generated/services/comments_service.rb
|
|
201
203
|
- lib/basecamp/generated/services/documents_service.rb
|
|
202
204
|
- lib/basecamp/generated/services/drafts_service.rb
|
|
205
|
+
- lib/basecamp/generated/services/event_feed_service.rb
|
|
203
206
|
- lib/basecamp/generated/services/events_service.rb
|
|
204
207
|
- lib/basecamp/generated/services/everything_service.rb
|
|
205
208
|
- lib/basecamp/generated/services/folders_service.rb
|
|
@@ -236,10 +239,12 @@ files:
|
|
|
236
239
|
- lib/basecamp/generated/types.rb
|
|
237
240
|
- lib/basecamp/hooks.rb
|
|
238
241
|
- lib/basecamp/http.rb
|
|
242
|
+
- lib/basecamp/ids.rb
|
|
239
243
|
- lib/basecamp/limit_exceeded_error.rb
|
|
240
244
|
- lib/basecamp/list_enumerator.rb
|
|
241
245
|
- lib/basecamp/list_meta.rb
|
|
242
246
|
- lib/basecamp/logger_hooks.rb
|
|
247
|
+
- lib/basecamp/mentions.rb
|
|
243
248
|
- lib/basecamp/network_error.rb
|
|
244
249
|
- lib/basecamp/noop_hooks.rb
|
|
245
250
|
- lib/basecamp/not_found_error.rb
|
|
@@ -264,19 +269,26 @@ files:
|
|
|
264
269
|
- lib/basecamp/operation_info.rb
|
|
265
270
|
- lib/basecamp/operation_result.rb
|
|
266
271
|
- lib/basecamp/people_confirmation_required_error.rb
|
|
272
|
+
- lib/basecamp/person_id_sites.rb
|
|
267
273
|
- lib/basecamp/rate_limit_error.rb
|
|
274
|
+
- lib/basecamp/recording_routing_error.rb
|
|
275
|
+
- lib/basecamp/recording_summary_error.rb
|
|
268
276
|
- lib/basecamp/request_info.rb
|
|
269
277
|
- lib/basecamp/request_result.rb
|
|
270
278
|
- lib/basecamp/security.rb
|
|
271
279
|
- lib/basecamp/services/authorization_service.rb
|
|
272
280
|
- lib/basecamp/services/cards_extensions.rb
|
|
281
|
+
- lib/basecamp/services/comments_extensions.rb
|
|
273
282
|
- lib/basecamp/services/documents_extensions.rb
|
|
274
283
|
- lib/basecamp/services/merge_safe.rb
|
|
284
|
+
- lib/basecamp/services/recordings_extensions.rb
|
|
275
285
|
- lib/basecamp/services/schedules_extensions.rb
|
|
276
286
|
- lib/basecamp/services/todolists_extensions.rb
|
|
277
287
|
- lib/basecamp/services/todos_extensions.rb
|
|
278
288
|
- lib/basecamp/static_token_provider.rb
|
|
289
|
+
- lib/basecamp/text.rb
|
|
279
290
|
- lib/basecamp/token_provider.rb
|
|
291
|
+
- lib/basecamp/unresolved_recording_error.rb
|
|
280
292
|
- lib/basecamp/usage_error.rb
|
|
281
293
|
- lib/basecamp/validation_error.rb
|
|
282
294
|
- lib/basecamp/version.rb
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Basecamp
|
|
4
|
-
module Services
|
|
5
|
-
# Service for Automation operations
|
|
6
|
-
#
|
|
7
|
-
# @generated from OpenAPI spec
|
|
8
|
-
class AutomationService < BaseService
|
|
9
|
-
|
|
10
|
-
# List all lineup markers for the account
|
|
11
|
-
# @return [Array<Hash>] response data
|
|
12
|
-
def list_lineup_markers()
|
|
13
|
-
with_operation(service: "automation", operation: "list_lineup_markers", is_mutation: false) do
|
|
14
|
-
http_get("/lineup/markers.json", operation: "ListLineupMarkers").json
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|