redmine_crm 0.0.23 → 0.0.25

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