introspective_grape 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +35 -0
- data/Gemfile +15 -0
- data/MIT-LICENSE +20 -0
- data/README.md +103 -0
- data/Rakefile +26 -0
- data/app/assets/images/introspective_grape/.keep +0 -0
- data/app/assets/stylesheets/introspective_grape/.keep +0 -0
- data/app/controllers/.keep +0 -0
- data/app/helpers/.keep +0 -0
- data/app/mailers/.keep +0 -0
- data/app/models/.keep +0 -0
- data/app/views/.keep +0 -0
- data/bin/rails +12 -0
- data/introspective_grape.gemspec +49 -0
- data/lib/introspective_grape/api.rb +445 -0
- data/lib/introspective_grape/camel_snake.rb +71 -0
- data/lib/introspective_grape/version.rb +3 -0
- data/lib/introspective_grape.rb +4 -0
- data/lib/tasks/introspective_grape_tasks.rake +4 -0
- data/spec/dummy/Gemfile +4 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/api/active_record_helpers.rb +17 -0
- data/spec/dummy/app/api/api_helpers.rb +36 -0
- data/spec/dummy/app/api/dummy/chat_api.rb +108 -0
- data/spec/dummy/app/api/dummy/company_api.rb +8 -0
- data/spec/dummy/app/api/dummy/entities.rb +25 -0
- data/spec/dummy/app/api/dummy/location_api.rb +37 -0
- data/spec/dummy/app/api/dummy/project_api.rb +51 -0
- data/spec/dummy/app/api/dummy/role_api.rb +7 -0
- data/spec/dummy/app/api/dummy/sessions.rb +55 -0
- data/spec/dummy/app/api/dummy/user_api.rb +32 -0
- data/spec/dummy/app/api/dummy_api.rb +57 -0
- data/spec/dummy/app/api/error_handlers.rb +28 -0
- data/spec/dummy/app/api/permissions_helper.rb +7 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/abstract_adapter.rb +13 -0
- data/spec/dummy/app/models/admin_user.rb +6 -0
- data/spec/dummy/app/models/chat.rb +18 -0
- data/spec/dummy/app/models/chat_message.rb +34 -0
- data/spec/dummy/app/models/chat_message_user.rb +17 -0
- data/spec/dummy/app/models/chat_user.rb +16 -0
- data/spec/dummy/app/models/company.rb +14 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/models/image.rb +21 -0
- data/spec/dummy/app/models/job.rb +10 -0
- data/spec/dummy/app/models/locatable.rb +6 -0
- data/spec/dummy/app/models/location.rb +26 -0
- data/spec/dummy/app/models/location_beacon.rb +16 -0
- data/spec/dummy/app/models/location_gps.rb +14 -0
- data/spec/dummy/app/models/project.rb +20 -0
- data/spec/dummy/app/models/project_job.rb +7 -0
- data/spec/dummy/app/models/role.rb +30 -0
- data/spec/dummy/app/models/super_user.rb +11 -0
- data/spec/dummy/app/models/team.rb +9 -0
- data/spec/dummy/app/models/team_user.rb +13 -0
- data/spec/dummy/app/models/user/chatter.rb +79 -0
- data/spec/dummy/app/models/user.rb +84 -0
- data/spec/dummy/app/models/user_location.rb +28 -0
- data/spec/dummy/app/models/user_project_job.rb +16 -0
- data/spec/dummy/app/policies/application_policy.rb +47 -0
- data/spec/dummy/app/policies/chat_policy.rb +22 -0
- data/spec/dummy/app/policies/company_policy.rb +32 -0
- data/spec/dummy/app/policies/location_policy.rb +29 -0
- data/spec/dummy/app/policies/project_policy.rb +42 -0
- data/spec/dummy/app/policies/role_policy.rb +33 -0
- data/spec/dummy/app/policies/user_location_policy.rb +12 -0
- data/spec/dummy/app/policies/user_policy.rb +8 -0
- data/spec/dummy/app/views/layouts/application.html.erb +13 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +29 -0
- data/spec/dummy/config/application.rb +38 -0
- data/spec/dummy/config/boot.rb +6 -0
- data/spec/dummy/config/database.yml +23 -0
- data/spec/dummy/config/environment.rb +11 -0
- data/spec/dummy/config/environments/development.rb +41 -0
- data/spec/dummy/config/environments/production.rb +79 -0
- data/spec/dummy/config/environments/test.rb +43 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/devise.rb +262 -0
- data/spec/dummy/config/initializers/devise_async.rb +2 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/paperclip.rb +13 -0
- data/spec/dummy/config/initializers/paperclip_adapter.rb +13 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/devise.en.yml +60 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +8 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20141002205024_devise_create_users.rb +42 -0
- data/spec/dummy/db/migrate/20141002211055_devise_create_admin_users.rb +48 -0
- data/spec/dummy/db/migrate/20141002211057_create_active_admin_comments.rb +19 -0
- data/spec/dummy/db/migrate/20141002220722_add_lockable_to_users.rb +8 -0
- data/spec/dummy/db/migrate/20150406213646_create_companies.rb +11 -0
- data/spec/dummy/db/migrate/20150414213154_add_user_authentication_token.rb +11 -0
- data/spec/dummy/db/migrate/20150415222005_create_roles.rb +12 -0
- data/spec/dummy/db/migrate/20150505181635_create_chats.rb +9 -0
- data/spec/dummy/db/migrate/20150505181636_create_chat_users.rb +11 -0
- data/spec/dummy/db/migrate/20150505181640_create_chat_messages.rb +11 -0
- data/spec/dummy/db/migrate/20150507191529_create_chat_message_users.rb +11 -0
- data/spec/dummy/db/migrate/20150601200526_create_locations.rb +12 -0
- data/spec/dummy/db/migrate/20150601200533_create_locatables.rb +10 -0
- data/spec/dummy/db/migrate/20150601212924_create_location_beacons.rb +15 -0
- data/spec/dummy/db/migrate/20150601213542_create_location_gps.rb +12 -0
- data/spec/dummy/db/migrate/20150609201823_create_user_locations.rb +14 -0
- data/spec/dummy/db/migrate/20150616205336_add_role_user_constraint.rb +9 -0
- data/spec/dummy/db/migrate/20150617232519_create_projects.rb +10 -0
- data/spec/dummy/db/migrate/20150617232521_create_jobs.rb +9 -0
- data/spec/dummy/db/migrate/20150617232522_create_project_jobs.rb +11 -0
- data/spec/dummy/db/migrate/20150623170133_create_user_project_jobs.rb +12 -0
- data/spec/dummy/db/migrate/20150701234929_create_teams.rb +11 -0
- data/spec/dummy/db/migrate/20150701234930_create_team_users.rb +11 -0
- data/spec/dummy/db/migrate/20150727214950_add_confirmable_to_devise.rb +11 -0
- data/spec/dummy/db/migrate/20150820190524_add_user_names.rb +6 -0
- data/spec/dummy/db/migrate/20150824215701_create_images.rb +15 -0
- data/spec/dummy/db/migrate/20150909225019_add_password_to_project.rb +5 -0
- data/spec/dummy/db/schema.rb +278 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/fixtures/images/avatar.jpeg +0 -0
- data/spec/fixtures/images/exif.jpeg +0 -0
- data/spec/models/chat_spec.rb +32 -0
- data/spec/models/image_spec.rb +14 -0
- data/spec/models/locatable_spec.rb +10 -0
- data/spec/models/project_spec.rb +17 -0
- data/spec/models/role_spec.rb +63 -0
- data/spec/models/team_spec.rb +17 -0
- data/spec/models/team_user_spec.rb +20 -0
- data/spec/models/user_location_spec.rb +35 -0
- data/spec/models/user_project_job_spec.rb +30 -0
- data/spec/models/user_spec.rb +125 -0
- data/spec/rails_helper.rb +23 -0
- data/spec/requests/chat_api_spec.rb +174 -0
- data/spec/requests/company_api_spec.rb +61 -0
- data/spec/requests/location_api_spec.rb +96 -0
- data/spec/requests/project_api_spec.rb +151 -0
- data/spec/requests/role_api_spec.rb +37 -0
- data/spec/requests/sessions_api_spec.rb +55 -0
- data/spec/requests/user_api_spec.rb +191 -0
- data/spec/support/blueprints.rb +103 -0
- data/spec/support/location_helper.rb +56 -0
- data/spec/support/pundit_helpers.rb +13 -0
- data/spec/support/request_helpers.rb +22 -0
- 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
|
+
|