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,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dune::Api::V1::SessionsController do
4
+ routes { Dune::Api::Engine.routes }
5
+ let!(:user) { FactoryGirl.create(:user) }
6
+ let(:parsed_response) { JSON.parse(response.body) }
7
+
8
+ describe '#create' do
9
+ it 'responds with 401 when requested with invalid email/password combination' do
10
+ post :create, email: user.email, password: 'wrong-password'
11
+ expect(response.status).to eql(401)
12
+ end
13
+
14
+ it 'responds with 401 when requested with invalid email' do
15
+ post :create, email: 'wrong-email', password: 'wrong-password'
16
+ expect(response.status).to eql(401)
17
+ end
18
+
19
+ it 'responds with 400 when requested with no email' do
20
+ post :create, password: 'right-password'
21
+ expect(response.status).to eql(400)
22
+ end
23
+
24
+ it 'responds with 400 when requested with no password' do
25
+ post :create, email: user.email
26
+ expect(response.status).to eql(400)
27
+ end
28
+
29
+ it 'responds with 201 when requested with valid email and password combination' do
30
+ post :create, email: user.email, password: 'right-password'
31
+ expect(response.status).to eql(201)
32
+ end
33
+
34
+ it 'returns session data when requested with valid email and password combination' do
35
+ post :create, email: user.email, password: 'right-password'
36
+ expect(parsed_response['access_token']).to eql(user.get_access_token)
37
+ expect(parsed_response['user_id']).to eql(user.id)
38
+ end
39
+ end
40
+
41
+ describe '#destroy', authorized: true do
42
+ let(:do_request) { delete :destroy }
43
+
44
+ context 'when access_token is provided' do
45
+ context 'and is valid' do
46
+ before do
47
+ request.env['HTTP_AUTHORIZATION'] = "Token token=#{valid_access_token.code}"
48
+ end
49
+ let(:valid_access_token) { FactoryGirl.create(:access_token, user: user) }
50
+
51
+ it 'responds with 200' do
52
+ expect(response.status).to eql(200)
53
+ end
54
+
55
+ it 'expires given access_token' do
56
+ delete :destroy
57
+ expect(valid_access_token.reload).to be_expired
58
+ end
59
+
60
+ it 'renders empty json' do
61
+ delete :destroy
62
+ expect(parsed_response).to be_empty
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,143 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dune::Api::V1::TagsController do
4
+ routes { Dune::Api::Engine.routes }
5
+ let(:parsed_response) { JSON.parse(response.body) }
6
+
7
+ describe '#index', authorized: true do
8
+ let!(:tag) { FactoryGirl.create(:tag) }
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 tags' do
19
+ do_request
20
+ expect(parsed_response.fetch('tags')).to be_a(Array)
21
+ end
22
+
23
+ it 'responds with data of tags' do
24
+ do_request
25
+ expect(
26
+ parsed_response.fetch('tags').first
27
+ ).to have_key('id')
28
+ end
29
+
30
+ describe 'filter by popular' do
31
+ let!(:popular) { FactoryGirl.create(:tag_popular) }
32
+
33
+ it 'accepts truthy popular parameter' do
34
+ get :index, format: :json, popular: '1'
35
+ response_ids = parsed_response.fetch('tags').map { |t| t['id'] }
36
+ expect(response_ids).to eql([popular.id])
37
+ end
38
+
39
+ it 'skip any filtering for popular when receiving falsy value' do
40
+ get :index, format: :json, popular: '0'
41
+ response_ids = parsed_response.fetch('tags').map { |t| t['id'] }
42
+ expect(response_ids).to eql(Tag.pluck(:id))
43
+ end
44
+ end
45
+ end
46
+
47
+ describe '#create', authorized: true, admin: true do
48
+ let(:do_request) { post :create, tag: { name: 'foobar', visible: true }, format: :json }
49
+
50
+ context 'on success' do
51
+ it 'returns a created http status' do
52
+ do_request
53
+ expect(response.status).to eq(201)
54
+ end
55
+
56
+ it 'returns a json' do
57
+ do_request
58
+
59
+ expect(parsed_response.count).to eq(1)
60
+ expect(parsed_response['tag']['name']).to eq('foobar')
61
+ expect(parsed_response['tag']['visible']).to eq(true)
62
+ end
63
+ end
64
+
65
+ context 'on failure' do
66
+ let(:do_request) { post :create, tag: { }, format: :json }
67
+
68
+ it 'returns a unprocessable entity http status' do
69
+ do_request
70
+ expect(response.status).to eq(422)
71
+ end
72
+
73
+ it 'returns a json with errors' do
74
+ do_request
75
+
76
+ expect(parsed_response.count).to eq(1)
77
+ expect(parsed_response['errors']['name']).not_to be_empty
78
+ end
79
+ end
80
+ end
81
+
82
+ describe '#update', authorized: true, admin: true do
83
+ let!(:tag) { FactoryGirl.create(:tag) }
84
+
85
+ let(:do_request) do
86
+ put :update,
87
+ id: tag,
88
+ tag: { name: 'foobar', visible: true }, format: :json
89
+ end
90
+
91
+ context 'on success' do
92
+ it 'returns a no content http status' do
93
+ do_request
94
+ expect(response.status).to eq(204)
95
+ end
96
+ end
97
+
98
+ context 'on failure' do
99
+ let(:do_request) { put :update, id: tag, tag: { name: '' }, format: :json }
100
+
101
+ it 'returns a unprocessable entity http status' do
102
+ do_request
103
+ expect(response.status).to eq(422)
104
+ end
105
+
106
+ it 'returns a json with errors' do
107
+ do_request
108
+
109
+ expect(parsed_response.count).to eq(1)
110
+ expect(parsed_response['errors']['name']).not_to be_empty
111
+ end
112
+ end
113
+ end
114
+
115
+ describe '#show', authorized: true do
116
+ let!(:tag) { FactoryGirl.create(:tag) }
117
+ let(:do_request) { get :show, id: tag, format: :json }
118
+
119
+ it 'returns a success http status' do
120
+ do_request
121
+ expect(response.status).to eq(200)
122
+ end
123
+
124
+ it 'returns a json' do
125
+ do_request
126
+
127
+ expect(parsed_response.count).to eq(1)
128
+ expect(parsed_response['tag']['name']).to eq(tag.name)
129
+ expect(parsed_response['tag']['visible']).to eq(tag.visible)
130
+ end
131
+ end
132
+
133
+ describe '#destroy', authorized: true, admin: true do
134
+ let!(:tag) { FactoryGirl.create(:tag) }
135
+ let(:do_request) { delete :destroy, id: tag, format: :json }
136
+
137
+ it 'returns a success http status' do
138
+ do_request
139
+ expect(response.status).to eq(204)
140
+ expect { tag.reload }.to raise_error
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dune::Api::V1::UsersController do
4
+ routes { Dune::Api::Engine.routes }
5
+ let(:parsed_response) { JSON.parse(response.body) }
6
+ let(:users_returned) do
7
+ parsed_response.fetch('users').map { |t| t['id'] }
8
+ end
9
+
10
+ describe '#index', authorized: true, admin: true do
11
+ let(:do_request) { get :index, format: :json }
12
+
13
+ it_behaves_like 'paginating results'
14
+
15
+ it 'filters by query' do
16
+ FactoryGirl.create(:user, name: 'Ordinary user')
17
+ _user = FactoryGirl.create(:user, name: 'Wonderful user')
18
+ get :index, format: :json, query: 'wonderful'
19
+ expect(users_returned).to eql([_user.id])
20
+ end
21
+ end
22
+
23
+ describe '#show', authorized: true do
24
+ let(:do_request) { get :show, id: user.id, format: :json }
25
+
26
+ it 'responds with 200' do
27
+ do_request
28
+ expect(response.status).to eql(200)
29
+ end
30
+
31
+ it 'has a top level element called user' do
32
+ do_request
33
+ expect(parsed_response.fetch('user')).to be_a(Hash)
34
+ end
35
+
36
+ it 'responds with data of the given user' do
37
+ do_request
38
+ expect(
39
+ parsed_response.fetch('user')
40
+ ).to have_key('id')
41
+ end
42
+ end
43
+ end
data/spec/factories.rb ADDED
@@ -0,0 +1,78 @@
1
+ FactoryGirl.define do
2
+ factory :access_token, class: 'Dune::Api::AccessToken' do
3
+ user
4
+ end
5
+
6
+ factory :category do
7
+ name_pt { "category-#{rand}" }
8
+ end
9
+
10
+ factory :project, class: 'Dune::Api::Project' do
11
+ about 'a-big-text-about-the-project'
12
+ goal 10_000
13
+ headline 'attractive-headline'
14
+ location 'New York, NY'
15
+ name 'z-project'
16
+ state :online
17
+ user
18
+ category
19
+ end
20
+
21
+ factory :investment do
22
+ project { create(:project, state: 'online') }
23
+ user
24
+ confirmed_at Time.now
25
+ value 10.00
26
+ state 'confirmed'
27
+ credits false
28
+ end
29
+
30
+ factory :tag do
31
+ name { "subject-#{rand}" }
32
+ visible true
33
+ end
34
+
35
+ factory :tag_popular, parent: :tag do
36
+ after(:create) do |resource, evaluator|
37
+ projects = create_list(:project, 4, state: :online)
38
+ projects.map do |project|
39
+ project.tags << resource
40
+ project.save
41
+ end
42
+ end
43
+ end
44
+
45
+ factory :user do
46
+ name 'Joãozinho'
47
+ password 'right-password'
48
+ email { "person#{rand}@example.com" }
49
+ confirmed_at { Time.now }
50
+ end
51
+
52
+ factory :channel do
53
+ user { create(:user, profile_type: 'channel') }
54
+ name 'Test'
55
+ description 'Lorem Ipsum'
56
+ sequence(:permalink) { |n| "#{n}-test-page" }
57
+ state 'online'
58
+ end
59
+
60
+ factory :channel_member do
61
+ user
62
+ channel
63
+ end
64
+
65
+ factory :press_asset do
66
+ title 'Lorem'
67
+ url 'http://lorem.com'
68
+ image File.open("#{Dune::Api::Engine.root}/spec/fixtures/image.png")
69
+ end
70
+
71
+ factory :reward do
72
+ project
73
+ title 'Awesome Foo Bar'
74
+ minimum_value 10.00
75
+ description 'Foo bar'
76
+ days_to_delivery 10
77
+ end
78
+ end
Binary file
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dune::Api::Investment do
4
+ describe '.between_values' do
5
+ it 'returns the investments with value between 15 and 20' do
6
+ FactoryGirl.create(:investment, value: 10)
7
+ FactoryGirl.create(:investment, value: 15)
8
+ FactoryGirl.create(:investment, value: 20)
9
+ FactoryGirl.create(:investment, value: 21)
10
+
11
+ expect(described_class.between_values(15, 20).size).to eq 2
12
+ end
13
+
14
+ it 'removes comma and transform it to float' do
15
+ expect(described_class).to receive(:where).with('value between ? and ?', 1000.0, 2000.4)
16
+ described_class.between_values('1,000', '2,000.40')
17
+ end
18
+ end
19
+
20
+ describe '.by_project_id' do
21
+ let(:first_project) { FactoryGirl.create(:project, state: 'online') }
22
+ let(:second_project) { FactoryGirl.create(:project, state: 'online') }
23
+
24
+ before do
25
+ FactoryGirl.create(:investment, value: 10, project: first_project)
26
+ FactoryGirl.create(:investment, value: 10, project: second_project)
27
+ end
28
+
29
+ it 'returns the investments from the first project' do
30
+ expect(described_class.by_project_id(first_project.id).size).to eq 1
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe User do
4
+ describe 'get_access_token' do
5
+ subject { FactoryGirl.create(:user) }
6
+
7
+ context 'when the user does not have an access token' do
8
+ it 'creates an access token and returns its code' do
9
+ expect {
10
+ subject.get_access_token
11
+ }.to change(subject.access_tokens.reload, :count).by(1)
12
+ end
13
+
14
+ it 'returns the last' do
15
+ expect(subject.get_access_token).to eql(subject.access_tokens.last.code)
16
+ end
17
+ end
18
+
19
+ context 'when the user already has one access token' do
20
+ before { subject.access_tokens.create }
21
+
22
+ it 'skips creation of a new' do
23
+ expect {
24
+ subject.get_access_token
25
+ }.to_not change(subject.access_tokens.reload, :count)
26
+ end
27
+
28
+ it 'returns the last' do
29
+ expect(subject.get_access_token).to eql(subject.access_tokens.last.code)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,43 @@
1
+ # Configure Rails Envinronment
2
+ ENV["RAILS_ENV"] = "test"
3
+
4
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
5
+ require 'rspec/rails'
6
+ require 'factories'
7
+
8
+ ENGINE_RAILS_ROOT=File.join(File.dirname(__FILE__), '../')
9
+
10
+ # Requires supporting ruby files with custom matchers and macros, etc,
11
+ # in spec/support/ and its subdirectories.
12
+ Dir[File.join(ENGINE_RAILS_ROOT, "spec/support/**/*.rb")].each {|f| require f }
13
+
14
+ require 'sidekiq/testing'
15
+ Sidekiq::Testing.fake!
16
+
17
+ Geocoder.configure(lookup: :test)
18
+ Geocoder::Lookup::Test.set_default_stub(
19
+ [
20
+ {
21
+ 'latitude' => 40.7143528,
22
+ 'longitude' => -74.0059731,
23
+ 'address' => 'New York, NY, USA',
24
+ 'state' => 'New York',
25
+ 'state_code' => 'NY',
26
+ 'country' => 'United States',
27
+ 'country_code' => 'US'
28
+ }
29
+ ]
30
+ )
31
+
32
+ RSpec.configure do |config|
33
+ config.include RSpec::Rails::ControllerExampleGroup,
34
+ file_path: %r(spec/controllers)
35
+ config.use_transactional_fixtures = true
36
+
37
+ # Stubs required from the main application
38
+ config.before(:each) do
39
+ double(::UserObserver)
40
+ allow_any_instance_of(UserObserver).to receive(:after_create)
41
+ allow_any_instance_of(UserObserver).to receive(:after_save)
42
+ end
43
+ end