redmine_crm 0.0.23 → 0.0.25

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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/doc/CHANGELOG +4 -0
  4. data/lib/redmine_crm.rb +28 -20
  5. data/lib/redmine_crm/{rcrm_acts_as_taggable.rb → acts_as_taggable/rcrm_acts_as_taggable.rb} +93 -87
  6. data/lib/redmine_crm/acts_as_taggable/tag.rb +81 -0
  7. data/lib/redmine_crm/acts_as_taggable/tag_list.rb +111 -0
  8. data/lib/redmine_crm/acts_as_taggable/tagging.rb +16 -0
  9. data/lib/redmine_crm/acts_as_viewed/rcrm_acts_as_viewed.rb +274 -0
  10. data/lib/redmine_crm/{rcrm_acts_as_votable.rb → acts_as_votable/rcrm_acts_as_votable.rb} +8 -11
  11. data/lib/redmine_crm/acts_as_votable/rcrm_acts_as_voter.rb +20 -0
  12. data/lib/redmine_crm/{votable.rb → acts_as_votable/votable.rb} +36 -47
  13. data/lib/redmine_crm/{vote.rb → acts_as_votable/vote.rb} +7 -10
  14. data/lib/redmine_crm/{voter.rb → acts_as_votable/voter.rb} +29 -34
  15. data/lib/redmine_crm/currency/formatting.rb +0 -3
  16. data/lib/redmine_crm/currency/heuristics.rb +1 -1
  17. data/lib/redmine_crm/currency/loader.rb +1 -1
  18. data/lib/redmine_crm/helpers/tags_helper.rb +1 -3
  19. data/lib/redmine_crm/helpers/vote_helper.rb +29 -32
  20. data/lib/redmine_crm/liquid/drops/issues_drop.rb +66 -0
  21. data/lib/redmine_crm/liquid/drops/news_drop.rb +54 -0
  22. data/lib/redmine_crm/liquid/drops/projects_drop.rb +86 -0
  23. data/lib/redmine_crm/liquid/drops/users_drop.rb +72 -0
  24. data/lib/redmine_crm/liquid/filters/arrays.rb +178 -0
  25. data/lib/redmine_crm/liquid/filters/base.rb +208 -0
  26. data/lib/redmine_crm/version.rb +1 -1
  27. data/redmine_crm.gemspec +1 -1
  28. data/test/{acts_as_taggable_test.rb → acts_as_taggable/rcrm_acts_as_taggable_test.rb} +114 -151
  29. data/test/acts_as_taggable/tag_list_test.rb +38 -0
  30. data/test/acts_as_taggable/tag_test.rb +74 -0
  31. data/test/acts_as_taggable/tagging_test.rb +15 -0
  32. data/test/{viewed_test.rb → acts_as_viewed/rcrm_acts_as_viewed_test.rb} +17 -15
  33. data/test/{votable_test.rb → acts_as_votable/rcrm_acts_as_votable_test.rb} +3 -3
  34. data/test/acts_as_votable/rcrm_acts_as_voter_test.rb +12 -0
  35. data/test/{votable_model_test.rb → acts_as_votable/votable_test.rb} +4 -4
  36. data/test/{voter_model_test.rb → acts_as_votable/voter_test.rb} +7 -7
  37. data/test/currency_test.rb +10 -10
  38. data/test/fixtures/issue.rb +6 -2
  39. data/test/fixtures/issues.yml +13 -1
  40. data/test/fixtures/news.rb +3 -0
  41. data/test/fixtures/news.yml +8 -0
  42. data/test/fixtures/project.rb +8 -0
  43. data/test/fixtures/projects.yml +10 -0
  44. data/test/fixtures/user.rb +5 -1
  45. data/test/fixtures/users.yml +3 -2
  46. data/test/fixtures/vote_classes.rb +2 -3
  47. data/test/liquid/drops/issues_drop_test.rb +34 -0
  48. data/test/liquid/drops/liquid_test.rb +52 -0
  49. data/test/liquid/drops/news_drop_test.rb +38 -0
  50. data/test/liquid/drops/projects_drop_test.rb +44 -0
  51. data/test/liquid/drops/uses_drop_test.rb +36 -0
  52. data/test/liquid/filters/arrays_filter_test.rb +24 -0
  53. data/test/liquid/filters/base_filter_test.rb +63 -0
  54. data/test/liquid/liquid_helper.rb +32 -0
  55. data/test/money_helper_test.rb +5 -5
  56. data/test/schema.rb +21 -9
  57. data/test/test_helper.rb +26 -25
  58. metadata +76 -28
  59. data/lib/redmine_crm/rcrm_acts_as_viewed.rb +0 -287
  60. data/lib/redmine_crm/rcrm_acts_as_voter.rb +0 -27
  61. data/lib/redmine_crm/tag.rb +0 -81
  62. data/lib/redmine_crm/tag_list.rb +0 -112
  63. data/lib/redmine_crm/tagging.rb +0 -20
  64. data/test/tag_test.rb +0 -64
  65. data/test/tagging_test.rb +0 -14
data/test/test_helper.rb CHANGED
@@ -1,50 +1,52 @@
1
1
  require 'minitest/autorun'
2
+ require 'byebug'
2
3
  # require 'test/unit'
3
4
 
4
5
  begin
5
6
  require File.dirname(__FILE__) + '/../../../../config/environment'
6
7
  rescue LoadError
7
8
  require 'rubygems'
8
- gem 'activerecord'
9
- gem 'actionpack'
9
+ gem 'activerecord', "4.2.7.1"
10
+ gem 'actionpack', "4.2.7.1"
10
11
  require 'active_record'
11
12
  # require 'action_controller'
12
13
  end
13
- require 'byebug'
14
14
  require "redmine_crm"
15
15
  require "active_record/fixtures"
16
16
 
17
- require File.dirname(__FILE__) + '/../lib/redmine_crm/rcrm_acts_as_taggable'
18
- require File.dirname(__FILE__) + '/../lib/redmine_crm/tag_list'
19
- require File.dirname(__FILE__) + '/../lib/redmine_crm/tag'
20
- require File.dirname(__FILE__) + '/../lib/redmine_crm/tagging'
17
+ require File.dirname(__FILE__) + '/../lib/redmine_crm/acts_as_taggable/tag'
18
+ require File.dirname(__FILE__) + '/../lib/redmine_crm/acts_as_taggable/tag_list'
19
+ require File.dirname(__FILE__) + '/../lib/redmine_crm/acts_as_taggable/tagging'
20
+ require File.dirname(__FILE__) + '/../lib/redmine_crm/acts_as_taggable/rcrm_acts_as_taggable'
21
21
  require File.dirname(__FILE__) + '/../lib/redmine_crm/helpers/tags_helper'
22
- require File.dirname(__FILE__) + '/../lib/redmine_crm/rcrm_acts_as_votable'
23
- require File.dirname(__FILE__) + '/../lib/redmine_crm/rcrm_acts_as_voter'
22
+ require File.dirname(__FILE__) + '/../lib/redmine_crm/acts_as_votable/rcrm_acts_as_votable'
23
+ require File.dirname(__FILE__) + '/../lib/redmine_crm/acts_as_votable/rcrm_acts_as_voter'
24
24
 
25
25
  # require_dependency File.dirname(__FILE__) + '/../lib/redmine_crm/tags_helper'
26
26
 
27
27
  ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + '/debug.log')
28
28
  ActiveRecord::Base.configurations = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
29
- ActiveRecord::Base.establish_connection(ENV['DB'] || 'sqlite3')
29
+ ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[ENV['DB'] || 'sqlite3'])
30
30
 
31
31
  load(File.dirname(__FILE__) + '/schema.rb')
32
32
  load(File.dirname(__FILE__) + '/fixtures/user.rb')
33
33
  load(File.dirname(__FILE__) + '/fixtures/issue.rb')
34
- load(File.dirname(__FILE__) + "/fixtures/vote_classes.rb")
34
+ load(File.dirname(__FILE__) + '/fixtures/vote_classes.rb')
35
+ load(File.dirname(__FILE__) + '/fixtures/news.rb')
36
+ load(File.dirname(__FILE__) + '/fixtures/project.rb')
35
37
 
36
38
  # Dir["/fixtures/*.rb"].each{|file| load file}
37
39
 
38
40
  class ActiveSupport::TestCase #:nodoc:
39
41
  include ActiveRecord::TestFixtures
40
-
42
+
41
43
  self.fixture_path = File.dirname(__FILE__) + "/fixtures/"
42
-
44
+
43
45
  self.use_transactional_fixtures = true
44
46
  self.use_instantiated_fixtures = false
45
- set_fixture_class :tags => RedmineCrm::Tag
46
- set_fixture_class :taggings => RedmineCrm::Tagging
47
-
47
+ set_fixture_class :tags => RedmineCrm::ActsAsTaggable::Tag
48
+ set_fixture_class :taggings => RedmineCrm::ActsAsTaggable::Tagging
49
+
48
50
  set_fixture_class :votable_caches => VotableCache
49
51
  fixtures :all
50
52
 
@@ -62,14 +64,14 @@ class ActiveSupport::TestCase #:nodoc:
62
64
  hash[tags(tag).name] = count
63
65
  hash
64
66
  end
65
-
67
+
66
68
  tags.each do |tag|
67
69
  value = expected_values.delete(tag.name)
68
-
70
+
69
71
  assert_not_nil value, "Expected count for #{tag.name} was not provided"
70
72
  assert_equal value, tag.count, "Expected value of #{value} for #{tag.name}, but was #{tag.count}"
71
73
  end
72
-
74
+
73
75
  unless expected_values.empty?
74
76
  assert false, "The following tag counts were not present: #{expected_values.inspect}"
75
77
  end
@@ -99,20 +101,19 @@ class ActiveSupport::TestCase #:nodoc:
99
101
  def assert_no_queries(&block)
100
102
  assert_queries(0, &block)
101
103
  end
102
-
104
+
103
105
  # From Rails trunk
104
106
  def assert_difference(expressions, difference = 1, message = nil, &block)
105
- expression_evaluations = [expressions].flatten.collect{|expression| lambda { eval(expression, block.binding) } }
106
-
107
+ expression_evaluations = [expressions].flatten.collect{ |expression| lambda { eval(expression, block.binding) } }
108
+
107
109
  original_values = expression_evaluations.inject([]) { |memo, expression| memo << expression.call }
108
110
  yield
109
111
  expression_evaluations.each_with_index do |expression, i|
110
112
  assert_equal original_values[i] + difference, expression.call, message
111
113
  end
112
114
  end
113
-
115
+
114
116
  def assert_no_difference(expressions, message = nil, &block)
115
117
  assert_difference expressions, 0, message, &block
116
118
  end
117
-
118
- end
119
+ end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redmine_crm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.23
4
+ version: 0.0.25
5
5
  platform: ruby
6
6
  authors:
7
7
  - RedmineCRM
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-28 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2017-03-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: liquid
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "<"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.6.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "<"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.6.4
13
27
  description: Common libraries for RedmineCRM plugins for Redmine. Requered Redmine
14
28
  from http://redmine.org
15
29
  email:
@@ -26,30 +40,48 @@ files:
26
40
  - doc/CHANGELOG
27
41
  - doc/LICENSE.txt
28
42
  - lib/redmine_crm.rb
43
+ - lib/redmine_crm/acts_as_taggable/rcrm_acts_as_taggable.rb
44
+ - lib/redmine_crm/acts_as_taggable/tag.rb
45
+ - lib/redmine_crm/acts_as_taggable/tag_list.rb
46
+ - lib/redmine_crm/acts_as_taggable/tagging.rb
47
+ - lib/redmine_crm/acts_as_viewed/rcrm_acts_as_viewed.rb
48
+ - lib/redmine_crm/acts_as_votable/rcrm_acts_as_votable.rb
49
+ - lib/redmine_crm/acts_as_votable/rcrm_acts_as_voter.rb
50
+ - lib/redmine_crm/acts_as_votable/votable.rb
51
+ - lib/redmine_crm/acts_as_votable/vote.rb
52
+ - lib/redmine_crm/acts_as_votable/voter.rb
29
53
  - lib/redmine_crm/currency.rb
30
54
  - lib/redmine_crm/currency/formatting.rb
31
55
  - lib/redmine_crm/currency/heuristics.rb
32
56
  - lib/redmine_crm/currency/loader.rb
33
57
  - lib/redmine_crm/helpers/tags_helper.rb
34
58
  - lib/redmine_crm/helpers/vote_helper.rb
59
+ - lib/redmine_crm/liquid/drops/issues_drop.rb
60
+ - lib/redmine_crm/liquid/drops/news_drop.rb
61
+ - lib/redmine_crm/liquid/drops/projects_drop.rb
62
+ - lib/redmine_crm/liquid/drops/users_drop.rb
63
+ - lib/redmine_crm/liquid/filters/arrays.rb
64
+ - lib/redmine_crm/liquid/filters/base.rb
35
65
  - lib/redmine_crm/money_helper.rb
36
- - lib/redmine_crm/rcrm_acts_as_taggable.rb
37
- - lib/redmine_crm/rcrm_acts_as_viewed.rb
38
- - lib/redmine_crm/rcrm_acts_as_votable.rb
39
- - lib/redmine_crm/rcrm_acts_as_voter.rb
40
- - lib/redmine_crm/tag.rb
41
- - lib/redmine_crm/tag_list.rb
42
- - lib/redmine_crm/tagging.rb
43
66
  - lib/redmine_crm/version.rb
44
- - lib/redmine_crm/votable.rb
45
- - lib/redmine_crm/vote.rb
46
- - lib/redmine_crm/voter.rb
47
67
  - redmine_crm.gemspec
48
- - test/acts_as_taggable_test.rb
68
+ - test/acts_as_taggable/rcrm_acts_as_taggable_test.rb
69
+ - test/acts_as_taggable/tag_list_test.rb
70
+ - test/acts_as_taggable/tag_test.rb
71
+ - test/acts_as_taggable/tagging_test.rb
72
+ - test/acts_as_viewed/rcrm_acts_as_viewed_test.rb
73
+ - test/acts_as_votable/rcrm_acts_as_votable_test.rb
74
+ - test/acts_as_votable/rcrm_acts_as_voter_test.rb
75
+ - test/acts_as_votable/votable_test.rb
76
+ - test/acts_as_votable/voter_test.rb
49
77
  - test/currency_test.rb
50
78
  - test/database.yml
51
79
  - test/fixtures/issue.rb
52
80
  - test/fixtures/issues.yml
81
+ - test/fixtures/news.rb
82
+ - test/fixtures/news.yml
83
+ - test/fixtures/project.rb
84
+ - test/fixtures/projects.yml
53
85
  - test/fixtures/taggings.yml
54
86
  - test/fixtures/tags.yml
55
87
  - test/fixtures/user.rb
@@ -58,17 +90,19 @@ files:
58
90
  - test/fixtures/votables.yml
59
91
  - test/fixtures/vote_classes.rb
60
92
  - test/fixtures/voters.yml
93
+ - test/liquid/drops/issues_drop_test.rb
94
+ - test/liquid/drops/liquid_test.rb
95
+ - test/liquid/drops/news_drop_test.rb
96
+ - test/liquid/drops/projects_drop_test.rb
97
+ - test/liquid/drops/uses_drop_test.rb
98
+ - test/liquid/filters/arrays_filter_test.rb
99
+ - test/liquid/filters/base_filter_test.rb
100
+ - test/liquid/liquid_helper.rb
61
101
  - test/money_helper_test.rb
62
102
  - test/schema.rb
63
- - test/tag_test.rb
64
- - test/tagging_test.rb
65
103
  - test/tags_helper_test.rb
66
104
  - test/test_helper.rb
67
- - test/viewed_test.rb
68
- - test/votable_model_test.rb
69
- - test/votable_test.rb
70
105
  - test/vote_helper_test.rb
71
- - test/voter_model_test.rb
72
106
  homepage: ''
73
107
  licenses:
74
108
  - GPL2
@@ -89,16 +123,28 @@ required_rubygems_version: !ruby/object:Gem::Requirement
89
123
  version: '0'
90
124
  requirements: []
91
125
  rubyforge_project:
92
- rubygems_version: 2.4.8
126
+ rubygems_version: 2.4.5.2
93
127
  signing_key:
94
128
  specification_version: 4
95
129
  summary: Common libraries for RedmineCRM plugins for Redmine
96
130
  test_files:
97
- - test/acts_as_taggable_test.rb
131
+ - test/acts_as_taggable/rcrm_acts_as_taggable_test.rb
132
+ - test/acts_as_taggable/tag_list_test.rb
133
+ - test/acts_as_taggable/tag_test.rb
134
+ - test/acts_as_taggable/tagging_test.rb
135
+ - test/acts_as_viewed/rcrm_acts_as_viewed_test.rb
136
+ - test/acts_as_votable/rcrm_acts_as_votable_test.rb
137
+ - test/acts_as_votable/rcrm_acts_as_voter_test.rb
138
+ - test/acts_as_votable/votable_test.rb
139
+ - test/acts_as_votable/voter_test.rb
98
140
  - test/currency_test.rb
99
141
  - test/database.yml
100
142
  - test/fixtures/issue.rb
101
143
  - test/fixtures/issues.yml
144
+ - test/fixtures/news.rb
145
+ - test/fixtures/news.yml
146
+ - test/fixtures/project.rb
147
+ - test/fixtures/projects.yml
102
148
  - test/fixtures/taggings.yml
103
149
  - test/fixtures/tags.yml
104
150
  - test/fixtures/user.rb
@@ -107,14 +153,16 @@ test_files:
107
153
  - test/fixtures/votables.yml
108
154
  - test/fixtures/vote_classes.rb
109
155
  - test/fixtures/voters.yml
156
+ - test/liquid/drops/issues_drop_test.rb
157
+ - test/liquid/drops/liquid_test.rb
158
+ - test/liquid/drops/news_drop_test.rb
159
+ - test/liquid/drops/projects_drop_test.rb
160
+ - test/liquid/drops/uses_drop_test.rb
161
+ - test/liquid/filters/arrays_filter_test.rb
162
+ - test/liquid/filters/base_filter_test.rb
163
+ - test/liquid/liquid_helper.rb
110
164
  - test/money_helper_test.rb
111
165
  - test/schema.rb
112
- - test/tag_test.rb
113
- - test/tagging_test.rb
114
166
  - test/tags_helper_test.rb
115
167
  - test/test_helper.rb
116
- - test/viewed_test.rb
117
- - test/votable_model_test.rb
118
- - test/votable_test.rb
119
168
  - test/vote_helper_test.rb
120
- - test/voter_model_test.rb
@@ -1,287 +0,0 @@
1
- # Copyright (c) 2008 Damian Martinelli
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining
4
- # a copy of this software and associated documentation files (the
5
- # "Software"), to deal in the Software without restriction, including
6
- # without limitation the rights to use, copy, modify, merge, publish,
7
- # distribute, sublicense, and/or sell copies of the Software, and to
8
- # permit persons to whom the Software is furnished to do so, subject to
9
- # the following conditions:
10
- #
11
- # The above copyright notice and this permission notice shall be
12
- # included in all copies or substantial portions of the Software.
13
- #
14
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
- module RedmineCrm
22
- module ActiveRecord #:nodoc:
23
- module Acts #:nodoc:
24
-
25
- # == acts_as_viewed
26
- # Adds views count capabilities to any ActiveRecord object.
27
- # It has the ability to work with objects that have or don't special fields to keep a tally of the
28
- # viewings for each object.
29
- # In addition it will by default use the User model as the viewer object and keep the viewings per-user.
30
- # It can be configured to use another class.
31
- # The IP address are used to not repeat views from the same ip. Only one view are count by user or IP.
32
- #
33
- # Special methods are provided to create the viewings table and if needed, to add the special fields needed
34
- # to keep per-objects viewings fast for access to viewed objects. Can be easily used in migrations.
35
- #
36
- # == Example of usage:
37
- #
38
- # class Video < ActiveRecord::Base
39
- # acts_as_viewed
40
- # end
41
- #
42
- # In a controller:
43
- #
44
- # bill = User.find_by_name 'bill'
45
- # batman = Video.find_by_title 'Batman'
46
- # toystory = Video.find_by_title 'Toy Story'
47
- #
48
- # batman.view request.remote_addr, bill
49
- # toystory.view request.remote_addr, bill
50
- #
51
- # batman.view_count # => 1
52
- #
53
- #
54
- module Viewed
55
-
56
- class ViewedError < RuntimeError; end
57
-
58
- def self.included(base) #:nodoc:
59
- base.extend(ClassMethods)
60
- end
61
-
62
- module ClassMethods
63
-
64
- # Make the model viewable.
65
- # The Viewing model, holding the details of the viewings, will be created dynamically if it doesn't exist.
66
- #
67
- # * Adds a <tt>has_many :viewings</tt> association to the model for easy retrieval of the detailed viewings.
68
- # * Adds a <tt>has_many :viewers</tt> association to the object.
69
- # * Adds a <tt>has_many :viewings</tt> associations to the viewer class.
70
- #
71
- # === Options
72
- # * <tt>:viewing_class</tt> -
73
- # class of the model used for the viewings. Defaults to Viewing. This class will be dynamically created if not already defined.
74
- # If the class is predefined, it must have in it the following definitions:
75
- # <tt>belongs_to :viewed, :polymorphic => true</tt>
76
- # <tt>belongs_to :viewer, :class_name => 'User', :foreign_key => :viewer_id</tt> replace user with the viewer class if needed.
77
- # * <tt>:viewer_class</tt> -
78
- # class of the model that creates the viewing.
79
- # Defaults to User This class will NOT be created, so it must be defined in the app.
80
- # Use the IP address to prevent multiple viewings from the same client.
81
- #
82
- def rcrm_acts_as_viewed(options = {})
83
- # don't allow multiple calls
84
- return if self.included_modules.include?(ActiveRecord::Acts::Viewed::ViewMethods)
85
- send :include, ActiveRecord::Acts::Viewed::ViewMethods
86
-
87
- # Create the model for ratings if it doesn't yet exist
88
- viewing_class = options[:viewing_class] || 'Viewing'
89
- viewer_class = options[:viewer_class] || 'User'
90
-
91
- unless Object.const_defined?(viewing_class)
92
- Object.class_eval <<-EOV
93
- class #{viewing_class} < ActiveRecord::Base
94
- belongs_to :viewed, :polymorphic => true
95
- belongs_to :viewer, :class_name => #{viewer_class}, :foreign_key => :viewer_id
96
- end
97
- EOV
98
- end
99
-
100
- # Rails < 3
101
- # write_inheritable_attribute( :acts_as_viewed_options ,
102
- # { :viewing_class => viewing_class,
103
- # :viewer_class => viewer_class } )
104
- # class_inheritable_reader :acts_as_viewed_options
105
-
106
- # Rails >= 3
107
- class_attribute :acts_as_viewed_options
108
- self.acts_as_viewed_options = { :viewing_class => viewing_class,
109
- :viewer_class => viewer_class }
110
- class_eval do
111
- has_many :viewings, :as => :viewed, :dependent => :delete_all, :class_name => viewing_class.to_s
112
- has_many(:viewers, :through => :viewings, :class_name => viewer_class.to_s)
113
-
114
- before_create :init_viewing_fields
115
- end
116
-
117
- # Add to the User (or whatever the viewer is) a has_many viewings
118
- viewer_as_class = viewer_class.constantize
119
- return if viewer_as_class.instance_methods.include?('find_in_viewings')
120
- viewer_as_class.class_eval <<-EOS
121
- has_many :viewings, :foreign_key => :viewer_id, :class_name => #{viewing_class.to_s}
122
- EOS
123
- end
124
- end
125
-
126
- module ViewMethods
127
-
128
- def self.included(base) #:nodoc:
129
- base.extend ClassMethods
130
- end
131
-
132
- # Is this object viewed already?
133
- def viewed?
134
- return (!self.views.nil? && self.views > 0) if attributes.has_key? 'views'
135
- !viewings.first.nil?
136
- end
137
-
138
- # Get the number of viewings for this object based on the views field,
139
- # or with a SQL query if the viewed objects doesn't have the views field
140
- def view_count
141
- return ("#{self.total_views}(#{self.views})" || 0) if attributes.has_key? 'views'
142
- viewings.count
143
- end
144
-
145
- # Change views count (total_views and views) if it's existing in object
146
- # If options[:only_total] == true count of unique views doesn't change
147
- def increase_views_count(options)
148
- if attributes.has_key?('views') && attributes.has_key?('total_views')
149
- target = self
150
- target.views = ( (target.views || 0) + 1 ) if !options[:only_total]
151
- target.total_views = ( (target.total_views || 0) + 1)
152
- target.save(:validate => false)
153
- # target.save_without_validation
154
- end
155
- end
156
-
157
- # View the object with or without a viewer - create new or update as needed
158
- #
159
- # * <tt>ip</tt> - the viewer ip
160
- # * <tt>viewer</tt> - an object of the viewer class. Must be valid and with an id to be used. Or nil
161
- def view ip, viewer = nil
162
- # Sanity checks for the parameters
163
- viewing_class = acts_as_viewed_options[:viewing_class].constantize
164
- if viewer && !(acts_as_viewed_options[:viewer_class].constantize === viewer)
165
- raise ViewedError, "the viewer object must be the one used when defining acts_as_viewed (or a descendent of it). other objects are not acceptable"
166
- end
167
-
168
- viewing_class.transaction do
169
- if !viewed_by? ip, viewer
170
- view = viewing_class.new
171
- view.viewer_id = viewer.id if viewer && !viewer.id.nil?
172
- view.ip = ip
173
- viewings << view
174
- view.save
175
- increase_views_count(:only_total => false)
176
- else
177
- increase_views_count(:only_total => true)
178
- end
179
- true
180
- end
181
- end
182
-
183
- # Check if an item was already viewed by the given viewer
184
- def viewed_by? ip, viewer = nil
185
- if viewer && !viewer.nil? && !(acts_as_viewed_options[:viewer_class].constantize === viewer)
186
- raise ViewedError, "the viewer object must be the one used when defining acts_as_viewed (or a descendent of it). other objects are not acceptable"
187
- end
188
- if viewer && !viewer.id.nil? && !viewer.anonymous?
189
- return viewings.where("viewer_id = '#{viewer.id}'").any?
190
- else
191
- return viewings.where("ip = '#{ip}'").any?
192
- end
193
- end
194
-
195
- private
196
-
197
- def init_viewing_fields #:nodoc:
198
- if attributes.has_key? 'views'
199
- self.views ||= 0
200
- end
201
- end
202
-
203
- end
204
-
205
- module ClassMethods
206
-
207
- # Generate the viewings columns on a table, to be used when creating the table
208
- # in a migration. This is the preferred way to do in a migration that creates
209
- # new tables as it will make it as part of the table creation, and not generate
210
- # ALTER TABLE calls after the fact
211
- def generate_viewings_columns table
212
- table.column :views, :integer #uniq views
213
- table.column :total_views, :integer
214
- end
215
-
216
- # Create the needed columns for acts_as_viewed.
217
- # To be used during migration, but can also be used in other places.
218
- def add_viewings_columns
219
- if !self.content_columns.find { |c| 'views' == c.name }
220
- self.connection.add_column table_name, :views, :integer, :default => '0'
221
- self.connection.add_column table_name, :total_views, :integer, :default => '0'
222
- self.reset_column_information
223
- end
224
- end
225
-
226
- # Remove the acts_as_viewed specific columns added with add_viewings_columns
227
- # To be used during migration, but can also be used in other places
228
- def remove_viewings_columns
229
- if self.content_columns.find { |c| 'views' == c.name }
230
- self.connection.remove_column table_name, :views
231
- self.connection.remove_column table_name, :total_views
232
- self.reset_column_information
233
- end
234
- end
235
-
236
- # Create the viewings table
237
- # === Options hash:
238
- # * <tt>:table_name</tt> - use a table name other than viewings
239
- # To be used during migration, but can also be used in other places
240
- def create_viewings_table options = {}
241
- name = options[:table_name] || :viewings
242
- if !self.connection.table_exists?(name)
243
- self.connection.create_table(name) do |t|
244
- t.column :viewer_id, :integer
245
- t.column :viewed_id, :integer
246
- t.column :viewed_type, :string
247
- t.column :ip, :string, :limit => '24'
248
- t.column :created_at, :datetime
249
- end
250
-
251
- self.connection.add_index(name, :viewer_id)
252
- self.connection.add_index(name, [:viewed_type, :viewed_id])
253
- end
254
- end
255
-
256
- # Drop the viewings table.
257
- # === Options hash:
258
- # * <tt>:table_name</tt> - the name of the viewings table, defaults to viewings
259
- # To be used during migration, but can also be used in other places
260
- def drop_viewings_table options = {}
261
- name = options[:table_name] || :viewings
262
- if self.connection.table_exists?(name)
263
- self.connection.drop_table(name)
264
- end
265
- end
266
-
267
- # Find all viewings for a specific viewer.
268
- def find_viewed_by viewer
269
- viewing_class = acts_as_viewed_options[:viewing_class].constantize
270
- if !(acts_as_viewed_options[:viewer_class].constantize === viewer)
271
- raise ViewedError, "The viewer object must be the one used when defining acts_as_viewed (or a descendent of it). other objects are not acceptable"
272
- end
273
- raise ViewedError, "Viewer must be a valid and existing object" if viewer.nil? || viewer.id.nil?
274
- raise ViewedError, 'Viewer must be a valid viewer' if !viewing_class.column_names.include? "viewer_id"
275
- viewed_class = ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s
276
- conds = [ 'viewed_type = ? AND viewer_id = ?', viewed_class, viewer.id ]
277
- acts_as_viewed_options[:viewing_class].constantize.find(:all, :conditions => conds).collect {|r| r.viewed_type.constantize.find_by_id r.viewed.id }
278
- end
279
- end
280
- end
281
- end
282
- end
283
- end
284
-
285
-
286
- ActiveRecord::Base.send :include, RedmineCrm::ActiveRecord::Acts::Viewed
287
-