Commit 4436e29d authored by azul's avatar azul
Browse files

track_actions for all participation tracking

Allows us to remove UserParticipationObserver and GroupParticipationObserver.

All changes to participations are now tracked by PageHistory::UpdateParticipation.
This will test it's subclasses if they take care of the participation in question.
The first subclass for which Class.tracks(changes, participation) returns true
will be used.

This allows us to handle different changes in different classes without a central
registry. It requires however for all classes to be defined in the same file or
the use of require_dependency directives. For now we still have all PageHistory
subclasses in one file.
parent 53ed48b5
......@@ -11,19 +11,20 @@ class Pages::ParticipationsController < Pages::SidebarsController
helper 'pages/participation', 'pages/share'
before_filter :fetch_data
track_actions :update
# this is used for ajax pagination
def index
end
def update
if params[:watch]
if params[:access]
raise_denied unless may_admin_page?
access
elsif params[:watch]
watch
elsif params[:star]
star
elsif params[:access]
raise_denied unless may_admin_page?
access
end
end
......@@ -49,9 +50,9 @@ class Pages::ParticipationsController < Pages::SidebarsController
if params[:access] == 'remove'
destroy
else
@page.add(@participation.entity, access: params[:access]).save!
@page.add(participation.entity, access: params[:access]).save!
render :update do |page|
page.replace_html dom_id(@participation), partial: 'pages/participations/permission_row', locals: {participation: @participation.reload}
page.replace_html dom_id(participation), partial: 'pages/participations/permission_row', locals: {participation: participation.reload}
end
end
end
......@@ -60,27 +61,35 @@ class Pages::ParticipationsController < Pages::SidebarsController
## however, since currently the existance of a participation means
## view access, then we need to destory them to remove access.
def destroy
if may_remove_participation?(@participation)
if @participation.is_a? UserParticipation
@page.remove(@participation.user)
if may_remove_participation?(participation)
if participation.is_a? UserParticipation
@page.remove(participation.user)
else
@page.remove(@participation.group)
@page.remove(participation.group)
end
else
raise ErrorMessage.new(:remove_access_error.t)
end
render :update do |page|
page.hide dom_id(@participation)
page.hide dom_id(@gpart || @upart)
end
end
protected
def track_action(event = nil, event_options = nil)
super participation: participation
end
# we always load the user participation for page sidebar controllers
# so use the group participation if it's present and fallback to user part.
def participation
@gpart || @upart
end
# we only act upon group participations access. There's no staring or
# watching group participations.
def fetch_data
if params[:group].blank? || params[:group] == 'false'
@participation = UserParticipation.find(params[:id]) if params[:id]
else
@participation = GroupParticipation.find(params[:id]) if params[:id]
if params[:group] && params[:access]
@gpart = GroupParticipation.find(params[:id]) if params[:id]
end
end
......
class Tracking::GroupParticipationObserver < ActiveRecord::Observer
observe :group_participation
def after_destroy(gp)
PageHistory::RevokedGroupAccess.create user: User.current,
page: gp.page,
item: gp.group
end
end
class Tracking::UserParticipationObserver < ActiveRecord::Observer
observe :user_participation
def after_save(up)
params = { user: User.current, page: up.page, item: up.user }
PageHistory::StartWatching.create(params) if up.start_watching?
PageHistory::StopWatching.create(params) if up.stop_watching?
PageHistory::AddStar.create(params) if up.star_added?
PageHistory::RemoveStar.create(params) if up.star_removed?
end
def after_destroy(up)
params = { user: User.current, page: up.page, item: up.user }
PageHistory::RevokedUserAccess.create(params)
end
end
......@@ -99,27 +99,22 @@ class PageHistory < ActiveRecord::Base
end
end
class PageHistory::AddStar < PageHistory; end
class PageHistory::RemoveStar < PageHistory; end
class PageHistory::MakePublic < PageHistory; end
class PageHistory::MakePrivate < PageHistory; end
class PageHistory::StartWatching < PageHistory; end
class PageHistory::StopWatching < PageHistory; end
# Factory class for the different page updates
class PageHistory::Update < PageHistory
def initialize(attrs = {}, options = {}, &block)
page = attrs[:page]
klass_for_update(page).new(attrs, options, &block)
def self.pick_class(attrs = {})
class_for_update(attrs[:page])
end
protected
def class_for_update(page)
return PageHistory::MakePrivate if page.marked_as_private?
return PageHistory::MakePublic if page.marked_as_public?
# return PageHistory::ChangeOwner if page.owner_id_changed?
end
end
class PageHistory::MakePublic < PageHistory; end
class PageHistory::MakePrivate < PageHistory; end
class PageHistory::PageCreated < PageHistory
after_save :page_updated_at
......@@ -161,6 +156,61 @@ class PageHistory::UpdatedContent < PageHistory
after_save :page_updated_at
end
# Factory class for the different page updates
# To track updates to participations:
# * inherit directly from this class
# * define self.tracks on your class to return true for changes that should
# be tracked.
# Changes will be a ActiveModel::Dirty changeset. You can use the activated
# and deactivated helper methods if you only need to look at the boolean value.
class PageHistory::UpdateParticipation < PageHistory
def self.pick_class(attrs = {})
class_for_update(attrs[:participation])
end
protected
def self.class_for_update(participation)
subclasses.detect{|klass|
klass.tracks participation.previous_changes, participation
}
end
def self.tracks(changes, part); false; end
def self.activated(old = nil, new = nil)
new && !old
end
def self.deactivated(old = nil, new = nil)
old && !new
end
end
class PageHistory::AddStar < PageHistory::UpdateParticipation
def self.tracks(changes, _part)
activated(*changes[:star])
end
end
class PageHistory::RemoveStar < PageHistory::UpdateParticipation
def self.tracks(changes, _part)
deactivated(*changes[:star])
end
end
class PageHistory::StartWatching < PageHistory::UpdateParticipation
def self.tracks(changes, _part)
activated(*changes[:watch])
end
end
class PageHistory::StopWatching < PageHistory::UpdateParticipation
def self.tracks(changes, _part)
deactivated(*changes[:watch])
end
end
# Module for the methods shared between
# GrantGroupAccess and GrantUserAccess.
module PageHistory::GrantAccess
......@@ -196,8 +246,13 @@ module PageHistory::GrantAccess
end
end
class PageHistory::GrantGroupAccess < PageHistory
class PageHistory::GrantGroupAccess < PageHistory::UpdateParticipation
include GrantAccess
def self.tracks(changes, part)
part.is_a?(GroupParticipation) && changes.keys.include?('access')
end
after_save :page_updated_at
validates_presence_of :item_id
......@@ -222,15 +277,29 @@ class PageHistory::GrantGroupFullAccess < PageHistory::GrantGroupAccess; end
class PageHistory::GrantGroupWriteAccess < PageHistory::GrantGroupAccess; end
class PageHistory::GrantGroupReadAccess < PageHistory::GrantGroupAccess; end
class PageHistory::RevokedGroupAccess < PageHistory
class PageHistory::RevokedGroupAccess < PageHistory::UpdateParticipation
after_save :page_updated_at
def self.tracks(changes, part)
part.is_a?(GroupParticipation) &&
!GroupParticipation.exists?(id: part.id)
end
def participation=(part)
self.item = part.try.group
end
validates_format_of :item_type, with: /Group/
validates_presence_of :item_id
end
class PageHistory::GrantUserAccess < PageHistory
class PageHistory::GrantUserAccess < PageHistory::UpdateParticipation
include GrantAccess
def self.tracks(changes, part)
part.is_a?(UserParticipation) && changes.keys.include?('access')
end
after_save :page_updated_at
validates_presence_of :item_id
......@@ -255,7 +324,16 @@ class PageHistory::GrantUserFullAccess < PageHistory::GrantUserAccess; end
class PageHistory::GrantUserWriteAccess < PageHistory::GrantUserAccess; end
class PageHistory::GrantUserReadAccess < PageHistory::GrantUserAccess; end
class PageHistory::RevokedUserAccess < PageHistory
class PageHistory::RevokedUserAccess < PageHistory::UpdateParticipation
def self.tracks(changes, part)
part.is_a?(UserParticipation) &&
!UserParticipation.exists?(id: part.id)
end
def participation=(part)
self.item = part.try.user
end
after_save :page_updated_at
validates_format_of :item_type, with: /User/
......
......@@ -14,6 +14,7 @@ module Tracking::Action
destroy_page: [],
delete_page: ['PageHistory::Deleted'],
undelete_page: [],
update_participation: ['PageHistory::UpdateParticipation'],
update_group_access: ['PageHistory::GrantGroupAccess'],
update_user_access: ['PageHistory::GrantUserAccess'],
update_title: ['PageHistory::ChangeTitle']
......@@ -24,7 +25,9 @@ module Tracking::Action
options[:key] ||= rand(Time.now.to_i)
EVENT_CREATES_ACTIVITIES[event].each do |class_name|
klass = class_name.constantize
klass.create! filter_options_for_class(klass, options)
klass = klass.pick_class(options) if klass.respond_to? :pick_class
next if klass.blank?
activity = klass.create! filter_options_for_class(klass, options)
end
end
......
......@@ -48,10 +48,7 @@ module Crabgrass
# We use strong parameters instead like rails4 does.
#config.active_record.whitelist_attributes = true
config.active_record.observers =
"tracking/wiki_observer",
"tracking/user_participation_observer",
"tracking/group_participation_observer"
config.active_record.observers = "tracking/wiki_observer"
config.session_store :cookie_store,
:key => 'crabgrass_session'
......
......@@ -4,25 +4,51 @@ class Pages::ParticipationsControllerTest < ActionController::TestCase
def setup
@user = FactoryGirl.create :user
@page = FactoryGirl.create(:page)
@upart = @page.add(@user, access: :view)
@page = FactoryGirl.create :page
@upart = @page.add(@user, access: :admin)
@upart.save
login_as @user
end
def test_star
post :update, page_id: @page, id: @upart, star: true
assert_difference 'PageHistory::AddStar.count' do
post :update, page_id: @page, id: @upart, star: true
end
assert @upart.reload.star
end
def test_watch
post :update, page_id: @page, id: @upart, watch: true
assert_difference 'PageHistory::StartWatching.count' do
post :update, page_id: @page, id: @upart, watch: true
end
assert @upart.reload.watch
end
def test_prevent_increasing_access
post :update, page_id: @page, id: @upart, access: :admin
@upart.access = :view
@upart.save
assert_no_difference 'PageHistory.count' do
post :update, page_id: @page, id: @upart, access: :admin
end
assert_equal :view, @upart.reload.access_sym
end
def test_destroy_user_participation
other_user = FactoryGirl.create :user
other_upart = @page.add(other_user, access: :view)
other_upart.save
assert_difference 'PageHistory.count' do
post :update, page_id: @page, id: other_upart, access: :remove
end
end
def test_destroy_group_participation
group = FactoryGirl.create :group
gpart = @page.add(group, access: :view)
gpart.save
assert_difference 'PageHistory.count' do
post :update, page_id: @page, id: gpart, group: true, access: :remove
end
end
end
......@@ -141,16 +141,12 @@ class Page::HistoryTest < ActiveSupport::TestCase
user_a = FactoryGirl.create(:user, receive_notifications: "Digest")
user_b = FactoryGirl.create(:user, receive_notifications: "Digest")
user_c = FactoryGirl.create(:user, receive_notifications: "Single")
@page.user_participations.create!(user: user_a, watch: true)
@page.user_participations.create!(user: user_b, watch: true)
@page.user_participations.create!(user: user_c, watch: true)
users = [user_a, user_b, user_c]
PageHistory.delete_all
@page.participation_for_user(user_a).update_attribute(:star, true)
@page.participation_for_user(user_b).update_attribute(:star, true)
@page.participation_for_user(user_c).update_attribute(:star, true)
users.each{ |user| @page.add(user, star: true, watch: true).save }
users.each{ |user| PageHistory::AddStar.create user: user, page: @page }
assert_equal 1, PageHistory.pending_digest_notifications_by_page.size
assert_equal 3, PageHistory.pending_digest_notifications_by_page[@page.id].size
......
......@@ -21,23 +21,6 @@ class Page::TrackingObserverTest < ActiveSupport::TestCase
assert_equal @last_count, @page.page_histories.count
end
def test_add_star
@upart = @page.add(@pepe, star: true ).save!
@page.reload
assert_equal @last_count + 1, @page.page_histories.count
assert_equal @pepe, PageHistory.last.user
assert_equal PageHistory::AddStar, PageHistory.last.class
end
def test_remove_star
@upart = @page.add(@pepe, star: true).save!
@upart = @page.add(@pepe, star: nil).save!
@page.reload
assert_equal @last_count + 2, @page.page_histories.count
assert_equal @pepe, PageHistory.last.user
assert_equal PageHistory::RemoveStar, PageHistory.last.class
end
def test_add_tag
true
end
......@@ -54,44 +37,6 @@ class Page::TrackingObserverTest < ActiveSupport::TestCase
true
end
def test_start_watching
@upart = @page.add(@pepe, watch: true).save!
@page.reload
assert_equal @last_count + 1, @page.page_histories.count
assert_equal @pepe, PageHistory.last.user
assert_equal PageHistory::StartWatching, PageHistory.last.class
end
def test_stop_watching
@upart = @page.add(@pepe, watch: true).save!
@page.reload
@upart = @page.add(@pepe, watch: nil).save!
@page.reload
assert_equal @last_count + 2, @page.page_histories.count
assert_equal @pepe, PageHistory.last.user
assert_equal PageHistory::StopWatching, PageHistory.last.class
end
def test_share_page_with_user_removing_access
@page.add(@manu, access: 3).save!
@page.user_participations.last.destroy
assert_equal @last_count + 1, @page.page_histories.count
assert_equal @pepe, PageHistory.last.user
assert_equal PageHistory::RevokedUserAccess, PageHistory.last.class
assert_equal User, PageHistory.last.item.class
end
def test_share_page_with_group_removing_access
group = FactoryGirl.create(:group)
group.add_user! @pepe
@page.add(group, access: 3).save!
@page.group_participations.last.destroy
assert_equal @last_count + 1, @page.page_histories.count
assert_equal @pepe, PageHistory.last.user
assert_equal PageHistory::RevokedGroupAccess, PageHistory.last.class
assert_equal Group, PageHistory.last.item.class
end
def test_update_content
page = FactoryGirl.create(:wiki_page, data: Wiki.new(user: @pepe, body: ""))
# for some reason creating the page didn't create a GrantUserFullExist history
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment