mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 22:43:33 +08:00
Add deleted_by
to Trashable
tables
This commit is contained in:
@ -77,9 +77,7 @@ Discourse.FlaggedPost = Discourse.Post.extend({
|
|||||||
return Discourse.ajax('/admin/flags/agree/' + this.id, { type: 'POST', cache: false });
|
return Discourse.ajax('/admin/flags/agree/' + this.id, { type: 'POST', cache: false });
|
||||||
},
|
},
|
||||||
|
|
||||||
postHidden: function() {
|
postHidden: Em.computed.alias('hidden'),
|
||||||
return (this.get('hidden'));
|
|
||||||
}.property(),
|
|
||||||
|
|
||||||
extraClasses: function() {
|
extraClasses: function() {
|
||||||
var classes = [];
|
var classes = [];
|
||||||
@ -92,9 +90,8 @@ Discourse.FlaggedPost = Discourse.Post.extend({
|
|||||||
return classes.join(' ');
|
return classes.join(' ');
|
||||||
}.property(),
|
}.property(),
|
||||||
|
|
||||||
deleted: function() {
|
deleted: Em.computed.or('deleted_at', 'topic_deleted_at')
|
||||||
return (this.get('deleted_at') || this.get('topic_deleted_at'));
|
|
||||||
}.property()
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Discourse.FlaggedPost.reopenClass({
|
Discourse.FlaggedPost.reopenClass({
|
||||||
|
@ -32,7 +32,7 @@ class InvitesController < ApplicationController
|
|||||||
|
|
||||||
invite = Invite.where(invited_by_id: current_user.id, email: params[:email]).first
|
invite = Invite.where(invited_by_id: current_user.id, email: params[:email]).first
|
||||||
raise Discourse::InvalidParameters.new(:email) if invite.blank?
|
raise Discourse::InvalidParameters.new(:email) if invite.blank?
|
||||||
invite.trash!
|
invite.trash!(current_user)
|
||||||
|
|
||||||
render nothing: true
|
render nothing: true
|
||||||
end
|
end
|
||||||
|
@ -169,7 +169,7 @@ class TopicsController < ApplicationController
|
|||||||
def destroy
|
def destroy
|
||||||
topic = Topic.where(id: params[:id]).first
|
topic = Topic.where(id: params[:id]).first
|
||||||
guardian.ensure_can_delete!(topic)
|
guardian.ensure_can_delete!(topic)
|
||||||
topic.trash!
|
topic.trash!(current_user)
|
||||||
render nothing: true
|
render nothing: true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -54,9 +54,9 @@ class Post < ActiveRecord::Base
|
|||||||
@types ||= Enum.new(:regular, :moderator_action)
|
@types ||= Enum.new(:regular, :moderator_action)
|
||||||
end
|
end
|
||||||
|
|
||||||
def trash!
|
def trash!(trashed_by=nil)
|
||||||
self.topic_links.each(&:destroy)
|
self.topic_links.each(&:destroy)
|
||||||
super
|
super(trashed_by)
|
||||||
end
|
end
|
||||||
|
|
||||||
def recover!
|
def recover!
|
||||||
|
@ -63,7 +63,7 @@ class PostAction < ActiveRecord::Base
|
|||||||
moderator_id == -1 ? PostActionType.auto_action_flag_types.values : PostActionType.flag_types.values
|
moderator_id == -1 ? PostActionType.auto_action_flag_types.values : PostActionType.flag_types.values
|
||||||
end
|
end
|
||||||
|
|
||||||
PostAction.where({ post_id: post.id, post_action_type_id: actions }).update_all({ deleted_at: Time.zone.now, deleted_by: moderator_id })
|
PostAction.where({ post_id: post.id, post_action_type_id: actions }).update_all({ deleted_at: Time.zone.now, deleted_by_id: moderator_id })
|
||||||
f = actions.map{|t| ["#{PostActionType.types[t]}_count", 0]}
|
f = actions.map{|t| ["#{PostActionType.types[t]}_count", 0]}
|
||||||
Post.where(id: post.id).with_deleted.update_all(Hash[*f.flatten])
|
Post.where(id: post.id).with_deleted.update_all(Hash[*f.flatten])
|
||||||
update_flagged_posts_count
|
update_flagged_posts_count
|
||||||
@ -140,13 +140,13 @@ class PostAction < ActiveRecord::Base
|
|||||||
user_id: user.id,
|
user_id: user.id,
|
||||||
post_action_type_id:
|
post_action_type_id:
|
||||||
post_action_type_id).first
|
post_action_type_id).first
|
||||||
action.trash!
|
action.trash!(user)
|
||||||
action.run_callbacks(:save)
|
action.run_callbacks(:save)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_act!(user)
|
def remove_act!(user)
|
||||||
trash!
|
trash!(user)
|
||||||
run_callbacks(:save)
|
run_callbacks(:save)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -390,7 +390,7 @@ end
|
|||||||
# deleted_at :datetime
|
# deleted_at :datetime
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
# updated_at :datetime not null
|
# updated_at :datetime not null
|
||||||
# deleted_by :integer
|
# deleted_by_id :integer
|
||||||
# message :text
|
# message :text
|
||||||
# related_post_id :integer
|
# related_post_id :integer
|
||||||
# staff_took_action :boolean default(FALSE), not null
|
# staff_took_action :boolean default(FALSE), not null
|
||||||
|
@ -21,9 +21,9 @@ class Topic < ActiveRecord::Base
|
|||||||
|
|
||||||
versioned if: :new_version_required?
|
versioned if: :new_version_required?
|
||||||
|
|
||||||
def trash!
|
def trash!(trashed_by=nil)
|
||||||
update_category_topic_count_by(-1) if deleted_at.nil?
|
update_category_topic_count_by(-1) if deleted_at.nil?
|
||||||
super
|
super(trashed_by)
|
||||||
update_flagged_posts_count
|
update_flagged_posts_count
|
||||||
end
|
end
|
||||||
|
|
||||||
|
8
db/migrate/20130709184941_add_deleted_by_id_to_posts.rb
Normal file
8
db/migrate/20130709184941_add_deleted_by_id_to_posts.rb
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
class AddDeletedByIdToPosts < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :posts, :deleted_by_id, :integer, null: true
|
||||||
|
add_column :topics, :deleted_by_id, :integer, null: true
|
||||||
|
add_column :invites, :deleted_by_id, :integer, null: true
|
||||||
|
rename_column :post_actions, :deleted_by, :deleted_by_id
|
||||||
|
end
|
||||||
|
end
|
@ -37,12 +37,14 @@ class PostDestroyer
|
|||||||
# Feature users in the topic
|
# Feature users in the topic
|
||||||
Jobs.enqueue(:feature_topic_users, topic_id: @post.topic_id, except_post_id: @post.id)
|
Jobs.enqueue(:feature_topic_users, topic_id: @post.topic_id, except_post_id: @post.id)
|
||||||
|
|
||||||
@post.post_actions.map(&:trash!)
|
@post.post_actions.each do |pa|
|
||||||
|
pa.trash!(@user)
|
||||||
|
end
|
||||||
|
|
||||||
f = PostActionType.types.map{|k,v| ["#{k}_count", 0]}
|
f = PostActionType.types.map{|k,v| ["#{k}_count", 0]}
|
||||||
Post.with_deleted.where(id: @post.id).update_all(Hash[*f.flatten])
|
Post.with_deleted.where(id: @post.id).update_all(Hash[*f.flatten])
|
||||||
|
|
||||||
@post.trash!
|
@post.trash!(@user)
|
||||||
|
|
||||||
Topic.reset_highest(@post.topic_id)
|
Topic.reset_highest(@post.topic_id)
|
||||||
|
|
||||||
@ -59,7 +61,7 @@ class PostDestroyer
|
|||||||
# Remove any notifications that point to this deleted post
|
# Remove any notifications that point to this deleted post
|
||||||
Notification.delete_all topic_id: @post.topic_id, post_number: @post.post_number
|
Notification.delete_all topic_id: @post.topic_id, post_number: @post.post_number
|
||||||
|
|
||||||
@post.topic.trash! if @post.post_number == 1
|
@post.topic.trash!(@user) if @post.post_number == 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@ module Trashable
|
|||||||
default_scope where(with_deleted_scope_sql)
|
default_scope where(with_deleted_scope_sql)
|
||||||
|
|
||||||
# scope unscoped does not work
|
# scope unscoped does not work
|
||||||
|
|
||||||
|
belongs_to :deleted_by, class_name: 'User'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -24,23 +26,31 @@ module Trashable
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def trash!
|
def trash!(trashed_by=nil)
|
||||||
# note, an argument could be made that the column should probably called trashed_at
|
# note, an argument could be made that the column should probably called trashed_at
|
||||||
# however, deleted_at is the terminology used in the UI
|
# however, deleted_at is the terminology used in the UI
|
||||||
#
|
#
|
||||||
# we could hijack use a delete! and delete - redirecting the originals elsewhere, but that is
|
# we could hijack use a delete! and delete - redirecting the originals elsewhere, but that is
|
||||||
# confusing as well. So for now, we go with trash!
|
# confusing as well. So for now, we go with trash!
|
||||||
#
|
#
|
||||||
update_column(:deleted_at, DateTime.now)
|
trash_update(DateTime.now, trashed_by.try(:id))
|
||||||
end
|
end
|
||||||
|
|
||||||
def recover!
|
def recover!
|
||||||
|
trash_update(nil, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def trash_update(deleted_at, deleted_by_id)
|
||||||
# see: https://github.com/rails/rails/issues/8436
|
# see: https://github.com/rails/rails/issues/8436
|
||||||
#
|
#
|
||||||
# Fixed in Rails 4
|
# Fixed in Rails 4
|
||||||
#
|
#
|
||||||
self.class.unscoped.where(id: self.id).update_all({deleted_at: nil})
|
self.class.unscoped.where(id: self.id).update_all(deleted_at: deleted_at, deleted_by_id: deleted_by_id)
|
||||||
raw_write_attribute :deleted_at, nil
|
raw_write_attribute :deleted_at, deleted_at
|
||||||
|
raw_write_attribute :deleted_by_id, deleted_by_id
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -229,20 +229,22 @@ describe Guardian do
|
|||||||
end
|
end
|
||||||
|
|
||||||
describe 'a Post' do
|
describe 'a Post' do
|
||||||
|
|
||||||
|
let(:another_admin) { Fabricate(:admin) }
|
||||||
it 'correctly handles post visibility' do
|
it 'correctly handles post visibility' do
|
||||||
post = Fabricate(:post)
|
post = Fabricate(:post)
|
||||||
topic = post.topic
|
topic = post.topic
|
||||||
|
|
||||||
Guardian.new(user).can_see?(post).should be_true
|
Guardian.new(user).can_see?(post).should be_true
|
||||||
|
|
||||||
post.trash!
|
post.trash!(another_admin)
|
||||||
post.reload
|
post.reload
|
||||||
Guardian.new(user).can_see?(post).should be_false
|
Guardian.new(user).can_see?(post).should be_false
|
||||||
Guardian.new(admin).can_see?(post).should be_true
|
Guardian.new(admin).can_see?(post).should be_true
|
||||||
|
|
||||||
post.recover!
|
post.recover!
|
||||||
post.reload
|
post.reload
|
||||||
topic.trash!
|
topic.trash!(another_admin)
|
||||||
topic.reload
|
topic.reload
|
||||||
Guardian.new(user).can_see?(post).should be_false
|
Guardian.new(user).can_see?(post).should be_false
|
||||||
Guardian.new(admin).can_see?(post).should be_true
|
Guardian.new(admin).can_see?(post).should be_true
|
||||||
|
@ -23,6 +23,7 @@ describe PostDestroyer do
|
|||||||
|
|
||||||
it "doesn't delete the post" do
|
it "doesn't delete the post" do
|
||||||
post.deleted_at.should be_blank
|
post.deleted_at.should be_blank
|
||||||
|
post.deleted_by.should be_blank
|
||||||
post.raw.should == I18n.t('js.post.deleted_by_author')
|
post.raw.should == I18n.t('js.post.deleted_by_author')
|
||||||
post.version.should == 2
|
post.version.should == 2
|
||||||
end
|
end
|
||||||
@ -35,6 +36,7 @@ describe PostDestroyer do
|
|||||||
|
|
||||||
it "deletes the post" do
|
it "deletes the post" do
|
||||||
post.deleted_at.should be_present
|
post.deleted_at.should be_present
|
||||||
|
post.deleted_by.should == moderator
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -45,6 +47,7 @@ describe PostDestroyer do
|
|||||||
|
|
||||||
it "deletes the post" do
|
it "deletes the post" do
|
||||||
post.deleted_at.should be_present
|
post.deleted_at.should be_present
|
||||||
|
post.deleted_by.should == admin
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ describe InvitesController do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "destroys the invite" do
|
it "destroys the invite" do
|
||||||
Invite.any_instance.expects(:trash!)
|
Invite.any_instance.expects(:trash!).with(user)
|
||||||
delete :destroy, email: invite.email
|
delete :destroy, email: invite.email
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ describe PostActionsController do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "works with a deleted post" do
|
it "works with a deleted post" do
|
||||||
flagged_post.trash!
|
flagged_post.trash!(user)
|
||||||
xhr :post, :clear_flags, id: flagged_post.id, post_action_type_id: PostActionType.types[:spam]
|
xhr :post, :clear_flags, id: flagged_post.id, post_action_type_id: PostActionType.types[:spam]
|
||||||
response.should be_success
|
response.should be_success
|
||||||
end
|
end
|
||||||
|
@ -14,7 +14,8 @@ describe PostsController do
|
|||||||
|
|
||||||
describe 'show' do
|
describe 'show' do
|
||||||
|
|
||||||
let(:post) { Fabricate(:post, user: log_in) }
|
let(:user) { log_in }
|
||||||
|
let(:post) { Fabricate(:post, user: user) }
|
||||||
|
|
||||||
it 'ensures the user can see the post' do
|
it 'ensures the user can see the post' do
|
||||||
Guardian.any_instance.expects(:can_see?).with(post).returns(false)
|
Guardian.any_instance.expects(:can_see?).with(post).returns(false)
|
||||||
@ -30,7 +31,7 @@ describe PostsController do
|
|||||||
context "deleted post" do
|
context "deleted post" do
|
||||||
|
|
||||||
before do
|
before do
|
||||||
post.trash!
|
post.trash!(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can't find deleted posts as an anonymous user" do
|
it "can't find deleted posts as an anonymous user" do
|
||||||
|
@ -58,7 +58,7 @@ describe PostAction do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context "a post is deleted" do
|
context "a post is deleted" do
|
||||||
When { spam_post.trash!; spammer.reload }
|
When { spam_post.trash!(moderator); spammer.reload }
|
||||||
Then { expect(spammer.reload).to be_blocked }
|
Then { expect(spammer.reload).to be_blocked }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@ describe Notification do
|
|||||||
|
|
||||||
Notification.create!(read: false, user_id: p2.user_id, topic_id: p2.topic_id, post_number: p2.post_number, data: '[]',
|
Notification.create!(read: false, user_id: p2.user_id, topic_id: p2.topic_id, post_number: p2.post_number, data: '[]',
|
||||||
notification_type: Notification.types[:liked])
|
notification_type: Notification.types[:liked])
|
||||||
p2.trash!
|
p2.trash!(p.user)
|
||||||
|
|
||||||
# we may want to make notification "trashable" but for now we nuke pm notifications from deleted topics/posts
|
# we may want to make notification "trashable" but for now we nuke pm notifications from deleted topics/posts
|
||||||
Notification.ensure_consistency!
|
Notification.ensure_consistency!
|
||||||
|
@ -1296,16 +1296,17 @@ describe Topic do
|
|||||||
|
|
||||||
describe 'trash!' do
|
describe 'trash!' do
|
||||||
context "its category's topic count" do
|
context "its category's topic count" do
|
||||||
|
let(:moderator) { Fabricate(:moderator) }
|
||||||
let(:category) { Fabricate(:category) }
|
let(:category) { Fabricate(:category) }
|
||||||
|
|
||||||
it "subtracts 1 if topic is being deleted" do
|
it "subtracts 1 if topic is being deleted" do
|
||||||
topic = Fabricate(:topic, category: category)
|
topic = Fabricate(:topic, category: category)
|
||||||
expect { topic.trash! }.to change { category.reload.topic_count }.by(-1)
|
expect { topic.trash!(moderator) }.to change { category.reload.topic_count }.by(-1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't subtract 1 if topic is already deleted" do
|
it "doesn't subtract 1 if topic is already deleted" do
|
||||||
topic = Fabricate(:topic, category: category, deleted_at: 1.day.ago)
|
topic = Fabricate(:topic, category: category, deleted_at: 1.day.ago)
|
||||||
expect { topic.trash! }.to_not change { category.reload.topic_count }
|
expect { topic.trash!(moderator) }.to_not change { category.reload.topic_count }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -62,7 +62,7 @@ describe UserAction do
|
|||||||
|
|
||||||
other_stats.should == expecting
|
other_stats.should == expecting
|
||||||
|
|
||||||
public_topic.trash!
|
public_topic.trash!(user)
|
||||||
stats_for_user.should == []
|
stats_for_user.should == []
|
||||||
stream_count.should == 0
|
stream_count.should == 0
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user