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
@@ -0,0 +1,129 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dune::Api::V1::PressAssetsController do
4
+ routes { Dune::Api::Engine.routes }
5
+ let(:parsed_response) { JSON.parse(response.body) }
6
+
7
+ describe '#index', authorized: true do
8
+ let!(:press_asset) { FactoryGirl.create(:press_asset) }
9
+ let(:do_request) { get :index, format: :json }
10
+
11
+ it_behaves_like 'paginating results'
12
+
13
+ it 'responds with 200' do
14
+ do_request
15
+ expect(response.status).to eql(200)
16
+ end
17
+
18
+ it 'has a top level element called press_assets' do
19
+ do_request
20
+ expect(parsed_response.fetch('press_assets')).to be_a(Array)
21
+ end
22
+
23
+ it 'responds with data of press_assets' do
24
+ do_request
25
+ expect(
26
+ parsed_response.fetch('press_assets').first
27
+ ).to have_key('id')
28
+ end
29
+ end
30
+
31
+ describe '#create', authorized: true, admin: true do
32
+ let(:params) { FactoryGirl.build(:press_asset).attributes.merge(image: Rack::Test::UploadedFile.new("#{Dune::Api::Engine.root}/spec/fixtures/image.png"))}
33
+ let(:do_request) { post :create, press_asset: params, format: :json }
34
+
35
+ context 'on success' do
36
+ it 'returns a created http status' do
37
+ do_request
38
+ expect(response.status).to eq(201)
39
+ end
40
+
41
+ it 'returns a json' do
42
+ do_request
43
+
44
+ expect(parsed_response.count).to eq(1)
45
+ expect(parsed_response['press_asset']['title']).to eq('Lorem')
46
+ expect(parsed_response['press_asset']['url']).to eq('http://lorem.com')
47
+ end
48
+ end
49
+
50
+ context 'on failure' do
51
+ let(:do_request) { post :create, press_asset: { }, format: :json }
52
+
53
+ it 'returns a unprocessable entity http status' do
54
+ do_request
55
+ expect(response.status).to eq(422)
56
+ end
57
+
58
+ it 'returns a json with errors' do
59
+ do_request
60
+
61
+ expect(parsed_response.count).to eq(1)
62
+ expect(parsed_response['errors']['title']).not_to be_empty
63
+ end
64
+ end
65
+ end
66
+
67
+ describe '#update', authorized: true, admin: true do
68
+ let!(:press_asset) { FactoryGirl.create(:press_asset) }
69
+
70
+ let(:do_request) do
71
+ put :update,
72
+ id: press_asset,
73
+ press_asset: { title: 'foobar' }, format: :json
74
+ end
75
+
76
+ context 'on success' do
77
+ it 'returns a no content http status' do
78
+ do_request
79
+ expect(response.status).to eq(204)
80
+ end
81
+ end
82
+
83
+ context 'on failure' do
84
+ let(:do_request) { put :update, id: press_asset, press_asset: { title: '' }, format: :json }
85
+
86
+ it 'returns a unprocessable entity http status' do
87
+ do_request
88
+ expect(response.status).to eq(422)
89
+ end
90
+
91
+ it 'returns a json with errors' do
92
+ do_request
93
+
94
+ expect(parsed_response.count).to eq(1)
95
+ expect(parsed_response['errors']['title']).not_to be_empty
96
+ end
97
+ end
98
+ end
99
+
100
+ describe '#show', authorized: true do
101
+ let!(:press_asset) { FactoryGirl.create(:press_asset) }
102
+ let(:do_request) { get :show, id: press_asset, format: :json }
103
+
104
+ it 'returns a success http status' do
105
+ do_request
106
+ expect(response.status).to eq(200)
107
+ end
108
+
109
+ it 'returns a json' do
110
+ do_request
111
+
112
+ expect(parsed_response.count).to eq(1)
113
+ expect(parsed_response['press_asset']['title']).to eq(press_asset.title)
114
+ expect(parsed_response['press_asset']['url']).to eq(press_asset.url)
115
+ end
116
+ end
117
+
118
+ describe '#destroy', authorized: true, admin: true do
119
+ let!(:press_asset) { FactoryGirl.create(:press_asset) }
120
+ let(:do_request) { delete :destroy, id: press_asset, format: :json }
121
+
122
+ it 'returns a success http status' do
123
+ do_request
124
+ expect(response.status).to eq(204)
125
+ expect { press_asset.reload }.to raise_error
126
+ end
127
+ end
128
+ end
129
+
@@ -0,0 +1,317 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dune::Api::V1::ProjectsController do
4
+ include ActiveSupport::Testing::TimeHelpers
5
+ routes { Dune::Api::Engine.routes }
6
+ let(:projects_returned) do
7
+ parsed_response.fetch('projects').map { |t| t['id'] }
8
+ end
9
+ let(:parsed_response) { JSON.parse(response.body) }
10
+
11
+ describe '#index', authorized: true do
12
+ let!(:project) { FactoryGirl.create(:project) }
13
+ let(:do_request) { get :index, format: :json }
14
+
15
+ it_behaves_like 'paginating results'
16
+
17
+ describe 'manageable' do
18
+ before do
19
+ @draft_project = FactoryGirl.create(:project, state: 'draft', user: user)
20
+ @online_project = FactoryGirl.create(:project, state: 'online')
21
+ end
22
+
23
+ context 'when filtering by manageable projects' do
24
+ let(:do_request) { get :index, format: :json, manageable: true }
25
+
26
+ context 'when user is not an admin' do
27
+ let(:user) { FactoryGirl.create(:user, admin: false) }
28
+
29
+ it 'returns only mangeable projects' do
30
+ do_request
31
+ expect(projects_returned).to include(@draft_project.id)
32
+ end
33
+ end
34
+
35
+ context 'when user is an admin' do
36
+ let(:user) { FactoryGirl.create(:user, admin: true) }
37
+
38
+ it 'returns all projects' do
39
+ do_request
40
+ expect(projects_returned).to include(@draft_project.id, @online_project.id)
41
+ end
42
+ end
43
+ end
44
+
45
+ context 'when not filtering by manageable projects' do
46
+ let(:do_request) { get :index, format: :json, manageable: false }
47
+
48
+ context 'when user is not an admin' do
49
+ let(:user) { FactoryGirl.create(:user, admin: false) }
50
+
51
+ it 'returns only public projects' do
52
+ do_request
53
+ expect(projects_returned).to include(@online_project.id)
54
+ expect(projects_returned).not_to include(@draft_project.id)
55
+ end
56
+ end
57
+
58
+ context 'when user is an admin' do
59
+ let(:user) { FactoryGirl.create(:user, admin: true) }
60
+
61
+ it 'returns only public projects' do
62
+ do_request
63
+ expect(projects_returned).to include(@online_project.id)
64
+ expect(projects_returned).not_to include(@draft_project.id)
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ describe 'ordering' do
71
+ let!(:project_1) { FactoryGirl.create(:project, name: 'abc') }
72
+ let!(:project_2) { FactoryGirl.create(:project, name: 'xyz') }
73
+
74
+ it 'order by given attribute' do
75
+ get :index, format: :json, order_by: 'name desc'
76
+ expected_projects = [
77
+ project.id,
78
+ project_2.id,
79
+ project_1.id
80
+ ]
81
+ expect(projects_returned).to eql(expected_projects)
82
+ end
83
+ end
84
+
85
+ it 'filters by query' do
86
+ FactoryGirl.create(:project, name: 'Ordinary project')
87
+ project = FactoryGirl.create(:project, name: 'Wonderful project')
88
+ get :index, format: :json, query: 'wonderful'
89
+ expect(projects_returned).to eql([project.id])
90
+ end
91
+
92
+ describe 'filter by state' do
93
+ let!(:draft_project) do
94
+ FactoryGirl.create(:project, state: :draft, user: user)
95
+ end
96
+
97
+ Project.state_names.each do |state|
98
+ it "filters by state #{state}" do
99
+ project = FactoryGirl.create(:project, state: state, user: user)
100
+ expected_ids = if state.eql?(:draft)
101
+ [project.id, draft_project.id]
102
+ else
103
+ [project.id]
104
+ end
105
+
106
+ get :index, format: :json, state => '1', manageable: true
107
+ expect(projects_returned).to include(*expected_ids)
108
+ end
109
+ end
110
+ end
111
+
112
+ describe 'filtering by created_at' do
113
+ before do
114
+ travel_to(10.days.ago) do
115
+ FactoryGirl.create(:project)
116
+ end
117
+ end
118
+
119
+ it 'returns just those projects in the given range' do
120
+ project = travel_to(3.days.ago) do
121
+ FactoryGirl.create(:project)
122
+ end
123
+ get :index, format: :json,
124
+ between_created_at: {
125
+ starts_at: 6.days.ago.to_date.to_s,
126
+ ends_at: Time.now.to_date.to_s
127
+ }
128
+ expect(projects_returned).to eql([project.id])
129
+ end
130
+ end
131
+
132
+ describe 'filtering by expires_at' do
133
+ before do
134
+ travel_to(10.days.ago) do
135
+ FactoryGirl.create(:project, online_date: Date.current, online_days: 1)
136
+ end
137
+ end
138
+
139
+ it 'returns just those projects in the given range' do
140
+ project = travel_to(3.days.ago) do
141
+ FactoryGirl.create(:project, online_date: Date.current, online_days: 1)
142
+ end
143
+ get :index, format: :json,
144
+ between_expires_at: {
145
+ starts_at: 6.days.ago.to_date.to_s,
146
+ ends_at: Time.now.to_date.to_s
147
+ }
148
+ expect(projects_returned).to eql([project.id])
149
+ end
150
+ end
151
+
152
+ describe 'filtering by online_date' do
153
+ before do
154
+ FactoryGirl.create(:project, online_date: 10.days.from_now)
155
+ end
156
+
157
+ it 'returns just those projects in the given range' do
158
+ project = FactoryGirl.create(:project, online_date: 3.days.from_now)
159
+ get :index, format: :json,
160
+ between_online_date: {
161
+ starts_at: Time.now.to_date.to_s,
162
+ ends_at: 6.days.from_now.to_date.to_s
163
+ }
164
+ expect(projects_returned).to eql([project.id])
165
+ end
166
+ end
167
+
168
+ it 'checks permissions' do
169
+ project = FactoryGirl.create(:project, state: :draft)
170
+ do_request
171
+ expect(projects_returned).not_to include(project.id)
172
+ end
173
+ end
174
+
175
+ describe '#show', authorized: true do
176
+ let(:project) { FactoryGirl.create(:project, user: user) }
177
+ let(:do_request) { get :show, id: project.id, format: :json }
178
+
179
+ context 'when user has access to the project' do
180
+ it 'responds with 200' do
181
+ do_request
182
+ expect(response.status).to eql(200)
183
+ end
184
+
185
+ it 'has a top level element called project' do
186
+ do_request
187
+ expect(parsed_response.fetch('project')).to be_a(Hash)
188
+ end
189
+
190
+ it 'responds with data of the given project' do
191
+ do_request
192
+ expect(
193
+ parsed_response.fetch('project')
194
+ ).to have_key('id')
195
+ end
196
+ end
197
+
198
+ context 'when user does not have access to the project' do
199
+ let(:project) { FactoryGirl.create(:project, state: 'draft') }
200
+
201
+ it 'returns a forbidden http status' do
202
+ do_request
203
+ expect(response.status).to eq(403)
204
+ end
205
+ end
206
+ end
207
+
208
+ describe '#update', authorized: true do
209
+ let(:project) { FactoryGirl.create(:project, user: user) }
210
+
211
+ let(:do_request) do
212
+ put :update,
213
+ id: project.id,
214
+ project: { name: 'Foo Bar Updated' },
215
+ format: :json
216
+ end
217
+
218
+ context 'when user has access to the project' do
219
+ it 'updates the record' do
220
+ expect(Project).to receive(:update)
221
+ .with(project.id.to_s, { "name" => 'Foo Bar Updated' })
222
+
223
+ do_request
224
+ end
225
+
226
+ context 'on success' do
227
+ it 'returns a no content http status' do
228
+ do_request
229
+ expect(response.status).to eq(204)
230
+ end
231
+ end
232
+
233
+ context 'on failure' do
234
+ let(:do_request) do
235
+ put :update,
236
+ id: project.id,
237
+ project: { name: '' },
238
+ format: :json
239
+ end
240
+
241
+ it 'returns a unprocessable entity http status' do
242
+ do_request
243
+ expect(response.status).to eq(422)
244
+ end
245
+
246
+ it 'returns a json with errors' do
247
+ do_request
248
+
249
+ expect(parsed_response.count).to eq(1)
250
+ expect(parsed_response['errors']['name']).not_to be_empty
251
+ end
252
+ end
253
+ end
254
+
255
+ context 'when user does not have access to the project' do
256
+ let(:project) { FactoryGirl.create(:project) }
257
+
258
+ it 'does not update the record' do
259
+ expect(Project).not_to receive(:update)
260
+ do_request
261
+ end
262
+
263
+ it 'returns a forbidden http status' do
264
+ do_request
265
+ expect(response.status).to eq(403)
266
+ expect(project.reload.deleted?).to be_falsy
267
+ end
268
+ end
269
+ end
270
+
271
+ describe 'destroy', authorized: true do
272
+ let(:user) { FactoryGirl.create(:user, admin: true) }
273
+ let(:project) { FactoryGirl.create(:project, user: user, state: :draft) }
274
+ let(:do_request) { delete :destroy, id: project.id, format: :json }
275
+
276
+ context 'when it can be pushed to trash' do
277
+ it 'returns a success http status' do
278
+ do_request
279
+ expect(response.status).to eq(204)
280
+ expect(project.reload.deleted?).to be_truthy
281
+ end
282
+ end
283
+
284
+ context 'when it cannot be pushed to trash' do
285
+ let(:project) { FactoryGirl.create(:project, user: user, state: :online) }
286
+
287
+ it 'returns a forbidden http status' do
288
+ do_request
289
+ expect(response.status).to eq(403)
290
+ expect(project.reload.deleted?).to be_falsy
291
+ end
292
+ end
293
+ end
294
+
295
+ [:approve, :launch, :reject, :push_to_draft].each do |name|
296
+ describe "#{name}", authorized: true do
297
+ let(:user) { FactoryGirl.create(:user, admin: true) }
298
+ let(:project) { FactoryGirl.create(:project, state: :draft) }
299
+ let(:do_request) { put name, id: project.id, format: :json }
300
+
301
+ it 'returns a success http status' do
302
+ do_request
303
+ expect(response.status).to eq(204)
304
+ end
305
+
306
+ it 'authorizes the resource' do
307
+ expect(controller).to receive(:authorize).with(project)
308
+ do_request
309
+ end
310
+
311
+ it 'calls the state machine helper to change the state' do
312
+ expect_any_instance_of(Project).to receive("#{name}!")
313
+ do_request
314
+ end
315
+ end
316
+ end
317
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dune::Api::V1::RewardsController do
4
+ routes { Dune::Api::Engine.routes }
5
+ let(:parsed_response) { JSON.parse(response.body) }
6
+ let!(:reward) { FactoryGirl.create(:reward) }
7
+
8
+ describe '#show', authorized: true do
9
+ let(:do_request) { get :show, id: reward.id, format: :json }
10
+
11
+ it 'responds with 200' do
12
+ do_request
13
+ expect(response.status).to eql(200)
14
+ end
15
+
16
+ it 'has a top level element called reward' do
17
+ do_request
18
+ expect(parsed_response.fetch('reward')).to be_a(Hash)
19
+ end
20
+
21
+ it 'responds with data of the given reward' do
22
+ do_request
23
+ expect(
24
+ parsed_response.fetch('reward')
25
+ ).to have_key('id')
26
+ end
27
+ end
28
+ end