introspective_admin 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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