introspective_grape 0.0.3
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.
- 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
|
+
|