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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 34a8d5c710a6b80906412e0fe2cb801d6b52fd4e
4
- data.tar.gz: e2fca9348cc6a20528ef56d6e4888232e4902b22
3
+ metadata.gz: 31c04925094186ee8656917b8d3a0072df365a4d
4
+ data.tar.gz: f2e55a36107edededc44be81a4589d3f383bcbca
5
5
  SHA512:
6
- metadata.gz: d71883839c6bb9c36da4d1410859600227c1e2fd270c1ec405057c1d2abdbb32fbe3ba2f0b4b8bf2fa393385d75a1c39ced44c0d9429fa35fc8b77da6e9494b3
7
- data.tar.gz: 3b15037166cfae55f8333a2d79b5b55004d855c79e4e0c16a47b0df20d53df23bb68ed6cdb18aa6ed063a8618c36d1a3d445f7bd716f4694ecaae31ad8fb5f27
6
+ metadata.gz: 00d867fe289e8029f9364bcfcab98b7eca31154b06b4b2711c28e0e1b21dea49cd162acee0f82348b3320d5391bbe31e255bdb6b99cd29bacd3b74dcf13e2825
7
+ data.tar.gz: 321c9ba8b69d8abce6c719a8d73fcc8197491d46bb59974bf5c2c3f82338fc9b1f267a8c59fcff19906f03a00f57a61dabd8d54bd32828cf427231f7a2002414
@@ -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', git: 'https://github.com/buermann/introspective_admin.git'
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
- # Add additional ActiveAdmin configuration options under the Admin::MyModelController namespace.
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
@@ -22,17 +22,20 @@ Gem::Specification.new do |s|
22
22
 
23
23
  s.add_dependency 'sass-rails'
24
24
 
25
- s.add_development_dependency "sqlite3"
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|
@@ -1,3 +1,3 @@
1
1
  module IntrospectiveAdmin
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -6,7 +6,6 @@ class AbstractAdapter < ActiveRecord::Base
6
6
  # The default formatting of validation errors sucks, this helps a little syntatically:
7
7
  super.titleize+":"
8
8
  end
9
-
10
9
  end
11
10
 
12
11
  end
@@ -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
- development:
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
- adapter: sqlite3
14
- database: ":memory:"
19
+ <<: *default
15
20
 
16
21
  production:
17
- adapter: sqlite3
18
- database: ":memory:"
22
+ <<: *default
@@ -1,5 +1,3 @@
1
- require 'byebug'
2
-
3
1
  ENV["RAILS_ENV"] ||= 'test'
4
2
  require File.expand_path("../dummy/config/environment", __FILE__)
5
3
  require 'rspec/rails'
@@ -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.1
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-10-28 00:00:00.000000000 Z
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: rspec-rails
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: devise-async
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: machinist
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: simplecov
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: rufus-mnemo
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: schema_plus
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: byebug
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