dune-api 1.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 (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +35 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +19 -0
  6. data/CHANGELOG.md +48 -0
  7. data/Gemfile +7 -0
  8. data/Gemfile.lock +601 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +19 -0
  11. data/README.md.backup +61 -0
  12. data/Rakefile +2 -0
  13. data/apiary.apib +1769 -0
  14. data/app/constraints/dune/api/api_constraint.rb +17 -0
  15. data/app/controllers/dune/api/base_controller.rb +68 -0
  16. data/app/controllers/dune/api/v1/channels/members_controller.rb +33 -0
  17. data/app/controllers/dune/api/v1/channels_controller.rb +73 -0
  18. data/app/controllers/dune/api/v1/investments_controller.rb +70 -0
  19. data/app/controllers/dune/api/v1/press_assets_controller.rb +38 -0
  20. data/app/controllers/dune/api/v1/projects_controller.rb +76 -0
  21. data/app/controllers/dune/api/v1/rewards_controller.rb +9 -0
  22. data/app/controllers/dune/api/v1/sessions_controller.rb +27 -0
  23. data/app/controllers/dune/api/v1/tags_controller.rb +37 -0
  24. data/app/controllers/dune/api/v1/users_controller.rb +26 -0
  25. data/app/models/dune/api/access_token.rb +24 -0
  26. data/app/models/dune/api/investment.rb +14 -0
  27. data/app/models/dune/api/project.rb +23 -0
  28. data/app/models/dune/api/user_concern.rb +11 -0
  29. data/app/serializers/channel_member_serializer.rb +7 -0
  30. data/app/serializers/channel_serializer.rb +34 -0
  31. data/app/serializers/dune/api/investment_serializer.rb +44 -0
  32. data/app/serializers/dune/api/project_serializer.rb +86 -0
  33. data/app/serializers/press_asset_serializer.rb +11 -0
  34. data/app/serializers/reward_serializer.rb +13 -0
  35. data/app/serializers/tag_serializer.rb +10 -0
  36. data/app/serializers/user_serializer.rb +46 -0
  37. data/bin/rails +8 -0
  38. data/config/initializers/mime_types.rb +1 -0
  39. data/config/routes.rb +42 -0
  40. data/db/migrate/20140624141405_create_dune_api_access_tokens.rb +11 -0
  41. data/dune-api.gemspec +28 -0
  42. data/lib/dune/api.rb +12 -0
  43. data/lib/dune/api/engine.rb +11 -0
  44. data/lib/dune/api/paginated_controller.rb +19 -0
  45. data/lib/dune/api/version.rb +5 -0
  46. data/spec/constraints/neighborly/api/api_constraint_spec.rb +50 -0
  47. data/spec/controllers/neighborly/api/v1/channels/members_controller_spec.rb +82 -0
  48. data/spec/controllers/neighborly/api/v1/channels_controller_spec.rb +188 -0
  49. data/spec/controllers/neighborly/api/v1/investments_controller_spec.rb +178 -0
  50. data/spec/controllers/neighborly/api/v1/press_assets_controller_spec.rb +129 -0
  51. data/spec/controllers/neighborly/api/v1/projects_controller_spec.rb +317 -0
  52. data/spec/controllers/neighborly/api/v1/rewards_controller_spec.rb +28 -0
  53. data/spec/controllers/neighborly/api/v1/sessions_controller_spec.rb +67 -0
  54. data/spec/controllers/neighborly/api/v1/tags_controller_spec.rb +143 -0
  55. data/spec/controllers/neighborly/api/v1/users_controller_spec.rb +43 -0
  56. data/spec/factories.rb +78 -0
  57. data/spec/fixtures/image.png +0 -0
  58. data/spec/models/neighborly/api/investment_spec.rb +33 -0
  59. data/spec/models/neighborly/api/user_concern_spec.rb +33 -0
  60. data/spec/spec_helper.rb +43 -0
  61. data/spec/support/shared_examples.rb +96 -0
  62. metadata +219 -0
data/lib/dune/api.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'dune/api/engine'
2
+ require 'dune/api/paginated_controller'
3
+ require 'dune/api/version'
4
+ require 'active_model_serializers'
5
+ require 'has_scope'
6
+ require 'kaminari'
7
+ require 'pundit'
8
+
9
+ module Dune
10
+ module Api
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module Dune
2
+ module Api
3
+ class Engine < ::Rails::Engine
4
+ isolate_namespace Dune::Api
5
+
6
+ config.to_prepare do
7
+ ::User.send(:include, Dune::Api::UserConcern)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ module Dune
2
+ module Api
3
+ module PaginatedController
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ has_scope :page, default: 1
8
+ end
9
+
10
+ def respond_with_pagination(collection)
11
+ render json: collection, meta: {
12
+ page: collection.current_page,
13
+ total: collection.total_count,
14
+ total_pages: collection.total_pages
15
+ }
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,5 @@
1
+ module Dune
2
+ module Api
3
+ VERSION = '1.0.1'
4
+ end
5
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dune::Api::ApiConstraint do
4
+ let(:request) { double :request }
5
+
6
+ describe '#matches?' do
7
+ let(:revision) { 1 }
8
+
9
+ def header_for_revision(revision)
10
+ "revision=#{revision}"
11
+ end
12
+
13
+ context 'when default is false' do
14
+ subject(:constraint) { described_class.new(revision: revision) }
15
+
16
+
17
+ it 'matches requests including the versioned vendor mime type' do
18
+ headers = { accept: header_for_revision(revision) }
19
+ allow(request).to receive(:headers).and_return(headers)
20
+
21
+ expect(constraint.matches?(request)).to eq true
22
+ end
23
+
24
+ it 'does not match requests for other revisions' do
25
+ headers = { accept: header_for_revision(revision + 1) }
26
+ allow(request).to receive(:headers).and_return(headers)
27
+
28
+ expect(constraint.matches?(request)).to eq false
29
+ end
30
+ end
31
+
32
+ context 'when default is true' do
33
+ subject(:constraint) { described_class.new(revision: revision, default: true) }
34
+
35
+ it 'matches requests including the versioned vendor mime type' do
36
+ headers = { accept: header_for_revision(revision) }
37
+ allow(request).to receive(:headers).and_return(headers)
38
+
39
+ expect(constraint.matches?(request)).to eq true
40
+ end
41
+
42
+ it 'matches requests when default is true' do
43
+ headers = { accept: header_for_revision(revision + 1) }
44
+ allow(request).to receive(:headers).and_return(headers)
45
+
46
+ expect(constraint.matches?(request)).to eq true
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dune::Api::V1::Channels::MembersController do
4
+ routes { Dune::Api::Engine.routes }
5
+ let(:parsed_response) { JSON.parse(response.body) }
6
+ let!(:channel) { FactoryGirl.create(:channel) }
7
+ let!(:member) { FactoryGirl.create(:channel_member, channel: channel) }
8
+
9
+ let(:records_returned) do
10
+ parsed_response.fetch('users').map { |t| t['id'] }
11
+ end
12
+
13
+ describe '#index', authorized: true, admin: true do
14
+ let(:do_request) { get :index, channel_id: channel.id, format: :json }
15
+
16
+ it 'returns the members list' do
17
+ do_request
18
+ expect(records_returned.count).to eq 1
19
+ end
20
+ end
21
+
22
+ describe '#create', authorized: true, admin: true do
23
+ let(:new_user) { FactoryGirl.create(:user) }
24
+
25
+ let(:do_request) do
26
+ post :create,
27
+ channel_id: channel.id,
28
+ channel_member: { user_id: new_user.id },
29
+ format: :json
30
+ end
31
+
32
+ it 'creates the record' do
33
+ expect{ do_request }.to change{ channel.channel_members.count }.from(1).to(2)
34
+ end
35
+
36
+ context 'on success' do
37
+ it 'returns a success http status' do
38
+ do_request
39
+ expect(response.status).to eq(201)
40
+ end
41
+
42
+ it 'returns the user' do
43
+ do_request
44
+ expect(parsed_response.fetch('user').fetch('id')).to eq new_user.id
45
+ end
46
+ end
47
+
48
+ context 'on failure' do
49
+ let(:do_request) do
50
+ post :create,
51
+ channel_id: channel.id,
52
+ channel_member: { user_id: nil },
53
+ format: :json
54
+ end
55
+
56
+ it 'returns a unprocessable entity http status' do
57
+ do_request
58
+ expect(response.status).to eq(422)
59
+ end
60
+
61
+ it 'returns a json with errors' do
62
+ do_request
63
+
64
+ expect(parsed_response.count).to eq(1)
65
+ expect(parsed_response['errors']['user_id']).not_to be_empty
66
+ end
67
+ end
68
+ end
69
+
70
+ describe 'destroy', authorized: true, admin: true do
71
+ let(:do_request) do
72
+ delete :destroy, id: member.user.id, channel_id: channel.id, format: :json
73
+ end
74
+
75
+ it 'returns a success http status' do
76
+ do_request
77
+ expect(response.status).to eq(204)
78
+ expect{ member.reload }.to raise_error
79
+ end
80
+ end
81
+ end
82
+
@@ -0,0 +1,188 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dune::Api::V1::ChannelsController do
4
+ routes { Dune::Api::Engine.routes }
5
+ let(:parsed_response) { JSON.parse(response.body) }
6
+ let!(:channel) { FactoryGirl.create(:channel) }
7
+
8
+ let(:channels_returned) do
9
+ parsed_response.fetch('channels').map { |t| t['id'] }
10
+ end
11
+
12
+ describe '#index', authorized: true do
13
+ let(:do_request) { get :index, format: :json }
14
+
15
+ it_behaves_like 'paginating results'
16
+
17
+ it 'applies the policy scope' do
18
+ expect(controller).to receive(:policy_scope).with(Channel).and_call_original
19
+ do_request
20
+ end
21
+
22
+ it 'filters by query' do
23
+ FactoryGirl.create(:channel, name: 'Ordinary channel')
24
+ channel = FactoryGirl.create(:channel, name: 'Wonderful channel')
25
+ get :index, format: :json, query: 'wonderful'
26
+ expect(channels_returned).to eql([channel.id])
27
+ end
28
+
29
+ describe 'filter by state' do
30
+ let!(:draft_channel) do
31
+ FactoryGirl.create(:channel, state: :draft, user: user)
32
+ end
33
+
34
+ Channel.state_names.each do |state|
35
+ it "filters by state #{state}" do
36
+ channel = FactoryGirl.create(:channel, state: state, user: user)
37
+ expected_ids = if state.eql?(:draft)
38
+ [channel.id, draft_channel.id]
39
+ else
40
+ [channel.id]
41
+ end
42
+
43
+ get :index, format: :json, state => '1'
44
+ expect(channels_returned).to include(*expected_ids)
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ describe '#create', authorized: true, admin: true do
51
+ let(:do_request) do
52
+ post :create,
53
+ channel: FactoryGirl.build(:channel).attributes,
54
+ format: :json
55
+ end
56
+
57
+ it 'creates the record' do
58
+ expect{ do_request }.to change{ Channel.count }.from(1).to(2)
59
+ end
60
+
61
+ context 'on success' do
62
+ it 'returns a success http status' do
63
+ do_request
64
+ expect(response.status).to eq(201)
65
+ end
66
+ end
67
+
68
+ context 'on failure' do
69
+ let(:do_request) do
70
+ post :create,
71
+ channel: { name: nil },
72
+ format: :json
73
+ end
74
+
75
+ it 'returns a unprocessable entity http status' do
76
+ do_request
77
+ expect(response.status).to eq(422)
78
+ end
79
+
80
+ it 'returns a json with errors' do
81
+ do_request
82
+
83
+ expect(parsed_response.count).to eq(1)
84
+ expect(parsed_response['errors']['name']).not_to be_empty
85
+ end
86
+ end
87
+ end
88
+
89
+ describe '#update', authorized: true do
90
+ let(:user) { channel.user }
91
+
92
+ let(:do_request) do
93
+ put :update,
94
+ id: channel.id,
95
+ channel: { name: 'foo bar' },
96
+ format: :json
97
+ end
98
+
99
+ it 'updates the record' do
100
+ expect(Channel).to receive(:update)
101
+ .with(channel.id.to_s, { 'name' => 'foo bar' })
102
+
103
+ do_request
104
+ end
105
+
106
+ context 'on success' do
107
+ it 'returns a no content http status' do
108
+ do_request
109
+ expect(response.status).to eq(204)
110
+ end
111
+ end
112
+
113
+ context 'on failure' do
114
+ let(:do_request) do
115
+ put :update,
116
+ id: channel.id,
117
+ channel: { name: nil },
118
+ format: :json
119
+ end
120
+
121
+ it 'returns a unprocessable entity http status' do
122
+ do_request
123
+ expect(response.status).to eq(422)
124
+ end
125
+
126
+ it 'returns a json with errors' do
127
+ do_request
128
+
129
+ expect(parsed_response.count).to eq(1)
130
+ expect(parsed_response['errors']['name']).not_to be_empty
131
+ end
132
+ end
133
+ end
134
+
135
+ describe '#show', authorized: true do
136
+ let(:do_request) { get :show, id: channel.id, format: :json }
137
+
138
+ it 'responds with 200' do
139
+ do_request
140
+ expect(response.status).to eql(200)
141
+ end
142
+
143
+ it 'has a top level element called channel' do
144
+ do_request
145
+ expect(parsed_response.fetch('channel')).to be_a(Hash)
146
+ end
147
+
148
+ it 'responds with data of the given channel' do
149
+ do_request
150
+ expect(
151
+ parsed_response.fetch('channel')
152
+ ).to have_key('id')
153
+ end
154
+ end
155
+
156
+ describe 'destroy', authorized: true, admin: true do
157
+ let(:do_request) { delete :destroy, id: channel.id, format: :json }
158
+
159
+ it 'returns a success http status' do
160
+ do_request
161
+ expect(response.status).to eq(204)
162
+ expect{ channel.reload }.to raise_error
163
+ end
164
+ end
165
+
166
+ [:push_to_draft, :push_to_online].each do |name|
167
+ describe "#{name}", authorized: true, admin: true do
168
+ let(:user) { FactoryGirl.create(:user, admin: true) }
169
+ let(:channel) { FactoryGirl.create(:channel, state: 'draft') }
170
+ let(:do_request) { put name, id: channel.id, format: :json }
171
+
172
+ it 'returns a success http status' do
173
+ do_request
174
+ expect(response.status).to eq(204)
175
+ end
176
+
177
+ it 'authorizes the resource' do
178
+ expect(controller).to receive(:authorize).with(channel)
179
+ do_request
180
+ end
181
+
182
+ it 'calls the state machine helper to change the state' do
183
+ expect_any_instance_of(Channel).to receive("#{name}!")
184
+ do_request
185
+ end
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,178 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dune::Api::V1::InvestmentsController do
4
+ routes { Dune::Api::Engine.routes }
5
+ let!(:investment) { FactoryGirl.create(:investment) }
6
+
7
+ let(:investments_returned) do
8
+ parsed_response.fetch('investments').map { |t| t['id'] }
9
+ end
10
+
11
+ let(:parsed_response) { JSON.parse(response.body) }
12
+
13
+ describe '#index', authorized: true, admin: true do
14
+ let(:do_request) { get :index, format: :json }
15
+
16
+ it_behaves_like 'paginating results'
17
+
18
+ it 'filters by query' do
19
+ investment = FactoryGirl.create(:investment, payment_method: 'balanced')
20
+ FactoryGirl.create(:investment, payment_method: 'paypal')
21
+ get :index, format: :json, query: 'balanced'
22
+ expect(investments_returned).to eql([investment.id])
23
+ end
24
+
25
+ describe 'filtering by between_values' do
26
+ before do
27
+ @investment_30 = FactoryGirl.create(:investment, value: 30)
28
+ @investment_35 = FactoryGirl.create(:investment, value: 35)
29
+ FactoryGirl.create(:investment, value: 40)
30
+ end
31
+
32
+ it 'returns just those investments in the given range' do
33
+ get :index, format: :json,
34
+ between_values: {
35
+ initial: 30,
36
+ final: 35
37
+ }
38
+ expect(investments_returned).to eql([@investment_35.id, @investment_30.id])
39
+ end
40
+ end
41
+
42
+ describe 'filter by state' do
43
+ let!(:pending_investment) do
44
+ FactoryGirl.create(:investment, state: :pending)
45
+ end
46
+
47
+ Investment.state_names.each do |state|
48
+ it "filters by state #{state}" do
49
+ investment = FactoryGirl.create(:investment, state: state)
50
+ expected_ids = if state.eql?(:pending)
51
+ [investment.id, pending_investment.id]
52
+ else
53
+ [investment.id]
54
+ end
55
+
56
+ get :index, format: :json, state => '1'
57
+ expect(investments_returned).to include(*expected_ids)
58
+ end
59
+ end
60
+ end
61
+
62
+ describe 'filter by project id' do
63
+ let(:first_project) { FactoryGirl.create(:project, state: 'online') }
64
+ let(:second_project) { FactoryGirl.create(:project, state: 'online') }
65
+
66
+ before do
67
+ @investment = FactoryGirl.create(:investment, value: 10, project: first_project)
68
+ FactoryGirl.create(:investment, value: 10, project: second_project)
69
+ end
70
+
71
+ it 'returns just those investments in the given project id' do
72
+ get :index, project_id: first_project.id, format: :json
73
+ expect(investments_returned).to eql([@investment.id])
74
+ end
75
+ end
76
+ end
77
+
78
+ describe '#show', authorized: true, admin: true do
79
+ let(:do_request) { get :show, id: investment.id, format: :json }
80
+
81
+ it 'responds with 200' do
82
+ do_request
83
+ expect(response.status).to eql(200)
84
+ end
85
+
86
+ it 'has a top level element called investment' do
87
+ do_request
88
+ expect(parsed_response.fetch('investment')).to be_a(Hash)
89
+ end
90
+
91
+ it 'responds with data of the given investment' do
92
+ do_request
93
+ expect(
94
+ parsed_response.fetch('investment')
95
+ ).to have_key('id')
96
+ end
97
+ end
98
+
99
+ describe '#update', authorized: true, admin: true do
100
+ let(:do_request) do
101
+ put :update,
102
+ id: investment.id,
103
+ investment: { value: 15 },
104
+ format: :json
105
+ end
106
+
107
+ it 'updates the record' do
108
+ expect(::Investment).to receive(:update)
109
+ .with(investment.id.to_s, { 'value' => 15 })
110
+
111
+ do_request
112
+ end
113
+
114
+ context 'on success' do
115
+ it 'returns a no content http status' do
116
+ do_request
117
+ expect(response.status).to eq(204)
118
+ end
119
+ end
120
+
121
+ context 'on failure' do
122
+ let(:do_request) do
123
+ put :update,
124
+ id: investment.id,
125
+ investment: { value: nil },
126
+ format: :json
127
+ end
128
+
129
+ it 'returns a unprocessable entity http status' do
130
+ do_request
131
+ expect(response.status).to eq(422)
132
+ end
133
+
134
+ it 'returns a json with errors' do
135
+ do_request
136
+
137
+ expect(parsed_response.count).to eq(1)
138
+ expect(parsed_response['errors']['value']).not_to be_empty
139
+ end
140
+ end
141
+ end
142
+
143
+ describe 'destroy', authorized: true, admin: true do
144
+ let(:do_request) { delete :destroy, id: investment.id, format: :json }
145
+
146
+ it 'returns a success http status' do
147
+ do_request
148
+ expect(response.status).to eq(204)
149
+ expect(investment.reload.deleted?).to be_truthy
150
+ end
151
+ end
152
+
153
+ [:confirm, :pendent, :refund, :hide, :cancel].each do |name|
154
+ describe "#{name}", authorized: true, admin: true do
155
+ let(:user) { FactoryGirl.create(:user, admin: true) }
156
+ let(:investment) do
157
+ state = (name == :refund) ? 'confirmed' : 'deleted'
158
+ FactoryGirl.create(:investment, state: state)
159
+ end
160
+ let(:do_request) { put name, id: investment.id, format: :json }
161
+
162
+ it 'returns a success http status' do
163
+ do_request
164
+ expect(response.status).to eq(204)
165
+ end
166
+
167
+ it 'authorizes the resource' do
168
+ expect(controller).to receive(:authorize).with(investment)
169
+ do_request
170
+ end
171
+
172
+ it 'calls the state machine helper to change the state' do
173
+ expect_any_instance_of(Investment).to receive("#{name}!")
174
+ do_request
175
+ end
176
+ end
177
+ end
178
+ end