forked from tildeverse/tilde.news
disown old coments
A user who wanted to 'start fresh' turned a bunch of discussions into swiss cheese by deleting old comments. This allows disowning old comments, similar to the option to disown all comments when self-deleting.
This commit is contained in:
parent
859f195e07
commit
28754db22b
|
@ -483,6 +483,16 @@ $(document).ready(function() {
|
|||
}
|
||||
});
|
||||
|
||||
$(document).on("click", "a.comment_disownor", function() {
|
||||
if (confirm("Are you sure you want to disown this comment?")) {
|
||||
var li = $(this).closest(".comment");
|
||||
$.post("/comments/" + $(li).attr("data-shortid") + "/disown",
|
||||
function(d) {
|
||||
$(li).replaceWith(d);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("click", "a.comment_moderator", function() {
|
||||
var reason = prompt("Moderation reason:");
|
||||
if (reason == null || reason == "")
|
||||
|
|
|
@ -139,6 +139,18 @@ class CommentsController < ApplicationController
|
|||
:content_type => "text/html", :locals => { :comment => comment }
|
||||
end
|
||||
|
||||
def disown
|
||||
if !((comment = find_comment) && comment.is_disownable_by_user?(@user))
|
||||
return render :plain => "can't find comment", :status => 400
|
||||
end
|
||||
|
||||
InactiveUser.disown! comment
|
||||
comment = find_comment
|
||||
|
||||
render :partial => "comment", :layout => false,
|
||||
:content_type => "text/html", :locals => { :comment => comment }
|
||||
end
|
||||
|
||||
def update
|
||||
if !((comment = find_comment) && comment.is_editable_by_user?(@user))
|
||||
return render :plain => "can't find comment", :status => 400
|
||||
|
|
|
@ -21,7 +21,7 @@ class SettingsController < ApplicationController
|
|||
|
||||
@user.delete!
|
||||
if params[:disown].present?
|
||||
@user.disown_comments!
|
||||
InactiveUser.disown_all_by_author! @user
|
||||
end
|
||||
reset_session
|
||||
flash[:success] = "Your account has been deleted."
|
||||
|
|
|
@ -27,6 +27,7 @@ class Comment < ApplicationRecord
|
|||
scope :active, -> { where(:is_deleted => false, :is_moderated => false) }
|
||||
|
||||
DOWNVOTABLE_DAYS = 7
|
||||
DELETEABLE_DAYS = DOWNVOTABLE_DAYS * 2
|
||||
|
||||
# the lowest a score can go
|
||||
DOWNVOTABLE_MIN_SCORE = -10
|
||||
|
@ -324,12 +325,16 @@ class Comment < ApplicationRecord
|
|||
if user && user.is_moderator?
|
||||
return true
|
||||
elsif user && user.id == self.user_id
|
||||
return true
|
||||
return self.created_at >= DELETEABLE_DAYS.days.ago
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def is_disownable_by_user?(user)
|
||||
user && user.id == self.user_id && self.created_at && self.created_at < DELETEABLE_DAYS.days.ago
|
||||
end
|
||||
|
||||
def is_downvotable?
|
||||
if self.created_at && self.score > DOWNVOTABLE_MIN_SCORE
|
||||
Time.current - self.created_at <= DOWNVOTABLE_DAYS.days
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
module InactiveUser
|
||||
def self.inactive_user
|
||||
@inactive_user ||= User.find_by!(username: 'inactive-user')
|
||||
end
|
||||
|
||||
def self.disown! comment
|
||||
author = comment.user
|
||||
comment.update_column(:user_id, inactive_user.id)
|
||||
refresh_comment_counts! author
|
||||
end
|
||||
|
||||
def self.disown_all_by_author! author
|
||||
author.comments.update_all(:user_id => inactive_user.id)
|
||||
refresh_comment_counts! author
|
||||
end
|
||||
|
||||
def self.refresh_comment_counts! user
|
||||
user.update_comments_posted_count! if user
|
||||
inactive_user.update_comments_posted_count!
|
||||
end
|
||||
end
|
|
@ -366,12 +366,6 @@ class User < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
def disown_comments!
|
||||
inactive_user = User.find_by!(:username => 'inactive-user')
|
||||
self.comments.update_all(:user_id => inactive_user.id)
|
||||
inactive_user.update_comments_posted_count!
|
||||
end
|
||||
|
||||
def disable_2fa!
|
||||
self.totp_secret = nil
|
||||
self.save!
|
||||
|
|
|
@ -91,14 +91,17 @@ class="comment <%= comment.current_vote ? (comment.current_vote[:vote] == 1 ?
|
|||
|
||||
<% if comment.is_gone? && comment.is_undeletable_by_user?(@user) %>
|
||||
|
|
||||
<a tabindex="0" class="comment_undeletor">undelete</a>
|
||||
<a tabindex="0" class="comment_undeletor" href="#">undelete</a>
|
||||
<% elsif !comment.is_gone? && comment.is_deletable_by_user?(@user) %>
|
||||
|
|
||||
<% if @user && @user.is_moderator? && @user.id != comment.user_id %>
|
||||
<a tabindex="0" class="comment_moderator">delete</a>
|
||||
<a tabindex="0" class="comment_moderator" href="#">delete</a>
|
||||
<% else %>
|
||||
<a tabindex="0" class="comment_deletor">delete</a>
|
||||
<a tabindex="0" class="comment_deletor" href="#">delete</a>
|
||||
<% end %>
|
||||
<% elsif !comment.is_gone? && comment.is_disownable_by_user?(@user) %>
|
||||
|
|
||||
<a tabindex="0" class="comment_disownor" href="#">disown</a>
|
||||
<% end %>
|
||||
|
||||
<% if @user && !comment.story.is_gone? && !comment.is_gone? %>
|
||||
|
|
|
@ -89,6 +89,7 @@ Lobsters::Application.routes.draw do
|
|||
|
||||
post "delete"
|
||||
post "undelete"
|
||||
post "disown"
|
||||
end
|
||||
end
|
||||
get "/comments/page/:page" => "comments#index"
|
||||
|
|
|
@ -3,7 +3,7 @@ require "rails_helper"
|
|||
describe TagsController do
|
||||
let(:user_id) { 5 }
|
||||
before do
|
||||
stub_login_as double('admin', id: user_id, is_active?: true, username: 'admin')
|
||||
stub_login_as User.make!(id: user_id)
|
||||
allow(controller).to receive(:require_logged_in_admin)
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
require 'rails_helper'
|
||||
|
||||
# uses page.driver.post because we're not running a full js engine,
|
||||
# so the call can't just be click_on('delete'), etc.
|
||||
|
||||
RSpec.feature "Commenting" do
|
||||
let(:story) { Story.make! title: "Example Story" }
|
||||
let(:user) { User.make! username: 'user' }
|
||||
|
||||
before(:each) { stub_login_as user }
|
||||
|
||||
scenario 'posting a comment' do
|
||||
visit "/s/#{story.short_id}"
|
||||
expect(page).to have_button('Post')
|
||||
fill_in 'comment', with: 'An example comment'
|
||||
click_on 'Post'
|
||||
visit "/s/#{story.short_id}"
|
||||
expect(page).to have_content('example comment')
|
||||
end
|
||||
|
||||
feature "deleting comments" do
|
||||
scenario 'deleting a comment' do
|
||||
comment = Comment.make!(
|
||||
comment: 'An example comment',
|
||||
user_id: user.id,
|
||||
story_id: story.id,
|
||||
created_at: 1.day.ago,
|
||||
)
|
||||
visit "/s/#{story.short_id}"
|
||||
expect(page).to have_link('delete')
|
||||
|
||||
page.driver.post "/comments/#{comment.short_id}/delete"
|
||||
visit "/s/#{story.short_id}"
|
||||
expect(page).to have_link('undelete')
|
||||
comment.reload
|
||||
expect(comment.is_deleted?)
|
||||
end
|
||||
|
||||
scenario 'trying to delete old comments' do
|
||||
comment = Comment.make!(
|
||||
comment: 'An example comment',
|
||||
user_id: user.id,
|
||||
story_id: story.id,
|
||||
created_at: 90.days.ago,
|
||||
)
|
||||
visit "/s/#{story.short_id}"
|
||||
expect(page).not_to have_link('delete')
|
||||
|
||||
page.driver.post "/comments/#{comment.short_id}/delete"
|
||||
comment.reload
|
||||
expect(!comment.is_deleted?)
|
||||
end
|
||||
end
|
||||
|
||||
feature "disowning comments" do
|
||||
scenario 'disowning a comment' do
|
||||
# bypass validations to create inactive-user:
|
||||
User.make!.tap {|u| u.update_column :username, 'inactive-user' }
|
||||
|
||||
comment = Comment.make! user_id: user.id, story_id: story.id, created_at: 90.days.ago
|
||||
visit "/s/#{story.short_id}"
|
||||
expect(page).to have_link('disown')
|
||||
|
||||
page.driver.post "/comments/#{comment.short_id}/disown"
|
||||
comment.reload
|
||||
expect(comment.user).not_to eq(user)
|
||||
visit "/s/#{story.short_id}"
|
||||
expect(page).to have_content('inactive-user')
|
||||
end
|
||||
|
||||
scenario 'trying to disown recent comments' do
|
||||
comment = Comment.make! user_id: user.id, story_id: story.id, created_at: 1.day.ago
|
||||
visit "/s/#{story.short_id}"
|
||||
expect(page).not_to have_link('disown')
|
||||
|
||||
page.driver.post "/comments/#{comment.short_id}/disown"
|
||||
puts page.body
|
||||
comment.reload
|
||||
expect(comment.user).to eq(user)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,6 +1,6 @@
|
|||
module AuthenticationHelper
|
||||
def stub_login_as user
|
||||
allow(User).to receive(:find_by).and_return(user)
|
||||
user.update_column(:session_token, 'asdf')
|
||||
allow_any_instance_of(ApplicationController).to receive(:session).and_return(u: 'asdf')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -46,6 +46,7 @@ Comment.blueprint do
|
|||
story_id { Story.make!.id }
|
||||
comment { "comment text #{sn}" }
|
||||
hat { nil }
|
||||
created_at { Time.current }
|
||||
end
|
||||
|
||||
Message.blueprint do
|
||||
|
|
Loading…
Reference in New Issue