introspective_grape 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (165) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.travis.yml +35 -0
  4. data/Gemfile +15 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +103 -0
  7. data/Rakefile +26 -0
  8. data/app/assets/images/introspective_grape/.keep +0 -0
  9. data/app/assets/stylesheets/introspective_grape/.keep +0 -0
  10. data/app/controllers/.keep +0 -0
  11. data/app/helpers/.keep +0 -0
  12. data/app/mailers/.keep +0 -0
  13. data/app/models/.keep +0 -0
  14. data/app/views/.keep +0 -0
  15. data/bin/rails +12 -0
  16. data/introspective_grape.gemspec +49 -0
  17. data/lib/introspective_grape/api.rb +445 -0
  18. data/lib/introspective_grape/camel_snake.rb +71 -0
  19. data/lib/introspective_grape/version.rb +3 -0
  20. data/lib/introspective_grape.rb +4 -0
  21. data/lib/tasks/introspective_grape_tasks.rake +4 -0
  22. data/spec/dummy/Gemfile +4 -0
  23. data/spec/dummy/README.rdoc +28 -0
  24. data/spec/dummy/Rakefile +6 -0
  25. data/spec/dummy/app/api/active_record_helpers.rb +17 -0
  26. data/spec/dummy/app/api/api_helpers.rb +36 -0
  27. data/spec/dummy/app/api/dummy/chat_api.rb +108 -0
  28. data/spec/dummy/app/api/dummy/company_api.rb +8 -0
  29. data/spec/dummy/app/api/dummy/entities.rb +25 -0
  30. data/spec/dummy/app/api/dummy/location_api.rb +37 -0
  31. data/spec/dummy/app/api/dummy/project_api.rb +51 -0
  32. data/spec/dummy/app/api/dummy/role_api.rb +7 -0
  33. data/spec/dummy/app/api/dummy/sessions.rb +55 -0
  34. data/spec/dummy/app/api/dummy/user_api.rb +32 -0
  35. data/spec/dummy/app/api/dummy_api.rb +57 -0
  36. data/spec/dummy/app/api/error_handlers.rb +28 -0
  37. data/spec/dummy/app/api/permissions_helper.rb +7 -0
  38. data/spec/dummy/app/assets/images/.keep +0 -0
  39. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  40. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  41. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  42. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  43. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  44. data/spec/dummy/app/mailers/.keep +0 -0
  45. data/spec/dummy/app/models/.keep +0 -0
  46. data/spec/dummy/app/models/abstract_adapter.rb +13 -0
  47. data/spec/dummy/app/models/admin_user.rb +6 -0
  48. data/spec/dummy/app/models/chat.rb +18 -0
  49. data/spec/dummy/app/models/chat_message.rb +34 -0
  50. data/spec/dummy/app/models/chat_message_user.rb +17 -0
  51. data/spec/dummy/app/models/chat_user.rb +16 -0
  52. data/spec/dummy/app/models/company.rb +14 -0
  53. data/spec/dummy/app/models/concerns/.keep +0 -0
  54. data/spec/dummy/app/models/image.rb +21 -0
  55. data/spec/dummy/app/models/job.rb +10 -0
  56. data/spec/dummy/app/models/locatable.rb +6 -0
  57. data/spec/dummy/app/models/location.rb +26 -0
  58. data/spec/dummy/app/models/location_beacon.rb +16 -0
  59. data/spec/dummy/app/models/location_gps.rb +14 -0
  60. data/spec/dummy/app/models/project.rb +20 -0
  61. data/spec/dummy/app/models/project_job.rb +7 -0
  62. data/spec/dummy/app/models/role.rb +30 -0
  63. data/spec/dummy/app/models/super_user.rb +11 -0
  64. data/spec/dummy/app/models/team.rb +9 -0
  65. data/spec/dummy/app/models/team_user.rb +13 -0
  66. data/spec/dummy/app/models/user/chatter.rb +79 -0
  67. data/spec/dummy/app/models/user.rb +84 -0
  68. data/spec/dummy/app/models/user_location.rb +28 -0
  69. data/spec/dummy/app/models/user_project_job.rb +16 -0
  70. data/spec/dummy/app/policies/application_policy.rb +47 -0
  71. data/spec/dummy/app/policies/chat_policy.rb +22 -0
  72. data/spec/dummy/app/policies/company_policy.rb +32 -0
  73. data/spec/dummy/app/policies/location_policy.rb +29 -0
  74. data/spec/dummy/app/policies/project_policy.rb +42 -0
  75. data/spec/dummy/app/policies/role_policy.rb +33 -0
  76. data/spec/dummy/app/policies/user_location_policy.rb +12 -0
  77. data/spec/dummy/app/policies/user_policy.rb +8 -0
  78. data/spec/dummy/app/views/layouts/application.html.erb +13 -0
  79. data/spec/dummy/bin/bundle +3 -0
  80. data/spec/dummy/bin/rails +4 -0
  81. data/spec/dummy/bin/rake +4 -0
  82. data/spec/dummy/bin/setup +29 -0
  83. data/spec/dummy/config/application.rb +38 -0
  84. data/spec/dummy/config/boot.rb +6 -0
  85. data/spec/dummy/config/database.yml +23 -0
  86. data/spec/dummy/config/environment.rb +11 -0
  87. data/spec/dummy/config/environments/development.rb +41 -0
  88. data/spec/dummy/config/environments/production.rb +79 -0
  89. data/spec/dummy/config/environments/test.rb +43 -0
  90. data/spec/dummy/config/initializers/assets.rb +11 -0
  91. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  92. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  93. data/spec/dummy/config/initializers/devise.rb +262 -0
  94. data/spec/dummy/config/initializers/devise_async.rb +2 -0
  95. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  96. data/spec/dummy/config/initializers/inflections.rb +16 -0
  97. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  98. data/spec/dummy/config/initializers/paperclip.rb +13 -0
  99. data/spec/dummy/config/initializers/paperclip_adapter.rb +13 -0
  100. data/spec/dummy/config/initializers/session_store.rb +3 -0
  101. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  102. data/spec/dummy/config/locales/devise.en.yml +60 -0
  103. data/spec/dummy/config/locales/en.yml +23 -0
  104. data/spec/dummy/config/routes.rb +8 -0
  105. data/spec/dummy/config/secrets.yml +22 -0
  106. data/spec/dummy/config.ru +4 -0
  107. data/spec/dummy/db/migrate/20141002205024_devise_create_users.rb +42 -0
  108. data/spec/dummy/db/migrate/20141002211055_devise_create_admin_users.rb +48 -0
  109. data/spec/dummy/db/migrate/20141002211057_create_active_admin_comments.rb +19 -0
  110. data/spec/dummy/db/migrate/20141002220722_add_lockable_to_users.rb +8 -0
  111. data/spec/dummy/db/migrate/20150406213646_create_companies.rb +11 -0
  112. data/spec/dummy/db/migrate/20150414213154_add_user_authentication_token.rb +11 -0
  113. data/spec/dummy/db/migrate/20150415222005_create_roles.rb +12 -0
  114. data/spec/dummy/db/migrate/20150505181635_create_chats.rb +9 -0
  115. data/spec/dummy/db/migrate/20150505181636_create_chat_users.rb +11 -0
  116. data/spec/dummy/db/migrate/20150505181640_create_chat_messages.rb +11 -0
  117. data/spec/dummy/db/migrate/20150507191529_create_chat_message_users.rb +11 -0
  118. data/spec/dummy/db/migrate/20150601200526_create_locations.rb +12 -0
  119. data/spec/dummy/db/migrate/20150601200533_create_locatables.rb +10 -0
  120. data/spec/dummy/db/migrate/20150601212924_create_location_beacons.rb +15 -0
  121. data/spec/dummy/db/migrate/20150601213542_create_location_gps.rb +12 -0
  122. data/spec/dummy/db/migrate/20150609201823_create_user_locations.rb +14 -0
  123. data/spec/dummy/db/migrate/20150616205336_add_role_user_constraint.rb +9 -0
  124. data/spec/dummy/db/migrate/20150617232519_create_projects.rb +10 -0
  125. data/spec/dummy/db/migrate/20150617232521_create_jobs.rb +9 -0
  126. data/spec/dummy/db/migrate/20150617232522_create_project_jobs.rb +11 -0
  127. data/spec/dummy/db/migrate/20150623170133_create_user_project_jobs.rb +12 -0
  128. data/spec/dummy/db/migrate/20150701234929_create_teams.rb +11 -0
  129. data/spec/dummy/db/migrate/20150701234930_create_team_users.rb +11 -0
  130. data/spec/dummy/db/migrate/20150727214950_add_confirmable_to_devise.rb +11 -0
  131. data/spec/dummy/db/migrate/20150820190524_add_user_names.rb +6 -0
  132. data/spec/dummy/db/migrate/20150824215701_create_images.rb +15 -0
  133. data/spec/dummy/db/migrate/20150909225019_add_password_to_project.rb +5 -0
  134. data/spec/dummy/db/schema.rb +278 -0
  135. data/spec/dummy/lib/assets/.keep +0 -0
  136. data/spec/dummy/log/.keep +0 -0
  137. data/spec/dummy/public/404.html +67 -0
  138. data/spec/dummy/public/422.html +67 -0
  139. data/spec/dummy/public/500.html +66 -0
  140. data/spec/dummy/public/favicon.ico +0 -0
  141. data/spec/fixtures/images/avatar.jpeg +0 -0
  142. data/spec/fixtures/images/exif.jpeg +0 -0
  143. data/spec/models/chat_spec.rb +32 -0
  144. data/spec/models/image_spec.rb +14 -0
  145. data/spec/models/locatable_spec.rb +10 -0
  146. data/spec/models/project_spec.rb +17 -0
  147. data/spec/models/role_spec.rb +63 -0
  148. data/spec/models/team_spec.rb +17 -0
  149. data/spec/models/team_user_spec.rb +20 -0
  150. data/spec/models/user_location_spec.rb +35 -0
  151. data/spec/models/user_project_job_spec.rb +30 -0
  152. data/spec/models/user_spec.rb +125 -0
  153. data/spec/rails_helper.rb +23 -0
  154. data/spec/requests/chat_api_spec.rb +174 -0
  155. data/spec/requests/company_api_spec.rb +61 -0
  156. data/spec/requests/location_api_spec.rb +96 -0
  157. data/spec/requests/project_api_spec.rb +151 -0
  158. data/spec/requests/role_api_spec.rb +37 -0
  159. data/spec/requests/sessions_api_spec.rb +55 -0
  160. data/spec/requests/user_api_spec.rb +191 -0
  161. data/spec/support/blueprints.rb +103 -0
  162. data/spec/support/location_helper.rb +56 -0
  163. data/spec/support/pundit_helpers.rb +13 -0
  164. data/spec/support/request_helpers.rb +22 -0
  165. metadata +562 -0
@@ -0,0 +1,151 @@
1
+ require 'rails_helper'
2
+
3
+ describe Dummy::ProjectAPI, type: :request do
4
+ before :all do
5
+ [User,Project,Company,Location].map(&:destroy_all)
6
+ cm = User.make!(email:'company.admin@springshot.com')
7
+ pm = User.make!(email:'project.admin@springshot.com')
8
+
9
+ 2.times { Project.make! }
10
+
11
+ c = Company.make!(name:"Sprockets")
12
+ p = Project.make!(name:"Manufacture Sprockets", owner: c)
13
+ Project.make!(name:"Disassemble Sprockets", owner: c)
14
+
15
+ cm.admin_companies.push c
16
+ pm.admin_projects.push p
17
+
18
+ cm.save!
19
+ pm.save!
20
+ end
21
+
22
+ let(:company) { Company.find_by_name("Sprockets") }
23
+ let(:project) { Project.find_by_name("Manufacture Sprockets") }
24
+
25
+ context "As a super admin" do
26
+ it "should return a list of all projects" do
27
+ get '/api/v1/projects'
28
+ response.should be_success
29
+ json.length.should == Project.count
30
+ json.map{|c| c['id'].to_i}.include?(project.id).should == true
31
+ end
32
+
33
+ it "should return the specified project" do
34
+ get "/api/v1/projects/#{project.id}"
35
+ response.should be_success
36
+ json['name'].should == project.name
37
+ end
38
+
39
+ it "should return an error if the project doesn't exist" do
40
+ get "/api/v1/projects/#{Project.last.id+1}"
41
+ response.code.should == "404"
42
+ end
43
+
44
+ context "edit a project team" do
45
+
46
+ before(:each) do
47
+ @team = Team.make!(project: project)
48
+ @u1 = User.make!
49
+ @u2 = User.make!
50
+ UserProjectJob.make!(project: project, job: project.jobs.first, user: @u1)
51
+ UserProjectJob.make!(project: project, job: project.jobs.first, user: @u2)
52
+ end
53
+
54
+ context "via nested attributes" do
55
+ it "should create a team with users" do
56
+ p = { name: 'New Team',
57
+ team_users_attributes: [{ user_id: @u1.id }, { user_id: @u2.id }]
58
+ }
59
+ post "/api/v1/projects/#{project.id}/teams", p
60
+ response.should be_success
61
+ Team.last.name.should == 'New Team'
62
+ Team.last.users.to_a.should == [@u1,@u2]
63
+ end
64
+
65
+ it "should add a team member" do
66
+ p = { team_users_attributes: [
67
+ { user_id: @u1.id }, { user_id: @u2.id }
68
+ ] }
69
+ put "/api/v1/projects/#{project.id}/teams/#{@team.id}", p
70
+ response.should be_success
71
+
72
+ Team.last.users.to_a.should == [@u1,@u2]
73
+ end
74
+
75
+ it "should delete a team member" do
76
+ @team.users << [@u1,@u2]
77
+ @team.save!
78
+ p = { team_users_attributes: [
79
+ { id: @team.team_users.where(user_id:@u1.id).first.id, _destroy: 1 }
80
+ ] }
81
+ put "/api/v1/projects/#{project.id}/teams/#{@team.id}", p
82
+ response.should be_success
83
+ Team.last.users.to_a.should == [@u2]
84
+ end
85
+ end
86
+
87
+ context "edit a project team via nested routes" do
88
+ it "should add a team member" do
89
+ p = { user_id: @u1.id }
90
+ post "/api/v1/projects/#{project.id}/teams/#{@team.id}/team_users", p
91
+ response.should be_success
92
+ Team.last.users.to_a.should == [@u1]
93
+ end
94
+
95
+ it "should delete a team member" do
96
+ @team.users << [@u1,@u2]
97
+ @team.save!
98
+ id = @team.team_users.where(user_id:@u1.id).first.id
99
+ delete "/api/v1/projects/#{project.id}/teams/#{@team.id}/team_users/#{id}"
100
+ response.should be_success
101
+ Team.last.users.to_a.should == [@u2]
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ context "As a company admin" do
108
+ before :all do
109
+ @without_authentication = true
110
+ end
111
+
112
+ before :each do
113
+ Grape::Endpoint.before_each do |endpoint|
114
+ allow(endpoint).to receive(:current_user) do
115
+ User.find_by_email("company.admin@springshot.com")
116
+ end
117
+ end
118
+ end
119
+
120
+ it "should return a list of all the company's projects" do
121
+ get '/api/v1/projects'
122
+ response.should be_success
123
+ json.length.should == 2
124
+ json.map{|c| c['name']}.include?("Manufacture Sprockets").should == true
125
+ json.map{|c| c['name']}.include?("Disassemble Sprockets").should == true
126
+ end
127
+
128
+ end
129
+
130
+ context "As a project admin" do
131
+ before :all do
132
+ @without_authentication = true
133
+ end
134
+ before :each do
135
+ Grape::Endpoint.before_each do |endpoint|
136
+ allow(endpoint).to receive(:current_user) do
137
+ User.find_by_email("project.admin@springshot.com")
138
+ end
139
+ end
140
+ end
141
+
142
+ it "should return a list of all the project admin's projects" do
143
+ get '/api/v1/projects'
144
+ response.should be_success
145
+ json.length.should == 1
146
+ json.map{|c| c['name']}.include?("Manufacture Sprockets").should == true
147
+ json.map{|c| c['name']}.include?("Disassemble Sprockets").should == false
148
+ end
149
+ end
150
+
151
+ end
@@ -0,0 +1,37 @@
1
+ require 'rails_helper'
2
+
3
+ describe Dummy::RoleAPI, type: :request do
4
+ let(:role) { Role.last }
5
+ let(:user) { User.last }
6
+
7
+ before :all do
8
+ Role.destroy_all
9
+ User.make!
10
+ Role.make!(user_id: User.last.id, ownable_type: 'SuperUser')
11
+ end
12
+
13
+ it 'should return a list of user roles' do
14
+ get '/api/v1/roles'
15
+ response.should be_success
16
+ json.length.should == 1
17
+ json.first['id'].to_i.should == role.id
18
+ end
19
+
20
+ it 'should return the specified user role' do
21
+ get "/api/v1/roles/#{role.id}"
22
+ response.should be_success
23
+ json['email'].should == role.email
24
+ end
25
+
26
+ it "should return an error if the role doesn't exist" do
27
+ get "/api/v1/roles/#{role.id+1}"
28
+ response.code.should == '404'
29
+ end
30
+
31
+ it 'should not duplicate user roles' do
32
+ post '/api/v1/roles', { user_id: user.id, ownable_type: 'SuperUser' }
33
+ response.code.should == '400'
34
+ json['error'].should =~ /user has already been assigned that role/
35
+ end
36
+
37
+ end
@@ -0,0 +1,55 @@
1
+ require 'rails_helper'
2
+ describe Dummy::Sessions, type: :request do
3
+ @without_authentication = true
4
+
5
+ before :all do
6
+ @without_authentication = true
7
+ User.make!
8
+ end
9
+
10
+ let(:user) { User.last }
11
+
12
+ context :sign_in do
13
+
14
+ it "should set a user token on login" do
15
+ post '/api/v1/sessions', { login: user.email, password: 'abc12345', token: true }
16
+ response.should be_success
17
+ json['id'].to_i.should == user.id
18
+ json['email'].should == user.email
19
+ json['authentication_token'].should be_truthy
20
+ end
21
+
22
+ it "should not set a token if the login fails" do
23
+ post '/api/v1/sessions', { login: user.email, password: 'bad password', token: true }
24
+ response.should_not be_success
25
+ json['error'].should be_truthy
26
+ json['error']['type'].should == 'unauthorized'
27
+ user.authentication_token.should be_nil
28
+ end
29
+ end
30
+
31
+ context :sign_out do
32
+ it "should reset a user's auth token" do
33
+ user.authentication_token = "1234567890"
34
+ user.save!
35
+ delete "/api/v1/sessions", { api_key: "1234567890" }
36
+ response.should be_success
37
+ user.reload
38
+ user.authentication_token.should be_nil
39
+ end
40
+
41
+ it "signing out an already signed-out user should look fine, right?" do
42
+ user.authentication_token = "1234567890"
43
+ user.save!
44
+ delete "/api/v1/sessions", { api_key: "1234567890" }
45
+ response.should be_success
46
+ user.reload
47
+ user.authentication_token.should be_nil
48
+ delete "/api/v1/sessions", { api_key: "1234567890" }
49
+ response.should be_success
50
+ user.reload
51
+ user.authentication_token.should be_nil
52
+ end
53
+ end
54
+
55
+ end
@@ -0,0 +1,191 @@
1
+ require 'rails_helper'
2
+ describe Dummy::UserAPI, type: :request do
3
+
4
+ let(:user) { User.last || User.make!}
5
+ let(:company) { Company.last || Company.make! }
6
+
7
+ before :all do
8
+ User.destroy_all
9
+ c = Company.make
10
+ u = User.make
11
+ u.roles.push Role.new(ownable: c)
12
+ u.save
13
+ end
14
+
15
+ context :index do
16
+
17
+ it "should return a list of users" do
18
+ get '/api/v1/users'
19
+ response.should be_success
20
+ json.length.should == 1
21
+ json.first['id'].to_i.should == user.id
22
+ json.first['first_name'].should == user.first_name
23
+ json.first['last_name'].should == user.last_name
24
+ json.first['roles_attributes'].size.should == 1
25
+ json.first['roles_attributes'].first['ownable_type'].should == 'Company'
26
+ json.first['roles_attributes'].first['ownable_id'].should == company.id
27
+ end
28
+
29
+ it "should not expose users' encrypted_passwords" do
30
+ get "/api/v1/users"
31
+ response.should be_success
32
+ json.first['encrypted_password'].should be_nil
33
+ end
34
+ end
35
+
36
+
37
+ context :show do
38
+ it "should return the specified user" do
39
+ get "/api/v1/users/#{user.id}"
40
+ response.should be_success
41
+ json['email'].should == user.email
42
+ end
43
+
44
+ it "should not expose a user's encrypted_password" do
45
+ get "/api/v1/users/#{user.id}"
46
+ response.should be_success
47
+ json['encrypted_password'].should be_nil
48
+ end
49
+
50
+ it "should return an error if the user doesn't exist" do
51
+ get "/api/v1/users/#{user.id+1}"
52
+ response.code.should == "404"
53
+ end
54
+ end
55
+
56
+
57
+ context :create do
58
+
59
+ it "should create a user and send the confirmation email" do
60
+ post "/api/v1/users", { email: 'email@test.com', password: 'abc12345' }
61
+ response.should be_success
62
+ json['email'].should == user.email
63
+ User.last.confirmed_at.should == nil
64
+ User.last.confirmation_sent_at.should_not == nil
65
+ end
66
+
67
+ it "should create a user and skip the confirmation email" do
68
+ post "/api/v1/users", { email: 'email@test.com', password: 'abc12345', skip_confirmation_email: true }
69
+ response.should be_success
70
+ json['email'].should == user.email
71
+ User.last.confirmed_at.should_not == nil
72
+ User.last.confirmation_sent_at.should == nil
73
+ end
74
+
75
+ it "should validate a new user" do
76
+ post "/api/v1/users", { email: 'a'*257, password: '' }
77
+ response.code.should == "400"
78
+ json['error'].should == "Email: is invalid, Password: can't be blank"
79
+ end
80
+
81
+ let(:params) do
82
+ { email: 'test@test.com', password: 'abc12345', roles_attributes:[] }
83
+ end
84
+
85
+ let(:role) do
86
+ { ownable_id: company.id, ownable_type: 'Company' }
87
+ end
88
+
89
+ it "should create a company admin" do
90
+ params[:roles_attributes].push(role)
91
+ post "/api/v1/users", params
92
+ response.should be_success
93
+ User.last.admin?(company).should be_truthy
94
+ end
95
+
96
+
97
+ context "Project default passwords for new users" do
98
+ let(:job) { Job.make! }
99
+ let(:project) { Project.make!(jobs: [job], default_password: "super secret") }
100
+ let(:params) do
101
+ {
102
+ email: 'test@test.com', password: '',
103
+ user_project_jobs_attributes: [ job_id: project.jobs.first.id, project_id: project.id ]
104
+ }
105
+ end
106
+
107
+ it "should set an empty password to an assigned project's default password" do
108
+ post "/api/v1/users", params
109
+ response.should be_success
110
+ json['user_project_jobs_attributes'][0]['name'].should == project.name
111
+ json['user_project_jobs_attributes'][0]['title'].should == job.title
112
+ end
113
+
114
+ it "should return a validation error if the user's assigned project has no default password" do
115
+ project.update_attributes(default_password: nil)
116
+ post "/api/v1/users", params
117
+ response.status.should == 400
118
+ json['error'].should == "Password: can't be blank"
119
+ end
120
+ end
121
+
122
+ end
123
+
124
+ context :update do
125
+ it "should upload a user avatar via the root route" do
126
+ params = { avatar_attributes: { file: Rack::Test::UploadedFile.new(Rails.root+'../fixtures/images/avatar.jpeg', 'image/jpeg', true) } }
127
+
128
+ put "/api/v1/users/#{user.id}", params
129
+
130
+ response.should be_success
131
+ user.avatar.should == Image.last
132
+ user.avatar_url.should == Image.last.file.url(:medium)
133
+ end
134
+
135
+ it "should upload a user avatar via the nested route, to test the restful api's handling of has_one associations" do
136
+ params = { file: Rack::Test::UploadedFile.new(Rails.root+'../fixtures/images/avatar.jpeg', 'image/jpeg', true) }
137
+
138
+ post "/api/v1/users/#{user.id}/avatars", params
139
+
140
+ response.should be_success
141
+ user.avatar.should == Image.last
142
+ user.avatar_url.should == Image.last.file.url(:medium)
143
+ user.avatar_url
144
+ end
145
+
146
+ it "should require a devise re-confirmation email to update a user's email address" do
147
+ new_email = 'new.email@test.com'
148
+ old_email = user.email
149
+ put "/api/v1/users/#{user.id}", { email: new_email }
150
+ response.should be_success
151
+ user.reload
152
+ user.email.should == old_email
153
+ user.unconfirmed_email.should == new_email
154
+ json['email'].should == old_email
155
+ end
156
+
157
+ it "should skip the confirmation and update a user's email address" do
158
+ new_email = 'new.email@test.com'
159
+ put "/api/v1/users/#{user.id}", { email: new_email, skip_confirmation_email: true }
160
+ response.should be_success
161
+ json['email'].should == new_email
162
+ user.reload
163
+ user.email.should == new_email
164
+ end
165
+
166
+ it "should validate the uniqueness of a user role" do
167
+ put "/api/v1/users/#{user.id}", { roles_attributes: [{ownable_type: 'Company', ownable_id: company.id}] }
168
+ response.should_not be_success
169
+ json['error'].should =~ /user has already been assigned that role/
170
+ user.admin?(company).should be_truthy
171
+ end
172
+
173
+ it "should update a user to be company admin" do
174
+ c = Company.make
175
+ c.save!
176
+ put "/api/v1/users/#{user.id}", { roles_attributes: [{ownable_type: 'Company', ownable_id: c.id}] }
177
+ response.should be_success
178
+ user.reload
179
+ user.admin?(c).should be_truthy
180
+ end
181
+
182
+ it "should destroy a user's company admin role" do
183
+ user.admin?(company).should be_truthy
184
+ put "/api/v1/users/#{user.id}", { roles_attributes: [{id: user.roles.last.id, _destroy: '1'}] }
185
+ response.should be_success
186
+ user.reload
187
+ user.admin?(company).should be_falsey
188
+ end
189
+ end
190
+
191
+ end
@@ -0,0 +1,103 @@
1
+ require 'machinist/active_record'
2
+ require 'rufus/mnemo'
3
+
4
+ def _index # prevent unique string collisions over the test cycle
5
+ @_uniq_idx ||= 0
6
+ (@_uniq_idx+=1).to_s(36)
7
+ end
8
+
9
+ def syllable(length=-1)
10
+ s = Rufus::Mnemo::from_integer(rand(8**5)+1) #+ _index
11
+ s[0..length]
12
+ end
13
+
14
+ def word(max_syl=3)
15
+ (1+rand(max_syl)).times.collect { syllable }.join
16
+ end
17
+
18
+ def words(n=3)
19
+ n.times.collect { word }.join
20
+ end
21
+
22
+ def paragraph(n=25)
23
+ words(n)
24
+ end
25
+
26
+ Company.blueprint do
27
+ name { words }
28
+ short_name { syllable(10) }
29
+ end
30
+
31
+ User.blueprint do
32
+ email { "test-"+syllable+'@springshot.com' }
33
+ first_name { word(4) }
34
+ last_name { word(5) }
35
+ password { 'abc12345' }
36
+ confirmed_at { Time.now }
37
+ end
38
+
39
+ Role.blueprint {
40
+ user_id { User.first||User.make }
41
+ ownable_id { Company.first||Company.make }
42
+ ownable_type { 'Company' }
43
+ }
44
+
45
+ Locatable.blueprint {
46
+ location { Location.make }
47
+ locatable { Company.make }
48
+ }
49
+ Location.blueprint {
50
+ name { (65+rand(8)).chr+"1"}
51
+ kind { 'gate' }
52
+ gps { LocationGps.new(lat: 37.615223, lng: -122.389977 ) }
53
+ }
54
+ LocationBeacon.blueprint {
55
+ location { Location.make }
56
+ company { Company.make }
57
+ mac_address { SecureRandom.hex(6) }
58
+ # e.g. 2F234454-CF6D-4A0F-ADF2-F4911BA9FFA6
59
+ uuid { SecureRandom.hex(4)+'-'+SecureRandom.hex(2)+'-'+SecureRandom.hex(2)+'-'+SecureRandom.hex(2)+'-'+SecureRandom.hex(6) }
60
+ major { rand(9999) }
61
+ minor { rand(9999) }
62
+ }
63
+ LocationGps.blueprint {
64
+ location { Location.make }
65
+ # place the point randomly within about a mile radius of the TEST airport (LocationHelper)
66
+ lat { 37.615223 + 0.01609*rand(0.1) * (rand(2) > 0 ? 1 : -1) }
67
+ lng { -122.389977 + 0.01609*rand(0.1)*Math.cos(37.615223*Math::PI/180) * (rand(2) > 0 ? 1 : -1) }
68
+ alt { 0 }
69
+ }
70
+
71
+ Project.blueprint {
72
+ name { words(2) }
73
+ owner { Company.make }
74
+ jobs { [Job.make, Job.make] }
75
+ admins { [User.make] }
76
+ }
77
+ Job.blueprint {
78
+ title { words(2) }
79
+ }
80
+ UserProjectJob.blueprint {
81
+ user { User.make }
82
+ project { Project.make }
83
+ job { Job.make }
84
+ }
85
+ ProjectJob.blueprint {
86
+ project { Project.make }
87
+ job { Job.make }
88
+ }
89
+
90
+
91
+ Team.blueprint {
92
+ p = Project.make
93
+ project { p }
94
+ creator { p.admins.first }
95
+ name { words(2) }
96
+ }
97
+ TeamUser.blueprint {
98
+ t = Team.make
99
+ t.project.users.push User.make(projects: [t.project])
100
+ team { t }
101
+ user { t.project.users.first }
102
+ }
103
+
@@ -0,0 +1,56 @@
1
+ module LocationHelper
2
+
3
+ def rand_coords # generate a random point somewhere around the test airport
4
+ l = LocationGps.make
5
+ [l.lat,l.lng,l.alt]
6
+ end
7
+
8
+ def create_test_airport
9
+ ### build an airport with 8 terminals each with 3 gates along each cardinal and ordinal
10
+ ### axis, for two companies each with their own set of bluetooth beacons at every gate:
11
+ ###
12
+ ### (1)A B C
13
+ ### \|/
14
+ ### (8)H-*-D e.g.->(Terminal D with gates D1, D2, and D3)
15
+ ### /|\
16
+ ### G F E
17
+
18
+ @sprocketCo = Company.find_by_name("Sprockets") || Company.make(name:'Sprockets')
19
+ @widgetCo = Company.find_by_name("Widgets") || Company.make(name:'Widgets')
20
+ if @airport = Location.find_by_name("TEST")
21
+ return @airport
22
+ end
23
+
24
+ @airport = Location.new(name:'TEST',kind:'airport')
25
+ @airport.companies.push @sprocketCo
26
+ @airport.companies.push @widgetCo
27
+ @airport.gps = LocationGps.new(lat: 37.615223, lng: -122.389977 )
28
+ (1..8).each do |terminal|
29
+ gate = (64+terminal).chr # A-H
30
+ t = Location.new(name:"Terminal #{gate}",kind:'terminal')
31
+
32
+ @airport.child_locations.push t
33
+
34
+ (1..3).each do |number|
35
+
36
+ lat, lng = [@airport.gps.lat, @airport.gps.lng]
37
+ adj = 0.003*number # push successive gates ~0.21 miles out
38
+
39
+ lat += (1..3).include?(terminal) ? adj : 0
40
+ lat -= (5..7).include?(terminal) ? adj : 0
41
+
42
+ adj *= Math.cos(37.615223*Math::PI/180)
43
+ lng += (3..5).include?( terminal) ? adj : 0
44
+ lng -= [1,7,8].include?(terminal) ? adj : 0
45
+
46
+ g = Location.new(name:"Gate #{gate}#{number}", kind:'gate')
47
+ g.gps = LocationGps.make(location: g, lat: lat, lng: lng)
48
+ g.beacons.push LocationBeacon.make(company: @sprocketCo, location: g)
49
+ g.beacons.push LocationBeacon.make(company: @widgetCo, location: g)
50
+ t.child_locations.push g
51
+ end
52
+ end
53
+ @airport.save!
54
+ @airport
55
+ end
56
+ end
@@ -0,0 +1,13 @@
1
+ RSpec::Matchers.define :permit do |action|
2
+ match do |policy|
3
+ policy.public_send("#{action}?")
4
+ end
5
+
6
+ failure_message_when_negated do |policy|
7
+ "#{policy.class} does not permit #{action} on #{policy.record} for #{policy.user.inspect}."
8
+ end
9
+
10
+ failure_message do |policy|
11
+ "#{policy.class} does not forbid #{action} on #{policy.record} for #{policy.user.inspect}."
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ require 'introspective_grape/camel_snake'
2
+ module RequestHelpers
3
+ include IntrospectiveGrape::CamelSnake
4
+
5
+ def json
6
+ @json ||= snake_keys(JSON.parse(response.body))
7
+ end
8
+
9
+ def with_authentication(role=:superuser)
10
+ return if @without_authentication
11
+ current_user = User.new #double('User')
12
+ allow(current_user).to receive(:admin?) { true } if role == :superuser
13
+ allow(current_user).to receive(:superuser?) { true } if role == :superuser
14
+
15
+ # Stubbing API helper methods requires this very nearly undocumented invokation
16
+ Grape::Endpoint.before_each do |endpoint|
17
+ allow(endpoint).to receive(:current_user) { current_user }
18
+ end
19
+ end
20
+ end
21
+
22
+