muck-activity 0.1.1
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.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +65 -0
- data/Rakefile +76 -0
- data/VERSION +1 -0
- data/app/controllers/muck/activities_controller.rb +155 -0
- data/app/helpers/muck_activity_helper.rb +16 -0
- data/app/models/activity.rb +50 -0
- data/app/models/activity_feed.rb +14 -0
- data/app/views/activities/_activity_feed.html.erb +26 -0
- data/app/views/activities/_cached_activities.html.erb +7 -0
- data/app/views/activities/_current_status.html.erb +15 -0
- data/app/views/activities/_delete.html.erb +11 -0
- data/app/views/activities/_status_update.html.erb +38 -0
- data/app/views/activity_templates/_status_update.html.erb +6 -0
- data/config/muck_activity_routes.rb +3 -0
- data/db/migrate/20090402033319_add_muck_activities.rb +36 -0
- data/install.rb +1 -0
- data/lib/muck_activity/initialize_routes.rb +8 -0
- data/lib/muck_activity/tasks.rb +28 -0
- data/lib/muck_activity.rb +76 -0
- data/locales/en.yml +22 -0
- data/public/images/loading.gif +0 -0
- data/rails/init.rb +4 -0
- data/tasks/muck_activity_tasks.rake +1 -0
- data/test/factories.rb +41 -0
- data/test/functional/activities_controller_test.rb +64 -0
- data/test/muck_activity_test.rb +8 -0
- data/test/shoulda_macros/controller.rb +43 -0
- data/test/test_helper.rb +35 -0
- data/test/unit/activity_feed_test.rb +5 -0
- data/test/unit/activity_test.rb +49 -0
- data/uninstall.rb +1 -0
- metadata +109 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Justin Ball
|
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.
|
data/README.rdoc
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
= MuckActivity
|
2
|
+
|
3
|
+
== Installation
|
4
|
+
The muck activity engine is part of the muck framework and relies upon the muck_engine. The main engine can be found here:
|
5
|
+
http://github.com/jbasdf/muck_engine
|
6
|
+
|
7
|
+
The easiest way to get started with muck is to generate your application using a template:
|
8
|
+
$ rails <your-app> -m http://github.com/jbasdf/rails-templates/raw/master/muck.rb
|
9
|
+
|
10
|
+
Add optional functionality with the following command:
|
11
|
+
$ rake rails:template LOCATION=http://github.com/jbasdf/rails-templates/raw/master/mucktoo.rb
|
12
|
+
|
13
|
+
== Usage
|
14
|
+
This engine implements simple activity tracking.
|
15
|
+
|
16
|
+
Models that can have activity feed should call 'has_activities'
|
17
|
+
|
18
|
+
Example:
|
19
|
+
class User
|
20
|
+
has_activities
|
21
|
+
end
|
22
|
+
|
23
|
+
Adding an item to the activity feed requires 'acts_as_activity_source' which then profiles the method 'add_activity'
|
24
|
+
|
25
|
+
add_activity(feed_to, actor, item, template, check_method)
|
26
|
+
|
27
|
+
feed_to - contains an array of objects (typically users) that have use acts_as_activity_user
|
28
|
+
actor - the user performing the action
|
29
|
+
item - a reference to the object that
|
30
|
+
template - the template (partial) to use to render the activity
|
31
|
+
check_method - and optional method to call on each object in the feed_to array that determines whether or not to add the activity
|
32
|
+
|
33
|
+
Example:
|
34
|
+
add_activity(user.feed_to, user, comment, 'comment')
|
35
|
+
|
36
|
+
=== Authorization
|
37
|
+
By default 'has_activities' will add a simple 'can_view?' method:
|
38
|
+
|
39
|
+
def can_view?(check_object)
|
40
|
+
self == check_object
|
41
|
+
end
|
42
|
+
|
43
|
+
This method determines whether or not the check_object has access to the current object's activity feeds. For example, if the
|
44
|
+
intent is to recover the activities for a given user where the user is '@parent' thus:
|
45
|
+
|
46
|
+
@parent.can_view?(current_user)
|
47
|
+
|
48
|
+
The can view method will determine whether or not the current_user has the right to view the activity feed.
|
49
|
+
|
50
|
+
In most instances you will need to override this method to implement proper security. For example, for a group that has an activity feed
|
51
|
+
you might add a can_view? method like this:
|
52
|
+
|
53
|
+
def can_view?(check_object)
|
54
|
+
self.member?(check_object) || (check_object.is_a?(User) && check_object.admin?)
|
55
|
+
end
|
56
|
+
|
57
|
+
== Live Updates
|
58
|
+
If you would like to add live updates to the user's activity feed you can do so by adding an entry to GlobalConfig.yml (configuration file added by muck)
|
59
|
+
|
60
|
+
enable_live_activity_updates: true
|
61
|
+
live_activity_update_interval: 5
|
62
|
+
|
63
|
+
Note that this will poll the server every 5 seconds and so will increase server load and bandwidth usage.
|
64
|
+
|
65
|
+
Copyright (c) 2009 Justin Ball, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the muck_activity plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.libs << 'test'
|
12
|
+
t.pattern = 'test/**/*_test.rb'
|
13
|
+
t.verbose = true
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Generate documentation for the muck_activity plugin.'
|
17
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
18
|
+
rdoc.rdoc_dir = 'rdoc'
|
19
|
+
rdoc.title = 'MuckActivity'
|
20
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
21
|
+
rdoc.rdoc_files.include('README')
|
22
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
23
|
+
end
|
24
|
+
|
25
|
+
begin
|
26
|
+
require 'jeweler'
|
27
|
+
Jeweler::Tasks.new do |gemspec|
|
28
|
+
gemspec.name = "muck-activity"
|
29
|
+
gemspec.summary = "Activity engine for the muck system"
|
30
|
+
gemspec.email = "justinball@gmail.com"
|
31
|
+
gemspec.homepage = "http://github.com/jbasdf/muck_activity"
|
32
|
+
gemspec.description = "Activity engine for the muck system."
|
33
|
+
gemspec.authors = ["Justin Ball"]
|
34
|
+
gemspec.rubyforge_project = 'muck-activity'
|
35
|
+
gemspec.add_dependency "muck-engine"
|
36
|
+
gemspec.add_dependency "muck-users"
|
37
|
+
gemspec.files.include %w( lib/muck_users
|
38
|
+
tasks/*
|
39
|
+
db/migrate/*.rb
|
40
|
+
app/**/**/**/*
|
41
|
+
config/*
|
42
|
+
locales/*
|
43
|
+
rails/*
|
44
|
+
test/*
|
45
|
+
lib/**/* )
|
46
|
+
end
|
47
|
+
rescue LoadError
|
48
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
49
|
+
end
|
50
|
+
|
51
|
+
# rubyforge tasks
|
52
|
+
begin
|
53
|
+
require 'rake/contrib/sshpublisher'
|
54
|
+
namespace :rubyforge do
|
55
|
+
|
56
|
+
desc "Release gem and RDoc documentation to RubyForge"
|
57
|
+
task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
|
58
|
+
|
59
|
+
namespace :release do
|
60
|
+
desc "Publish RDoc to RubyForge."
|
61
|
+
task :docs => [:rdoc] do
|
62
|
+
config = YAML.load(
|
63
|
+
File.read(File.expand_path('~/.rubyforge/user-config.yml'))
|
64
|
+
)
|
65
|
+
|
66
|
+
host = "#{config['username']}@rubyforge.org"
|
67
|
+
remote_dir = "/var/www/gforge-projects/muck_activity/"
|
68
|
+
local_dir = 'rdoc'
|
69
|
+
|
70
|
+
Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
rescue LoadError
|
75
|
+
puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
|
76
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.1
|
@@ -0,0 +1,155 @@
|
|
1
|
+
class Muck::ActivitiesController < ApplicationController
|
2
|
+
unloadable
|
3
|
+
|
4
|
+
include ApplicationHelper
|
5
|
+
|
6
|
+
before_filter :login_required
|
7
|
+
before_filter :find_parent, :only => [:index, :create]
|
8
|
+
before_filter :get_activity, :only => [:destroy]
|
9
|
+
|
10
|
+
def index
|
11
|
+
if @parent.can_view?(current_user)
|
12
|
+
if params[:latest_activity_id]
|
13
|
+
@activities = @parent.activities.after(params[:latest_activity_id]).paginate(:page => @page, :per_page => @per_page)
|
14
|
+
else
|
15
|
+
@activities = @parent.activities.paginate(:page => @page, :per_page => @per_page)
|
16
|
+
end
|
17
|
+
respond_to do |format|
|
18
|
+
format.js do
|
19
|
+
render :partial => "activities/cached_activities", :locals => {:activities => @activities}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def create
|
26
|
+
@activity = @parent.activities.build(params[:activity])
|
27
|
+
@activity.source = @parent
|
28
|
+
@activity.content.gsub!(@parent.display_name, '')
|
29
|
+
@parent.save!
|
30
|
+
|
31
|
+
@activity_html = get_activity_html(@activity)
|
32
|
+
if @activity.template == 'status_update'
|
33
|
+
@status_html = get_status_html(@parent)
|
34
|
+
else
|
35
|
+
@status_html = ''
|
36
|
+
end
|
37
|
+
respond_to do |format|
|
38
|
+
format.js do
|
39
|
+
render :update do |page|
|
40
|
+
page.insert_html :top, 'activity-feed-content', @activity_html
|
41
|
+
page.replace_html 'current-status', @status_html if @status_html
|
42
|
+
page.visual_effect :highlight, "#{@activity.dom_id}".to_sym
|
43
|
+
page << 'jQuery("#status_update").val(\'\');'
|
44
|
+
page << "jQuery('#status-update-field').removeClass('status-update-lit');"
|
45
|
+
page << "jQuery('#status-update-field').addClass('status-update-dim');"
|
46
|
+
page << 'jQuery("#status-update-field").show();'
|
47
|
+
page << 'jQuery("#submit_status").show();'
|
48
|
+
page << 'jQuery("#progress-bar").hide();'
|
49
|
+
page << 'setup_submit_delete();'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
format.html do
|
53
|
+
redirect_back_or_default(@parent)
|
54
|
+
end
|
55
|
+
format.json do
|
56
|
+
render :json => { :success => true,
|
57
|
+
:is_status_update => @activity.is_status_update,
|
58
|
+
:html => @activity_html,
|
59
|
+
:status_html => @status_html,
|
60
|
+
:message => t("muck.activities.created") }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
rescue => ex
|
65
|
+
|
66
|
+
if @activity
|
67
|
+
errors = @activity.errors.full_messages.to_sentence
|
68
|
+
else
|
69
|
+
errors = ex
|
70
|
+
end
|
71
|
+
message = t('muck.activities.update_error', :errors => errors)
|
72
|
+
respond_to do |format|
|
73
|
+
format.html do
|
74
|
+
flash[:error] = message
|
75
|
+
redirect_back_or_default(@parent)
|
76
|
+
end
|
77
|
+
format.js do
|
78
|
+
render :update do |page|
|
79
|
+
page_alert(page, message)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
def destroy
|
87
|
+
@activities_object = @activity.source
|
88
|
+
@activity.destroy
|
89
|
+
respond_to do |format|
|
90
|
+
format.html do
|
91
|
+
flash[:notice] = t("muck.activities.item_removed")
|
92
|
+
redirect_back_or_default(@activities_object)
|
93
|
+
end
|
94
|
+
format.js do
|
95
|
+
if @activity.is_status_update
|
96
|
+
@new_status = get_status_html(@activities_object)
|
97
|
+
render(:update) do |page|
|
98
|
+
page << "jQuery('#activity_#{@activity.id}').fadeOut();"
|
99
|
+
page.replace_html 'current-status', @new_status if @new_status
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
format.json do
|
104
|
+
@new_status = get_status_html(@activities_object)
|
105
|
+
render :json => { :success => true,
|
106
|
+
:is_status_update => @activity.is_status_update,
|
107
|
+
:html => @new_status,
|
108
|
+
:message => t("muck.activities.item_removed") }
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
rescue => ex
|
113
|
+
respond_to do |format|
|
114
|
+
format.html do
|
115
|
+
flash[:notice] = t("muck.activities.item_could_not_be_removed")
|
116
|
+
redirect_back_or_default(current_user)
|
117
|
+
end
|
118
|
+
format.js do
|
119
|
+
render(:update){ |page| page_alert(page, t("muck.activities.item_could_not_be_removed")) }
|
120
|
+
end
|
121
|
+
format.json { render :json => { :success => false, :message => t("muck.activities.item_could_not_be_removed") } }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
protected
|
126
|
+
|
127
|
+
def get_status_html(activity)
|
128
|
+
@template.template_format = :html
|
129
|
+
render_to_string(:partial => 'activities/current_status', :locals => {:activities_object => activity})
|
130
|
+
end
|
131
|
+
|
132
|
+
def get_activity_html(activity)
|
133
|
+
render_to_string(:partial => "activity_templates/#{activity.template}", :locals => { :activity => activity })
|
134
|
+
end
|
135
|
+
|
136
|
+
def find_parent
|
137
|
+
@klass = params[:parent_type].to_s.capitalize.constantize
|
138
|
+
@parent = @klass.find(params[:parent_id])
|
139
|
+
end
|
140
|
+
|
141
|
+
def get_activity
|
142
|
+
@activity = Activity.find(params[:id])
|
143
|
+
unless @activity.can_edit?(current_user)
|
144
|
+
respond_to do |format|
|
145
|
+
format.html do
|
146
|
+
flash[:notice] = t("muck.activities.permission_denied")
|
147
|
+
redirect_back_or_default(current_user)
|
148
|
+
end
|
149
|
+
format.js { render(:update){|page| page_alert(page, t("muck.activities.permission_denied"))}}
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module MuckActivityHelper
|
2
|
+
|
3
|
+
def activity_feed_for(activities_object)
|
4
|
+
activities = activities_object.activities.paginate(:page => @page, :per_page => @per_page)
|
5
|
+
render :partial => 'activities/activity_feed', :locals => { :activities_object => activities_object, :activities => activities }
|
6
|
+
end
|
7
|
+
|
8
|
+
def status_update(activities_object)
|
9
|
+
render :partial => 'activities/status_update', :locals => { :activities_object => activities_object }
|
10
|
+
end
|
11
|
+
|
12
|
+
def delete_activity(activity, button_type = :button, button_text = t("muck.activities.clear"))
|
13
|
+
render :partial => 'activities/delete', :locals => { :activity => activity, :button_type => button_type, :button_text => button_text }
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# == Schema Information
|
2
|
+
#
|
3
|
+
# Table name: activities
|
4
|
+
#
|
5
|
+
# id :integer(4) not null, primary key
|
6
|
+
# item_id :integer(4)
|
7
|
+
# item_type :string(255)
|
8
|
+
# template :string(255)
|
9
|
+
# source_id :integer(4)
|
10
|
+
# source_type :string(255)
|
11
|
+
# content :text
|
12
|
+
# title :string(255)
|
13
|
+
# status_update :boolean(1)
|
14
|
+
# created_at :datetime
|
15
|
+
# updated_at :datetime
|
16
|
+
#
|
17
|
+
|
18
|
+
class Activity < ActiveRecord::Base
|
19
|
+
|
20
|
+
belongs_to :item, :polymorphic => true
|
21
|
+
belongs_to :source, :polymorphic => true
|
22
|
+
has_many :activity_feeds
|
23
|
+
|
24
|
+
validates_presence_of :source
|
25
|
+
|
26
|
+
named_scope :since, lambda { |time| {:conditions => ["activities.created_at > ?", time] } }
|
27
|
+
named_scope :before, lambda {|time| {:conditions => ["activities.created_at < ?", time] } }
|
28
|
+
named_scope :recent, :order => "activities.created_at DESC"
|
29
|
+
named_scope :after, lambda {|id| {:conditions => ["activities.id > ?", id] } }
|
30
|
+
named_scope :only_public, :conditions => ["activities.is_public = true"]
|
31
|
+
|
32
|
+
def validate
|
33
|
+
errors.add_to_base(I18n.t('muck.activities.template_or_item_required')) if template.blank? && item.blank?
|
34
|
+
end
|
35
|
+
|
36
|
+
# Provides a template that can be used to render a view of this activity.
|
37
|
+
# If 'template' is not specified when the object created then the item class
|
38
|
+
# name will be used to generated a template
|
39
|
+
def partial
|
40
|
+
template || item.class.name.underscore
|
41
|
+
end
|
42
|
+
|
43
|
+
# Checks to see if the specified object can edit this activity.
|
44
|
+
# Most likely check_object will be a user
|
45
|
+
def can_edit?(check_object)
|
46
|
+
return true if check_object.is_a?(User) && check_object.admin?
|
47
|
+
source == check_object
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# == Schema Information
|
2
|
+
#
|
3
|
+
# Table name: activity_feeds
|
4
|
+
#
|
5
|
+
# id :integer(4) not null, primary key
|
6
|
+
# activity_id :integer(4)
|
7
|
+
# ownable_id :integer(4)
|
8
|
+
# ownable_type :string(255)
|
9
|
+
#
|
10
|
+
|
11
|
+
class ActivityFeed < ActiveRecord::Base
|
12
|
+
belongs_to :activity
|
13
|
+
belongs_to :ownable, :polymorphic => true
|
14
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<div id="activity-feed">
|
2
|
+
<h2><%= t('muck.activities.activity_feed_title') %></h2>
|
3
|
+
<div id="activity-feed-content">
|
4
|
+
<%= render( :partial => "activities/cached_activities", :locals => {:activities => activities}) %>
|
5
|
+
</div>
|
6
|
+
</div>
|
7
|
+
<%= will_paginate activities, :previous_label => t('muck.activities.paging_newer'), :next_label => t('muck.activities.paging_older') -%>
|
8
|
+
<% content_for :javascript do -%>
|
9
|
+
jQuery(document).ready(function(){
|
10
|
+
setup_submit_delete();
|
11
|
+
<% if GlobalConfig.enable_live_activity_updates -%>
|
12
|
+
setInterval(function() {jQuery.ajax({success:function(request){update_feed(request);},url:'<%= activities_path(:parent_id => activities_object, :parent_type => activities_object.type, :format => 'js') %>&latest_activity_id=' + get_latest_activity_id()})}, <%=GlobalConfig.live_activity_update_interval%> * 1000)
|
13
|
+
<% end -%>
|
14
|
+
});
|
15
|
+
function get_latest_activity_id(){
|
16
|
+
var activities = jQuery('#activity-feed-content').children('.activity-status-update')
|
17
|
+
if(activities.length > 0){
|
18
|
+
return activities[0].id.replace('activity_', '');
|
19
|
+
} else {
|
20
|
+
return '';
|
21
|
+
}
|
22
|
+
}
|
23
|
+
function update_feed(request){
|
24
|
+
jQuery('#activity-feed-content').prepend(request);
|
25
|
+
}
|
26
|
+
<% end -%>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<% if !activities.blank? -%>
|
2
|
+
<% activities.each do |activity| -%>
|
3
|
+
<% cache ("activities/#{I18n.locale}/#{activity.id}") do -%>
|
4
|
+
<%= render( :partial => "activity_templates/#{activity.partial}", :locals => {:activity => activity}) rescue '' %>
|
5
|
+
<% end -%>
|
6
|
+
<% end -%>
|
7
|
+
<% end -%>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<% if activities_object.status
|
2
|
+
status = h(activities_object.status.content)
|
3
|
+
time = activities_object.status.created_at
|
4
|
+
else
|
5
|
+
status = t('muck.activities.update_status_message')
|
6
|
+
time = false
|
7
|
+
end -%>
|
8
|
+
<span id="current-status-name"><%= activities_object.display_name %></span>
|
9
|
+
<span id="current-status-text"><%= status %></span>
|
10
|
+
<span id="status-time" class="status-time"><%= t('muck.activities.time_ago', :time_in_words => time_ago_in_words(time)) if time %></span>
|
11
|
+
<span id="status-clear">
|
12
|
+
<% if activities_object.status -%>
|
13
|
+
- <%= delete_activity(activities_object.status, :text, t("muck.activities.clear")) %>
|
14
|
+
<% end -%>
|
15
|
+
</span>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<% if button_type == :text -%>
|
2
|
+
<%= link_to_remote( button_text, :url => activity_path(activity, :format => 'js'), :method => :delete) %>
|
3
|
+
<% else -%>
|
4
|
+
<% remote_form_for(:activity, :url => activity_path(activity, :format => 'js'), :html => { :class => "delete-form activity-delete", :method => :delete } ) do |f| -%>
|
5
|
+
<% if button_type == :image -%>
|
6
|
+
<%= image_submit_tag '/images/icons/delete.png', {:title => button_text, :width => '15', :height => '15', :alt => button_text } %>
|
7
|
+
<% else -%>
|
8
|
+
<%= submit_tag button_text, { :title => button_text } %>
|
9
|
+
<% end -%>
|
10
|
+
<% end -%>
|
11
|
+
<% end -%>
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<div id="status-update">
|
2
|
+
<%= output_errors(t('muck.users.problem_with_status'), {:class => 'help-box'}, @activity) %>
|
3
|
+
|
4
|
+
<div id="activity-icon"><%= icon activities_object %></div>
|
5
|
+
<div id="current-status"><%= render :partial => 'activities/current_status', :locals => {:activities_object => activities_object} %></div>
|
6
|
+
<% remote_form_for(:activity,
|
7
|
+
:url => activities_path(:parent_id => activities_object, :parent_type => activities_object.type, :format => 'js'),
|
8
|
+
:html => { :id => 'status_update_form',
|
9
|
+
:action => activities_path(:parent_id => activities_object, :parent_type => activities_object.type) } ) do |f| -%>
|
10
|
+
<div id="progress-bar" style="display:none;">
|
11
|
+
<h3><%= t('muck.activities.updating_status_message') %></h3>
|
12
|
+
<img src="/images/loading.gif" alt="progress bar">
|
13
|
+
</div>
|
14
|
+
<div id="status-update-field" class="status-update-dim">
|
15
|
+
<%= t("muck.activities.status_update_prompt") %>
|
16
|
+
<%= f.text_field :content, :id => 'status_update' %>
|
17
|
+
<span id="status-update-button">
|
18
|
+
<%= f.submit t('muck.activities.post'), :id => 'submit_status', :class=>"button" %>
|
19
|
+
</span>
|
20
|
+
</div>
|
21
|
+
<%= f.hidden_field :template, :value => 'status_update' %>
|
22
|
+
<%= f.hidden_field :is_status_update, :value => true %>
|
23
|
+
<% end %>
|
24
|
+
</div>
|
25
|
+
<% content_for :javascript do -%>
|
26
|
+
jQuery(document).ready(function() {
|
27
|
+
jQuery('#status_update').click(function(){
|
28
|
+
jQuery('#status-update-field').removeClass('status-update-dim');
|
29
|
+
jQuery('#status-update-field').addClass('status-update-lit');
|
30
|
+
});
|
31
|
+
|
32
|
+
jQuery("#status_update_form").submit(function() {
|
33
|
+
jQuery("#status-update-field").hide();
|
34
|
+
jQuery("#submit_status").hide();
|
35
|
+
jQuery("#progress-bar").show();
|
36
|
+
});
|
37
|
+
});
|
38
|
+
<% end -%>
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<div class="activity-status-update delete-container" id="<%= activity.dom_id %>">
|
2
|
+
<%= icon activity.source %> <%= link_to activity.source.display_name, activity.source %> <%= activity.content %>
|
3
|
+
<span class="activity-time"><%= t("muck.activities.time_ago", :time_in_words => time_ago_in_words(activity.created_at)) %></span>
|
4
|
+
<%= delete_activity(activity, :image) %>
|
5
|
+
<div class="clear"></div>
|
6
|
+
</div>
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class AddMuckActivities < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
|
5
|
+
create_table :activities, :force => true do |t|
|
6
|
+
t.integer :item_id
|
7
|
+
t.string :item_type
|
8
|
+
t.string :template
|
9
|
+
t.integer :source_id
|
10
|
+
t.string :source_type
|
11
|
+
t.text :content
|
12
|
+
t.string :title
|
13
|
+
t.boolean :is_status_update, :default => false
|
14
|
+
t.boolean :is_public, :default => true
|
15
|
+
t.timestamps
|
16
|
+
end
|
17
|
+
|
18
|
+
add_index :activities, ["item_id", "item_type"]
|
19
|
+
|
20
|
+
create_table :activity_feeds, :force => true do |t|
|
21
|
+
t.integer :activity_id
|
22
|
+
t.integer :ownable_id
|
23
|
+
t.string :ownable_type
|
24
|
+
end
|
25
|
+
|
26
|
+
add_index :activity_feeds, ["activity_id"]
|
27
|
+
add_index :activity_feeds, ["ownable_id", "ownable_type"]
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.down
|
32
|
+
drop_table :activities
|
33
|
+
drop_table :activity_feeds
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/install.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Install hook code here
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class ActionController::Routing::RouteSet
|
2
|
+
def load_routes_with_muck_activity!
|
3
|
+
muck_activity_routes = File.join(File.dirname(__FILE__), *%w[.. .. config muck_activity_routes.rb])
|
4
|
+
add_configuration_file(muck_activity_routes) unless configuration_files.include? muck_activity_routes
|
5
|
+
load_routes_without_muck_activity!
|
6
|
+
end
|
7
|
+
alias_method_chain :load_routes!, :muck_activity
|
8
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/tasklib'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module MuckActivity
|
6
|
+
class Tasks < ::Rake::TaskLib
|
7
|
+
def initialize
|
8
|
+
define
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
def define
|
13
|
+
|
14
|
+
namespace :muck do
|
15
|
+
namespace :activity do
|
16
|
+
desc "Sync required files from activity."
|
17
|
+
task :sync do
|
18
|
+
path = File.join(File.dirname(__FILE__), *%w[.. ..])
|
19
|
+
system "rsync -ruv #{path}/db ."
|
20
|
+
system "rsync -ruv #{path}/public ."
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
MuckActivity::Tasks.new
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module MuckActivity # :nodoc:
|
4
|
+
|
5
|
+
def self.included(base) # :nodoc:
|
6
|
+
base.extend ActMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module ActMethods
|
10
|
+
|
11
|
+
# +has_activities+ gives the class it is called on an activity feed and a method called
|
12
|
+
# +add_activity+ that can add activities into a feed. Retrieve activity feed items
|
13
|
+
# via object.activities. ie @user.activities.
|
14
|
+
def has_activities
|
15
|
+
unless included_modules.include? InstanceMethods
|
16
|
+
has_many :activity_feeds, :as => :ownable
|
17
|
+
has_many :activities, :through => :activity_feeds, :order => 'created_at desc'
|
18
|
+
include InstanceMethods
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# +acts_as_activity_source+ gives the class it is called on a method called
|
23
|
+
# +add_activity+ that can add activities into a feed.
|
24
|
+
def acts_as_activity_source
|
25
|
+
unless included_modules.include? InstanceMethods
|
26
|
+
include InstanceMethods
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
module InstanceMethods
|
33
|
+
|
34
|
+
# +add_activity+ adds an activity to all activites feeds that belong to the objects found in feed_to.
|
35
|
+
# * +feed_to+: an array of objects that have +has_activities+ declared on them. The generated activity
|
36
|
+
# will be pushed into the feed of each of these objects.
|
37
|
+
# * +source+: the object that peformed the activity ie a user or group
|
38
|
+
# * +item+: an object that will be used to generated the entry in an activity feed
|
39
|
+
# * +template+: name of an partial that will be used to generated the entry in the activity feed. Place
|
40
|
+
# templates in /app/views/activity_templates
|
41
|
+
# * +title+: optional title that can be used in the template
|
42
|
+
# * +content+: option content that can be used in the template. Useful for activities that might not have
|
43
|
+
# an item but instead might have a message or other text.
|
44
|
+
# * +check_method+: method that will be called on each item in the feed_to array. If the method evaluates
|
45
|
+
# to false the activity won't be added to the object's activity feed. An example usage would be
|
46
|
+
# letting users configure which items they want to have in their activity feed.
|
47
|
+
def add_activity(feed_to, source, item, template, title = '', content = '', check_method = nil)
|
48
|
+
feed_to = [feed_to] unless feed_to.is_a?(Array)
|
49
|
+
activity = Activity.create(:item => item, :source => source, :template => template, :title => title, :content => content)
|
50
|
+
feed_to.each do |ft|
|
51
|
+
if check_method
|
52
|
+
ft.activities << activity if ft.send(check_method)
|
53
|
+
else
|
54
|
+
ft.activities << activity
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# +status+ returns the first activity item from the user's activity feed that is a status update.
|
60
|
+
# Used for displaying the last status update the user made
|
61
|
+
def status
|
62
|
+
self.activities.find(:first, :conditions => ['is_status_update = true'], :order => 'created_at DESC')
|
63
|
+
end
|
64
|
+
|
65
|
+
def can_view?(check_object)
|
66
|
+
self == check_object
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
ActiveRecord::Base.send(:include, MuckActivity)
|
73
|
+
ActionController::Base.send(:include, MuckActivity)
|
74
|
+
ActionController::Base.send :helper, MuckActivityHelper
|
75
|
+
|
76
|
+
I18n.load_path += Dir[ File.join(File.dirname(__FILE__), '..', 'locales', '*.{rb,yml}') ]
|
data/locales/en.yml
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
en:
|
2
|
+
muck:
|
3
|
+
activities:
|
4
|
+
item_removed: 'Item successfully removed from the recent activities list.'
|
5
|
+
item_could_not_be_removed: 'Item could not be removed from the recent activities list.'
|
6
|
+
item_created: 'Added activity'
|
7
|
+
permission_denied: "Sorry, you can't do that."
|
8
|
+
status_update_prompt: "What are you doing right now?"
|
9
|
+
activity_feed_title: 'Recent Activity'
|
10
|
+
updating_status_message: "Updating your status. Please wait."
|
11
|
+
status_indicator: is
|
12
|
+
invite_friends: Invite Friends
|
13
|
+
joined_status: "{{name}} joined {{application_name}}"
|
14
|
+
post: Share
|
15
|
+
clear: Clear
|
16
|
+
problem_with_status: "There was a problem changing your status"
|
17
|
+
update_error: "Oops... There was a problem. {{errors}}"
|
18
|
+
update_status_message: "update your status!"
|
19
|
+
time_ago: "{{time_in_words}} ago"
|
20
|
+
template_or_item_required: "An activity requires a template or an item to display correctly"
|
21
|
+
paging_newer: '« Newer'
|
22
|
+
paging_older: 'Older »'
|
Binary file
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '/../lib/muck_activity/tasks')
|
data/test/factories.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
Factory.sequence :email do |n|
|
2
|
+
"somebody#{n}@example.com"
|
3
|
+
end
|
4
|
+
|
5
|
+
Factory.sequence :login do |n|
|
6
|
+
"inquire#{n}"
|
7
|
+
end
|
8
|
+
|
9
|
+
Factory.sequence :name do |n|
|
10
|
+
"a_name#{n}"
|
11
|
+
end
|
12
|
+
|
13
|
+
Factory.sequence :abbr do |n|
|
14
|
+
"abbr#{n}"
|
15
|
+
end
|
16
|
+
|
17
|
+
Factory.sequence :description do |n|
|
18
|
+
"This is the description: #{n}"
|
19
|
+
end
|
20
|
+
|
21
|
+
Factory.define :user do |f|
|
22
|
+
f.login { Factory.next(:login) }
|
23
|
+
f.email { Factory.next(:email) }
|
24
|
+
f.password 'inquire_pass'
|
25
|
+
f.password_confirmation 'inquire_pass'
|
26
|
+
f.first_name 'test'
|
27
|
+
f.last_name 'guy'
|
28
|
+
f.terms_of_service true
|
29
|
+
f.activated_at DateTime.now
|
30
|
+
end
|
31
|
+
|
32
|
+
Factory.define :activity do |f|
|
33
|
+
f.item {|a| a.association(:user)}
|
34
|
+
f.template ''
|
35
|
+
f.source {|a| a.association(:user)}
|
36
|
+
f.content ''
|
37
|
+
f.title ''
|
38
|
+
f.is_status_update false
|
39
|
+
f.is_public true
|
40
|
+
f.created_at DateTime.now
|
41
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
|
3
|
+
class Muck::ActivitiesControllerTest < ActionController::TestCase
|
4
|
+
|
5
|
+
tests Muck::ActivitiesController
|
6
|
+
|
7
|
+
context "activities controller" do
|
8
|
+
setup do
|
9
|
+
activate_authlogic
|
10
|
+
@user = Factory(:user)
|
11
|
+
login_as @user
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'on GET to index (js)' do
|
15
|
+
setup do
|
16
|
+
@activity = Factory(:activity)
|
17
|
+
get :index, :parent_type => @user.type, :parent_id => @user, :format => 'js', :latest_activity_id => @activity.to_param
|
18
|
+
end
|
19
|
+
should_respond_with :success
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'on GET to index (js) no latest activity id' do
|
23
|
+
setup do
|
24
|
+
get :index, :parent_type => @user.type, :parent_id => @user, :format => 'js', :latest_activity_id => nil
|
25
|
+
end
|
26
|
+
should_respond_with :success
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'on POST to create (js)' do
|
30
|
+
setup do
|
31
|
+
post :create, :activity => { :content => 'test activity' }, :parent_type => @user.type, :parent_id => @user, :format => 'js'
|
32
|
+
end
|
33
|
+
should_respond_with :success
|
34
|
+
should_not_set_the_flash
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'on POST to create' do
|
38
|
+
setup do
|
39
|
+
post :create, :activity => { :content => 'test activity' }, :parent_type => @user.type, :parent_id => @user
|
40
|
+
end
|
41
|
+
should_redirect_to('show user page (user dashboard)') { @user }
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'on DELETE to destroy' do
|
45
|
+
setup do
|
46
|
+
@activity = Factory(:activity, :source => @user)
|
47
|
+
delete :destroy, :id => @activity.id
|
48
|
+
end
|
49
|
+
should_respond_with :redirect
|
50
|
+
should_set_the_flash_to(I18n.t("muck.activities.item_removed"))
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'on DELETE to destroy (js)' do
|
54
|
+
setup do
|
55
|
+
@activity = Factory(:activity, :source => @user)
|
56
|
+
delete :destroy, :id => @activity.id, :format => 'js'
|
57
|
+
end
|
58
|
+
should_respond_with :success
|
59
|
+
should_not_set_the_flash
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
ActiveSupport::TestCase.class_eval do
|
2
|
+
|
3
|
+
def self.should_require_login(*args)
|
4
|
+
args = Hash[*args]
|
5
|
+
login_url = args.delete :login_url
|
6
|
+
args.each do |action, verb|
|
7
|
+
should "Require login for '#{action}' action" do
|
8
|
+
send(verb, action)
|
9
|
+
assert_redirected_to(login_url)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.should_require_role(role, redirect_url, *actions)
|
15
|
+
actions.each do |action|
|
16
|
+
should "require role for '#{action}' action" do
|
17
|
+
get(action)
|
18
|
+
ensure_flash(/permission/i)
|
19
|
+
assert_response :redirect
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
#from: http://blog.internautdesign.com/2008/9/11/more-on-custom-shoulda-macros-scoping-of-instance-variables
|
25
|
+
def self.should_not_allow action, object, url= "/login", msg=nil
|
26
|
+
msg ||= "a #{object.class.to_s.downcase}"
|
27
|
+
should "not be able to #{action} #{msg}" do
|
28
|
+
object = eval(object, self.send(:binding), __FILE__, __LINE__)
|
29
|
+
get action, :id => object.id
|
30
|
+
assert_redirected_to url
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.should_allow action, object, msg=nil
|
35
|
+
msg ||= "a #{object.class.to_s.downcase}"
|
36
|
+
should "be able to #{action} #{msg}" do
|
37
|
+
object = eval(object, self.send(:binding), __FILE__, __LINE__)
|
38
|
+
get action, :id => object.id
|
39
|
+
assert_response :success
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
$:.reject! { |e| e.include? 'TextMate' }
|
2
|
+
ENV["RAILS_ENV"] = "test"
|
3
|
+
#require File.expand_path(File.dirname(__FILE__) + "/../../../../config/environment")
|
4
|
+
require 'factory_girl'
|
5
|
+
require 'ruby-debug'
|
6
|
+
require 'mocha'
|
7
|
+
require 'authlogic/test_case'
|
8
|
+
require 'redgreen' rescue LoadError
|
9
|
+
require File.expand_path(File.dirname(__FILE__) + '/factories')
|
10
|
+
require File.join(File.dirname(__FILE__), 'shoulda_macros', 'controller')
|
11
|
+
class ActiveSupport::TestCase
|
12
|
+
self.use_transactional_fixtures = true
|
13
|
+
self.use_instantiated_fixtures = false
|
14
|
+
|
15
|
+
include Authlogic::TestCase
|
16
|
+
|
17
|
+
def login_as(user)
|
18
|
+
success = UserSession.create(user)
|
19
|
+
if !success
|
20
|
+
errors = user.errors.full_messages.to_sentence
|
21
|
+
message = 'User has not been activated' if !user.active?
|
22
|
+
raise "could not login as #{user.to_param}. Please make sure the user is valid. #{message} #{errors}"
|
23
|
+
end
|
24
|
+
UserSession.find
|
25
|
+
end
|
26
|
+
|
27
|
+
def assure_logout
|
28
|
+
user_session = UserSession.find
|
29
|
+
user_session.destroy if user_session
|
30
|
+
end
|
31
|
+
|
32
|
+
def ensure_flash(val)
|
33
|
+
assert_contains flash.values, val, ", Flash: #{flash.inspect}"
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
|
3
|
+
class ActivityTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
context 'An Activity' do
|
6
|
+
|
7
|
+
should_validate_presence_of :source
|
8
|
+
|
9
|
+
should_belong_to :item
|
10
|
+
should_belong_to :source
|
11
|
+
should_have_many :activity_feeds
|
12
|
+
|
13
|
+
should_have_named_scope :since
|
14
|
+
should_have_named_scope :before
|
15
|
+
should_have_named_scope :recent
|
16
|
+
should_have_named_scope :only_public
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
should "require template or item" do
|
21
|
+
activity = Factory.build(:activity, :template => nil, :item => nil)
|
22
|
+
assert !activity.valid?
|
23
|
+
end
|
24
|
+
|
25
|
+
should "get the partial from the template" do
|
26
|
+
template = 'status_update'
|
27
|
+
activity = Factory(:activity, :template => template, :item => nil)
|
28
|
+
assert activity.partial == template, "The activity partial was not set to the specified template"
|
29
|
+
end
|
30
|
+
|
31
|
+
should "get the partial from the item" do
|
32
|
+
user = Factory(:user)
|
33
|
+
activity = Factory(:activity, :item => user, :template => nil)
|
34
|
+
assert activity.partial == user.class.name.underscore
|
35
|
+
end
|
36
|
+
|
37
|
+
should "be able to edit the activity" do
|
38
|
+
user = Factory(:user)
|
39
|
+
activity = Factory(:activity, :source => user)
|
40
|
+
assert activity.can_edit?(user)
|
41
|
+
end
|
42
|
+
|
43
|
+
should "not be able to edit the activity" do
|
44
|
+
user = Factory(:user)
|
45
|
+
activity = Factory(:activity)
|
46
|
+
assert !activity.can_edit?(user)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
data/uninstall.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Uninstall hook code here
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: muck-activity
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Justin Ball
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-06-11 00:00:00 -06:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: muck-engine
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: muck-users
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
description: Activity engine for the muck system.
|
36
|
+
email: justinball@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- README.rdoc
|
43
|
+
files:
|
44
|
+
- MIT-LICENSE
|
45
|
+
- README.rdoc
|
46
|
+
- Rakefile
|
47
|
+
- VERSION
|
48
|
+
- app/controllers/muck/activities_controller.rb
|
49
|
+
- app/helpers/muck_activity_helper.rb
|
50
|
+
- app/models/activity.rb
|
51
|
+
- app/models/activity_feed.rb
|
52
|
+
- app/views/activities/_activity_feed.html.erb
|
53
|
+
- app/views/activities/_cached_activities.html.erb
|
54
|
+
- app/views/activities/_current_status.html.erb
|
55
|
+
- app/views/activities/_delete.html.erb
|
56
|
+
- app/views/activities/_status_update.html.erb
|
57
|
+
- app/views/activity_templates/_status_update.html.erb
|
58
|
+
- config/muck_activity_routes.rb
|
59
|
+
- db/migrate/20090402033319_add_muck_activities.rb
|
60
|
+
- install.rb
|
61
|
+
- lib/muck_activity.rb
|
62
|
+
- lib/muck_activity/initialize_routes.rb
|
63
|
+
- lib/muck_activity/tasks.rb
|
64
|
+
- locales/en.yml
|
65
|
+
- public/images/loading.gif
|
66
|
+
- rails/init.rb
|
67
|
+
- tasks/muck_activity_tasks.rake
|
68
|
+
- test/factories.rb
|
69
|
+
- test/functional/activities_controller_test.rb
|
70
|
+
- test/muck_activity_test.rb
|
71
|
+
- test/shoulda_macros/controller.rb
|
72
|
+
- test/test_helper.rb
|
73
|
+
- test/unit/activity_feed_test.rb
|
74
|
+
- test/unit/activity_test.rb
|
75
|
+
- uninstall.rb
|
76
|
+
has_rdoc: true
|
77
|
+
homepage: http://github.com/jbasdf/muck_activity
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options:
|
80
|
+
- --charset=UTF-8
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: "0"
|
88
|
+
version:
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: "0"
|
94
|
+
version:
|
95
|
+
requirements: []
|
96
|
+
|
97
|
+
rubyforge_project: muck-activity
|
98
|
+
rubygems_version: 1.3.1
|
99
|
+
signing_key:
|
100
|
+
specification_version: 2
|
101
|
+
summary: Activity engine for the muck system
|
102
|
+
test_files:
|
103
|
+
- test/factories.rb
|
104
|
+
- test/functional/activities_controller_test.rb
|
105
|
+
- test/muck_activity_test.rb
|
106
|
+
- test/shoulda_macros/controller.rb
|
107
|
+
- test/test_helper.rb
|
108
|
+
- test/unit/activity_feed_test.rb
|
109
|
+
- test/unit/activity_test.rb
|