blue_state_digital 0.6.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 (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +1 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +3 -0
  7. data/Gemfile +2 -0
  8. data/Guardfile +5 -0
  9. data/LICENSE +24 -0
  10. data/README.md +123 -0
  11. data/Rakefile +11 -0
  12. data/blue_state_digital.gemspec +37 -0
  13. data/lib/blue_state_digital.rb +32 -0
  14. data/lib/blue_state_digital/address.rb +28 -0
  15. data/lib/blue_state_digital/api_data_model.rb +31 -0
  16. data/lib/blue_state_digital/collection_resource.rb +14 -0
  17. data/lib/blue_state_digital/connection.rb +119 -0
  18. data/lib/blue_state_digital/constituent.rb +178 -0
  19. data/lib/blue_state_digital/constituent_group.rb +151 -0
  20. data/lib/blue_state_digital/contribution.rb +73 -0
  21. data/lib/blue_state_digital/dataset.rb +139 -0
  22. data/lib/blue_state_digital/dataset_map.rb +138 -0
  23. data/lib/blue_state_digital/email.rb +22 -0
  24. data/lib/blue_state_digital/email_unsubscribe.rb +11 -0
  25. data/lib/blue_state_digital/error_middleware.rb +29 -0
  26. data/lib/blue_state_digital/event.rb +46 -0
  27. data/lib/blue_state_digital/event_rsvp.rb +17 -0
  28. data/lib/blue_state_digital/event_type.rb +19 -0
  29. data/lib/blue_state_digital/phone.rb +20 -0
  30. data/lib/blue_state_digital/version.rb +3 -0
  31. data/spec/blue_state_digital/address_spec.rb +25 -0
  32. data/spec/blue_state_digital/api_data_model_spec.rb +13 -0
  33. data/spec/blue_state_digital/connection_spec.rb +153 -0
  34. data/spec/blue_state_digital/constituent_group_spec.rb +269 -0
  35. data/spec/blue_state_digital/constituent_spec.rb +422 -0
  36. data/spec/blue_state_digital/contribution_spec.rb +132 -0
  37. data/spec/blue_state_digital/dataset_map_spec.rb +137 -0
  38. data/spec/blue_state_digital/dataset_spec.rb +177 -0
  39. data/spec/blue_state_digital/email_spec.rb +16 -0
  40. data/spec/blue_state_digital/error_middleware_spec.rb +15 -0
  41. data/spec/blue_state_digital/event_rsvp_spec.rb +17 -0
  42. data/spec/blue_state_digital/event_spec.rb +70 -0
  43. data/spec/blue_state_digital/event_type_spec.rb +51 -0
  44. data/spec/blue_state_digital/phone_spec.rb +16 -0
  45. data/spec/fixtures/multiple_event_types.json +234 -0
  46. data/spec/fixtures/single_event_type.json +117 -0
  47. data/spec/spec_helper.rb +21 -0
  48. data/spec/support/matchers/fields.rb +23 -0
  49. metadata +334 -0
@@ -0,0 +1,132 @@
1
+ require 'spec_helper'
2
+
3
+ describe BlueStateDigital::Contribution do
4
+ let(:attributes) {
5
+ {
6
+ external_id: 'GUID_1234',
7
+ firstname: 'carlos',
8
+ lastname: 'the jackal',
9
+ transaction_amt: 1.0,
10
+ transaction_dt: '2012-12-31 23:59:59',
11
+ cc_type_cd: 'vs'
12
+ }
13
+ }
14
+
15
+ it { is_expected.to have_fields(
16
+ :external_id,
17
+ :prefix,:firstname,:middlename,:lastname,:suffix,
18
+ :transaction_dt,:transaction_amt,:cc_type_cd,:gateway_transaction_id,
19
+ :contribution_page_id,:stg_contribution_recurring_id,:contribution_page_slug,
20
+ :outreach_page_id,:source,:opt_compliance,
21
+ :addr1,:addr2,:city,:state_cd,:zip,:country,
22
+ :phone,:email,
23
+ :employer,:occupation,
24
+ :custom_fields
25
+ ) }
26
+
27
+ describe 'as_json' do
28
+ let(:connection) { double }
29
+
30
+ it 'should include contribution_page_id and contribution_page_slug if they are set' do
31
+ contribution = BlueStateDigital::Contribution.new(attributes.merge({ connection: connection, contribution_page_slug: 'donate-here-12', contribution_page_id: 4 }))
32
+ expect(contribution.as_json).to include('contribution_page_id')
33
+ expect(contribution.as_json).to include('contribution_page_slug')
34
+ end
35
+
36
+ it 'should not include contribution_page_id and contribution_page_slug if they are not set' do
37
+ contribution = BlueStateDigital::Contribution.new(attributes.merge({ connection: connection }))
38
+ expect(contribution.as_json).not_to include('contribution_page_id')
39
+ expect(contribution.as_json).not_to include('contribution_page_slug')
40
+ end
41
+ end
42
+
43
+ describe 'save' do
44
+ let(:connection) { double }
45
+ let(:contribution) { BlueStateDigital::Contribution.new(attributes.merge({ connection: connection })) }
46
+
47
+ before :each do
48
+ expect(connection)
49
+ .to receive(:perform_request)
50
+ .with(
51
+ '/contribution/add_external_contribution',
52
+ {accept: 'application/json'},
53
+ 'POST',
54
+ [contribution].to_json
55
+ )
56
+ .and_return(response)
57
+ end
58
+
59
+ context 'successful' do
60
+ let(:response) {
61
+ {
62
+ 'summary'=> {
63
+ 'sucesses'=> 1,
64
+ 'failures'=> 0,
65
+ 'missing_ids'=> 0
66
+ },
67
+ 'errors'=> {
68
+ }
69
+ }.to_json
70
+ }
71
+
72
+ it "should perform API request" do
73
+ saved_contribution = contribution.save
74
+ expect(saved_contribution).not_to be_nil
75
+ end
76
+ end
77
+
78
+ context 'failure' do
79
+ context 'bad request' do
80
+ let(:response) { 'Method add_external_contribution expects a JSON array.' }
81
+ it "should raise error" do
82
+ expect { contribution.save }.to raise_error(
83
+ BlueStateDigital::Contribution::ContributionSaveFailureException,
84
+ /Method add_external_contribution expects a JSON array/m
85
+ )
86
+ end
87
+ end
88
+ context 'missing ID' do
89
+ let(:response) {
90
+ {
91
+ 'summary'=> {
92
+ 'sucesses'=> 0,
93
+ 'failures'=> 0,
94
+ 'missing_ids'=> 1
95
+ },
96
+ 'errors'=>{
97
+ }
98
+ }.to_json
99
+ }
100
+ it "should raise error" do
101
+ expect { contribution.save }.to raise_error(
102
+ BlueStateDigital::Contribution::ContributionExternalIdMissingException
103
+ )
104
+ end
105
+ end
106
+ context 'validation errors' do
107
+ let(:response) {
108
+ {
109
+ 'summary'=> {
110
+ 'sucesses'=> 0,
111
+ 'failures'=> 1,
112
+ 'missing_ids'=> 0
113
+ },
114
+ 'errors'=>{
115
+ 'UNIQUE_ID_1234567890'=>
116
+ [
117
+ 'Parameter source is expected to be a list of strings',
118
+ 'Parameter email does not appear to be a valid email address.'
119
+ ]
120
+ }
121
+ }.to_json
122
+ }
123
+ it "should raise error" do
124
+ expect { contribution.save }.to raise_error(
125
+ BlueStateDigital::Contribution::ContributionSaveValidationException,
126
+ /Error for Contribution.ID. UNIQUE_ID_1234567890.. Parameter source is expected to be a list of strings, Parameter email does not appear to be a valid email address/m
127
+ )
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,137 @@
1
+ require 'spec_helper'
2
+
3
+ describe BlueStateDigital::DatasetMap do
4
+
5
+ let(:connection) { double }
6
+ let(:dataset_map_attributes) do
7
+ {
8
+ }
9
+ end
10
+ subject { BlueStateDigital::DatasetMap.new(dataset_map_attributes.merge({connection: connection}))}
11
+
12
+ describe "new" do
13
+ it "should accept dataset_map params" do
14
+ dataset = BlueStateDigital::Dataset.new(dataset_map_attributes)
15
+ dataset_map_attributes.each do |k,v|
16
+ expect(dataset.send(k)).to eq(v)
17
+ end
18
+ end
19
+ end
20
+
21
+ describe "save" do
22
+ context "validations" do
23
+ it "should not error if there is no data" do
24
+ expect(subject.data).to be_blank
25
+ expect(subject).to be_valid
26
+ end
27
+ it "should error if there is data but no data header" do
28
+ subject.add_data_row([1])
29
+ expect(subject).not_to be_valid
30
+ expect(subject.errors.full_messages).to eq(["data_header is missing"])
31
+ end
32
+ end
33
+ context "csv upload" do
34
+ let(:header) { ['a','b','c','d'] }
35
+ let(:row1) { ['1','2','3','4'] }
36
+ let(:csv) { "#{header.join(',')}\n#{row1.join(',')}\n"}
37
+ before(:each) do
38
+ expect(connection)
39
+ .to receive(:perform_request_raw)
40
+ .with('/cons/upload_dataset_map', { api_ver: 2, content_type: "text/csv", accept: "application/json" }, 'PUT',csv)
41
+ .and_return(response)
42
+ end
43
+ let(:response) { Hashie::Mash.new(status: 202,body: "accepted") }
44
+ it "should convert data into csv and dispatch" do
45
+ subject.add_data_header(header)
46
+ subject.add_data_row(row1)
47
+ expect(subject.save).to be_truthy
48
+ end
49
+ context "failure" do
50
+ let(:response) { Hashie::Mash.new(status: 404,body: "Something bad happened") }
51
+ it "should return false if save fails" do
52
+ subject.add_data_header(header)
53
+ subject.add_data_row(row1)
54
+ expect(subject.save).to be_falsey
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ describe "delete" do
61
+ context "validations" do
62
+ it "should complaing if map_id is not provided" do
63
+ subject.map_id = nil
64
+ expect(subject.delete).to be false
65
+ expect(subject.errors.full_messages).to eq(["map_id is missing"])
66
+ end
67
+ end
68
+ context "service" do
69
+ let(:map_id) { 1 }
70
+ let(:delete_payload){ {map_id: map_id} }
71
+ before :each do
72
+ expect(connection)
73
+ .to receive(:perform_request_raw)
74
+ .with('/cons/delete_dataset_map', {api_ver: 2}, 'POST',delete_payload.to_json)
75
+ .and_return(response)
76
+ end
77
+ context "failure" do
78
+ let(:response) { Hashie::Mash.new(status: 404,body: "Something bad happened") }
79
+ it "should return false if delete fails" do
80
+ subject.map_id = map_id
81
+ expect(subject.delete).to be_falsey
82
+ expect(subject.errors.full_messages).to eq(["web_service Something bad happened"])
83
+ end
84
+ end
85
+ context "success" do
86
+ let(:response) { Hashie::Mash.new(status: 200,body: "") }
87
+ it "should return true" do
88
+ subject.map_id = map_id
89
+ expect(subject.delete).to be_truthy
90
+ expect(subject.errors.full_messages).to eq([])
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ describe "get_dataset_maps" do
97
+ let(:connection) { BlueStateDigital::Connection.new({}) }
98
+ let(:dataset_map1) do
99
+ {
100
+ map_id:1,
101
+ type:"state"
102
+ }
103
+ end
104
+ let(:dataset_map2) do
105
+ {
106
+ map_id:2,
107
+ type:"downballot"
108
+ }
109
+ end
110
+ let(:response) do
111
+ {
112
+ data:[
113
+ dataset_map1,
114
+ dataset_map2
115
+ ]
116
+ }.to_json
117
+ end
118
+ before :each do
119
+ expect(connection)
120
+ .to receive(:perform_request)
121
+ .with('/cons/list_dataset_maps', {api_ver: 2}, 'GET')
122
+ .and_return(response)
123
+ end
124
+ it "should fetch datasets" do
125
+ dataset_maps = connection.dataset_maps.get_dataset_maps
126
+ expect(dataset_maps.length).to eq(2)
127
+ expect(dataset_maps[0].to_json).to eq(dataset_map1.to_json)
128
+ expect(dataset_maps[1].to_json).to eq(dataset_map2.to_json)
129
+ end
130
+ context "failure" do
131
+ let(:response) { "Something bad happened" }
132
+ it "should raise exception if fetch fails" do
133
+ expect { connection.dataset_maps.get_dataset_maps }.to raise_error(BlueStateDigital::CollectionResource::FetchFailureException)
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,177 @@
1
+ require 'spec_helper'
2
+
3
+ describe BlueStateDigital::Dataset do
4
+
5
+ let(:connection) { double }
6
+ let(:slug) { "my_dataset" }
7
+ let(:map_type) { "state" }
8
+ let(:dataset_attributes) do
9
+ {
10
+ "dataset_id" => 42,
11
+ "slug" => slug,
12
+ "rows" => 100,
13
+ "map_type" => map_type
14
+ }
15
+ end
16
+
17
+ subject { BlueStateDigital::Dataset.new(dataset_attributes.merge({connection: connection}))}
18
+
19
+ describe "new" do
20
+ it "should accept dataset params" do
21
+ dataset = BlueStateDigital::Dataset.new(dataset_attributes)
22
+ dataset_attributes.each do |k,v|
23
+ expect(dataset.send(k)).to eq(v)
24
+ end
25
+ end
26
+ end
27
+
28
+ describe "save" do
29
+ context "validations" do
30
+ it "should error if required params are not provided" do
31
+ [:slug,:map_type].each do |field|
32
+ val = subject.send(field)
33
+ subject.send("#{field}=",nil)
34
+ expect(subject).not_to be_valid
35
+ expect(subject.errors.full_messages).to eq(["#{field} can't be blank"])
36
+ subject.send("#{field}=",val)
37
+ end
38
+ end
39
+
40
+ it "should not error if there is no data" do
41
+ expect(subject.data).to be_blank
42
+ expect(subject).to be_valid
43
+ end
44
+
45
+ it "should error if there is data but no data header" do
46
+ subject.add_data_row([1])
47
+ expect(subject).not_to be_valid
48
+ expect(subject.errors.full_messages).to eq(["data_header is missing"])
49
+ end
50
+ end
51
+
52
+ context "csv upload" do
53
+ let(:header) { ['a','b','c','d'] }
54
+ let(:row1) { ['1','2','3','4'] }
55
+ let(:csv) { "#{header.join(',')}\n#{row1.join(',')}\n"}
56
+ let(:response) { Hashie::Mash.new(status: 202, body: "accepted") }
57
+
58
+ before(:each) do
59
+ expect(connection)
60
+ .to receive(:perform_request_raw)
61
+ .with('/cons/upload_dataset', { api_ver: 2, slug: slug,map_type: map_type, content_type: "text/csv", accept: "application/json" }, 'PUT',csv)
62
+ .and_return(response)
63
+ end
64
+
65
+
66
+ it "should convert data into csv and dispatch" do
67
+ subject.add_data_header(header)
68
+ subject.add_data_row(row1)
69
+ expect(subject.save).to be_truthy
70
+ end
71
+
72
+ context "failure" do
73
+ let(:response) { Hashie::Mash.new(status: 404,body: "Something bad happened") }
74
+
75
+ it "should return false if save fails" do
76
+ subject.add_data_header(header)
77
+ subject.add_data_row(row1)
78
+ expect(subject.save).to be_falsey
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ describe "delete" do
85
+ context "validations" do
86
+ it "should complaing if map_id is not provided" do
87
+ subject.dataset_id = nil
88
+ expect(subject.delete).to be false
89
+ expect(subject.errors.full_messages).to eq(["dataset_id is missing"])
90
+ end
91
+ end
92
+
93
+ context "service" do
94
+ let(:dataset_id) { 1 }
95
+ let(:delete_payload){ {dataset_id: dataset_id} }
96
+
97
+ before :each do
98
+ expect(connection)
99
+ .to receive(:perform_request_raw)
100
+ .with('/cons/delete_dataset', {api_ver: 2}, 'POST',delete_payload.to_json)
101
+ .and_return(response)
102
+ end
103
+
104
+ context "failure" do
105
+ let(:response) { Hashie::Mash.new(status: 404,body: "Something bad happened") }
106
+
107
+ it "should return false if delete fails" do
108
+ subject.dataset_id = dataset_id
109
+ expect(subject.delete).to be_falsey
110
+ expect(subject.errors.full_messages).to eq(["web_service Something bad happened"])
111
+ end
112
+ end
113
+
114
+ context "success" do
115
+ let(:response) { Hashie::Mash.new(status: 200,body: "") }
116
+
117
+ it "should return true" do
118
+ subject.dataset_id = dataset_id
119
+ expect(subject.delete).to be_truthy
120
+ expect(subject.errors.full_messages).to eq([])
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ describe "get_datasets" do
127
+ let(:connection) { BlueStateDigital::Connection.new({}) }
128
+ let(:dataset1) do
129
+ {
130
+ dataset_id:42,
131
+ map_type:"state",
132
+ slug:"my_dataset",
133
+ rows:100,
134
+ }
135
+ end
136
+
137
+ let(:dataset2) do
138
+ {
139
+ dataset_id:43,
140
+ map_type:"downballot",
141
+ slug:"downballot_dataset",
142
+ rows:50,
143
+ }
144
+ end
145
+
146
+ let(:response) do
147
+ {
148
+ data:[
149
+ dataset1,
150
+ dataset2
151
+ ]
152
+ }.to_json
153
+ end
154
+
155
+ before :each do
156
+ expect(connection)
157
+ .to receive(:perform_request)
158
+ .with('/cons/list_datasets', { api_ver: 2 }, 'GET')
159
+ .and_return(response)
160
+ end
161
+
162
+ it "should fetch datasets" do
163
+ datasets = connection.datasets.get_datasets
164
+ expect(datasets.length).to eq(2)
165
+ expect(datasets[0].to_json).to eq(dataset1.to_json)
166
+ expect(datasets[1].to_json).to eq(dataset2.to_json)
167
+ end
168
+
169
+ context "failure" do
170
+ let(:response) { "Something bad happened" }
171
+
172
+ it "should raise exception if fetch fails" do
173
+ expect { connection.datasets.get_datasets }.to raise_error(BlueStateDigital::CollectionResource::FetchFailureException)
174
+ end
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe BlueStateDigital::Email do
4
+ describe :to_hash do
5
+ it "should return a hash of all fields" do
6
+ attr_hash = {email: '123432', email_type: 'personal', is_primary: '1', is_subscribed: '0'}
7
+ phone = BlueStateDigital::Email.new attr_hash
8
+ expect(phone.to_hash).to eq(attr_hash)
9
+ end
10
+ it "should include nil fields" do
11
+ expected_hash = {email: nil, email_type: nil, is_primary: nil, is_subscribed: nil}
12
+ phone = BlueStateDigital::Email.new {}
13
+ expect(phone.to_hash).to eq(expected_hash)
14
+ end
15
+ end
16
+ end