evilmarty_activity_stream 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +20 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README +113 -0
- data/Rakefile +25 -0
- data/activity_stream.gemspec +24 -0
- data/generators/activity_stream/USAGE +1 -0
- data/generators/activity_stream/activity_stream_generator.rb +12 -0
- data/generators/activity_stream/templates/migrate/create_activities.rb +16 -0
- data/generators/activity_stream/templates/models/activity.rb +18 -0
- data/init.rb +1 -0
- data/lib/activity_observer.rb +23 -0
- data/lib/activity_stream.rb +223 -0
- data/lib/activity_stream/CHANGELOG.md +2 -0
- data/lib/activity_stream/version.rb +3 -0
- data/lib/version.rb +3 -0
- data/rails/init.rb +9 -0
- data/tasks/activity_stream_tasks.rake +4 -0
- data/test/activity_stream_test.rb +68 -0
- data/test/database.yml +22 -0
- data/test/fixtures/comment.rb +16 -0
- data/test/fixtures/comments.yml +17 -0
- data/test/fixtures/people.yml +9 -0
- data/test/fixtures/person.rb +10 -0
- data/test/fixtures/post.rb +11 -0
- data/test/fixtures/posts.yml +9 -0
- data/test/schema.rb +15 -0
- data/test/test_helper.rb +54 -0
- metadata +149 -0
data/.gitignore
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
test/debug.log
|
18
|
+
tmp
|
19
|
+
.rbenv-gemsets
|
20
|
+
.rbenv-version
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 erikecoologic
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
# ActivityStream
|
2
|
+
|
3
|
+
Activity Stream will keep trace of your activity on the db.
|
4
|
+
|
5
|
+
This Gem is sutable for whom have installed [the plugin activity_stream by evilmarty](https://github.com/evilmarty/activity_stream) and want to use it with a Gem.
|
6
|
+
|
7
|
+
All tests are passing.
|
8
|
+
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
gem 'activity_stream'
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install activity_stream
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
See below original readme.
|
27
|
+
|
28
|
+
## Contributing
|
29
|
+
|
30
|
+
Contributions are welcome, but be aware that we're not the original developers of the code and our own part was to move the existing code into a Gem.
|
31
|
+
|
32
|
+
1. Fork it
|
33
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
34
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
35
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
36
|
+
5. Create new Pull Request
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
ActivityStream
|
42
|
+
==============
|
43
|
+
|
44
|
+
A dead easy way to log activity streams.
|
45
|
+
|
46
|
+
Installation
|
47
|
+
============
|
48
|
+
|
49
|
+
script/plugin install http://github.com/evilmarty/activity_stream
|
50
|
+
|
51
|
+
Then run...
|
52
|
+
|
53
|
+
script/generate activity_stream
|
54
|
+
|
55
|
+
this will create the Activity model and place it in your app/models path as a migration file.
|
56
|
+
|
57
|
+
|
58
|
+
DON'T FORGET to add :activity_observer to your config.active_record.observers in environments.rb like so...
|
59
|
+
|
60
|
+
config.active_record.observers = :activity_observer
|
61
|
+
|
62
|
+
Usage
|
63
|
+
=====
|
64
|
+
|
65
|
+
For all the models you want to log an activity for do the following...
|
66
|
+
|
67
|
+
class Comment < ActiveRecord::Base
|
68
|
+
log_activities
|
69
|
+
end
|
70
|
+
|
71
|
+
this will log an activity for :create, :update and :destroy. To only log an activity for :create simply say so...
|
72
|
+
|
73
|
+
class Comment < ActiveRecord::Base
|
74
|
+
log_activities :create
|
75
|
+
end
|
76
|
+
|
77
|
+
You can also pass a Proc which can be used to check whether to log the activity or not, just return false
|
78
|
+
|
79
|
+
class Comment < ActiveRecord::Base
|
80
|
+
log_activities :create, :destroy
|
81
|
+
log_activities :update do |record|
|
82
|
+
record.status == 1
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
and you can call it multiple times for different actions with different Procs
|
87
|
+
|
88
|
+
|
89
|
+
Now once your done with your logging, it's time to define your actors. Like so...
|
90
|
+
|
91
|
+
class User < ActiveRecord::Base
|
92
|
+
acts_as_actor
|
93
|
+
end
|
94
|
+
|
95
|
+
and now when you want to log activities simply do the following in your controllers or wherever you please
|
96
|
+
|
97
|
+
class CommentsController < ApplicationController
|
98
|
+
def create
|
99
|
+
current_user.log_activity('web') do
|
100
|
+
Comment.create params[:comment]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
that little argument for log_activity is the context of the activity but you can omit it should you feel so.
|
106
|
+
|
107
|
+
TODO
|
108
|
+
====
|
109
|
+
|
110
|
+
* write better doc
|
111
|
+
* add support for indirect objects maybe?
|
112
|
+
|
113
|
+
Copyright (c) 2009 Marty Zalega (evil.marty@gmail.com), released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
require 'rake'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
|
7
|
+
desc 'Default: run unit tests.'
|
8
|
+
task :default => :test
|
9
|
+
|
10
|
+
desc 'Test the retrieve_resource plugin.'
|
11
|
+
Rake::TestTask.new(:test) do |t|
|
12
|
+
t.libs << 'lib'
|
13
|
+
t.libs << 'test'
|
14
|
+
t.pattern = 'test/**/*_test.rb'
|
15
|
+
t.verbose = true
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'Generate documentation for the retrieve_resource plugin.'
|
19
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
20
|
+
rdoc.rdoc_dir = 'rdoc'
|
21
|
+
rdoc.title = 'RetrieveResource'
|
22
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
23
|
+
rdoc.rdoc_files.include('README')
|
24
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'activity_stream/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "evilmarty_activity_stream"
|
8
|
+
gem.version = ActivityStream::VERSION
|
9
|
+
gem.authors = ["ecoologic"]
|
10
|
+
gem.email = ["erik@netengine.com.au"]
|
11
|
+
gem.description = %q{A Gem for the plugin: https://github.com/evilmarty/activity_stream}
|
12
|
+
gem.summary = %q{This is a dependency we intend to maintain in order to upgrade our own projects from Rails 2.3.5 to 3.2 (or 4?)}
|
13
|
+
gem.homepage = "https://github.com/organizations/net-engine/activity_stream"
|
14
|
+
|
15
|
+
gem.add_development_dependency 'rake', ['0.8.7']
|
16
|
+
gem.add_development_dependency 'rails', ['2.3.16']
|
17
|
+
gem.add_development_dependency 'sqlite3'
|
18
|
+
|
19
|
+
|
20
|
+
gem.files = `git ls-files`.split($/)
|
21
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
22
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
23
|
+
gem.require_paths = ["lib"]
|
24
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Just run with no arguments
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class ActivityStreamGenerator < Rails::Generator::Base
|
2
|
+
def manifest
|
3
|
+
record do |m|
|
4
|
+
m.file 'models/activity.rb', 'app/models/activity.rb'
|
5
|
+
m.migration_template 'migrate/create_activities.rb', 'db/migrate'
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def file_name
|
10
|
+
'create_activities'
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CreateActivities < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :activities do |t|
|
4
|
+
t.string :verb, :null => false, :limit => 24
|
5
|
+
t.references :actor, :polymorphic => true
|
6
|
+
t.references :object, :polymorphic => true
|
7
|
+
t.references :indirect_object, :polymorphic => true
|
8
|
+
t.string :context, :limit => 32
|
9
|
+
t.datetime :timestamp, :null => false
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.down
|
14
|
+
drop_table :activities
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Activity < ActiveRecord::Base
|
2
|
+
default_scope :order => 'timestamp DESC'
|
3
|
+
|
4
|
+
belongs_to :actor, :polymorphic => true
|
5
|
+
belongs_to :object, :polymorphic => true
|
6
|
+
belongs_to :indirect_object, :polymorphic => true
|
7
|
+
|
8
|
+
validates_presence_of :actor, :object, :verb
|
9
|
+
|
10
|
+
def before_create
|
11
|
+
self.timestamp ||= Time.now
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
default = ["objects.#{object_type.underscore}.#{verb}".intern, "verbs.#{verb}".intern, "#{actor_type.underscore} #{verb} #{object_type.intern}"]
|
16
|
+
I18n.t "actors.#{actor_type.underscore}.#{object_type.underscore}.#{verb}", :scope => 'activity_streams', :default => default, :actor => actor, :verb => verb, :object => object, :object_type => object_type
|
17
|
+
end
|
18
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'rails/init.rb'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class ActivityObserver < ActiveRecord::Observer
|
2
|
+
class << self
|
3
|
+
# we don't want to include the activity model
|
4
|
+
def observed_class
|
5
|
+
nil
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def update(observed_method, object)
|
10
|
+
# check the object isn't an activity
|
11
|
+
return if object.is_a? Activity
|
12
|
+
context, block = Thread.current[:activity_stream_context], object.class.activity_triggers[observed_method]
|
13
|
+
# lets not log an activity if we don't have an actor or isn't an allowed callback
|
14
|
+
return unless !!context and (block.is_a?(Proc) ? block.call(object) != false : block == true)
|
15
|
+
|
16
|
+
verb = observed_method.to_s.gsub /^after_/, ''
|
17
|
+
|
18
|
+
attributes = context.attributes.merge :verb => verb, :object => object
|
19
|
+
attributes[:indirect_object] ||= object.instance_variable_get('@_indirect_object')
|
20
|
+
|
21
|
+
Activity.create(attributes)
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
require "activity_stream/version"
|
2
|
+
|
3
|
+
module ActivityStream
|
4
|
+
class Context
|
5
|
+
attr_reader :attributes
|
6
|
+
|
7
|
+
def initialize(attributes = {})
|
8
|
+
@attributes = attributes
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(&block)
|
12
|
+
raise ArgumentError unless block_given?
|
13
|
+
current_context = Thread.current[:activity_stream_context]
|
14
|
+
Thread.current[:activity_stream_context] = self
|
15
|
+
|
16
|
+
yield
|
17
|
+
|
18
|
+
Thread.current[:activity_stream_context] = current_context
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
attributes[:context].to_s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module ActiveRecord
|
27
|
+
def self.included(base)
|
28
|
+
base.extend ClassMethods
|
29
|
+
end
|
30
|
+
|
31
|
+
module ClassMethods
|
32
|
+
def activity_triggers
|
33
|
+
read_inheritable_attribute(:activity_triggers) || {}
|
34
|
+
end
|
35
|
+
|
36
|
+
def log_activities(*args, &block)
|
37
|
+
args = [:create, :update, :destroy] if args.length == 0
|
38
|
+
|
39
|
+
activity_triggers = self.activity_triggers
|
40
|
+
callback = block_given?? block : true
|
41
|
+
args.each { |verb| activity_triggers["after_#{verb}".intern] = callback }
|
42
|
+
write_inheritable_attribute :activity_triggers, activity_triggers
|
43
|
+
|
44
|
+
unless defined? @_activity_observed
|
45
|
+
has_many :activities, :as => :object do
|
46
|
+
def all(options = {})
|
47
|
+
klass = proxy_owner.klass
|
48
|
+
Scope.new scope_for_reflection(:find => {:conditions => ['object_type = ? OR indirect_object_type = ?', klass.name, klass.name]}), :find => options
|
49
|
+
end
|
50
|
+
|
51
|
+
def indirectly(options = {})
|
52
|
+
klass = proxy_owner.klass
|
53
|
+
Scope.new scope_for_reflection(:find => {:conditions => {:indirect_object_type => klass.name}}), :find => options
|
54
|
+
end
|
55
|
+
|
56
|
+
def directly(options = {})
|
57
|
+
klass = proxy_owner.klass
|
58
|
+
Scope.new scope_for_reflection(:find => {:conditions => {:object_type => klass.name}}), :find => options
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
def scope_for_reflection(options)
|
63
|
+
Scope.new proxy_reflection.klass, options
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
add_observer ActivityObserver.instance
|
68
|
+
# to ensure we don't add the observer multiple times
|
69
|
+
@_activity_observed = true
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def skip_log_activity(*args)
|
74
|
+
args = args.map(&:to_sym)
|
75
|
+
write_inheritable_attribute :activity_triggers, activity_triggers.reject { |k, v| args.include?("after_#{k}".intern) }
|
76
|
+
end
|
77
|
+
|
78
|
+
def acts_as_actor
|
79
|
+
class_eval do
|
80
|
+
def log_activity(options = {}, &block)
|
81
|
+
raise ArgumentError unless block_given?
|
82
|
+
|
83
|
+
context = ActivityStream::Context.new options.merge(:actor => self)
|
84
|
+
context.call(&block)
|
85
|
+
end
|
86
|
+
|
87
|
+
def log_activity_indirectly_for(record, options = {}, &block)
|
88
|
+
log_activity options.merge(:indirect_object => record), &block
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
has_many :activities, :as => :actor
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
module AssociationProxy
|
98
|
+
def self.included(base)
|
99
|
+
base.class_eval do
|
100
|
+
private
|
101
|
+
def find_indirect_object
|
102
|
+
# we don't want activity to be our indirect object
|
103
|
+
return nil if @owner.class == Activity
|
104
|
+
|
105
|
+
# tried to use memoize but too many errors, bah!
|
106
|
+
@indirect_object ||= if @owner.class.respond_to?(:activity_triggers)
|
107
|
+
@owner
|
108
|
+
elsif ivar = @owner.instance_variable_get('@_indirect_object')
|
109
|
+
ivar
|
110
|
+
else
|
111
|
+
nil
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def tag_with_indirect_object(record)
|
116
|
+
record.instance_variable_set '@_indirect_object', find_indirect_object if find_indirect_object
|
117
|
+
end
|
118
|
+
|
119
|
+
def set_belongs_to_association_for_with_indirect_object(record)
|
120
|
+
tag_with_indirect_object record
|
121
|
+
set_belongs_to_association_for_without_indirect_object record
|
122
|
+
end
|
123
|
+
alias_method_chain :set_belongs_to_association_for, :indirect_object
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
module AssociationCollection
|
129
|
+
def self.included(base)
|
130
|
+
base.class_eval do
|
131
|
+
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
module BelongsToAssociation
|
137
|
+
def self.included(base)
|
138
|
+
base.class_eval do
|
139
|
+
def replace_with_indirect_object(record)
|
140
|
+
tag_with_indirect_object record
|
141
|
+
replace_without_indirect_object record
|
142
|
+
end
|
143
|
+
alias_method_chain :replace, :indirect_object
|
144
|
+
|
145
|
+
def find_target_with_indirect_object
|
146
|
+
record = find_target_without_indirect_object
|
147
|
+
tag_with_indirect_object record
|
148
|
+
record
|
149
|
+
end
|
150
|
+
alias_method_chain :find_target, :indirect_object
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
module HasOneAssociation
|
156
|
+
def self.included(base)
|
157
|
+
base.class_eval do
|
158
|
+
def replace_with_indirect_object(*args)
|
159
|
+
tag_with_indirect_object args.first
|
160
|
+
replace_without_indirect_object *args
|
161
|
+
end
|
162
|
+
alias_method_chain :replace, :indirect_object
|
163
|
+
|
164
|
+
def new_record_with_indirect_object(replace_existing, &block)
|
165
|
+
new_record_without_indirect_object replace_existing do |reflection|
|
166
|
+
record = block.call reflection
|
167
|
+
# if we are going to replace_existing, this'll get done in our
|
168
|
+
# replace_with_parental_control above - no point in doing it twice
|
169
|
+
tag_with_indirect_object record unless replace_existing
|
170
|
+
record
|
171
|
+
end
|
172
|
+
end
|
173
|
+
alias_method_chain :new_record, :indirect_object
|
174
|
+
|
175
|
+
def find_target_with_indirect_object
|
176
|
+
record = find_target_without_indirect_object
|
177
|
+
tag_with_indirect_object record
|
178
|
+
record
|
179
|
+
end
|
180
|
+
alias_method_chain :find_target, :indirect_object
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
module HasManyAssociation
|
186
|
+
def self.included(base)
|
187
|
+
base.class_eval do
|
188
|
+
def add_record_to_target_with_callbacks_with_indirect_object(record, &block)
|
189
|
+
tag_with_indirect_object record
|
190
|
+
add_record_to_target_with_callbacks_without_indirect_object record, &block
|
191
|
+
end
|
192
|
+
alias_method_chain :add_record_to_target_with_callbacks, :indirect_object
|
193
|
+
|
194
|
+
def find_target_with_indirect_object
|
195
|
+
records = find_target_without_indirect_object
|
196
|
+
records.each { |record| tag_with_indirect_object(record) }
|
197
|
+
records
|
198
|
+
end
|
199
|
+
alias_method_chain :find_target, :indirect_object
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
module BelongsToPolymorphicAssociation
|
206
|
+
def self.included(base)
|
207
|
+
base.class_eval do
|
208
|
+
def replace_with_indirect_object(record)
|
209
|
+
tag_with_indirect_object record
|
210
|
+
replace_without_indirect_object record
|
211
|
+
end
|
212
|
+
alias_method_chain :replace, :indirect_object
|
213
|
+
|
214
|
+
def find_target_with_indirect_object
|
215
|
+
record = find_target_without_indirect_object
|
216
|
+
tag_with_indirect_object record
|
217
|
+
record
|
218
|
+
end
|
219
|
+
alias_method_chain :find_target, :indirect_object
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
data/lib/version.rb
ADDED
data/rails/init.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'activity_stream'
|
2
|
+
require 'activity_observer'
|
3
|
+
|
4
|
+
ActiveRecord::Base.class_eval { include ActivityStream::ActiveRecord }
|
5
|
+
ActiveRecord::Associations::AssociationProxy.class_eval { include ActivityStream::AssociationProxy }
|
6
|
+
ActiveRecord::Associations::BelongsToAssociation.class_eval { include ActivityStream::BelongsToAssociation }
|
7
|
+
ActiveRecord::Associations::HasOneAssociation.class_eval { include ActivityStream::HasOneAssociation }
|
8
|
+
ActiveRecord::Associations::HasManyAssociation.class_eval { include ActivityStream::HasManyAssociation }
|
9
|
+
ActiveRecord::Associations::BelongsToPolymorphicAssociation.class_eval { include ActivityStream::BelongsToPolymorphicAssociation }
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper.rb')
|
2
|
+
|
3
|
+
class ActivityStreamTest < ActiveSupport::TestCase
|
4
|
+
load_schema
|
5
|
+
load_fixtures
|
6
|
+
load_activity_model
|
7
|
+
|
8
|
+
def test_model_actor_setup
|
9
|
+
assert @person = Person.first
|
10
|
+
assert_respond_to @person, :log_activity
|
11
|
+
assert_respond_to @person, :activities
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_model_activity_setup
|
15
|
+
assert @comment = Comment.first
|
16
|
+
assert_respond_to Comment, :log_activities
|
17
|
+
assert_respond_to Comment, :activity_triggers
|
18
|
+
assert_instance_of Hash, Comment.activity_triggers
|
19
|
+
assert_equal true, Comment.activity_triggers[:after_create]
|
20
|
+
assert_instance_of Proc, Comment.activity_triggers[:after_update]
|
21
|
+
assert_instance_of Proc, Comment.activity_triggers[:after_destroy]
|
22
|
+
assert_equal 1, Comment.count_observers
|
23
|
+
assert_respond_to @comment, :activities
|
24
|
+
assert_respond_to @comment.activities, :indirectly
|
25
|
+
assert_respond_to @comment.activities, :directly
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_activity_observer
|
29
|
+
assert_respond_to ActivityObserver, :instance
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_log_activity
|
33
|
+
assert @person = Person.first
|
34
|
+
Activity.delete_all
|
35
|
+
@person.log_activity do
|
36
|
+
@comment = @person.comments.build(:message => "I'm going to leave an activity")
|
37
|
+
assert @comment.save
|
38
|
+
end
|
39
|
+
assert @activity = Activity.first
|
40
|
+
assert_equal @person, @activity.actor
|
41
|
+
assert_equal @comment, @activity.object
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_indirect_object
|
45
|
+
Activity.delete_all
|
46
|
+
assert @person = Person.last
|
47
|
+
assert @post = Post.first
|
48
|
+
assert @comment = @post.comments.build(:message => 'testing indirect object')
|
49
|
+
|
50
|
+
@person.log_activity do
|
51
|
+
assert @comment.save
|
52
|
+
end
|
53
|
+
assert_equal @post, Activity.first.indirect_object
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_explicit_indirect_object
|
57
|
+
Activity.delete_all
|
58
|
+
assert @person = Person.last
|
59
|
+
assert @post = Post.first
|
60
|
+
assert @other_post = Post.last
|
61
|
+
assert_not_equal @post, @other_post
|
62
|
+
|
63
|
+
@person.log_activity_indirectly_for(@other_post) do
|
64
|
+
assert @post.comments.create :message => 'testing explicit indirect'
|
65
|
+
end
|
66
|
+
assert_equal @other_post, Activity.first.indirect_object
|
67
|
+
end
|
68
|
+
end
|
data/test/database.yml
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
sqlite3:
|
2
|
+
database: ":memory:"
|
3
|
+
adapter: sqlite3
|
4
|
+
timeout: 500
|
5
|
+
|
6
|
+
sqlite2:
|
7
|
+
database: ":memory:"
|
8
|
+
adapter: sqlite2
|
9
|
+
|
10
|
+
mysql:
|
11
|
+
adapter: mysql
|
12
|
+
username: root
|
13
|
+
password:
|
14
|
+
encoding: utf8
|
15
|
+
database: activity_stream_unittest
|
16
|
+
|
17
|
+
postgres:
|
18
|
+
adapter: postgresql
|
19
|
+
username: root
|
20
|
+
password:
|
21
|
+
database: activity_stream_unittest
|
22
|
+
min_messages: warning
|
@@ -0,0 +1,17 @@
|
|
1
|
+
witty_comment:
|
2
|
+
id: 1
|
3
|
+
person_id: 1
|
4
|
+
post_id: 1
|
5
|
+
message: "Birdman is better!"
|
6
|
+
|
7
|
+
plea_comment:
|
8
|
+
id: 2
|
9
|
+
person_id: 1
|
10
|
+
post_id: 1
|
11
|
+
message: "I beg of you wont someone please think of the children"
|
12
|
+
|
13
|
+
robbery:
|
14
|
+
id: 3
|
15
|
+
person_id: 2
|
16
|
+
post_id: 2
|
17
|
+
message: "Nobody this is a robbery!"
|
data/test/schema.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 0) do
|
2
|
+
create_table :people, :force => true do |t|
|
3
|
+
t.string :firstname
|
4
|
+
t.string :lastname
|
5
|
+
t.timestamps
|
6
|
+
end
|
7
|
+
create_table :posts, :force => true do |t|
|
8
|
+
t.string :message
|
9
|
+
t.references :person
|
10
|
+
end
|
11
|
+
create_table :comments, :force => true do |t|
|
12
|
+
t.string :message
|
13
|
+
t.references :person, :post
|
14
|
+
end
|
15
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
ENV['RAILS_ENV'] = 'test'
|
2
|
+
ENV['RAILS_ROOT'] ||= File.dirname(__FILE__) + '/../../../..'
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
require 'yaml'
|
6
|
+
require 'rubygems'
|
7
|
+
require 'active_record'
|
8
|
+
require 'active_record/version'
|
9
|
+
require 'active_record/fixtures'
|
10
|
+
|
11
|
+
require File.join(File.dirname(__FILE__), '..', 'init.rb')
|
12
|
+
|
13
|
+
def load_schema
|
14
|
+
config = YAML::load(IO.read(File.join(File.dirname(__FILE__), 'database.yml')))
|
15
|
+
ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), "/debug.log"))
|
16
|
+
|
17
|
+
db_adapter = ENV['DB']
|
18
|
+
|
19
|
+
# no db passed, try one of these fine config-free DBs before bombing.
|
20
|
+
db_adapter ||=
|
21
|
+
begin
|
22
|
+
require 'rubygems'
|
23
|
+
require 'sqlite'
|
24
|
+
'sqlite'
|
25
|
+
rescue MissingSourceFile
|
26
|
+
begin
|
27
|
+
require 'sqlite3'
|
28
|
+
'sqlite3'
|
29
|
+
rescue MissingSourceFile
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
if db_adapter.nil?
|
34
|
+
raise "No DB Adapter selected. Pass the DB= option to pick one, or install Sqlite or Sqlite3."
|
35
|
+
end
|
36
|
+
|
37
|
+
ActiveRecord::Base.establish_connection(config[db_adapter])
|
38
|
+
load(File.join(File.dirname(__FILE__), "schema.rb"))
|
39
|
+
end
|
40
|
+
|
41
|
+
def load_fixtures
|
42
|
+
filepath = File.join(File.dirname(__FILE__), 'fixtures')
|
43
|
+
ActiveSupport::Dependencies.load_paths.unshift filepath
|
44
|
+
Fixtures.create_fixtures(filepath, ActiveRecord::Base.connection.tables)
|
45
|
+
end
|
46
|
+
|
47
|
+
def load_activity_model
|
48
|
+
template_path = File.join(File.dirname(__FILE__), '..', 'generators', 'activity_stream', 'templates')
|
49
|
+
|
50
|
+
load(File.join(template_path, 'migrate', 'create_activities.rb'))
|
51
|
+
CreateActivities.up
|
52
|
+
|
53
|
+
load(File.join(template_path, 'models', 'activity.rb'))
|
54
|
+
end
|
metadata
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: evilmarty_activity_stream
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- ecoologic
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2013-02-02 00:00:00 +10:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rake
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - "="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 49
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 8
|
33
|
+
- 7
|
34
|
+
version: 0.8.7
|
35
|
+
type: :development
|
36
|
+
requirement: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rails
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - "="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 35
|
46
|
+
segments:
|
47
|
+
- 2
|
48
|
+
- 3
|
49
|
+
- 16
|
50
|
+
version: 2.3.16
|
51
|
+
type: :development
|
52
|
+
requirement: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: sqlite3
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
type: :development
|
66
|
+
requirement: *id003
|
67
|
+
description: "A Gem for the plugin: https://github.com/evilmarty/activity_stream"
|
68
|
+
email:
|
69
|
+
- erik@netengine.com.au
|
70
|
+
executables: []
|
71
|
+
|
72
|
+
extensions: []
|
73
|
+
|
74
|
+
extra_rdoc_files: []
|
75
|
+
|
76
|
+
files:
|
77
|
+
- .gitignore
|
78
|
+
- Gemfile
|
79
|
+
- LICENSE.txt
|
80
|
+
- README
|
81
|
+
- Rakefile
|
82
|
+
- activity_stream.gemspec
|
83
|
+
- generators/activity_stream/USAGE
|
84
|
+
- generators/activity_stream/activity_stream_generator.rb
|
85
|
+
- generators/activity_stream/templates/migrate/create_activities.rb
|
86
|
+
- generators/activity_stream/templates/models/activity.rb
|
87
|
+
- init.rb
|
88
|
+
- lib/activity_observer.rb
|
89
|
+
- lib/activity_stream.rb
|
90
|
+
- lib/activity_stream/CHANGELOG.md
|
91
|
+
- lib/activity_stream/version.rb
|
92
|
+
- lib/version.rb
|
93
|
+
- rails/init.rb
|
94
|
+
- tasks/activity_stream_tasks.rake
|
95
|
+
- test/activity_stream_test.rb
|
96
|
+
- test/database.yml
|
97
|
+
- test/fixtures/comment.rb
|
98
|
+
- test/fixtures/comments.yml
|
99
|
+
- test/fixtures/people.yml
|
100
|
+
- test/fixtures/person.rb
|
101
|
+
- test/fixtures/post.rb
|
102
|
+
- test/fixtures/posts.yml
|
103
|
+
- test/schema.rb
|
104
|
+
- test/test_helper.rb
|
105
|
+
has_rdoc: true
|
106
|
+
homepage: https://github.com/organizations/net-engine/activity_stream
|
107
|
+
licenses: []
|
108
|
+
|
109
|
+
post_install_message:
|
110
|
+
rdoc_options: []
|
111
|
+
|
112
|
+
require_paths:
|
113
|
+
- lib
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
hash: 3
|
120
|
+
segments:
|
121
|
+
- 0
|
122
|
+
version: "0"
|
123
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
|
+
none: false
|
125
|
+
requirements:
|
126
|
+
- - ">="
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
hash: 3
|
129
|
+
segments:
|
130
|
+
- 0
|
131
|
+
version: "0"
|
132
|
+
requirements: []
|
133
|
+
|
134
|
+
rubyforge_project:
|
135
|
+
rubygems_version: 1.6.2
|
136
|
+
signing_key:
|
137
|
+
specification_version: 3
|
138
|
+
summary: This is a dependency we intend to maintain in order to upgrade our own projects from Rails 2.3.5 to 3.2 (or 4?)
|
139
|
+
test_files:
|
140
|
+
- test/activity_stream_test.rb
|
141
|
+
- test/database.yml
|
142
|
+
- test/fixtures/comment.rb
|
143
|
+
- test/fixtures/comments.yml
|
144
|
+
- test/fixtures/people.yml
|
145
|
+
- test/fixtures/person.rb
|
146
|
+
- test/fixtures/post.rb
|
147
|
+
- test/fixtures/posts.yml
|
148
|
+
- test/schema.rb
|
149
|
+
- test/test_helper.rb
|