lobbying_disclosure_client 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +50 -0
  3. data/.ruby-version +1 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +78 -0
  6. data/Rakefile +17 -0
  7. data/lefthook.yml +9 -0
  8. data/lib/lobbying_disclosure_client/auth/login.rb +33 -0
  9. data/lib/lobbying_disclosure_client/auth/password/reset/confirm.rb +39 -0
  10. data/lib/lobbying_disclosure_client/auth/password/reset.rb +34 -0
  11. data/lib/lobbying_disclosure_client/auth/password.rb +9 -0
  12. data/lib/lobbying_disclosure_client/auth.rb +7 -0
  13. data/lib/lobbying_disclosure_client/client.rb +108 -0
  14. data/lib/lobbying_disclosure_client/enums/contribution_type.rb +16 -0
  15. data/lib/lobbying_disclosure_client/enums/country.rb +269 -0
  16. data/lib/lobbying_disclosure_client/enums/expenses_method.rb +14 -0
  17. data/lib/lobbying_disclosure_client/enums/filer_type.rb +13 -0
  18. data/lib/lobbying_disclosure_client/enums/filing_period.rb +17 -0
  19. data/lib/lobbying_disclosure_client/enums/filing_type.rb +61 -0
  20. data/lib/lobbying_disclosure_client/enums/general_issue_code.rb +90 -0
  21. data/lib/lobbying_disclosure_client/enums/prefix.rb +18 -0
  22. data/lib/lobbying_disclosure_client/enums/route.rb +103 -0
  23. data/lib/lobbying_disclosure_client/enums/state.rb +71 -0
  24. data/lib/lobbying_disclosure_client/enums/suffix.rb +34 -0
  25. data/lib/lobbying_disclosure_client/enums.rb +7 -0
  26. data/lib/lobbying_disclosure_client/errors/bad_request_error.rb +8 -0
  27. data/lib/lobbying_disclosure_client/errors/invalid_api_key_error.rb +8 -0
  28. data/lib/lobbying_disclosure_client/errors/not_found_error.rb +8 -0
  29. data/lib/lobbying_disclosure_client/errors/request_throttled_error.rb +26 -0
  30. data/lib/lobbying_disclosure_client/errors/unknown_error.rb +8 -0
  31. data/lib/lobbying_disclosure_client/errors/unsupported_http_method_error.rb +8 -0
  32. data/lib/lobbying_disclosure_client/errors.rb +7 -0
  33. data/lib/lobbying_disclosure_client/types/affiliated_organization.rb +26 -0
  34. data/lib/lobbying_disclosure_client/types/client.rb +42 -0
  35. data/lib/lobbying_disclosure_client/types/client_with_registrant.rb +43 -0
  36. data/lib/lobbying_disclosure_client/types/constant.rb +11 -0
  37. data/lib/lobbying_disclosure_client/types/contribution_item.rb +34 -0
  38. data/lib/lobbying_disclosure_client/types/contribution_report.rb +53 -0
  39. data/lib/lobbying_disclosure_client/types/conviction_disclosure.rb +29 -0
  40. data/lib/lobbying_disclosure_client/types/filing.rb +59 -0
  41. data/lib/lobbying_disclosure_client/types/foreign_entity.rb +41 -0
  42. data/lib/lobbying_disclosure_client/types/government_entity.rb +11 -0
  43. data/lib/lobbying_disclosure_client/types/lobbying_activity.rb +15 -0
  44. data/lib/lobbying_disclosure_client/types/lobbyist.rb +18 -0
  45. data/lib/lobbying_disclosure_client/types/lobbyist_for_lobbying_activity.rb +12 -0
  46. data/lib/lobbying_disclosure_client/types/lobbyist_with_registrant.rb +19 -0
  47. data/lib/lobbying_disclosure_client/types/registrant.rb +46 -0
  48. data/lib/lobbying_disclosure_client/types.rb +7 -0
  49. data/lib/lobbying_disclosure_client/util/constants_validator.rb +122 -0
  50. data/lib/lobbying_disclosure_client/util.rb +7 -0
  51. data/lib/lobbying_disclosure_client/v1/clients/list_clients.rb +49 -0
  52. data/lib/lobbying_disclosure_client/v1/clients/retrieve_client.rb +36 -0
  53. data/lib/lobbying_disclosure_client/v1/clients.rb +9 -0
  54. data/lib/lobbying_disclosure_client/v1/constants/contribution/list_contribution_item_types.rb +26 -0
  55. data/lib/lobbying_disclosure_client/v1/constants/contribution.rb +11 -0
  56. data/lib/lobbying_disclosure_client/v1/constants/filing/list_filing_types.rb +26 -0
  57. data/lib/lobbying_disclosure_client/v1/constants/filing/list_government_entities.rb +26 -0
  58. data/lib/lobbying_disclosure_client/v1/constants/filing/list_lobbying_activity_general_issues.rb +26 -0
  59. data/lib/lobbying_disclosure_client/v1/constants/filing.rb +11 -0
  60. data/lib/lobbying_disclosure_client/v1/constants/general/list_countries.rb +26 -0
  61. data/lib/lobbying_disclosure_client/v1/constants/general/list_states.rb +26 -0
  62. data/lib/lobbying_disclosure_client/v1/constants/general.rb +11 -0
  63. data/lib/lobbying_disclosure_client/v1/constants/lobbyist/list_lobbyist_prefixes.rb +26 -0
  64. data/lib/lobbying_disclosure_client/v1/constants/lobbyist/list_lobbyist_suffixes.rb +26 -0
  65. data/lib/lobbying_disclosure_client/v1/constants/lobbyist.rb +11 -0
  66. data/lib/lobbying_disclosure_client/v1/constants.rb +9 -0
  67. data/lib/lobbying_disclosure_client/v1/contribution_reports/list_contribution_reports.rb +60 -0
  68. data/lib/lobbying_disclosure_client/v1/contribution_reports/retrieve_contribution_report.rb +36 -0
  69. data/lib/lobbying_disclosure_client/v1/contribution_reports.rb +9 -0
  70. data/lib/lobbying_disclosure_client/v1/filings/list_filings.rb +77 -0
  71. data/lib/lobbying_disclosure_client/v1/filings/retrieve_filing.rb +36 -0
  72. data/lib/lobbying_disclosure_client/v1/filings.rb +9 -0
  73. data/lib/lobbying_disclosure_client/v1/lobbyists/list_lobbyists.rb +45 -0
  74. data/lib/lobbying_disclosure_client/v1/lobbyists/retrieve_lobbyist.rb +36 -0
  75. data/lib/lobbying_disclosure_client/v1/lobbyists.rb +9 -0
  76. data/lib/lobbying_disclosure_client/v1/registrants/list_registrants.rb +48 -0
  77. data/lib/lobbying_disclosure_client/v1/registrants/retrieve_registrant.rb +36 -0
  78. data/lib/lobbying_disclosure_client/v1/registrants.rb +9 -0
  79. data/lib/lobbying_disclosure_client/v1.rb +16 -0
  80. data/lib/lobbying_disclosure_client/version.rb +6 -0
  81. data/lib/lobbying_disclosure_client.rb +105 -0
  82. data/sorbet/config +4 -0
  83. data/sorbet/rbi/gems/.gitattributes +1 -0
  84. data/sorbet/rbi/gems/erubi@1.13.0.rbi +150 -0
  85. data/sorbet/rbi/gems/minitest-stub-const@0.6.rbi +72 -0
  86. data/sorbet/rbi/gems/minitest@5.20.0.rbi +1498 -0
  87. data/sorbet/rbi/gems/netrc@0.11.0.rbi +159 -0
  88. data/sorbet/rbi/gems/parallel@1.26.2.rbi +291 -0
  89. data/sorbet/rbi/gems/prism@0.30.0.rbi +37863 -0
  90. data/sorbet/rbi/gems/rake@13.1.0.rbi +3220 -0
  91. data/sorbet/rbi/gems/rbi@0.1.14.rbi +3305 -0
  92. data/sorbet/rbi/gems/spoom@1.4.2.rbi +4932 -0
  93. data/sorbet/rbi/gems/tapioca@0.16.0.rbi +3543 -0
  94. data/sorbet/rbi/gems/thor@1.3.1.rbi +4319 -0
  95. data/sorbet/rbi/gems/vcr@6.3.1.rbi +3040 -0
  96. data/sorbet/rbi/gems/yard-sorbet@0.9.0.rbi +435 -0
  97. data/sorbet/rbi/gems/yard@0.9.36.rbi +18086 -0
  98. data/sorbet/rbi/shims/faraday.rbi +10 -0
  99. data/sorbet/tapioca/config.yml +13 -0
  100. data/sorbet/tapioca/require.rb +5 -0
  101. metadata +185 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 443db2822b042a2ca0d0d0e1ee2f0a4013f8e707fca59befc559e149572d8205
4
+ data.tar.gz: '028781104589d3694a4b22fe6dd612e99e9ae8b50aede4e1a3c7389ae97b4681'
5
+ SHA512:
6
+ metadata.gz: 4073fd1e091d6ffb15308a10fcfcb69c23b92f8b7f882d09aa49ab9932cf129e9b067a50393fca5ffe8a2b3e888a7fc89242b05102f1d1ab7ba1103e0b122bb8
7
+ data.tar.gz: 8d2e685e8e48fd1e9e7fe7fc0d7a4763adbad7546d00c48a30140d9c254ced283bc09c2652a390ae6d75d615369476e630378d87aca141b047d2777c28397096
data/.rubocop.yml ADDED
@@ -0,0 +1,50 @@
1
+ require:
2
+ - rubocop-minitest
3
+ - rubocop-rake
4
+ - rubocop-sorbet
5
+
6
+ AllCops:
7
+ NewCops: enable
8
+
9
+ Style/Documentation:
10
+ Enabled: false
11
+
12
+ Style/MultilineBlockChain:
13
+ Enabled: false
14
+
15
+ Metrics/MethodLength:
16
+ Enabled: false
17
+
18
+ Metrics/ClassLength:
19
+ Enabled: false
20
+
21
+ Metrics/BlockLength:
22
+ Enabled: false
23
+
24
+ Naming/VariableNumber:
25
+ Enabled: false
26
+
27
+ RuboCopStyle/OptionalBooleanParameter:
28
+ Enabled: false
29
+
30
+ Metrics/CyclomaticComplexity:
31
+ Enabled: false
32
+
33
+ Metrics/AbcSize:
34
+ Enabled: false
35
+
36
+ Metrics/PerceivedComplexity:
37
+ Enabled: false
38
+
39
+ Layout/LineLength:
40
+ Enabled: false
41
+
42
+ Sorbet/StrictSigil:
43
+ Enabled: true
44
+ Exclude:
45
+ - 'test/**/*'
46
+
47
+ Sorbet/FalseSigil:
48
+ Enabled: true
49
+ Include:
50
+ - 'test/**/*'
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.3.4
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Daniel Lee
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,78 @@
1
+ # Lobbying Disclosure Client
2
+
3
+ This gem acts as a client for the Lobbying Disclosure Client REST API. See [the full API documentation](https://lda.senate.gov/api/redoc/v1/) for more detail.
4
+
5
+ ## Installation
6
+
7
+ Add to your Gemfile:
8
+
9
+ ```
10
+ gem 'lobbying_disclosure_client'
11
+ ```
12
+
13
+ ```
14
+ bundle install
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ### Using an API key
20
+
21
+ The API _does_ allow for "anonymous" requests (i.e. without an API key), but the rate limit is pretty unforgiving. It's very easy to [register for one](https://lda.senate.gov/api/register/). You can configure the gem to use your key as such:
22
+
23
+ ```ruby
24
+ LobbyingDisclosureClient.api_key = ENV['YOUR_API_KEY']
25
+ ```
26
+
27
+ ### Supported endpoints
28
+
29
+ The gem supports all V1 endpoints, which can be called as such:
30
+
31
+ ```ruby
32
+ LobbyingDisclosureClient::V1::Clients::ListClients.call(...)
33
+ LobbyingDisclosureClient::V1::Clients::RetrieveClient.call(...)
34
+
35
+ LobbyingDisclosureClient::V1::ContributionReports::ListContributionReports.call(...)
36
+ LobbyingDisclosureClient::V1::ContributionReports::RetrieveContributionReport.call(...)
37
+
38
+ LobbyingDisclosureClient::V1::Filings::ListFilings.call(...)
39
+ LobbyingDisclosureClient::V1::Filings::RetrieveFiling.call(...)
40
+
41
+ LobbyingDisclosureClient::V1::Lobbyists::ListLobbyists.call(...)
42
+ LobbyingDisclosureClient::V1::Lobbyists::RetrieveLobbyist.call(...)
43
+
44
+ LobbyingDisclosureClient::V1::Registrants::ListRegistrants.call(...)
45
+ LobbyingDisclosureClient::V1::Registrants::RetrieveRegistrant.call(...)
46
+
47
+ # Lists all endpoints
48
+ LobbyingDisclosureClient::V1.call
49
+ ```
50
+
51
+ Endpoints namespaced under `/v1/constants` return valid values for various enums. The Ruby representations of these enums are automatically validated against the live API as part of the CI pipeline.
52
+
53
+ ```ruby
54
+ LobbyingDisclosureClient::V1::Constants::Contribution::ListContributionItemTypes.call
55
+
56
+ LobbyingDisclosureClient::V1::Constants::Filing::ListFilingTypes.call
57
+ LobbyingDisclosureClient::V1::Constants::Filing::ListGovernmentEntities.call
58
+ LobbyingDisclosureClient::V1::Constants::Filing::ListLobbyingActivityGeneralIssues.call
59
+
60
+ LobbyingDisclosureClient::V1::Constants::General::ListCountries.call
61
+ LobbyingDisclosureClient::V1::Constants::General::ListStates.call
62
+
63
+ LobbyingDisclosureClient::V1::Constants::Lobbyist::ListLobbyistPrefixes.call
64
+ LobbyingDisclosureClient::V1::Constants::Lobbyist::ListLobbyistSuffixes.call
65
+ ```
66
+
67
+ There are also a few endpoints related to auth/login.
68
+
69
+ ```ruby
70
+ # Given username/password, returns an API key
71
+ LobbyingDisclosureClient::Auth::Login.call(...)
72
+
73
+ # Sends a password reset email
74
+ LobbyingDisclosureClient::Auth::Password::Reset.call(...)
75
+
76
+ # Sets a new password, given a UID from the password reset email
77
+ LobbyingDisclosureClient::Auth::Password::Reset::Confirm.call(...)
78
+ ```
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rake/testtask'
4
+ require 'lobbying_disclosure_client'
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.libs << 'test'
8
+ t.test_files = FileList['test/**/*_test.rb']
9
+ end
10
+
11
+ task default: :test
12
+
13
+ desc 'Validate enums against values from the API'
14
+ task :validate_constants do
15
+ require_relative 'lib/lobbying_disclosure_client/util/constants_validator'
16
+ LobbyingDisclosureClient::Util::ConstantsValidator.validate!
17
+ end
data/lefthook.yml ADDED
@@ -0,0 +1,9 @@
1
+ pre-commit:
2
+ parallel: true
3
+ commands:
4
+ Rubocop:
5
+ glob: "{*.rb,*.rake,Rakefile}"
6
+ run: bundle exec rubocop --color --force-exclusion --format simple
7
+ Sorbet:
8
+ glob: "{*.rb,*.rake,Rakefile}"
9
+ run: bundle exec srb tc
@@ -0,0 +1,33 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module LobbyingDisclosureClient
5
+ module Auth
6
+ class Login
7
+ extend T::Sig
8
+
9
+ class Input < T::Struct
10
+ const :username, String
11
+ const :password, String
12
+ end
13
+
14
+ class Output < T::Struct
15
+ const :key, String
16
+ end
17
+
18
+ sig do
19
+ params(
20
+ input: Input
21
+ ).returns(Output)
22
+ end
23
+ def self.call(input:)
24
+ client = Client.new
25
+ response = client.post(LobbyingDisclosureClient::Enums::Route::Auth_Login, input.serialize)
26
+
27
+ Output.new(
28
+ key: T.must(response['key'])
29
+ )
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,39 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module LobbyingDisclosureClient
5
+ module Auth
6
+ module Password
7
+ class Reset
8
+ class Confirm
9
+ extend T::Sig
10
+
11
+ class Input < T::Struct
12
+ const :new_password1, String
13
+ const :new_password2, String
14
+ const :uid, String
15
+ const :token, String
16
+ end
17
+
18
+ class Output < T::Struct
19
+ const :detail, String
20
+ end
21
+
22
+ sig do
23
+ params(
24
+ input: Input
25
+ ).returns(Output)
26
+ end
27
+ def self.call(input:)
28
+ client = Client.new
29
+ response = client.post(LobbyingDisclosureClient::Enums::Route::Auth_Password_Reset_Confirm, input.serialize)
30
+
31
+ Output.new(
32
+ detail: T.must(response['detail'])
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,34 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module LobbyingDisclosureClient
5
+ module Auth
6
+ module Password
7
+ class Reset
8
+ extend T::Sig
9
+
10
+ class Input < T::Struct
11
+ const :email, String
12
+ end
13
+
14
+ class Output < T::Struct
15
+ const :detail, String
16
+ end
17
+
18
+ sig do
19
+ params(
20
+ input: Input
21
+ ).returns(Output)
22
+ end
23
+ def self.call(input:)
24
+ client = Client.new
25
+ response = client.post(LobbyingDisclosureClient::Enums::Route::Auth_Password_Reset, input.serialize)
26
+
27
+ Output.new(
28
+ detail: T.must(response['detail'])
29
+ )
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,9 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module LobbyingDisclosureClient
5
+ module Auth
6
+ module Password
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module LobbyingDisclosureClient
5
+ module Auth
6
+ end
7
+ end
@@ -0,0 +1,108 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require 'faraday'
5
+
6
+ module LobbyingDisclosureClient
7
+ class Client
8
+ extend T::Sig
9
+
10
+ sig do
11
+ params(
12
+ route: LobbyingDisclosureClient::Enums::Route,
13
+ path_params: T::Array[T.any(String, Integer)],
14
+ query_params: T::Hash[String, T.untyped]
15
+ ).returns(
16
+ T.untyped
17
+ )
18
+ end
19
+ def get(route, path_params: [], query_params: {})
20
+ handle_response(
21
+ connection.get(
22
+ route.to_full_api_path(path_params:),
23
+ query_params
24
+ )
25
+ )
26
+ end
27
+
28
+ sig do
29
+ params(
30
+ route: LobbyingDisclosureClient::Enums::Route,
31
+ body: T::Hash[String, String]
32
+ ).returns(
33
+ T::Hash[String, String]
34
+ )
35
+ end
36
+ def post(route, body = {})
37
+ handle_response(
38
+ connection.post(
39
+ route.to_full_api_path,
40
+ body.to_json
41
+ )
42
+ )
43
+ end
44
+
45
+ private
46
+
47
+ sig do
48
+ returns(Faraday::Connection)
49
+ end
50
+ def connection
51
+ Faraday.new(
52
+ headers: build_headers
53
+ ) do |conn|
54
+ conn.adapter :net_http
55
+ end
56
+ end
57
+
58
+ sig do
59
+ returns(T::Hash[String, String])
60
+ end
61
+ def build_headers
62
+ headers = { 'Content-Type' => 'application/json' }
63
+
64
+ # The Lobbying Disclosure API does allow unauthenticated ("anonymous") requests,
65
+ # though they are aggressively rate-limited.
66
+
67
+ headers['Authorization'] = "Token #{LobbyingDisclosureClient.api_key}" if LobbyingDisclosureClient.api_key
68
+
69
+ headers
70
+ end
71
+
72
+ sig do
73
+ params(
74
+ response: T.untyped
75
+ ).returns(T.untyped)
76
+ end
77
+ def handle_response(response)
78
+ response_code = response.status
79
+ response_body = JSON.parse(response.body)
80
+
81
+ case response_code
82
+ when 200
83
+ response_body
84
+ when 400
85
+ # The API docs specify two distinct response schemas for 400 errors:
86
+ # 1. { "detail": "..." }
87
+ # 2. { "registrant_id": ["Enter a number."], "another_field": ["Another error message"] }
88
+ # Collapsing these into one error type for now.
89
+
90
+ raise LobbyingDisclosureClient::Errors::BadRequestError, response_body
91
+ when 401
92
+ raise LobbyingDisclosureClient::Errors::InvalidApiKeyError, response_body['detail']
93
+ when 404
94
+ raise LobbyingDisclosureClient::Errors::NotFoundError, response_body['detail']
95
+ when 405
96
+ raise LobbyingDisclosureClient::Errors::UnsupportedHttpMethodError, response_body['detail']
97
+ when 429
98
+ raise LobbyingDisclosureClient::Errors::RequestThrottledError.new(
99
+ response_body['detail'],
100
+ Integer(response.headers['Retry-After'], 10)
101
+ )
102
+ else
103
+ raise LobbyingDisclosureClient::Errors::UnknownError,
104
+ "Got #{response_code}. Response: #{response_body}"
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,16 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module LobbyingDisclosureClient
5
+ module Enums
6
+ class ContributionType < T::Enum
7
+ enums do
8
+ Feca = new('feca')
9
+ HonoraryExpenses = new('he')
10
+ MeetingExpenses = new('me')
11
+ PresidentialLibraryExpenses = new('ple')
12
+ PresidentialInauguralCommittee = new('pic')
13
+ end
14
+ end
15
+ end
16
+ end