Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
69ab9b1
close...
forceofcalm May 20, 2026
7e7d691
added tests
forceofcalm May 20, 2026
16d19e7
some progress on code cleanup
forceofcalm May 20, 2026
e1b9efa
maybe better?
forceofcalm May 20, 2026
db9f657
stray comment...
forceofcalm May 20, 2026
ed8d536
matching template to rest of codebase
forceofcalm May 22, 2026
9fc1ade
removed unused key
forceofcalm May 22, 2026
3700d67
lol jk readded the key and updated template and tests
forceofcalm May 22, 2026
f1c857f
i think??
forceofcalm May 22, 2026
42dac9f
rubo cop my dearest
forceofcalm May 22, 2026
58ceb39
updating t() to ts()
forceofcalm May 22, 2026
f0696e5
im going to kill my linter
forceofcalm May 22, 2026
585d903
reverting pre-linter... going to readd the keys...
forceofcalm May 22, 2026
66dbf9c
readded keys
forceofcalm May 22, 2026
839915d
i s2g
forceofcalm May 22, 2026
0e5a37e
losing my mind a bit, will have an easier time refocusing on changes …
forceofcalm May 22, 2026
e445e3b
missed on when redoing translations
forceofcalm May 24, 2026
cd5612b
getting lost in the sauce again, committing again for the git compare
forceofcalm May 24, 2026
001a899
updated route for editing a preview comment
forceofcalm May 24, 2026
cffad9e
decoupled the comment loading; not DRY, but i think easier to read/ma…
forceofcalm May 24, 2026
43ec3cb
okay... i think this is better.
forceofcalm May 24, 2026
ec69575
might as well fix all ts()
forceofcalm May 24, 2026
08e1473
rubocop
forceofcalm May 24, 2026
793b2db
okay so we cant do a POST on :new im so glad that took me hours to fi…
forceofcalm May 25, 2026
69fba89
normalized localization files
forceofcalm May 25, 2026
edd82a7
i think i fixed my tests idk i hate this part
forceofcalm May 25, 2026
6a277f6
rubocop exists only to torment me
forceofcalm May 25, 2026
a1e5b1a
probably fixes the test...
forceofcalm May 26, 2026
765a2d1
new layout/flow for comment previews
forceofcalm May 26, 2026
4054a54
modified cancel flow
forceofcalm May 27, 2026
4cc19bd
test updates
forceofcalm May 27, 2026
0c352f8
linter errors
forceofcalm May 27, 2026
120ea14
removed the ts()
forceofcalm May 27, 2026
0735ce4
translation files
forceofcalm May 27, 2026
702cec6
reverted to ts and only updated to t on functions we have modified in…
forceofcalm May 27, 2026
bf9e71d
oops
forceofcalm May 27, 2026
0f2e829
missed a couple
forceofcalm May 27, 2026
4c7a4f6
and some more!
forceofcalm May 27, 2026
e6a8ed7
i think these follow best practice more!
forceofcalm May 27, 2026
e09c845
oops
forceofcalm May 27, 2026
c69e9df
more yml changes
forceofcalm May 27, 2026
0434ae0
localized
forceofcalm May 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 123 additions & 60 deletions app/controllers/comments_controller.rb
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
class CommentsController < ApplicationController
before_action :load_commentable,
only: [:index, :new, :create, :edit, :update, :show_comments,
only: [:index, :new, :create, :preview, :edit, :update, :show_comments,
:hide_comments, :add_comment_reply,
:cancel_comment_reply, :delete_comment,
:cancel_comment_delete, :unreviewed, :review_all]
before_action :check_user_status, only: [:new, :create, :edit, :update, :destroy]
before_action :check_user_status, only: [:new, :create, :preview, :edit, :update, :destroy]
before_action :load_comment, only: [:show, :edit, :update, :delete_comment, :destroy, :cancel_comment_edit, :cancel_comment_delete, :review, :approve, :reject, :freeze, :unfreeze, :hide, :unhide]
before_action :check_visibility, only: [:show]
before_action :check_if_restricted
before_action :check_tag_wrangler_access
before_action :check_parent_visible
before_action :check_modify_parent,
only: [:new, :create, :edit, :update, :add_comment_reply,
only: [:new, :create, :preview, :edit, :update, :add_comment_reply,
:cancel_comment_reply, :cancel_comment_edit]
before_action :check_pseud_ownership, only: [:create, :update]
before_action :check_ownership, only: [:edit, :update, :cancel_comment_edit]
before_action :check_permission_to_edit, only: [:edit, :update]
before_action :check_permission_to_delete, only: [:delete_comment, :destroy]
before_action :check_guest_comment_admin_setting, only: [:new, :create, :add_comment_reply]
before_action :check_parent_comment_permissions, only: [:new, :create, :add_comment_reply]
before_action :check_guest_comment_admin_setting, only: [:new, :create, :preview, :add_comment_reply]
before_action :check_parent_comment_permissions, only: [:new, :create, :preview, :add_comment_reply]
before_action :check_unreviewed, only: [:add_comment_reply]
before_action :check_frozen, only: [:new, :create, :add_comment_reply]
before_action :check_hidden_by_admin, only: [:new, :create, :add_comment_reply]
before_action :check_not_replying_to_spam, only: [:new, :create, :add_comment_reply]
before_action :check_guest_replies_preference, only: [:new, :create, :add_comment_reply]
before_action :check_frozen, only: [:new, :create, :preview, :add_comment_reply]
before_action :check_hidden_by_admin, only: [:new, :create, :preview, :add_comment_reply]
before_action :check_not_replying_to_spam, only: [:new, :create, :preview, :add_comment_reply]
before_action :check_guest_replies_preference, only: [:new, :create, :preview, :add_comment_reply]
before_action :check_permission_to_review, only: [:unreviewed]
before_action :check_permission_to_access_single_unreviewed, only: [:show]
before_action :check_permission_to_moderate, only: [:approve, :reject]
Expand All @@ -36,7 +36,7 @@ class CommentsController < ApplicationController
include WorksHelper
include BlockHelper

before_action :check_blocked, only: [:new, :create, :add_comment_reply, :edit, :update]
before_action :check_blocked, only: [:new, :create, :preview, :add_comment_reply, :edit, :update]
def check_blocked
parent = find_parent

Expand Down Expand Up @@ -362,23 +362,21 @@ def show
# GET /comments/new
def new
if @commentable.nil?
flash[:error] = ts("What did you want to comment on?")
flash[:error] = t("comments.new.missing_commentable")
redirect_back_or_to root_path
else
@comment = Comment.new
@comment = build_comment_for_form
@controller_name = params[:controller_name] if params[:controller_name]
@name =
case @commentable.class.name
when /Work/
when /Work/, /AdminPost/
@commentable.title
when /Chapter/
@commentable.work.title
when /Tag/
@commentable.name
when /AdminPost/
@commentable.title
when /Comment/
ts("Previous Comment")
t("comments.new.previous_comment")
else
@commentable.class.name
end
Expand All @@ -393,57 +391,108 @@ def edit
end
end

# GET /comments/preview
def preview
if @commentable.nil?
flash[:error] = t(".missing_commentable")
redirect_back_or_to root_path
return
end

@comment = Comment.new(comment_params)
@comment.commentable = Comment.commentable_object(@commentable)

@comment.set_parent_and_unreviewed

unless @comment.valid?
render :new, locals: { show_errors: true }
return
end

@preview_mode = true
@form_state = { comment_content: @comment.comment_content }
@form_state[:pseud_id] = @comment.pseud_id if @comment.pseud_id
@form_state[:name] = @comment.name if @comment.name
@form_state[:email] = @comment.email if @comment.email
@form_state[:view_full_work] = params[:view_full_work] if params[:view_full_work]
@form_state[:page] = params[:page] if params[:page]
@form_state[:controller_name] = params[:controller_name] if params[:controller_name]

case @commentable
when Work
@form_state[:work_id] = @commentable.id
when Chapter
@form_state[:chapter_id] = @commentable.id
when AdminPost
@form_state[:admin_post_id] = @commentable.id
when Tag
@form_state[:tag_id] = @commentable.name
when Comment
@form_state[:comment_id] = @commentable.id
end

@form_state[:filters] = filter_params.to_h if controller_name == "inbox" && params[:filters]

render :preview
end

# POST /comments
# POST /comments.xml
def create
if @commentable.nil?
flash[:error] = ts("What did you want to comment on?")
if params[:preview_button]
preview
return
end

if @commentable.blank?
flash[:error] = t("comments.create.missing_commentable")
redirect_back_or_to root_path
else
@comment = Comment.new(comment_params)
@comment.ip_address = request.remote_ip
@comment.user_agent = request.env["HTTP_USER_AGENT"]&.to(499)
@comment.cloudflare_bot_score = request.env["HTTP_CF_BOT_SCORE"]
@comment.cloudflare_ja3_hash = request.env["HTTP_CF_JA3_HASH"]
@comment.cloudflare_ja4 = request.env["HTTP_CF_JA4"]
@comment.commentable = Comment.commentable_object(@commentable)
@controller_name = params[:controller_name]

# First, try saving the comment
if @comment.save
flash[:comment_notice] = if @comment.unreviewed?
# i18n-tasks-use t("comments.create.success.moderated.admin_post")
# i18n-tasks-use t("comments.create.success.moderated.work")
t("comments.create.success.moderated.#{@comment.ultimate_parent.model_name.i18n_key}")
else
t("comments.create.success.not_moderated")
end
respond_to do |format|
format.html do
if request.referer&.match(/inbox/)
redirect_to user_inbox_path(current_user, filters: filter_params, page: params[:page])
elsif request.referer&.match(/new/) || (@comment.unreviewed? && current_user)
# If the referer is the new comment page, go to the comment's page
# instead of reloading the full work.
# If the comment is unreviewed and commenter is logged in, take
# them to the comment's page so they can access the edit and
# delete options for the comment, since unreviewed comments don't
# appear on the commentable.
redirect_to comment_path(@comment)
elsif request.referer == root_url
# replying on the homepage
redirect_to root_path
elsif @comment.unreviewed?
redirect_to_all_comments(@commentable)
else
redirect_to_comment(@comment, { view_full_work: (params[:view_full_work] == "true"), page: params[:page] })
end
return
end

@comment = Comment.new(comment_params)
@comment.ip_address = request.remote_ip
@comment.user_agent = request.env["HTTP_USER_AGENT"]&.to(499)
@comment.cloudflare_bot_score = request.env["HTTP_CF_BOT_SCORE"]
@comment.cloudflare_ja3_hash = request.env["HTTP_CF_JA3_HASH"]
@comment.cloudflare_ja4 = request.env["HTTP_CF_JA4"]
@comment.commentable = Comment.commentable_object(@commentable)
@controller_name = params[:controller_name]

# First, try saving the comment
if @comment.save
flash[:comment_notice] = if @comment.unreviewed?
# i18n-tasks-use t("comments.create.success.moderated.admin_post")
# i18n-tasks-use t("comments.create.success.moderated.work")
t("comments.create.success.moderated.#{@comment.ultimate_parent.model_name.i18n_key}")
else
t("comments.create.success.not_moderated")
end
respond_to do |format|
format.html do
if request.referer&.match(/inbox/)
redirect_to user_inbox_path(current_user, filters: filter_params, page: params[:page])
elsif request.referer&.match(/new/) || (@comment.unreviewed? && current_user)
# If the referer is the new comment page, go to the comment's page
# instead of reloading the full work.
# If the comment is unreviewed and commenter is logged in, take
# them to the comment's page so they can access the edit and
# delete options for the comment, since unreviewed comments don't
# appear on the commentable.
redirect_to comment_path(@comment)
elsif request.referer == root_url
# replying on the homepage
redirect_to root_path
elsif @comment.unreviewed?
redirect_to_all_comments(@commentable)
else
redirect_to_comment(@comment, { view_full_work: (params[:view_full_work] == "true"), page: params[:page] })
end
end
else
flash[:error] = ts("Couldn't save comment!")
render action: "new"
end
else
flash[:error] = t("comments.create.error")
render action: "new"
end
end

Expand Down Expand Up @@ -764,6 +813,20 @@ def permission_to_modify_frozen_status

private

def build_comment_for_form
if params[:comment_content].present? || params[:comment].present?
comment_attrs = {
comment_content: params[:comment_content] || params.dig(:comment, :comment_content),
pseud_id: params[:pseud_id] || params.dig(:comment, :pseud_id),
name: params[:name] || params.dig(:comment, :name),
email: params[:email] || params.dig(:comment, :email)
}
Comment.new(comment_attrs.compact)
else
Comment.new
end
end

def comment_params
params.require(:comment).permit(
:pseud_id, :comment_content, :name, :email, :edited_at
Expand Down
5 changes: 4 additions & 1 deletion app/views/comments/_comment_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,11 @@
maximum_length: ArchiveConfig.COMMENT_MAX,
tooLongMessage: t(".comment_too_long", count: ArchiveConfig.COMMENT_MAX) %>
<p class="submit actions">
<%= f.submit t(".preview_button"), name: "preview_button", id: "comment_preview_for_#{commentable.id}" %>
<%= f.submit button_name, id: "comment_submit_for_#{commentable.id}", data: { disable_with: t(".processing_message") } %>
<% if controller.controller_name == 'inbox' %>
<% if local_assigns[:cancel_redirect] %>
<%= link_to t(".cancel_action"), local_assigns[:cancel_path], data: { confirm: t(".cancel_redirect_warning") } %>
<% elsif controller.controller_name == 'inbox' %>
<a name="comment_cancel" id="comment_cancel"><%= t(".cancel_action") %></a>
<% elsif comment.persisted? %>
<%= cancel_edit_comment_link(comment) %>
Expand Down
114 changes: 114 additions & 0 deletions app/views/comments/preview.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<h2 class="heading"><%= t(".page_heading") %></h2>
<p><%= t(".commenting_on_html", commentable_link: link_to_comment_ultimate_parent(@comment)) %></p>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this link could be part of the h2 header, like on the /comments page


<!--main content-->
<div id="previewpane">
<ol class="thread">
<% if @commentable.is_a?(Comment) %>
<li class="<%= cycle :odd, :even %> <%= css_classes_for_comment(@commentable) %>" id="comment_<%= @commentable.id %>" role="article">
<% if @commentable.is_deleted %>
<p><%= t(".deleted_comment") %></p>
<% elsif !can_see_hidden_comment?(@commentable) %>
<p class="message"><%= t(".hidden_comment") %></p>
<% else %>
<h4 class="heading byline">
<% if @commentable.by_anonymous_creator? %>
<%= t(".anonymous_creator") %>
<% else %>
<%= get_commenter_pseud_or_name(@commentable) %>
<% end %>
<span class="posted datetime">
<%= time_in_zone(@commentable.created_at) %>
</span>
</h4>
<div class="icon">
<% if @commentable.pseud %>
<% if @commentable.by_anonymous_creator? %>
<span class="anonymous icon"></span>
<% else %>
<%= icon_display(@commentable.pseud.user, @commentable.pseud) %>
<% end %>
<% else %>
<span class="visitor icon"></span>
<% end %>
</div>
<blockquote class="userstuff">
<%= raw sanitize_field(@commentable, :comment_content) %>
</blockquote>
<% end %>
</li>
<li>
<ol class="thread">
<li class="<%= cycle :odd, :even %> <%= css_classes_for_comment(@comment) %> preview" id="comment_preview" role="article">
<h4 class="heading byline">
<% if @comment.by_anonymous_creator? %>
<%= t(".anonymous_creator") %>
<% else %>
<%= get_commenter_pseud_or_name(@comment) %>
<% end %>
<span class="posted datetime">
<%= time_in_zone(Time.current) %>
</span>
</h4>
<div class="icon">
<% if @comment.pseud %>
<% if @comment.by_anonymous_creator? %>
<span class="anonymous icon"></span>
<% else %>
<%= icon_display(@comment.pseud.user, @comment.pseud) %>
<% end %>
<% else %>
<span class="visitor icon"></span>
<% end %>
</div>
<blockquote class="userstuff">
<%= raw sanitize_field(@comment, :comment_content) %>
</blockquote>
</li>
</ol>
</li>
<% else %>
<li class="<%= cycle :odd, :even %> <%= css_classes_for_comment(@comment) %> preview" id="comment_preview" role="article">
<h4 class="heading byline">
<% if @comment.by_anonymous_creator? %>
<%= t(".anonymous_creator") %>
<% else %>
<%= get_commenter_pseud_or_name(@comment) %>
<% end %>
<span class="posted datetime">
<%= time_in_zone(Time.current) %>
</span>
</h4>
<div class="icon">
<% if @comment.pseud %>
<% if @comment.by_anonymous_creator? %>
<span class="anonymous icon"></span>
<% else %>
<%= icon_display(@comment.pseud.user, @comment.pseud) %>
<% end %>
<% else %>
<span class="visitor icon"></span>
<% end %>
</div>
<blockquote class="userstuff">
<%= raw sanitize_field(@comment, :comment_content) %>
</blockquote>
</li>
<% end %>
</ol>
</div>
<!--/content-->

<!--inline edit form-->
<div id="edit_comment_on_preview">
<h3 class="heading"><%= t(".edit_comment_heading") %></h3>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this heading is potentially confusing because technically you're not editing a comment if it wasn't created yet, and probably unnecessary because it should be obvious it's a comment drafting form, though i'm saying that as someone very used to ao3's interface and therefore very biased

<% cancel_target = @commentable.is_a?(Comment) ? @commentable.ultimate_parent : @commentable %>
<%= render partial: "comments/comment_form",
locals: {
comment: @comment,
commentable: @commentable,
button_name: t(".post_comment"),
cancel_redirect: true,
cancel_path: cancel_target.is_a?(Tag) ? tag_path(cancel_target) : polymorphic_path(cancel_target)
} %>
</div>
5 changes: 5 additions & 0 deletions config/locales/controllers/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ en:
error:
frozen: Frozen comments cannot be edited.
create:
error: Couldn't save comment!
missing_commentable: What did you want to comment on?
success:
moderated:
admin_post: Your comment was received! It will appear publicly after it has been approved.
Expand All @@ -179,7 +181,10 @@ en:
index:
page_title: Comments on %{name}
new:
missing_commentable: What did you want to comment on?
page_title: New Comment on %{name}
preview:
missing_commentable: What did you want to comment on?
rate_limited:
error: You have made too many requests in a short time period. Please wait a while before trying again. If you are receiving this error repeatedly, try browsing more slowly or loading fewer pages at a time.
show:
Expand Down
Loading
Loading