introspective_admin 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +279 -0
- data/LICENSE +22 -0
- data/MIT-LICENSE +20 -0
- data/README.md +52 -0
- data/Rakefile +26 -0
- data/bin/rails +12 -0
- data/introspective_admin.gemspec +38 -0
- data/lib/introspective_admin/base.rb +170 -0
- data/lib/introspective_admin/version.rb +3 -0
- data/lib/introspective_admin.rb +4 -0
- data/lib/tasks/introspective_admin_tasks.rake +4 -0
- data/spec/admin/company_admin_spec.rb +72 -0
- data/spec/admin/job_admin_spec.rb +61 -0
- data/spec/admin/location_admin_spec.rb +65 -0
- data/spec/admin/project__admin_spec.rb +71 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/admin/company_admin.rb +4 -0
- data/spec/dummy/app/admin/job_admin.rb +4 -0
- data/spec/dummy/app/admin/location_admin.rb +4 -0
- data/spec/dummy/app/admin/project_admin.rb +6 -0
- data/spec/dummy/app/admin/role_admin.rb +5 -0
- data/spec/dummy/app/admin/user_admin.rb +9 -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 +12 -0
- data/spec/dummy/app/models/concerns/.keep +0 -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 +64 -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 +25 -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 +75 -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/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 +32 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +18 -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/active_admin.rb +7 -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 +260 -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/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +9 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/development.sqlite3 +0 -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/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/20150909225019_add_password_to_project.rb +5 -0
- data/spec/dummy/db/schema.rb +261 -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/rails_helper.rb +13 -0
- data/spec/support/blueprints.rb +119 -0
- data/spec/support/location_helper.rb +56 -0
- metadata +420 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
require 'rails_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe Admin::CompaniesController, :type => :controller do
|
|
4
|
+
render_views
|
|
5
|
+
|
|
6
|
+
before :each do
|
|
7
|
+
user = double('user')
|
|
8
|
+
allow(request.env['warden']).to receive(:authenticate!) { user }
|
|
9
|
+
allow(controller).to receive(:current_user) { user }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe "GET index" do
|
|
13
|
+
it "finds all companies" do
|
|
14
|
+
c = Company.make!
|
|
15
|
+
get :index
|
|
16
|
+
response.status.should == 200
|
|
17
|
+
assigns(:companies).include?(c).should == true
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe "SHOW record" do
|
|
22
|
+
it "finds the record" do
|
|
23
|
+
c = Company.make!
|
|
24
|
+
get :show, id: c.id
|
|
25
|
+
response.status.should == 200
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe "NEW record" do
|
|
30
|
+
it "renders the form for a new record" do
|
|
31
|
+
get :new
|
|
32
|
+
response.status.should == 200
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe "CREATE record" do
|
|
37
|
+
it "creates the record" do
|
|
38
|
+
c = Company.make
|
|
39
|
+
post :create, company: c.attributes
|
|
40
|
+
response.should redirect_to action: :show, id: Company.last.id
|
|
41
|
+
Company.last.name.should == c.name
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "creates a record with an admin" do
|
|
45
|
+
u = User.make!
|
|
46
|
+
c = Company.make
|
|
47
|
+
post :create, company: c.attributes.merge({
|
|
48
|
+
roles_attributes: {'0'=>{ user_id: u.id }}
|
|
49
|
+
})
|
|
50
|
+
response.should redirect_to action: :show, id: Company.last.id
|
|
51
|
+
Company.last.admins.include?(u).should be_truthy
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
describe "EDIT record" do
|
|
57
|
+
it "renders the edit form for an existing record" do
|
|
58
|
+
r = Company.make!
|
|
59
|
+
get :edit, id: r.id
|
|
60
|
+
response.status.should == 200
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
describe "UPDATE record" do
|
|
65
|
+
it "updates the record" do
|
|
66
|
+
c = Company.make!
|
|
67
|
+
put :update, id: c.id, company: { name: "New Name" }
|
|
68
|
+
response.should redirect_to action: :show, id: c.id
|
|
69
|
+
Company.find(c.id).name.should == "New Name"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require 'rails_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe Admin::JobsController, :type => :controller do
|
|
4
|
+
render_views
|
|
5
|
+
|
|
6
|
+
before :each do # Why can't I do this shit in a helper like I do for requests?
|
|
7
|
+
user = double('user')
|
|
8
|
+
allow(request.env['warden']).to receive(:authenticate!) { user }
|
|
9
|
+
allow(controller).to receive(:current_user) { user }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe "GET index" do
|
|
13
|
+
it "finds all Jobs" do
|
|
14
|
+
r = Job.make!
|
|
15
|
+
get :index
|
|
16
|
+
response.status.should == 200
|
|
17
|
+
assigns(:jobs).include?(r).should == true
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe "SHOW record" do
|
|
22
|
+
it "finds the record" do
|
|
23
|
+
r = Job.make!
|
|
24
|
+
get :show, id: r.id
|
|
25
|
+
response.status.should == 200
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe "NEW record" do
|
|
30
|
+
it "renders the form for a new record" do
|
|
31
|
+
get :new
|
|
32
|
+
response.status.should == 200
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe "CREATE record" do
|
|
37
|
+
it "creates the record" do
|
|
38
|
+
r = Job.make
|
|
39
|
+
post :create, job: r.attributes
|
|
40
|
+
response.should redirect_to action: :show, id: Job.last.id
|
|
41
|
+
Job.last.title.should == r.title
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe "EDIT record" do
|
|
46
|
+
it "renders the edit form for an existing record" do
|
|
47
|
+
r = Job.make!
|
|
48
|
+
get :edit, id: r.id
|
|
49
|
+
response.status.should == 200
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe "UPDATE record" do
|
|
54
|
+
it "updates the record" do
|
|
55
|
+
r = Job.make!
|
|
56
|
+
put :update, id: r.id, job: { title: "New Name" }
|
|
57
|
+
response.should redirect_to action: :show, id: r.id
|
|
58
|
+
Job.find(r.id).title.should == "New Name"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
require 'rails_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe Admin::LocationsController, :type => :controller do
|
|
4
|
+
render_views
|
|
5
|
+
|
|
6
|
+
before :each do # Why can't I do this shit in a helper like I do for requests?
|
|
7
|
+
user = double('user')
|
|
8
|
+
allow(request.env['warden']).to receive(:authenticate!) { user }
|
|
9
|
+
allow(controller).to receive(:current_user) { user }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe "GET index" do
|
|
13
|
+
it "finds all locations" do
|
|
14
|
+
c = Location.make!
|
|
15
|
+
get :index
|
|
16
|
+
response.status.should == 200
|
|
17
|
+
assigns(:locations).include?(c).should == true
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe "SHOW record" do
|
|
22
|
+
it "finds the record" do
|
|
23
|
+
c = Location.make!
|
|
24
|
+
get :show, id: c.id
|
|
25
|
+
response.status.should == 200
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe "NEW record" do
|
|
30
|
+
# will fail until https://github.com/activeadmin/activeadmin/pull/4010 is merged
|
|
31
|
+
it "renders the form for a new record" do
|
|
32
|
+
get :new
|
|
33
|
+
response.status.should == 200
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe "CREATE record" do
|
|
38
|
+
it "creates the record" do
|
|
39
|
+
c = Location.make
|
|
40
|
+
gps = LocationGps.make
|
|
41
|
+
post :create, location: c.attributes.merge(gps_attributes: gps.attributes)
|
|
42
|
+
response.should redirect_to action: :show, id: Location.last.id
|
|
43
|
+
Location.last.name.should == c.name
|
|
44
|
+
Location.last.gps.lat.round(10).should == gps.lat.round(10)
|
|
45
|
+
Location.last.gps.lng.round(10).should == gps.lng.round(10)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe "EDIT record" do
|
|
50
|
+
it "renders the edit form for an existing record" do
|
|
51
|
+
r = Location.make!
|
|
52
|
+
get :edit, id: r.id
|
|
53
|
+
response.status.should == 200
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe "UPDATE record" do
|
|
58
|
+
it "updates the record" do
|
|
59
|
+
r = Location.make!
|
|
60
|
+
put :update, id: r.id, location: { name: "New Name" }
|
|
61
|
+
response.should redirect_to action: :show, id: r.id
|
|
62
|
+
Location.find(r.id).name.should == "New Name"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require 'rails_helper'
|
|
2
|
+
RSpec.describe Admin::ProjectsController, :type => :controller do
|
|
3
|
+
render_views
|
|
4
|
+
|
|
5
|
+
before :each do # Why can't I do this shit in a helper like I do for requests?
|
|
6
|
+
user = double('user')
|
|
7
|
+
allow(request.env['warden']).to receive(:authenticate!) { user }
|
|
8
|
+
allow(controller).to receive(:current_user) { user }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe "GET index" do
|
|
12
|
+
it "finds all projects" do
|
|
13
|
+
r = Project.make!
|
|
14
|
+
get :index
|
|
15
|
+
response.status.should == 200
|
|
16
|
+
assigns(:projects).include?(r).should == true
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "SHOW record" do
|
|
21
|
+
it "finds the record" do
|
|
22
|
+
r = Project.make!
|
|
23
|
+
get :show, id: r.id
|
|
24
|
+
response.status.should == 200
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe "NEW record" do
|
|
29
|
+
it "renders the form for a new record" do
|
|
30
|
+
get :new
|
|
31
|
+
response.status.should == 200
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
describe "CREATE record" do
|
|
36
|
+
it "creates the record" do
|
|
37
|
+
r = Project.make
|
|
38
|
+
post :create, project: r.attributes
|
|
39
|
+
response.should redirect_to action: :show, id: Project.last.id
|
|
40
|
+
Project.last.name.should == r.name
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "the inverse_of declaration allows a new project to be created with a project_job" do
|
|
44
|
+
j = Job.make!
|
|
45
|
+
r = Project.make
|
|
46
|
+
post :create, project: r.attributes.merge({project_jobs_attributes:{'0'=>{job_id: j.id}}})
|
|
47
|
+
p = Project.last
|
|
48
|
+
p.name.should == r.name
|
|
49
|
+
p.project_jobs.size.should == 1
|
|
50
|
+
p.project_jobs.first.job.should == j
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
describe "EDIT record" do
|
|
56
|
+
it "renders the edit form for an existing record" do
|
|
57
|
+
r = Project.make!
|
|
58
|
+
get :edit, id: r.id
|
|
59
|
+
response.status.should == 200
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
describe "UPDATE record" do
|
|
64
|
+
it "updates the record" do
|
|
65
|
+
r = Project.make!
|
|
66
|
+
put :update, id: r.id, project: { name: "New Name" }
|
|
67
|
+
response.should redirect_to action: :show, id: r.id
|
|
68
|
+
Project.find(r.id).name.should == "New Name"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
== README
|
|
2
|
+
|
|
3
|
+
This README would normally document whatever steps are necessary to get the
|
|
4
|
+
application up and running.
|
|
5
|
+
|
|
6
|
+
Things you may want to cover:
|
|
7
|
+
|
|
8
|
+
* Ruby version
|
|
9
|
+
|
|
10
|
+
* System dependencies
|
|
11
|
+
|
|
12
|
+
* Configuration
|
|
13
|
+
|
|
14
|
+
* Database creation
|
|
15
|
+
|
|
16
|
+
* Database initialization
|
|
17
|
+
|
|
18
|
+
* How to run the test suite
|
|
19
|
+
|
|
20
|
+
* Services (job queues, cache servers, search engines, etc.)
|
|
21
|
+
|
|
22
|
+
* Deployment instructions
|
|
23
|
+
|
|
24
|
+
* ...
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
Please feel free to use a different markup language if you do not plan to run
|
|
28
|
+
<tt>rake doc:app</tt>.
|
data/spec/dummy/Rakefile
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
class UserAdmin < IntrospectiveAdmin::Base
|
|
2
|
+
def self.exclude_params
|
|
3
|
+
%w(reset_password_at current_sign_in_at current_sign_in_ip remember_created_at sign_in_count encrypted_password reset_password_sent_at reset_password_token password authentication_token unlock_token failed_attempts last_sign_in_at locked_at last_sign_in_ip)
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
register User do
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
end
|
|
File without changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
|
2
|
+
// listed below.
|
|
3
|
+
//
|
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
|
5
|
+
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
|
6
|
+
//
|
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
|
8
|
+
// compiled file.
|
|
9
|
+
//
|
|
10
|
+
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
|
11
|
+
// about supported directives.
|
|
12
|
+
//
|
|
13
|
+
//= require_tree .
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
|
3
|
+
* listed below.
|
|
4
|
+
*
|
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
|
7
|
+
*
|
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any styles
|
|
10
|
+
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new
|
|
11
|
+
* file per style scope.
|
|
12
|
+
*
|
|
13
|
+
*= require_tree .
|
|
14
|
+
*= require_self
|
|
15
|
+
*/
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class AbstractAdapter < ActiveRecord::Base
|
|
2
|
+
self.abstract_class = true
|
|
3
|
+
|
|
4
|
+
class << self
|
|
5
|
+
def human_attribute_name(attr, options = {})
|
|
6
|
+
# The default formatting of validation errors sucks, this helps a little syntatically:
|
|
7
|
+
super.titleize+":"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
end
|
|
13
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
class Chat < AbstractAdapter
|
|
2
|
+
belongs_to :creator, foreign_key: :creator_id, :class_name => "User", inverse_of: :own_chats
|
|
3
|
+
|
|
4
|
+
has_many :chat_users, dependent: :destroy
|
|
5
|
+
has_many :users, through: :chat_users
|
|
6
|
+
has_many :chat_messages, dependent: :destroy
|
|
7
|
+
has_many :messages, class_name: 'ChatMessage', dependent: :destroy
|
|
8
|
+
|
|
9
|
+
def active_users
|
|
10
|
+
chat_users.includes(:user).select {|cu| cu.departed_at.nil? }.map(&:user)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
before_create :add_creator_to_conversation
|
|
14
|
+
def add_creator_to_conversation
|
|
15
|
+
users.push creator
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
class ChatMessage < AbstractAdapter
|
|
2
|
+
belongs_to :chat
|
|
3
|
+
belongs_to :author, class_name: 'User'
|
|
4
|
+
|
|
5
|
+
has_many :chat_users, through: :chat
|
|
6
|
+
has_many :recipients, lambda {|message| where(':created_at >= chat_users.created_at and (chat_users.departed_at IS NULL OR :created_at <= chat_users.departed_at)', created_at: message.created_at ) }, through: :chat_users, source: :user, class_name: 'User'
|
|
7
|
+
|
|
8
|
+
# Create ChatUserMessage records for each recipient to track read status
|
|
9
|
+
has_many :chat_message_users, dependent: :destroy
|
|
10
|
+
|
|
11
|
+
validate :author_in_chat
|
|
12
|
+
|
|
13
|
+
def author_in_chat
|
|
14
|
+
errors[:base] << 'User not in chat session.' unless chat.active_users.include? author
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
before_save :create_message_users, if: :new_record?
|
|
18
|
+
def create_message_users
|
|
19
|
+
chat_users.merge(ChatUser.current).each do |cu|
|
|
20
|
+
chat_message_users.build(user: cu.user)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def read_by?(user)
|
|
25
|
+
chat_message_users.merge(ChatMessageUser.read).map(&:user_id).include?(user.id)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.find_chat_for_users(users)
|
|
29
|
+
# presumably much more efficient ways to run an intersecton, we want to find the last
|
|
30
|
+
# exact match with the users being messaged to append to the existing chat.
|
|
31
|
+
Chat.eager_load(:chat_users).where("chat_users.departed_at IS NULL").order('chats.created_at desc').detect {|c| c.chat_users.map(&:user_id).uniq.sort == users.map(&:id).sort }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class ChatMessageUser < AbstractAdapter
|
|
2
|
+
belongs_to :chat_message
|
|
3
|
+
belongs_to :user
|
|
4
|
+
has_one :chat, through: :chat_message
|
|
5
|
+
|
|
6
|
+
scope :read, ->{ where('read_at IS NOT NULL' ) }
|
|
7
|
+
scope :unread, ->{ where('read_at IS NULL' ) }
|
|
8
|
+
|
|
9
|
+
before_save :author_reads_message
|
|
10
|
+
def author_reads_message
|
|
11
|
+
self.read_at = Time.now if user == chat_message.author
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def read?
|
|
15
|
+
read_at.present?
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class ChatUser < AbstractAdapter
|
|
2
|
+
belongs_to :chat
|
|
3
|
+
belongs_to :user
|
|
4
|
+
|
|
5
|
+
alias_attribute :joined_at, :created_at
|
|
6
|
+
alias_attribute :left_at, :departed_at
|
|
7
|
+
|
|
8
|
+
scope :current, ->{ where(departed_at: nil) }
|
|
9
|
+
|
|
10
|
+
validate :user_not_already_active, on: :create
|
|
11
|
+
|
|
12
|
+
def user_not_already_active
|
|
13
|
+
errors[:base] << "#{user.name} is already present in this chat." if chat.chat_users.where(user_id: user.id, departed_at: nil).count > 0 if user.persisted?
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class Company < AbstractAdapter
|
|
2
|
+
has_many :roles, as: :ownable
|
|
3
|
+
has_many :admins, through: :roles, source: :user
|
|
4
|
+
accepts_nested_attributes_for :roles, allow_destroy: true
|
|
5
|
+
|
|
6
|
+
has_many :beacons, class_name: 'LocationBeacon', dependent: :destroy
|
|
7
|
+
has_many :locatables
|
|
8
|
+
has_many :locations, through: :locatables, source: :locatable, source_type: 'Company'
|
|
9
|
+
|
|
10
|
+
has_many :projects, foreign_key: :owner_id, dependent: :destroy, inverse_of: :owner
|
|
11
|
+
|
|
12
|
+
end
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
class Job < AbstractAdapter
|
|
2
|
+
|
|
3
|
+
has_many :project_jobs, dependent: :destroy
|
|
4
|
+
accepts_nested_attributes_for :project_jobs, allow_destroy: true
|
|
5
|
+
|
|
6
|
+
has_many :user_project_jobs, dependent: :destroy
|
|
7
|
+
has_many :users, through: :user_project_jobs
|
|
8
|
+
has_many :projects, through: :user_project_jobs
|
|
9
|
+
|
|
10
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
class Location < AbstractAdapter
|
|
2
|
+
has_many :locatables, dependent: :destroy
|
|
3
|
+
has_many :companies, through: :locatables, source: :locatable, source_type: 'Company'
|
|
4
|
+
|
|
5
|
+
has_many :beacons, class_name: 'LocationBeacon', dependent: :destroy
|
|
6
|
+
has_one :gps, class_name: 'LocationGps', dependent: :destroy
|
|
7
|
+
delegate :lat,:lng,:alt, to: :gps
|
|
8
|
+
|
|
9
|
+
belongs_to :parent_location, foreign_key: :parent_location_id, class_name: 'Location', inverse_of: :child_locations
|
|
10
|
+
has_many :child_locations, foreign_key: :parent_location_id, class_name: 'Location', dependent: :destroy, inverse_of: :parent_location
|
|
11
|
+
|
|
12
|
+
has_many :user_locations, dependent: :destroy
|
|
13
|
+
|
|
14
|
+
# isn't this list going to be kinda long? are there any reasonable constraints to put
|
|
15
|
+
# on this random bit of metadata?
|
|
16
|
+
validates_inclusion_of :kind, in: %w(airport terminal gate plane)
|
|
17
|
+
|
|
18
|
+
accepts_nested_attributes_for :child_locations, allow_destroy: true
|
|
19
|
+
accepts_nested_attributes_for :gps, allow_destroy: true
|
|
20
|
+
accepts_nested_attributes_for :beacons, allow_destroy: true
|
|
21
|
+
|
|
22
|
+
def coords
|
|
23
|
+
[gps.lat, gps.lng, gps.alt]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class LocationBeacon < AbstractAdapter
|
|
2
|
+
belongs_to :location
|
|
3
|
+
has_many :gps, through: :location
|
|
4
|
+
belongs_to :company
|
|
5
|
+
|
|
6
|
+
# B9407F30-F5F8-466E-AFF9-25556B57FE6D
|
|
7
|
+
validates_format_of :uuid, with: /[0-9a-fA-F]{32}/ # 32 digit hexadecimal UUID
|
|
8
|
+
validates_format_of :mac_address, with: /[0-9a-fA-F]{12}/ # 16 digit hexadecimal bluetooth MAC address
|
|
9
|
+
|
|
10
|
+
before_validation :massage_ids
|
|
11
|
+
def massage_ids
|
|
12
|
+
self.uuid = (uuid||'').gsub(/[^0-9a-fA-F]+/,'').upcase
|
|
13
|
+
self.mac_address = (mac_address||'').gsub(/[^0-9a-fA-F]+/,'').upcase
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
class LocationGps < AbstractAdapter
|
|
2
|
+
belongs_to :location
|
|
3
|
+
has_many :beacons, through: :location
|
|
4
|
+
|
|
5
|
+
# lat and lng in degrees altitude in meters
|
|
6
|
+
validates_numericality_of :lat, greater_than_or_equal_to: -90.0, less_than_or_equal_to: 90.0
|
|
7
|
+
validates_numericality_of :lng, greater_than_or_equal_to: -180.0, less_than_or_equal_to: 180.0
|
|
8
|
+
validates_numericality_of :alt
|
|
9
|
+
|
|
10
|
+
def distance_from(lat,lng) # calc distance between this location and the passed coords
|
|
11
|
+
Haversine.distance(self.lat,self.lng, lat,lng).to_meters
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
def bounding_box(lat,lng,alt)
|
|
16
|
+
# box constrain the nearest neighbor search to something reasonble
|
|
17
|
+
box = 0.1447 # 10 miles radius: 111132 meters/deg, 1609m a mile, 0.01447 deg to a mile
|
|
18
|
+
alt_box = 8 # we're trying to constrain the box to a floor of a building here...
|
|
19
|
+
["lat BETWEEN :lat-#{box} AND :lat+#{box} AND
|
|
20
|
+
lng BETWEEN :lng-#{box} AND :lng+#{box} AND
|
|
21
|
+
alt BETWEEN :alt-#{alt_box} AND :alt+#{alt_box}",
|
|
22
|
+
{ lat: lat, lng: lng, alt: alt } ]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def nearest_beacon(lat, lng, alt=0, companies)
|
|
26
|
+
company_ids = companies.kind_of?(Array) ? companies : [companies]
|
|
27
|
+
|
|
28
|
+
gps = nearest_approximation(lat,lng,alt).joins(:beacons).where("location_beacons.company_id"=>company_ids).first || ( raise ActiveRecord::RecordNotFound.new("Couldn't find a Beacon for that GPS Location.") )
|
|
29
|
+
# It's not clear, if they're doing this across multiple companies, how which beacon
|
|
30
|
+
# comes back is not arbitrary, so maybe we should require it be specific.
|
|
31
|
+
gps.beacons.where(company_id: company_ids).first
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def nearest(lat,lng,alt=0)
|
|
35
|
+
nearest_approximation(lat,lng,alt).first || ( raise ActiveRecord::RecordNotFound.new("Couldn't find GPS Location.") )
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def nearest_approximation(lat,lng,alt=0) # approximate as a flat-ish plane
|
|
39
|
+
dOrder= sanitize_sql_array(["(lat - ?)^2 + (lng - ?)^2 * COS(RADIANS(lat))", lat, lng])
|
|
40
|
+
|
|
41
|
+
self.select("location_gps.id, location_gps.location_id, #{dOrder} as dOrder").
|
|
42
|
+
where( bounding_box(lat,lng,alt) ).order("dOrder ASC")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def nearest_great_circle(lat,lng,alt=0)
|
|
46
|
+
dOrder = sanitize_sql_array(["acos( sin(radians(lat))*sin(radians(:lat)) + cos(radians(lat))*cos(radians(:lat))*cos(radians(lng - :lng)) )", { lat: lat, lng: lng } ] )
|
|
47
|
+
|
|
48
|
+
self.select("location_gps.id, location_gps.location_id, #{dOrder} as dOrder").
|
|
49
|
+
where( bounding_box(lat,lng,alt) ).order("dOrder ASC")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def nearest_haversine(lat,lng,alt=0)
|
|
53
|
+
dOrder = sanitize_sql_array(["asin( sqrt( (sin(radians(:lat - lat))/2)^2 + cos(radians(lat))*cos(radians(:lat))*(sin(radians(:lng - lng )/2))^2 ))", { lat: lat, lng: lng }])
|
|
54
|
+
|
|
55
|
+
self.select("location_gps.id, location_gps.location_id, #{dOrder} as dOrder").
|
|
56
|
+
where( bounding_box(lat,lng,alt) ).order("dOrder ASC")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
#def nearest_wgs84(lat,lng,alt=0)
|
|
60
|
+
# # vincenty's ellipsoid calculation is an iterative estimate available in postGIS
|
|
61
|
+
#end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|