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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +65 -1
  3. data/basecamp-sdk.gemspec +2 -3
  4. data/lib/basecamp/client.rb +5 -0
  5. data/lib/basecamp/generated/metadata.json +100 -33
  6. data/lib/basecamp/generated/services/base_service.rb +13 -0
  7. data/lib/basecamp/generated/services/campfires_service.rb +15 -3
  8. data/lib/basecamp/generated/services/card_columns_service.rb +26 -23
  9. data/lib/basecamp/generated/services/checkins_service.rb +5 -4
  10. data/lib/basecamp/generated/services/client_approvals_service.rb +1 -1
  11. data/lib/basecamp/generated/services/client_correspondences_service.rb +1 -1
  12. data/lib/basecamp/generated/services/documents_service.rb +3 -2
  13. data/lib/basecamp/generated/services/forwards_service.rb +1 -1
  14. data/lib/basecamp/generated/services/gauges_service.rb +4 -4
  15. data/lib/basecamp/generated/services/messages_service.rb +4 -3
  16. data/lib/basecamp/generated/services/my_assignments_service.rb +1 -1
  17. data/lib/basecamp/generated/services/my_notifications_service.rb +1 -1
  18. data/lib/basecamp/generated/services/people_service.rb +2 -2
  19. data/lib/basecamp/generated/services/projects_service.rb +2 -2
  20. data/lib/basecamp/generated/services/recordings_service.rb +1 -1
  21. data/lib/basecamp/generated/services/reports_service.rb +3 -3
  22. data/lib/basecamp/generated/services/schedules_service.rb +5 -4
  23. data/lib/basecamp/generated/services/search_service.rb +14 -3
  24. data/lib/basecamp/generated/services/templates_service.rb +4 -5
  25. data/lib/basecamp/generated/services/timesheets_service.rb +3 -3
  26. data/lib/basecamp/generated/services/todolists_service.rb +15 -3
  27. data/lib/basecamp/generated/services/todos_service.rb +5 -5
  28. data/lib/basecamp/generated/services/tools_service.rb +7 -6
  29. data/lib/basecamp/generated/services/uploads_service.rb +20 -2
  30. data/lib/basecamp/generated/services/webhooks_service.rb +2 -2
  31. data/lib/basecamp/generated/services/wormholes_service.rb +44 -0
  32. data/lib/basecamp/generated/types.rb +284 -64
  33. data/lib/basecamp/http.rb +86 -15
  34. data/lib/basecamp/oauth/config.rb +20 -5
  35. data/lib/basecamp/oauth/discovery.rb +134 -64
  36. data/lib/basecamp/oauth/discovery_result.rb +33 -0
  37. data/lib/basecamp/oauth/discovery_selection_error.rb +30 -0
  38. data/lib/basecamp/oauth/fetcher.rb +204 -0
  39. data/lib/basecamp/oauth/protected_resource_metadata.rb +22 -0
  40. data/lib/basecamp/oauth/resource.rb +95 -0
  41. data/lib/basecamp/oauth.rb +173 -0
  42. data/lib/basecamp/security.rb +83 -0
  43. data/lib/basecamp/services/authorization_service.rb +45 -0
  44. data/lib/basecamp/services/todos_extensions.rb +121 -0
  45. data/lib/basecamp/version.rb +2 -2
  46. data/lib/basecamp.rb +6 -0
  47. data/scripts/generate-services.rb +61 -13
  48. data/scripts/generate-types.rb +33 -1
  49. metadata +14 -21
  50. data/lib/basecamp/generated/services/authorization_service.rb +0 -47
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Auto-generated from OpenAPI spec. Do not edit manually.
4
- # Generated: 2026-03-26T04:17:28Z
4
+ # Generated: 2026-07-25T04:02:54Z
5
5
 
6
6
  require "json"
7
7
  require "time"
@@ -439,11 +439,11 @@ module Basecamp
439
439
  # Card
440
440
  class Card
441
441
  include TypeHelpers
442
- attr_accessor :app_url, :bucket, :created_at, :creator, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :assignees, :bookmark_url, :boosts_count, :boosts_url, :comments_count, :comments_url, :completed, :completed_at, :completer, :completion_subscribers, :completion_url, :content, :description, :due_on, :position, :steps, :subscription_url
442
+ attr_accessor :app_url, :bucket, :created_at, :creator, :description_attachments, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :assignees, :bookmark_url, :boosts_count, :boosts_url, :comments_count, :comments_url, :completed, :completed_at, :completer, :completion_subscribers, :completion_url, :content, :description, :due_on, :position, :steps, :subscription_url
443
443
 
444
444
  # @return [Array<Symbol>]
445
445
  def self.required_fields
446
- %i[app_url bucket created_at creator id inherits_status parent status title type updated_at url visible_to_clients].freeze
446
+ %i[app_url bucket created_at creator description_attachments id inherits_status parent status title type updated_at url visible_to_clients].freeze
447
447
  end
448
448
 
449
449
  def initialize(data = {})
@@ -451,6 +451,7 @@ module Basecamp
451
451
  @bucket = parse_type(data["bucket"], "TodoBucket")
452
452
  @created_at = parse_datetime(data["created_at"])
453
453
  @creator = parse_type(data["creator"], "Person")
454
+ @description_attachments = parse_array(data["description_attachments"], "RichTextAttachment")
454
455
  @id = parse_integer(data["id"])
455
456
  @inherits_status = parse_boolean(data["inherits_status"])
456
457
  @parent = parse_type(data["parent"], "RecordingParent")
@@ -485,6 +486,7 @@ module Basecamp
485
486
  "bucket" => @bucket,
486
487
  "created_at" => @created_at,
487
488
  "creator" => @creator,
489
+ "description_attachments" => @description_attachments,
488
490
  "id" => @id,
489
491
  "inherits_status" => @inherits_status,
490
492
  "parent" => @parent,
@@ -693,7 +695,7 @@ module Basecamp
693
695
  # CardTable
694
696
  class CardTable
695
697
  include TypeHelpers
696
- attr_accessor :app_url, :bucket, :created_at, :creator, :id, :inherits_status, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :lists, :subscribers, :subscription_url
698
+ attr_accessor :app_url, :bucket, :created_at, :creator, :id, :inherits_status, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :lists, :subscribers, :subscription_url, :wormholes
697
699
 
698
700
  # @return [Array<Symbol>]
699
701
  def self.required_fields
@@ -717,6 +719,7 @@ module Basecamp
717
719
  @lists = parse_array(data["lists"], "CardColumn")
718
720
  @subscribers = parse_array(data["subscribers"], "Person")
719
721
  @subscription_url = data["subscription_url"]
722
+ @wormholes = parse_array(data["wormholes"], "Wormhole")
720
723
  end
721
724
 
722
725
  def to_h
@@ -737,6 +740,7 @@ module Basecamp
737
740
  "lists" => @lists,
738
741
  "subscribers" => @subscribers,
739
742
  "subscription_url" => @subscription_url,
743
+ "wormholes" => @wormholes,
740
744
  }.compact
741
745
  end
742
746
 
@@ -787,16 +791,17 @@ module Basecamp
787
791
  # ClientApproval
788
792
  class ClientApproval
789
793
  include TypeHelpers
790
- attr_accessor :app_url, :bucket, :created_at, :creator, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :approval_status, :approver, :bookmark_url, :content, :due_on, :replies_count, :replies_url, :responses, :subject, :subscription_url
794
+ attr_accessor :app_url, :bucket, :content_attachments, :created_at, :creator, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :approval_status, :approver, :bookmark_url, :content, :due_on, :replies_count, :replies_url, :responses, :subject, :subscription_url
791
795
 
792
796
  # @return [Array<Symbol>]
793
797
  def self.required_fields
794
- %i[app_url bucket created_at creator id inherits_status parent status title type updated_at url visible_to_clients].freeze
798
+ %i[app_url bucket content_attachments created_at creator id inherits_status parent status title type updated_at url visible_to_clients].freeze
795
799
  end
796
800
 
797
801
  def initialize(data = {})
798
802
  @app_url = data["app_url"]
799
803
  @bucket = parse_type(data["bucket"], "RecordingBucket")
804
+ @content_attachments = parse_array(data["content_attachments"], "RichTextAttachment")
800
805
  @created_at = parse_datetime(data["created_at"])
801
806
  @creator = parse_type(data["creator"], "Person")
802
807
  @id = parse_integer(data["id"])
@@ -824,6 +829,7 @@ module Basecamp
824
829
  {
825
830
  "app_url" => @app_url,
826
831
  "bucket" => @bucket,
832
+ "content_attachments" => @content_attachments,
827
833
  "created_at" => @created_at,
828
834
  "creator" => @creator,
829
835
  "id" => @id,
@@ -931,16 +937,17 @@ module Basecamp
931
937
  # ClientCorrespondence
932
938
  class ClientCorrespondence
933
939
  include TypeHelpers
934
- attr_accessor :app_url, :bucket, :created_at, :creator, :id, :inherits_status, :parent, :status, :subject, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :content, :replies_count, :replies_url, :subscription_url
940
+ attr_accessor :app_url, :bucket, :content_attachments, :created_at, :creator, :id, :inherits_status, :parent, :status, :subject, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :content, :replies_count, :replies_url, :subscription_url
935
941
 
936
942
  # @return [Array<Symbol>]
937
943
  def self.required_fields
938
- %i[app_url bucket created_at creator id inherits_status parent status subject title type updated_at url visible_to_clients].freeze
944
+ %i[app_url bucket content_attachments created_at creator id inherits_status parent status subject title type updated_at url visible_to_clients].freeze
939
945
  end
940
946
 
941
947
  def initialize(data = {})
942
948
  @app_url = data["app_url"]
943
949
  @bucket = parse_type(data["bucket"], "RecordingBucket")
950
+ @content_attachments = parse_array(data["content_attachments"], "RichTextAttachment")
944
951
  @created_at = parse_datetime(data["created_at"])
945
952
  @creator = parse_type(data["creator"], "Person")
946
953
  @id = parse_integer(data["id"])
@@ -964,6 +971,7 @@ module Basecamp
964
971
  {
965
972
  "app_url" => @app_url,
966
973
  "bucket" => @bucket,
974
+ "content_attachments" => @content_attachments,
967
975
  "created_at" => @created_at,
968
976
  "creator" => @creator,
969
977
  "id" => @id,
@@ -992,17 +1000,18 @@ module Basecamp
992
1000
  # ClientReply
993
1001
  class ClientReply
994
1002
  include TypeHelpers
995
- attr_accessor :app_url, :bucket, :content, :created_at, :creator, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url
1003
+ attr_accessor :app_url, :bucket, :content, :content_attachments, :created_at, :creator, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url
996
1004
 
997
1005
  # @return [Array<Symbol>]
998
1006
  def self.required_fields
999
- %i[app_url bucket content created_at creator id inherits_status parent status title type updated_at url visible_to_clients].freeze
1007
+ %i[app_url bucket content content_attachments created_at creator id inherits_status parent status title type updated_at url visible_to_clients].freeze
1000
1008
  end
1001
1009
 
1002
1010
  def initialize(data = {})
1003
1011
  @app_url = data["app_url"]
1004
1012
  @bucket = parse_type(data["bucket"], "RecordingBucket")
1005
1013
  @content = data["content"]
1014
+ @content_attachments = parse_array(data["content_attachments"], "RichTextAttachment")
1006
1015
  @created_at = parse_datetime(data["created_at"])
1007
1016
  @creator = parse_type(data["creator"], "Person")
1008
1017
  @id = parse_integer(data["id"])
@@ -1022,6 +1031,7 @@ module Basecamp
1022
1031
  "app_url" => @app_url,
1023
1032
  "bucket" => @bucket,
1024
1033
  "content" => @content,
1034
+ "content_attachments" => @content_attachments,
1025
1035
  "created_at" => @created_at,
1026
1036
  "creator" => @creator,
1027
1037
  "id" => @id,
@@ -1043,6 +1053,7 @@ module Basecamp
1043
1053
  end
1044
1054
 
1045
1055
  # ClientSide
1056
+ # @deprecated This shape is deprecated since 2024-01: Use Client Visibility feature instead
1046
1057
  class ClientSide
1047
1058
  include TypeHelpers
1048
1059
  attr_accessor :app_url, :url
@@ -1067,17 +1078,18 @@ module Basecamp
1067
1078
  # Comment
1068
1079
  class Comment
1069
1080
  include TypeHelpers
1070
- attr_accessor :app_url, :bucket, :content, :created_at, :creator, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :boosts_count, :boosts_url
1081
+ attr_accessor :app_url, :bucket, :content, :content_attachments, :created_at, :creator, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :boosts_count, :boosts_url
1071
1082
 
1072
1083
  # @return [Array<Symbol>]
1073
1084
  def self.required_fields
1074
- %i[app_url bucket content created_at creator id inherits_status parent status title type updated_at url visible_to_clients].freeze
1085
+ %i[app_url bucket content content_attachments created_at creator id inherits_status parent status title type updated_at url visible_to_clients].freeze
1075
1086
  end
1076
1087
 
1077
1088
  def initialize(data = {})
1078
1089
  @app_url = data["app_url"]
1079
1090
  @bucket = parse_type(data["bucket"], "TodoBucket")
1080
1091
  @content = data["content"]
1092
+ @content_attachments = parse_array(data["content_attachments"], "RichTextAttachment")
1081
1093
  @created_at = parse_datetime(data["created_at"])
1082
1094
  @creator = parse_type(data["creator"], "Person")
1083
1095
  @id = parse_integer(data["id"])
@@ -1099,6 +1111,7 @@ module Basecamp
1099
1111
  "app_url" => @app_url,
1100
1112
  "bucket" => @bucket,
1101
1113
  "content" => @content,
1114
+ "content_attachments" => @content_attachments,
1102
1115
  "created_at" => @created_at,
1103
1116
  "creator" => @creator,
1104
1117
  "id" => @id,
@@ -1192,16 +1205,17 @@ module Basecamp
1192
1205
  # Document
1193
1206
  class Document
1194
1207
  include TypeHelpers
1195
- attr_accessor :app_url, :bucket, :created_at, :creator, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :boosts_count, :boosts_url, :comments_count, :comments_url, :content, :position, :subscription_url
1208
+ attr_accessor :app_url, :bucket, :content_attachments, :created_at, :creator, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :boosts_count, :boosts_url, :comments_count, :comments_url, :content, :position, :subscription_url
1196
1209
 
1197
1210
  # @return [Array<Symbol>]
1198
1211
  def self.required_fields
1199
- %i[app_url bucket created_at creator id inherits_status parent status title type updated_at url visible_to_clients].freeze
1212
+ %i[app_url bucket content_attachments created_at creator id inherits_status parent status title type updated_at url visible_to_clients].freeze
1200
1213
  end
1201
1214
 
1202
1215
  def initialize(data = {})
1203
1216
  @app_url = data["app_url"]
1204
1217
  @bucket = parse_type(data["bucket"], "TodoBucket")
1218
+ @content_attachments = parse_array(data["content_attachments"], "RichTextAttachment")
1205
1219
  @created_at = parse_datetime(data["created_at"])
1206
1220
  @creator = parse_type(data["creator"], "Person")
1207
1221
  @id = parse_integer(data["id"])
@@ -1227,6 +1241,7 @@ module Basecamp
1227
1241
  {
1228
1242
  "app_url" => @app_url,
1229
1243
  "bucket" => @bucket,
1244
+ "content_attachments" => @content_attachments,
1230
1245
  "created_at" => @created_at,
1231
1246
  "creator" => @creator,
1232
1247
  "id" => @id,
@@ -1320,16 +1335,17 @@ module Basecamp
1320
1335
  # Forward
1321
1336
  class Forward
1322
1337
  include TypeHelpers
1323
- attr_accessor :app_url, :bucket, :created_at, :creator, :id, :inherits_status, :parent, :status, :subject, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :content, :from, :replies_count, :replies_url, :subscription_url
1338
+ attr_accessor :app_url, :bucket, :content_attachments, :created_at, :creator, :id, :inherits_status, :parent, :status, :subject, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :content, :from, :replies_count, :replies_url, :subscription_url
1324
1339
 
1325
1340
  # @return [Array<Symbol>]
1326
1341
  def self.required_fields
1327
- %i[app_url bucket created_at creator id inherits_status parent status subject title type updated_at url visible_to_clients].freeze
1342
+ %i[app_url bucket content_attachments created_at creator id inherits_status parent status subject title type updated_at url visible_to_clients].freeze
1328
1343
  end
1329
1344
 
1330
1345
  def initialize(data = {})
1331
1346
  @app_url = data["app_url"]
1332
1347
  @bucket = parse_type(data["bucket"], "TodoBucket")
1348
+ @content_attachments = parse_array(data["content_attachments"], "RichTextAttachment")
1333
1349
  @created_at = parse_datetime(data["created_at"])
1334
1350
  @creator = parse_type(data["creator"], "Person")
1335
1351
  @id = parse_integer(data["id"])
@@ -1354,6 +1370,7 @@ module Basecamp
1354
1370
  {
1355
1371
  "app_url" => @app_url,
1356
1372
  "bucket" => @bucket,
1373
+ "content_attachments" => @content_attachments,
1357
1374
  "created_at" => @created_at,
1358
1375
  "creator" => @creator,
1359
1376
  "id" => @id,
@@ -1383,17 +1400,18 @@ module Basecamp
1383
1400
  # ForwardReply
1384
1401
  class ForwardReply
1385
1402
  include TypeHelpers
1386
- attr_accessor :app_url, :bucket, :content, :created_at, :creator, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :boosts_count, :boosts_url
1403
+ attr_accessor :app_url, :bucket, :content, :content_attachments, :created_at, :creator, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :boosts_count, :boosts_url
1387
1404
 
1388
1405
  # @return [Array<Symbol>]
1389
1406
  def self.required_fields
1390
- %i[app_url bucket content created_at creator id inherits_status parent status title type updated_at url visible_to_clients].freeze
1407
+ %i[app_url bucket content content_attachments created_at creator id inherits_status parent status title type updated_at url visible_to_clients].freeze
1391
1408
  end
1392
1409
 
1393
1410
  def initialize(data = {})
1394
1411
  @app_url = data["app_url"]
1395
1412
  @bucket = parse_type(data["bucket"], "TodoBucket")
1396
1413
  @content = data["content"]
1414
+ @content_attachments = parse_array(data["content_attachments"], "RichTextAttachment")
1397
1415
  @created_at = parse_datetime(data["created_at"])
1398
1416
  @creator = parse_type(data["creator"], "Person")
1399
1417
  @id = parse_integer(data["id"])
@@ -1415,6 +1433,7 @@ module Basecamp
1415
1433
  "app_url" => @app_url,
1416
1434
  "bucket" => @bucket,
1417
1435
  "content" => @content,
1436
+ "content_attachments" => @content_attachments,
1418
1437
  "created_at" => @created_at,
1419
1438
  "creator" => @creator,
1420
1439
  "id" => @id,
@@ -1440,7 +1459,7 @@ module Basecamp
1440
1459
  # Gauge
1441
1460
  class Gauge
1442
1461
  include TypeHelpers
1443
- attr_accessor :created_at, :id, :updated_at, :app_url, :bookmark_url, :bucket, :creator, :description, :enabled, :inherits_status, :last_needle_color, :last_needle_position, :previous_needle_position, :status, :title, :type, :url, :visible_to_clients
1462
+ attr_accessor :created_at, :id, :updated_at, :app_url, :bookmark_url, :bucket, :creator, :description, :description_attachments, :enabled, :inherits_status, :last_needle_color, :last_needle_position, :previous_needle_position, :status, :title, :type, :url, :visible_to_clients
1444
1463
 
1445
1464
  # @return [Array<Symbol>]
1446
1465
  def self.required_fields
@@ -1456,6 +1475,7 @@ module Basecamp
1456
1475
  @bucket = parse_type(data["bucket"], "RecordingBucket")
1457
1476
  @creator = parse_type(data["creator"], "Person")
1458
1477
  @description = data["description"]
1478
+ @description_attachments = parse_array(data["description_attachments"], "RichTextAttachment")
1459
1479
  @enabled = parse_boolean(data["enabled"])
1460
1480
  @inherits_status = parse_boolean(data["inherits_status"])
1461
1481
  @last_needle_color = data["last_needle_color"]
@@ -1478,6 +1498,7 @@ module Basecamp
1478
1498
  "bucket" => @bucket,
1479
1499
  "creator" => @creator,
1480
1500
  "description" => @description,
1501
+ "description_attachments" => @description_attachments,
1481
1502
  "enabled" => @enabled,
1482
1503
  "inherits_status" => @inherits_status,
1483
1504
  "last_needle_color" => @last_needle_color,
@@ -1499,15 +1520,16 @@ module Basecamp
1499
1520
  # GaugeNeedle
1500
1521
  class GaugeNeedle
1501
1522
  include TypeHelpers
1502
- attr_accessor :created_at, :id, :updated_at, :app_url, :bookmark_url, :boosts_count, :boosts_url, :bucket, :color, :comments_count, :comments_url, :creator, :description, :inherits_status, :parent, :position, :status, :subscription_url, :title, :type, :url, :visible_to_clients
1523
+ attr_accessor :created_at, :description_attachments, :id, :updated_at, :app_url, :bookmark_url, :boosts_count, :boosts_url, :bucket, :color, :comments_count, :comments_url, :creator, :description, :inherits_status, :parent, :position, :status, :subscription_url, :title, :type, :url, :visible_to_clients
1503
1524
 
1504
1525
  # @return [Array<Symbol>]
1505
1526
  def self.required_fields
1506
- %i[created_at id updated_at].freeze
1527
+ %i[created_at description_attachments id updated_at].freeze
1507
1528
  end
1508
1529
 
1509
1530
  def initialize(data = {})
1510
1531
  @created_at = parse_datetime(data["created_at"])
1532
+ @description_attachments = parse_array(data["description_attachments"], "RichTextAttachment")
1511
1533
  @id = parse_integer(data["id"])
1512
1534
  @updated_at = parse_datetime(data["updated_at"])
1513
1535
  @app_url = data["app_url"]
@@ -1534,6 +1556,7 @@ module Basecamp
1534
1556
  def to_h
1535
1557
  {
1536
1558
  "created_at" => @created_at,
1559
+ "description_attachments" => @description_attachments,
1537
1560
  "id" => @id,
1538
1561
  "updated_at" => @updated_at,
1539
1562
  "app_url" => @app_url,
@@ -1798,17 +1821,18 @@ module Basecamp
1798
1821
  # Message
1799
1822
  class Message
1800
1823
  include TypeHelpers
1801
- attr_accessor :app_url, :bucket, :content, :created_at, :creator, :id, :inherits_status, :parent, :status, :subject, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :boosts_count, :boosts_url, :category, :comments_count, :comments_url, :subscription_url
1824
+ attr_accessor :app_url, :bucket, :content, :content_attachments, :created_at, :creator, :id, :inherits_status, :parent, :status, :subject, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :boosts_count, :boosts_url, :category, :comments_count, :comments_url, :subscription_url
1802
1825
 
1803
1826
  # @return [Array<Symbol>]
1804
1827
  def self.required_fields
1805
- %i[app_url bucket content created_at creator id inherits_status parent status subject title type updated_at url visible_to_clients].freeze
1828
+ %i[app_url bucket content content_attachments created_at creator id inherits_status parent status subject title type updated_at url visible_to_clients].freeze
1806
1829
  end
1807
1830
 
1808
1831
  def initialize(data = {})
1809
1832
  @app_url = data["app_url"]
1810
1833
  @bucket = parse_type(data["bucket"], "TodoBucket")
1811
1834
  @content = data["content"]
1835
+ @content_attachments = parse_array(data["content_attachments"], "RichTextAttachment")
1812
1836
  @created_at = parse_datetime(data["created_at"])
1813
1837
  @creator = parse_type(data["creator"], "Person")
1814
1838
  @id = parse_integer(data["id"])
@@ -1835,6 +1859,7 @@ module Basecamp
1835
1859
  "app_url" => @app_url,
1836
1860
  "bucket" => @bucket,
1837
1861
  "content" => @content,
1862
+ "content_attachments" => @content_attachments,
1838
1863
  "created_at" => @created_at,
1839
1864
  "creator" => @creator,
1840
1865
  "id" => @id,
@@ -2093,7 +2118,7 @@ module Basecamp
2093
2118
  # Notification
2094
2119
  class Notification
2095
2120
  include TypeHelpers
2096
- attr_accessor :created_at, :id, :updated_at, :app_url, :bookmark_url, :bucket_name, :content_excerpt, :creator, :image_url, :memory_url, :named, :participants, :previewable_attachments, :read_at, :readable_identifier, :readable_sgid, :section, :subscribed, :subscription_url, :title, :type, :unread_at, :unread_count, :unread_url
2121
+ attr_accessor :created_at, :id, :updated_at, :app_url, :bookmark_url, :bubble_up_at, :bubble_up_url, :bucket_name, :content_excerpt, :creator, :image_url, :memory_url, :named, :participants, :previewable_attachments, :read_at, :readable_identifier, :readable_sgid, :section, :subscribed, :subscription_url, :title, :type, :unread_at, :unread_count, :unread_url
2097
2122
 
2098
2123
  # @return [Array<Symbol>]
2099
2124
  def self.required_fields
@@ -2106,6 +2131,8 @@ module Basecamp
2106
2131
  @updated_at = parse_datetime(data["updated_at"])
2107
2132
  @app_url = data["app_url"]
2108
2133
  @bookmark_url = data["bookmark_url"]
2134
+ @bubble_up_at = parse_datetime(data["bubble_up_at"])
2135
+ @bubble_up_url = data["bubble_up_url"]
2109
2136
  @bucket_name = data["bucket_name"]
2110
2137
  @content_excerpt = data["content_excerpt"]
2111
2138
  @creator = parse_type(data["creator"], "Person")
@@ -2134,6 +2161,8 @@ module Basecamp
2134
2161
  "updated_at" => @updated_at,
2135
2162
  "app_url" => @app_url,
2136
2163
  "bookmark_url" => @bookmark_url,
2164
+ "bubble_up_at" => @bubble_up_at,
2165
+ "bubble_up_url" => @bubble_up_url,
2137
2166
  "bucket_name" => @bucket_name,
2138
2167
  "content_excerpt" => @content_excerpt,
2139
2168
  "creator" => @creator,
@@ -2164,9 +2193,10 @@ module Basecamp
2164
2193
  # OutOfOffice
2165
2194
  class OutOfOffice
2166
2195
  include TypeHelpers
2167
- attr_accessor :enabled, :end_date, :ongoing, :person, :start_date
2196
+ attr_accessor :back_on_date, :enabled, :end_date, :ongoing, :person, :start_date
2168
2197
 
2169
2198
  def initialize(data = {})
2199
+ @back_on_date = data["back_on_date"]
2170
2200
  @enabled = parse_boolean(data["enabled"])
2171
2201
  @end_date = data["end_date"]
2172
2202
  @ongoing = parse_boolean(data["ongoing"])
@@ -2176,6 +2206,7 @@ module Basecamp
2176
2206
 
2177
2207
  def to_h
2178
2208
  {
2209
+ "back_on_date" => @back_on_date,
2179
2210
  "enabled" => @enabled,
2180
2211
  "end_date" => @end_date,
2181
2212
  "ongoing" => @ongoing,
@@ -2219,7 +2250,7 @@ module Basecamp
2219
2250
  # OutOfOfficePerson
2220
2251
  class OutOfOfficePerson
2221
2252
  include TypeHelpers
2222
- attr_accessor :id, :name
2253
+ attr_accessor :id, :avatar_url, :name
2223
2254
 
2224
2255
  # @return [Array<Symbol>]
2225
2256
  def self.required_fields
@@ -2228,12 +2259,14 @@ module Basecamp
2228
2259
 
2229
2260
  def initialize(data = {})
2230
2261
  @id = parse_integer(data["id"])
2262
+ @avatar_url = data["avatar_url"]
2231
2263
  @name = data["name"]
2232
2264
  end
2233
2265
 
2234
2266
  def to_h
2235
2267
  {
2236
2268
  "id" => @id,
2269
+ "avatar_url" => @avatar_url,
2237
2270
  "name" => @name,
2238
2271
  }.compact
2239
2272
  end
@@ -2246,7 +2279,7 @@ module Basecamp
2246
2279
  # Person
2247
2280
  class Person
2248
2281
  include TypeHelpers
2249
- attr_accessor :id, :name, :admin, :attachable_sgid, :avatar_url, :bio, :can_access_hill_charts, :can_access_timesheet, :can_manage_people, :can_manage_projects, :can_ping, :client, :company, :created_at, :email_address, :employee, :location, :owner, :personable_type, :time_zone, :title, :updated_at, :system_label
2282
+ attr_accessor :id, :name, :admin, :attachable_sgid, :avatar_url, :bio, :can_access_hill_charts, :can_access_timesheet, :can_manage_people, :can_manage_projects, :can_ping, :client, :company, :created_at, :email_address, :employee, :location, :owner, :personable_type, :tagline, :time_zone, :title, :updated_at, :system_label
2250
2283
 
2251
2284
  # @return [Array<Symbol>]
2252
2285
  def self.required_fields
@@ -2274,6 +2307,7 @@ module Basecamp
2274
2307
  @location = data["location"]
2275
2308
  @owner = parse_boolean(data["owner"])
2276
2309
  @personable_type = data["personable_type"]
2310
+ @tagline = data["tagline"]
2277
2311
  @time_zone = data["time_zone"]
2278
2312
  @title = data["title"]
2279
2313
  @updated_at = parse_datetime(data["updated_at"])
@@ -2300,6 +2334,7 @@ module Basecamp
2300
2334
  "location" => @location,
2301
2335
  "owner" => @owner,
2302
2336
  "personable_type" => @personable_type,
2337
+ "tagline" => @tagline,
2303
2338
  "time_zone" => @time_zone,
2304
2339
  "title" => @title,
2305
2340
  "updated_at" => @updated_at,
@@ -2427,7 +2462,9 @@ module Basecamp
2427
2462
  # Project
2428
2463
  class Project
2429
2464
  include TypeHelpers
2430
- attr_accessor :app_url, :created_at, :id, :name, :status, :updated_at, :url, :bookmark_url, :bookmarked, :client_company, :clients_enabled, :clientside, :description, :dock, :purpose
2465
+ # @!attribute [rw] clientside
2466
+ # @deprecated This shape is deprecated since 2024-01: Use Client Visibility feature instead
2467
+ attr_accessor :app_url, :created_at, :id, :name, :status, :updated_at, :url, :bookmark_url, :bookmarked, :client_company, :clients_enabled, :clientside, :description, :dock, :end_date, :purpose, :start_date
2431
2468
 
2432
2469
  # @return [Array<Symbol>]
2433
2470
  def self.required_fields
@@ -2449,7 +2486,9 @@ module Basecamp
2449
2486
  @clientside = parse_type(data["clientside"], "ClientSide")
2450
2487
  @description = data["description"]
2451
2488
  @dock = parse_array(data["dock"], "DockItem")
2489
+ @end_date = data["end_date"]
2452
2490
  @purpose = data["purpose"]
2491
+ @start_date = data["start_date"]
2453
2492
  end
2454
2493
 
2455
2494
  def to_h
@@ -2468,7 +2507,9 @@ module Basecamp
2468
2507
  "clientside" => @clientside,
2469
2508
  "description" => @description,
2470
2509
  "dock" => @dock,
2510
+ "end_date" => @end_date,
2471
2511
  "purpose" => @purpose,
2512
+ "start_date" => @start_date,
2472
2513
  }.compact
2473
2514
  end
2474
2515
 
@@ -2530,6 +2571,33 @@ module Basecamp
2530
2571
  end
2531
2572
  end
2532
2573
 
2574
+ # ProjectConstructionAttributes
2575
+ class ProjectConstructionAttributes
2576
+ include TypeHelpers
2577
+ attr_accessor :name, :description
2578
+
2579
+ # @return [Array<Symbol>]
2580
+ def self.required_fields
2581
+ %i[name].freeze
2582
+ end
2583
+
2584
+ def initialize(data = {})
2585
+ @name = data["name"]
2586
+ @description = data["description"]
2587
+ end
2588
+
2589
+ def to_h
2590
+ {
2591
+ "name" => @name,
2592
+ "description" => @description,
2593
+ }.compact
2594
+ end
2595
+
2596
+ def to_json(*args)
2597
+ to_h.to_json(*args)
2598
+ end
2599
+ end
2600
+
2533
2601
  # Question
2534
2602
  class Question
2535
2603
  include TypeHelpers
@@ -2594,17 +2662,18 @@ module Basecamp
2594
2662
  # QuestionAnswer
2595
2663
  class QuestionAnswer
2596
2664
  include TypeHelpers
2597
- attr_accessor :app_url, :bucket, :content, :created_at, :creator, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :boosts_count, :boosts_url, :comments_count, :comments_url, :group_on, :subscription_url
2665
+ attr_accessor :app_url, :bucket, :content, :content_attachments, :created_at, :creator, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :boosts_count, :boosts_url, :comments_count, :comments_url, :group_on, :subscription_url
2598
2666
 
2599
2667
  # @return [Array<Symbol>]
2600
2668
  def self.required_fields
2601
- %i[app_url bucket content created_at creator id inherits_status parent status title type updated_at url visible_to_clients].freeze
2669
+ %i[app_url bucket content content_attachments created_at creator id inherits_status parent status title type updated_at url visible_to_clients].freeze
2602
2670
  end
2603
2671
 
2604
2672
  def initialize(data = {})
2605
2673
  @app_url = data["app_url"]
2606
2674
  @bucket = parse_type(data["bucket"], "RecordingBucket")
2607
2675
  @content = data["content"]
2676
+ @content_attachments = parse_array(data["content_attachments"], "RichTextAttachment")
2608
2677
  @created_at = parse_datetime(data["created_at"])
2609
2678
  @creator = parse_type(data["creator"], "Person")
2610
2679
  @id = parse_integer(data["id"])
@@ -2630,6 +2699,7 @@ module Basecamp
2630
2699
  "app_url" => @app_url,
2631
2700
  "bucket" => @bucket,
2632
2701
  "content" => @content,
2702
+ "content_attachments" => @content_attachments,
2633
2703
  "created_at" => @created_at,
2634
2704
  "creator" => @creator,
2635
2705
  "id" => @id,
@@ -2830,7 +2900,7 @@ module Basecamp
2830
2900
  # Recording
2831
2901
  class Recording
2832
2902
  include TypeHelpers
2833
- attr_accessor :app_url, :bucket, :created_at, :creator, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :comments_count, :comments_url, :content, :subscription_url
2903
+ attr_accessor :app_url, :bucket, :created_at, :creator, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :comments_count, :comments_url, :content, :content_attachments, :description_attachments, :subscription_url
2834
2904
 
2835
2905
  # @return [Array<Symbol>]
2836
2906
  def self.required_fields
@@ -2855,6 +2925,8 @@ module Basecamp
2855
2925
  @comments_count = parse_integer(data["comments_count"])
2856
2926
  @comments_url = data["comments_url"]
2857
2927
  @content = data["content"]
2928
+ @content_attachments = parse_array(data["content_attachments"], "RichTextAttachment")
2929
+ @description_attachments = parse_array(data["description_attachments"], "RichTextAttachment")
2858
2930
  @subscription_url = data["subscription_url"]
2859
2931
  end
2860
2932
 
@@ -2877,6 +2949,8 @@ module Basecamp
2877
2949
  "comments_count" => @comments_count,
2878
2950
  "comments_url" => @comments_url,
2879
2951
  "content" => @content,
2952
+ "content_attachments" => @content_attachments,
2953
+ "description_attachments" => @description_attachments,
2880
2954
  "subscription_url" => @subscription_url,
2881
2955
  }.compact
2882
2956
  end
@@ -2948,6 +3022,51 @@ module Basecamp
2948
3022
  end
2949
3023
  end
2950
3024
 
3025
+ # RichTextAttachment
3026
+ class RichTextAttachment
3027
+ include TypeHelpers
3028
+ attr_accessor :byte_size, :content_type, :download_url, :filename, :id, :preview_url, :previewable, :sgid, :thumbnail_url, :height, :width
3029
+
3030
+ # @return [Array<Symbol>]
3031
+ def self.required_fields
3032
+ %i[byte_size content_type download_url filename id preview_url previewable sgid thumbnail_url].freeze
3033
+ end
3034
+
3035
+ def initialize(data = {})
3036
+ @byte_size = parse_integer(data["byte_size"])
3037
+ @content_type = data["content_type"]
3038
+ @download_url = data["download_url"]
3039
+ @filename = data["filename"]
3040
+ @id = parse_integer(data["id"])
3041
+ @preview_url = data["preview_url"]
3042
+ @previewable = parse_boolean(data["previewable"])
3043
+ @sgid = data["sgid"]
3044
+ @thumbnail_url = data["thumbnail_url"]
3045
+ @height = parse_integer(data["height"])
3046
+ @width = parse_integer(data["width"])
3047
+ end
3048
+
3049
+ def to_h
3050
+ {
3051
+ "byte_size" => @byte_size,
3052
+ "content_type" => @content_type,
3053
+ "download_url" => @download_url,
3054
+ "filename" => @filename,
3055
+ "id" => @id,
3056
+ "preview_url" => @preview_url,
3057
+ "previewable" => @previewable,
3058
+ "sgid" => @sgid,
3059
+ "thumbnail_url" => @thumbnail_url,
3060
+ "height" => @height,
3061
+ "width" => @width,
3062
+ }.compact
3063
+ end
3064
+
3065
+ def to_json(*args)
3066
+ to_h.to_json(*args)
3067
+ end
3068
+ end
3069
+
2951
3070
  # Schedule
2952
3071
  class Schedule
2953
3072
  include TypeHelpers
@@ -3030,11 +3149,11 @@ module Basecamp
3030
3149
  # ScheduleEntry
3031
3150
  class ScheduleEntry
3032
3151
  include TypeHelpers
3033
- attr_accessor :app_url, :bucket, :created_at, :creator, :id, :inherits_status, :parent, :status, :summary, :title, :type, :updated_at, :url, :visible_to_clients, :all_day, :bookmark_url, :boosts_count, :boosts_url, :comments_count, :comments_url, :description, :ends_at, :participants, :starts_at, :subscription_url
3152
+ attr_accessor :app_url, :bucket, :created_at, :creator, :description_attachments, :id, :inherits_status, :parent, :status, :summary, :title, :type, :updated_at, :url, :visible_to_clients, :all_day, :bookmark_url, :boosts_count, :boosts_url, :comments_count, :comments_url, :description, :ends_at, :participants, :starts_at, :subscription_url
3034
3153
 
3035
3154
  # @return [Array<Symbol>]
3036
3155
  def self.required_fields
3037
- %i[app_url bucket created_at creator id inherits_status parent status summary title type updated_at url visible_to_clients].freeze
3156
+ %i[app_url bucket created_at creator description_attachments id inherits_status parent status summary title type updated_at url visible_to_clients].freeze
3038
3157
  end
3039
3158
 
3040
3159
  def initialize(data = {})
@@ -3042,6 +3161,7 @@ module Basecamp
3042
3161
  @bucket = parse_type(data["bucket"], "TodoBucket")
3043
3162
  @created_at = parse_datetime(data["created_at"])
3044
3163
  @creator = parse_type(data["creator"], "Person")
3164
+ @description_attachments = parse_array(data["description_attachments"], "RichTextAttachment")
3045
3165
  @id = parse_integer(data["id"])
3046
3166
  @inherits_status = parse_boolean(data["inherits_status"])
3047
3167
  @parent = parse_type(data["parent"], "RecordingParent")
@@ -3071,6 +3191,7 @@ module Basecamp
3071
3191
  "bucket" => @bucket,
3072
3192
  "created_at" => @created_at,
3073
3193
  "creator" => @creator,
3194
+ "description_attachments" => @description_attachments,
3074
3195
  "id" => @id,
3075
3196
  "inherits_status" => @inherits_status,
3076
3197
  "parent" => @parent,
@@ -3103,37 +3224,32 @@ module Basecamp
3103
3224
  # SearchMetadata
3104
3225
  class SearchMetadata
3105
3226
  include TypeHelpers
3106
- attr_accessor :projects
3107
-
3108
- def initialize(data = {})
3109
- @projects = parse_array(data["projects"], "SearchProject")
3110
- end
3227
+ attr_accessor :default_bucket_label, :default_circle_label, :default_creator_label, :default_file_type_label, :default_type_label, :file_search_types, :recording_search_types
3111
3228
 
3112
- def to_h
3113
- {
3114
- "projects" => @projects,
3115
- }.compact
3116
- end
3117
-
3118
- def to_json(*args)
3119
- to_h.to_json(*args)
3229
+ # @return [Array<Symbol>]
3230
+ def self.required_fields
3231
+ %i[default_bucket_label default_circle_label default_creator_label default_file_type_label default_type_label file_search_types recording_search_types].freeze
3120
3232
  end
3121
- end
3122
-
3123
- # SearchProject
3124
- class SearchProject
3125
- include TypeHelpers
3126
- attr_accessor :id, :name
3127
3233
 
3128
3234
  def initialize(data = {})
3129
- @id = parse_integer(data["id"])
3130
- @name = data["name"]
3235
+ @default_bucket_label = data["default_bucket_label"]
3236
+ @default_circle_label = data["default_circle_label"]
3237
+ @default_creator_label = data["default_creator_label"]
3238
+ @default_file_type_label = data["default_file_type_label"]
3239
+ @default_type_label = data["default_type_label"]
3240
+ @file_search_types = parse_array(data["file_search_types"], "SearchType")
3241
+ @recording_search_types = parse_array(data["recording_search_types"], "SearchType")
3131
3242
  end
3132
3243
 
3133
3244
  def to_h
3134
3245
  {
3135
- "id" => @id,
3136
- "name" => @name,
3246
+ "default_bucket_label" => @default_bucket_label,
3247
+ "default_circle_label" => @default_circle_label,
3248
+ "default_creator_label" => @default_creator_label,
3249
+ "default_file_type_label" => @default_file_type_label,
3250
+ "default_type_label" => @default_type_label,
3251
+ "file_search_types" => @file_search_types,
3252
+ "recording_search_types" => @recording_search_types,
3137
3253
  }.compact
3138
3254
  end
3139
3255
 
@@ -3145,7 +3261,7 @@ module Basecamp
3145
3261
  # SearchResult
3146
3262
  class SearchResult
3147
3263
  include TypeHelpers
3148
- attr_accessor :app_url, :id, :title, :type, :url, :bookmark_url, :bucket, :content, :created_at, :creator, :description, :inherits_status, :parent, :status, :subject, :updated_at, :visible_to_clients
3264
+ attr_accessor :app_url, :id, :title, :type, :url, :bookmark_url, :bucket, :content, :content_attachments, :created_at, :creator, :description, :description_attachments, :inherits_status, :parent, :status, :subject, :updated_at, :visible_to_clients
3149
3265
 
3150
3266
  # @return [Array<Symbol>]
3151
3267
  def self.required_fields
@@ -3161,9 +3277,11 @@ module Basecamp
3161
3277
  @bookmark_url = data["bookmark_url"]
3162
3278
  @bucket = parse_type(data["bucket"], "RecordingBucket")
3163
3279
  @content = data["content"]
3280
+ @content_attachments = parse_array(data["content_attachments"], "RichTextAttachment")
3164
3281
  @created_at = parse_datetime(data["created_at"])
3165
3282
  @creator = parse_type(data["creator"], "Person")
3166
3283
  @description = data["description"]
3284
+ @description_attachments = parse_array(data["description_attachments"], "RichTextAttachment")
3167
3285
  @inherits_status = parse_boolean(data["inherits_status"])
3168
3286
  @parent = parse_type(data["parent"], "RecordingParent")
3169
3287
  @status = data["status"]
@@ -3182,9 +3300,11 @@ module Basecamp
3182
3300
  "bookmark_url" => @bookmark_url,
3183
3301
  "bucket" => @bucket,
3184
3302
  "content" => @content,
3303
+ "content_attachments" => @content_attachments,
3185
3304
  "created_at" => @created_at,
3186
3305
  "creator" => @creator,
3187
3306
  "description" => @description,
3307
+ "description_attachments" => @description_attachments,
3188
3308
  "inherits_status" => @inherits_status,
3189
3309
  "parent" => @parent,
3190
3310
  "status" => @status,
@@ -3199,6 +3319,33 @@ module Basecamp
3199
3319
  end
3200
3320
  end
3201
3321
 
3322
+ # SearchType
3323
+ class SearchType
3324
+ include TypeHelpers
3325
+ attr_accessor :key, :value
3326
+
3327
+ # @return [Array<Symbol>]
3328
+ def self.required_fields
3329
+ %i[key value].freeze
3330
+ end
3331
+
3332
+ def initialize(data = {})
3333
+ @key = data["key"]
3334
+ @value = data["value"]
3335
+ end
3336
+
3337
+ def to_h
3338
+ {
3339
+ "key" => @key,
3340
+ "value" => @value,
3341
+ }.reject { |k, v| v.nil? && !["key"].include?(k) }
3342
+ end
3343
+
3344
+ def to_json(*args)
3345
+ to_h.to_json(*args)
3346
+ end
3347
+ end
3348
+
3202
3349
  # Subscription
3203
3350
  class Subscription
3204
3351
  include TypeHelpers
@@ -3375,11 +3522,11 @@ module Basecamp
3375
3522
  # Todo
3376
3523
  class Todo
3377
3524
  include TypeHelpers
3378
- attr_accessor :app_url, :bucket, :content, :created_at, :creator, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :assignees, :bookmark_url, :boosts_count, :boosts_url, :comments_count, :comments_url, :completed, :completion_subscribers, :completion_url, :description, :due_on, :position, :starts_on, :subscription_url
3525
+ attr_accessor :app_url, :bucket, :content, :created_at, :creator, :description_attachments, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :assignees, :bookmark_url, :boosts_count, :boosts_url, :comments_count, :comments_url, :completed, :completion_subscribers, :completion_url, :description, :due_on, :position, :starts_on, :steps, :subscription_url
3379
3526
 
3380
3527
  # @return [Array<Symbol>]
3381
3528
  def self.required_fields
3382
- %i[app_url bucket content created_at creator id inherits_status parent status title type updated_at url visible_to_clients].freeze
3529
+ %i[app_url bucket content created_at creator description_attachments id inherits_status parent status title type updated_at url visible_to_clients].freeze
3383
3530
  end
3384
3531
 
3385
3532
  def initialize(data = {})
@@ -3388,6 +3535,7 @@ module Basecamp
3388
3535
  @content = data["content"]
3389
3536
  @created_at = parse_datetime(data["created_at"])
3390
3537
  @creator = parse_type(data["creator"], "Person")
3538
+ @description_attachments = parse_array(data["description_attachments"], "RichTextAttachment")
3391
3539
  @id = parse_integer(data["id"])
3392
3540
  @inherits_status = parse_boolean(data["inherits_status"])
3393
3541
  @parent = parse_type(data["parent"], "TodoParent")
@@ -3410,6 +3558,7 @@ module Basecamp
3410
3558
  @due_on = data["due_on"]
3411
3559
  @position = parse_integer(data["position"])
3412
3560
  @starts_on = data["starts_on"]
3561
+ @steps = parse_array(data["steps"], "CardStep")
3413
3562
  @subscription_url = data["subscription_url"]
3414
3563
  end
3415
3564
 
@@ -3420,6 +3569,7 @@ module Basecamp
3420
3569
  "content" => @content,
3421
3570
  "created_at" => @created_at,
3422
3571
  "creator" => @creator,
3572
+ "description_attachments" => @description_attachments,
3423
3573
  "id" => @id,
3424
3574
  "inherits_status" => @inherits_status,
3425
3575
  "parent" => @parent,
@@ -3442,6 +3592,7 @@ module Basecamp
3442
3592
  "due_on" => @due_on,
3443
3593
  "position" => @position,
3444
3594
  "starts_on" => @starts_on,
3595
+ "steps" => @steps,
3445
3596
  "subscription_url" => @subscription_url,
3446
3597
  }.compact
3447
3598
  end
@@ -3516,11 +3667,11 @@ module Basecamp
3516
3667
  # Todolist
3517
3668
  class Todolist
3518
3669
  include TypeHelpers
3519
- attr_accessor :app_url, :bucket, :created_at, :creator, :id, :inherits_status, :name, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :app_todos_url, :bookmark_url, :boosts_count, :boosts_url, :comments_count, :comments_url, :completed, :completed_ratio, :description, :groups_url, :position, :subscription_url, :todos_url
3670
+ attr_accessor :app_url, :bucket, :created_at, :creator, :description_attachments, :id, :inherits_status, :name, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :app_todos_url, :bookmark_url, :boosts_count, :boosts_url, :comments_count, :comments_url, :completed, :completed_ratio, :description, :groups_url, :position, :subscription_url, :todos_url
3520
3671
 
3521
3672
  # @return [Array<Symbol>]
3522
3673
  def self.required_fields
3523
- %i[app_url bucket created_at creator id inherits_status name parent status title type updated_at url visible_to_clients].freeze
3674
+ %i[app_url bucket created_at creator description_attachments id inherits_status name parent status title type updated_at url visible_to_clients].freeze
3524
3675
  end
3525
3676
 
3526
3677
  def initialize(data = {})
@@ -3528,6 +3679,7 @@ module Basecamp
3528
3679
  @bucket = parse_type(data["bucket"], "TodoBucket")
3529
3680
  @created_at = parse_datetime(data["created_at"])
3530
3681
  @creator = parse_type(data["creator"], "Person")
3682
+ @description_attachments = parse_array(data["description_attachments"], "RichTextAttachment")
3531
3683
  @id = parse_integer(data["id"])
3532
3684
  @inherits_status = parse_boolean(data["inherits_status"])
3533
3685
  @name = data["name"]
@@ -3559,6 +3711,7 @@ module Basecamp
3559
3711
  "bucket" => @bucket,
3560
3712
  "created_at" => @created_at,
3561
3713
  "creator" => @creator,
3714
+ "description_attachments" => @description_attachments,
3562
3715
  "id" => @id,
3563
3716
  "inherits_status" => @inherits_status,
3564
3717
  "name" => @name,
@@ -3662,7 +3815,7 @@ module Basecamp
3662
3815
  # Todoset
3663
3816
  class Todoset
3664
3817
  include TypeHelpers
3665
- attr_accessor :app_url, :bucket, :created_at, :creator, :id, :inherits_status, :name, :status, :title, :type, :updated_at, :url, :visible_to_clients, :app_todolists_url, :bookmark_url, :completed, :completed_ratio, :position, :todolists_count, :todolists_url
3818
+ attr_accessor :app_url, :bucket, :created_at, :creator, :id, :inherits_status, :name, :status, :title, :type, :updated_at, :url, :visible_to_clients, :app_todolists_url, :app_todos_url, :bookmark_url, :completed, :completed_loose_todos_count, :completed_ratio, :position, :todolists_count, :todolists_url, :todos_count, :todos_url
3666
3819
 
3667
3820
  # @return [Array<Symbol>]
3668
3821
  def self.required_fields
@@ -3684,12 +3837,16 @@ module Basecamp
3684
3837
  @url = data["url"]
3685
3838
  @visible_to_clients = parse_boolean(data["visible_to_clients"])
3686
3839
  @app_todolists_url = data["app_todolists_url"]
3840
+ @app_todos_url = data["app_todos_url"]
3687
3841
  @bookmark_url = data["bookmark_url"]
3688
3842
  @completed = parse_boolean(data["completed"])
3843
+ @completed_loose_todos_count = parse_integer(data["completed_loose_todos_count"])
3689
3844
  @completed_ratio = data["completed_ratio"]
3690
3845
  @position = parse_integer(data["position"])
3691
3846
  @todolists_count = parse_integer(data["todolists_count"])
3692
3847
  @todolists_url = data["todolists_url"]
3848
+ @todos_count = parse_integer(data["todos_count"])
3849
+ @todos_url = data["todos_url"]
3693
3850
  end
3694
3851
 
3695
3852
  def to_h
@@ -3708,12 +3865,16 @@ module Basecamp
3708
3865
  "url" => @url,
3709
3866
  "visible_to_clients" => @visible_to_clients,
3710
3867
  "app_todolists_url" => @app_todolists_url,
3868
+ "app_todos_url" => @app_todos_url,
3711
3869
  "bookmark_url" => @bookmark_url,
3712
3870
  "completed" => @completed,
3871
+ "completed_loose_todos_count" => @completed_loose_todos_count,
3713
3872
  "completed_ratio" => @completed_ratio,
3714
3873
  "position" => @position,
3715
3874
  "todolists_count" => @todolists_count,
3716
3875
  "todolists_url" => @todolists_url,
3876
+ "todos_count" => @todos_count,
3877
+ "todos_url" => @todos_url,
3717
3878
  }.compact
3718
3879
  end
3719
3880
 
@@ -3770,11 +3931,11 @@ module Basecamp
3770
3931
  # Upload
3771
3932
  class Upload
3772
3933
  include TypeHelpers
3773
- attr_accessor :app_url, :bucket, :created_at, :creator, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :boosts_count, :boosts_url, :byte_size, :comments_count, :comments_url, :content_type, :description, :download_url, :filename, :height, :position, :subscription_url, :width
3934
+ attr_accessor :app_url, :bucket, :created_at, :creator, :description_attachments, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :boosts_count, :boosts_url, :byte_size, :comments_count, :comments_url, :content_type, :description, :download_url, :filename, :height, :position, :subscription_url, :width
3774
3935
 
3775
3936
  # @return [Array<Symbol>]
3776
3937
  def self.required_fields
3777
- %i[app_url bucket created_at creator id inherits_status parent status title type updated_at url visible_to_clients].freeze
3938
+ %i[app_url bucket created_at creator description_attachments id inherits_status parent status title type updated_at url visible_to_clients].freeze
3778
3939
  end
3779
3940
 
3780
3941
  def initialize(data = {})
@@ -3782,6 +3943,7 @@ module Basecamp
3782
3943
  @bucket = parse_type(data["bucket"], "TodoBucket")
3783
3944
  @created_at = parse_datetime(data["created_at"])
3784
3945
  @creator = parse_type(data["creator"], "Person")
3946
+ @description_attachments = parse_array(data["description_attachments"], "RichTextAttachment")
3785
3947
  @id = parse_integer(data["id"])
3786
3948
  @inherits_status = parse_boolean(data["inherits_status"])
3787
3949
  @parent = parse_type(data["parent"], "RecordingParent")
@@ -3813,6 +3975,7 @@ module Basecamp
3813
3975
  "bucket" => @bucket,
3814
3976
  "created_at" => @created_at,
3815
3977
  "creator" => @creator,
3978
+ "description_attachments" => @description_attachments,
3816
3979
  "id" => @id,
3817
3980
  "inherits_status" => @inherits_status,
3818
3981
  "parent" => @parent,
@@ -4099,5 +4262,62 @@ module Basecamp
4099
4262
  to_h.to_json(*args)
4100
4263
  end
4101
4264
  end
4265
+
4266
+ # Wormhole
4267
+ class Wormhole
4268
+ include TypeHelpers
4269
+ attr_accessor :app_url, :bucket, :color, :created_at, :creator, :destination_url, :id, :inherits_status, :linked, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url
4270
+
4271
+ # @return [Array<Symbol>]
4272
+ def self.required_fields
4273
+ %i[app_url bucket color created_at creator destination_url id inherits_status linked parent status title type updated_at url visible_to_clients].freeze
4274
+ end
4275
+
4276
+ def initialize(data = {})
4277
+ @app_url = data["app_url"]
4278
+ @bucket = parse_type(data["bucket"], "TodoBucket")
4279
+ @color = data["color"]
4280
+ @created_at = parse_datetime(data["created_at"])
4281
+ @creator = parse_type(data["creator"], "Person")
4282
+ @destination_url = data["destination_url"]
4283
+ @id = parse_integer(data["id"])
4284
+ @inherits_status = parse_boolean(data["inherits_status"])
4285
+ @linked = parse_boolean(data["linked"])
4286
+ @parent = parse_type(data["parent"], "RecordingParent")
4287
+ @status = data["status"]
4288
+ @title = data["title"]
4289
+ @type = data["type"]
4290
+ @updated_at = parse_datetime(data["updated_at"])
4291
+ @url = data["url"]
4292
+ @visible_to_clients = parse_boolean(data["visible_to_clients"])
4293
+ @bookmark_url = data["bookmark_url"]
4294
+ end
4295
+
4296
+ def to_h
4297
+ {
4298
+ "app_url" => @app_url,
4299
+ "bucket" => @bucket,
4300
+ "color" => @color,
4301
+ "created_at" => @created_at,
4302
+ "creator" => @creator,
4303
+ "destination_url" => @destination_url,
4304
+ "id" => @id,
4305
+ "inherits_status" => @inherits_status,
4306
+ "linked" => @linked,
4307
+ "parent" => @parent,
4308
+ "status" => @status,
4309
+ "title" => @title,
4310
+ "type" => @type,
4311
+ "updated_at" => @updated_at,
4312
+ "url" => @url,
4313
+ "visible_to_clients" => @visible_to_clients,
4314
+ "bookmark_url" => @bookmark_url,
4315
+ }.reject { |k, v| v.nil? && !["color", "destination_url"].include?(k) }
4316
+ end
4317
+
4318
+ def to_json(*args)
4319
+ to_h.to_json(*args)
4320
+ end
4321
+ end
4102
4322
  end
4103
4323
  end