introspective_admin 0.0.1 → 0.0.2
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 +4 -4
- data/.travis.yml +34 -0
- data/README.md +49 -4
- data/introspective_admin.gemspec +8 -5
- data/lib/introspective_admin/base.rb +7 -0
- data/lib/introspective_admin/version.rb +1 -1
- data/spec/dummy/app/models/abstract_adapter.rb +0 -1
- data/spec/dummy/app/models/location_gps.rb +0 -53
- data/spec/dummy/app/models/user.rb +0 -7
- data/spec/dummy/config/database.yml +9 -5
- data/spec/rails_helper.rb +0 -2
- data/spec/support/blueprints.rb +0 -16
- metadata +12 -50
- data/spec/dummy/app/models/chat.rb +0 -18
- data/spec/dummy/app/models/chat_message.rb +0 -34
- data/spec/dummy/app/models/chat_message_user.rb +0 -17
- data/spec/dummy/app/models/chat_user.rb +0 -16
- data/spec/dummy/app/models/user/chatter.rb +0 -79
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31c04925094186ee8656917b8d3a0072df365a4d
|
4
|
+
data.tar.gz: f2e55a36107edededc44be81a4589d3f383bcbca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 00d867fe289e8029f9364bcfcab98b7eca31154b06b4b2711c28e0e1b21dea49cd162acee0f82348b3320d5391bbe31e255bdb6b99cd29bacd3b74dcf13e2825
|
7
|
+
data.tar.gz: 321c9ba8b69d8abce6c719a8d73fcc8197491d46bb59974bf5c2c3f82338fc9b1f267a8c59fcff19906f03a00f57a61dabd8d54bd32828cf427231f7a2002414
|
data/.travis.yml
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
language: ruby
|
2
|
+
install: bundle install --jobs=1 --retry=1
|
3
|
+
script:
|
4
|
+
- bundle install
|
5
|
+
- bundle exec rspec
|
6
|
+
rvm:
|
7
|
+
- 1.9
|
8
|
+
- 2.2.3
|
9
|
+
# - jruby-9.0.0.0
|
10
|
+
env:
|
11
|
+
matrix:
|
12
|
+
- RAILS=3.2.22
|
13
|
+
- RAILS=4.1.13
|
14
|
+
- RAILS=4.2.4
|
15
|
+
- RAILS=master
|
16
|
+
global:
|
17
|
+
- JRUBY_OPTS="-J-Xmx1024m --debug"
|
18
|
+
matrix:
|
19
|
+
fast_finish: true
|
20
|
+
exclude:
|
21
|
+
- rvm: 2.2.3
|
22
|
+
env: RAILS=3.2.22
|
23
|
+
- rvm: jruby-9.0.0.0
|
24
|
+
env: RAILS=3.2.22
|
25
|
+
- rvm: 1.9
|
26
|
+
env: RAILS=master
|
27
|
+
allow_failures:
|
28
|
+
- env: RAILS=master
|
29
|
+
notifications:
|
30
|
+
email:
|
31
|
+
recipients:
|
32
|
+
- buermann@gmail.com
|
33
|
+
on_success: change
|
34
|
+
on_failure: always
|
data/README.md
CHANGED
@@ -1,18 +1,34 @@
|
|
1
1
|
# IntrospectiveAdmin
|
2
2
|
|
3
|
+
[![Gem Version][GV img]][Gem Version]
|
4
|
+
[![Build Status][BS img]][Build Status]
|
5
|
+
[![Dependency Status][DS img]][Dependency Status]
|
6
|
+
[![Coverage Status][CS img]][Coverage Status]
|
7
|
+
|
8
|
+
[Gem Version]: https://rubygems.org/gems/introspective_admin
|
9
|
+
[Build Status]: https://travis-ci.org/buermann/introspective_admin
|
10
|
+
[travis pull requests]: https://travis-ci.org/buermann/introspective_admin/pull_requests
|
11
|
+
[Dependency Status]: https://gemnasium.com/buermann/introspective_admin
|
12
|
+
[Coverage Status]: https://coveralls.io/r/buermann/introspective_admin
|
13
|
+
|
14
|
+
[GV img]: https://badge.fury.io/rb/introspective_admin.png
|
15
|
+
[BS img]: https://travis-ci.org/buermann/introspective_admin.png
|
16
|
+
[DS img]: https://gemnasium.com/buermann/introspective_admin.png
|
17
|
+
[CS img]: https://coveralls.io/repos/buermann/introspective_admin/badge.png?branch=master
|
18
|
+
|
3
19
|
IntrospectiveAdmin is a Rails Plugin for DRYing up ActiveAdmin configurations by
|
4
20
|
laying out simple defaults and including nested relations according to the models'
|
5
|
-
accepts_nested_attributes_for :relation declarations.
|
21
|
+
accepts_nested_attributes_for :relation declarations.
|
6
22
|
|
7
23
|
## Documentation
|
8
24
|
|
9
25
|
In your Gemfile:
|
10
26
|
|
11
27
|
```
|
12
|
-
gem 'introspective_admin'
|
28
|
+
gem 'introspective_admin'
|
13
29
|
```
|
14
30
|
|
15
|
-
And bundle install.
|
31
|
+
And bundle install. In app/admin/my_admin.rb:
|
16
32
|
|
17
33
|
```
|
18
34
|
class MyAdmin < IntrospectiveAdmin::Base
|
@@ -21,11 +37,15 @@ class MyAdmin < IntrospectiveAdmin::Base
|
|
21
37
|
end
|
22
38
|
|
23
39
|
register MyModel do
|
24
|
-
#
|
40
|
+
# It yields the ActiveAdmin DSL context back, allowing further configuration to
|
41
|
+
# be added here, just as you would normally, to the Admin::MyModelController
|
42
|
+
# namespace.
|
25
43
|
end
|
26
44
|
end
|
27
45
|
```
|
28
46
|
|
47
|
+
Registering MyModel will set up the index, show, and form configurations for every attribute and nested association on the model excluding those in MyAdmin.exclude_params, with links to associated records (if they have ActiveAdmin screens) and permitting every attribute on the model.
|
48
|
+
|
29
49
|
Customizing select box options for associations is done by adding an
|
30
50
|
"options_for_X" class method on the administrated model:
|
31
51
|
|
@@ -41,6 +61,31 @@ class MyModel < ActiveRecord::Base
|
|
41
61
|
end
|
42
62
|
```
|
43
63
|
|
64
|
+
IntrospectiveAdmin will detect nested polymorphic relations and attempt to handle
|
65
|
+
them using virutal attributes that you must add to the model instance, plus a class
|
66
|
+
method for the select box options, using a shared delimiter string for the compound ID.
|
67
|
+
E.g. here we use a hyphen:
|
68
|
+
|
69
|
+
```
|
70
|
+
class MyModel < ActiveRecord::Base
|
71
|
+
belongs_to :poly_model, polymorphic: true
|
72
|
+
accepts_nested_attributes_for :poly_model, :allow_destroy => true
|
73
|
+
|
74
|
+
def self.options_for_poly_model
|
75
|
+
PolyModel.all.map { |i| [ "#{i.class}: #{i.name}", "#{i.class}-#{i.id}"] }
|
76
|
+
end
|
77
|
+
|
78
|
+
def poly_model_assign
|
79
|
+
poly_model.present? ? "#{poly_model_type}-#{poly_model_id}" : nil
|
80
|
+
end
|
81
|
+
|
82
|
+
def poly_model_assign=(value)
|
83
|
+
self.poly_model_type,self.poly_model_id = value.split('-')
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
44
89
|
## Dependencies
|
45
90
|
|
46
91
|
Tool | Description
|
data/introspective_admin.gemspec
CHANGED
@@ -22,17 +22,20 @@ Gem::Specification.new do |s|
|
|
22
22
|
|
23
23
|
s.add_dependency 'sass-rails'
|
24
24
|
|
25
|
-
|
25
|
+
if RUBY_PLATFORM == 'java'
|
26
|
+
s.add_development_dependency "jdbc-sqlite3"
|
27
|
+
else
|
28
|
+
s.add_development_dependency "sqlite3"
|
29
|
+
if RUBY_VERSION > '2.0.0'
|
30
|
+
s.add_development_dependency 'byebug'
|
31
|
+
end
|
32
|
+
end
|
26
33
|
s.add_development_dependency "rspec-rails", '>= 3.0'
|
27
34
|
s.add_development_dependency 'devise'
|
28
35
|
s.add_development_dependency 'devise-async'
|
29
36
|
s.add_development_dependency 'machinist'
|
30
37
|
s.add_development_dependency 'simplecov'
|
31
38
|
s.add_development_dependency 'rufus-mnemo'
|
32
|
-
# For compatibility of schema_validations with AR 4.2.1+
|
33
|
-
s.add_development_dependency "schema_plus", "2.0.0.pre12"
|
34
|
-
s.add_development_dependency "schema_validations"
|
35
|
-
s.add_development_dependency 'byebug'
|
36
39
|
|
37
40
|
end
|
38
41
|
|
@@ -71,7 +71,14 @@ module IntrospectiveAdmin
|
|
71
71
|
[assoc, options]
|
72
72
|
}]
|
73
73
|
|
74
|
+
|
74
75
|
ActiveAdmin.register model do
|
76
|
+
controller do
|
77
|
+
def scoped_collection
|
78
|
+
super.includes super.nested_attributes_options.keys
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
75
82
|
index do
|
76
83
|
cols = model.columns.map(&:name)-klass.exclude_params
|
77
84
|
cols.each_with_index do |c,i|
|
@@ -7,58 +7,5 @@ class LocationGps < AbstractAdapter
|
|
7
7
|
validates_numericality_of :lng, greater_than_or_equal_to: -180.0, less_than_or_equal_to: 180.0
|
8
8
|
validates_numericality_of :alt
|
9
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
10
|
|
64
11
|
end
|
@@ -19,13 +19,6 @@ class User < AbstractAdapter
|
|
19
19
|
has_many :team_users
|
20
20
|
has_many :teams, through: :team_users
|
21
21
|
|
22
|
-
has_many :own_chats, foreign_key: :creator_id, class_name: 'Chat'
|
23
|
-
has_many :chat_users
|
24
|
-
has_many :chats, through: :chat_users
|
25
|
-
has_many :chat_message_users
|
26
|
-
has_many :messages, ->{ where('chat_messages.created_at >= chat_users.created_at and (chat_users.departed_at IS NULL OR chat_messages.created_at <= chat_users.departed_at)') }, through: :chats
|
27
|
-
include User::Chatter
|
28
|
-
|
29
22
|
has_many :roles, dependent: :destroy, inverse_of: :user
|
30
23
|
accepts_nested_attributes_for :roles, allow_destroy: true
|
31
24
|
has_many :admin_companies, through: :roles, source: :ownable, source_type: Company
|
@@ -1,7 +1,13 @@
|
|
1
1
|
# SQLite version 3.x
|
2
2
|
# gem install sqlite3-ruby (not necessary on OS X Leopard)
|
3
|
-
|
3
|
+
|
4
|
+
default: &default
|
4
5
|
adapter: sqlite3
|
6
|
+
database: ":memory:"
|
7
|
+
|
8
|
+
|
9
|
+
development:
|
10
|
+
<<: *default
|
5
11
|
database: db/development.sqlite3
|
6
12
|
pool: 5
|
7
13
|
timeout: 5000
|
@@ -10,9 +16,7 @@ development:
|
|
10
16
|
# re-generated from your development database when you run "rake".
|
11
17
|
# Do not set this db to the same as development or production.
|
12
18
|
test:
|
13
|
-
|
14
|
-
database: ":memory:"
|
19
|
+
<<: *default
|
15
20
|
|
16
21
|
production:
|
17
|
-
|
18
|
-
database: ":memory:"
|
22
|
+
<<: *default
|
data/spec/rails_helper.rb
CHANGED
data/spec/support/blueprints.rb
CHANGED
@@ -42,22 +42,6 @@ Role.blueprint {
|
|
42
42
|
ownable_type { 'Company' }
|
43
43
|
}
|
44
44
|
|
45
|
-
Chat.blueprint {
|
46
|
-
creator { User.make }
|
47
|
-
}
|
48
|
-
ChatMessage.blueprint {
|
49
|
-
author = User.make
|
50
|
-
chat = Chat.make(users: [author, User.make])
|
51
|
-
chat.save
|
52
|
-
chat { chat }
|
53
|
-
author { author }
|
54
|
-
message { paragraph }
|
55
|
-
}
|
56
|
-
ChatUser.blueprint {
|
57
|
-
chat { Chat.make }
|
58
|
-
user { User.make }
|
59
|
-
}
|
60
|
-
|
61
45
|
Locatable.blueprint {
|
62
46
|
location { Location.make }
|
63
47
|
locatable { Company.make }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: introspective_admin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Buermann
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sass-rails
|
@@ -39,21 +39,7 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '3.0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '3.0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: devise
|
42
|
+
name: byebug
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
58
44
|
requirements:
|
59
45
|
- - ">="
|
@@ -67,21 +53,21 @@ dependencies:
|
|
67
53
|
- !ruby/object:Gem::Version
|
68
54
|
version: '0'
|
69
55
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
56
|
+
name: rspec-rails
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
72
58
|
requirements:
|
73
59
|
- - ">="
|
74
60
|
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
61
|
+
version: '3.0'
|
76
62
|
type: :development
|
77
63
|
prerelease: false
|
78
64
|
version_requirements: !ruby/object:Gem::Requirement
|
79
65
|
requirements:
|
80
66
|
- - ">="
|
81
67
|
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
68
|
+
version: '3.0'
|
83
69
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
70
|
+
name: devise
|
85
71
|
requirement: !ruby/object:Gem::Requirement
|
86
72
|
requirements:
|
87
73
|
- - ">="
|
@@ -95,7 +81,7 @@ dependencies:
|
|
95
81
|
- !ruby/object:Gem::Version
|
96
82
|
version: '0'
|
97
83
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
84
|
+
name: devise-async
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
100
86
|
requirements:
|
101
87
|
- - ">="
|
@@ -109,7 +95,7 @@ dependencies:
|
|
109
95
|
- !ruby/object:Gem::Version
|
110
96
|
version: '0'
|
111
97
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
98
|
+
name: machinist
|
113
99
|
requirement: !ruby/object:Gem::Requirement
|
114
100
|
requirements:
|
115
101
|
- - ">="
|
@@ -123,21 +109,7 @@ dependencies:
|
|
123
109
|
- !ruby/object:Gem::Version
|
124
110
|
version: '0'
|
125
111
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
128
|
-
requirements:
|
129
|
-
- - '='
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: 2.0.0.pre12
|
132
|
-
type: :development
|
133
|
-
prerelease: false
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
135
|
-
requirements:
|
136
|
-
- - '='
|
137
|
-
- !ruby/object:Gem::Version
|
138
|
-
version: 2.0.0.pre12
|
139
|
-
- !ruby/object:Gem::Dependency
|
140
|
-
name: schema_validations
|
112
|
+
name: simplecov
|
141
113
|
requirement: !ruby/object:Gem::Requirement
|
142
114
|
requirements:
|
143
115
|
- - ">="
|
@@ -151,7 +123,7 @@ dependencies:
|
|
151
123
|
- !ruby/object:Gem::Version
|
152
124
|
version: '0'
|
153
125
|
- !ruby/object:Gem::Dependency
|
154
|
-
name:
|
126
|
+
name: rufus-mnemo
|
155
127
|
requirement: !ruby/object:Gem::Requirement
|
156
128
|
requirements:
|
157
129
|
- - ">="
|
@@ -172,6 +144,7 @@ extensions: []
|
|
172
144
|
extra_rdoc_files: []
|
173
145
|
files:
|
174
146
|
- ".gitignore"
|
147
|
+
- ".travis.yml"
|
175
148
|
- Gemfile
|
176
149
|
- Gemfile.lock
|
177
150
|
- LICENSE
|
@@ -206,10 +179,6 @@ files:
|
|
206
179
|
- spec/dummy/app/models/.keep
|
207
180
|
- spec/dummy/app/models/abstract_adapter.rb
|
208
181
|
- spec/dummy/app/models/admin_user.rb
|
209
|
-
- spec/dummy/app/models/chat.rb
|
210
|
-
- spec/dummy/app/models/chat_message.rb
|
211
|
-
- spec/dummy/app/models/chat_message_user.rb
|
212
|
-
- spec/dummy/app/models/chat_user.rb
|
213
182
|
- spec/dummy/app/models/company.rb
|
214
183
|
- spec/dummy/app/models/concerns/.keep
|
215
184
|
- spec/dummy/app/models/job.rb
|
@@ -223,7 +192,6 @@ files:
|
|
223
192
|
- spec/dummy/app/models/team.rb
|
224
193
|
- spec/dummy/app/models/team_user.rb
|
225
194
|
- spec/dummy/app/models/user.rb
|
226
|
-
- spec/dummy/app/models/user/chatter.rb
|
227
195
|
- spec/dummy/app/models/user_location.rb
|
228
196
|
- spec/dummy/app/models/user_project_job.rb
|
229
197
|
- spec/dummy/app/views/layouts/application.html.erb
|
@@ -335,10 +303,6 @@ test_files:
|
|
335
303
|
- spec/dummy/app/models/.keep
|
336
304
|
- spec/dummy/app/models/abstract_adapter.rb
|
337
305
|
- spec/dummy/app/models/admin_user.rb
|
338
|
-
- spec/dummy/app/models/chat.rb
|
339
|
-
- spec/dummy/app/models/chat_message.rb
|
340
|
-
- spec/dummy/app/models/chat_message_user.rb
|
341
|
-
- spec/dummy/app/models/chat_user.rb
|
342
306
|
- spec/dummy/app/models/company.rb
|
343
307
|
- spec/dummy/app/models/concerns/.keep
|
344
308
|
- spec/dummy/app/models/job.rb
|
@@ -352,7 +316,6 @@ test_files:
|
|
352
316
|
- spec/dummy/app/models/team.rb
|
353
317
|
- spec/dummy/app/models/team_user.rb
|
354
318
|
- spec/dummy/app/models/user.rb
|
355
|
-
- spec/dummy/app/models/user/chatter.rb
|
356
319
|
- spec/dummy/app/models/user_location.rb
|
357
320
|
- spec/dummy/app/models/user_project_job.rb
|
358
321
|
- spec/dummy/app/views/layouts/application.html.erb
|
@@ -417,4 +380,3 @@ test_files:
|
|
417
380
|
- spec/rails_helper.rb
|
418
381
|
- spec/support/blueprints.rb
|
419
382
|
- spec/support/location_helper.rb
|
420
|
-
has_rdoc:
|
@@ -1,18 +0,0 @@
|
|
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
|
@@ -1,34 +0,0 @@
|
|
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
|
@@ -1,17 +0,0 @@
|
|
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
|
@@ -1,16 +0,0 @@
|
|
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
|
@@ -1,79 +0,0 @@
|
|
1
|
-
module User::Chatter
|
2
|
-
|
3
|
-
def message_query(chat_id: chat_id, new: true)
|
4
|
-
messages.joins(:chat_message_users)
|
5
|
-
.where('chat_message_users.user_id'=> id)
|
6
|
-
.where(new ? {'chat_message_users.read_at'=>nil} : '')
|
7
|
-
.where(chat_id ? {'chat_messages.chat_id'=> chat_id} : '')
|
8
|
-
.order('') # or it will add an order by id clause that breaks the count query.
|
9
|
-
end
|
10
|
-
|
11
|
-
def new_messages?(chat=nil) # returns a hash of chat_ids with new message counts
|
12
|
-
chat_id = chat.kind_of?(Chat) ? chat.id : chat
|
13
|
-
new = message_query(chat_id: chat_id, new: true)
|
14
|
-
.select("chat_messages.chat_id, count(chat_messages.id) as count")
|
15
|
-
.group('chat_id')
|
16
|
-
|
17
|
-
chat ? { chat_id => new.first.try(:count)||0 } : Hash[new.map {|c| [c.chat_id, c.count]} ]
|
18
|
-
end
|
19
|
-
|
20
|
-
def read_messages(chat: nil, mark_as_read: false, new: true)
|
21
|
-
chat_id = chat.kind_of?(Chat) ? chat.id : chat
|
22
|
-
new = message_query(chat_id: chat_id, new: new).order('chat_messages.created_at').includes(:author) # :chat?
|
23
|
-
new.map(&:chat).uniq.each {|chat| mark_as_read(chat) } if mark_as_read
|
24
|
-
new
|
25
|
-
end
|
26
|
-
|
27
|
-
def chat(users: users, message: message)
|
28
|
-
users = [users].flatten
|
29
|
-
users = users.first.kind_of?(User) ? users : User.where(id: users)
|
30
|
-
chat = Chat.create(creator: self)
|
31
|
-
chat.users.push users
|
32
|
-
chat.messages.build(message: message, author: self)
|
33
|
-
chat.save!
|
34
|
-
chat
|
35
|
-
end
|
36
|
-
|
37
|
-
def reply(chat: chat, message: message)
|
38
|
-
chat = chat.kind_of?(Chat) ? chat : Chat.find(chat)
|
39
|
-
mark_as_read(chat) # a reply implies that the thread has been read
|
40
|
-
chat.messages.build(message: message, author: self)
|
41
|
-
chat.save!
|
42
|
-
chat
|
43
|
-
end
|
44
|
-
|
45
|
-
def add_chatters(chat: chat, users: users)
|
46
|
-
users = [users].flatten
|
47
|
-
users = users.first.kind_of?(User) ? users : User.where(id: users)
|
48
|
-
chat = chat.kind_of?(Chat) ? chat : Chat.find(chat)
|
49
|
-
|
50
|
-
if chat.active_users.include?(self) # only current participants can add new users
|
51
|
-
chat.users.push users
|
52
|
-
chat.messages.build(chat: chat, author: self, message: "#{self.name} [[ADDED_USER_MESSAGE]] #{users.map(&:name).join(',')}")
|
53
|
-
chat.save!
|
54
|
-
else
|
55
|
-
chat.errors[:base] << "Only current chat participants can add users."
|
56
|
-
raise ActiveRecord::RecordInvalid.new(chat)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def leave_chat(chat)
|
61
|
-
chat = chat.kind_of?(Chat) ? chat : Chat.find(chat)
|
62
|
-
|
63
|
-
if chat.active_users.include?(self)
|
64
|
-
reply(chat:chat, message: "#{name} [[DEPARTS_MESSAGE]]")
|
65
|
-
chat.chat_users.detect {|cu| cu.user_id == self.id}.update_attributes(departed_at: Time.now)
|
66
|
-
else
|
67
|
-
true
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def mark_as_read(chat)
|
72
|
-
ChatMessageUser.joins(:chat_message).where('read_at IS NULL AND chat_messages.chat_id = ? AND user_id = ?', chat.id, id).update_all(read_at: Time.now)
|
73
|
-
end
|
74
|
-
|
75
|
-
def mark_messages_as_read(messages)
|
76
|
-
chat_message_users.where("chat_message_id in (?) and read_at IS NULL", messages.map(&:id)).update_all(read_at: Time.now)
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|