diff --git a/app/controllers/user_feedbacks_controller.rb b/app/controllers/user_feedbacks_controller.rb index a02e49357..50650d5a9 100644 --- a/app/controllers/user_feedbacks_controller.rb +++ b/app/controllers/user_feedbacks_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class UserFeedbacksController < ApplicationController - before_action :moderator_only, :only => [:new, :edit, :create, :update, :destroy] + before_action :moderator_only, except: %i[index show] respond_to :html, :json def new @@ -11,17 +11,18 @@ class UserFeedbacksController < ApplicationController def edit @user_feedback = UserFeedback.find(params[:id]) - check_privilege(@user_feedback) + check_edit_privilege(@user_feedback) respond_with(@user_feedback) end def show @user_feedback = UserFeedback.find(params[:id]) + raise(User::PrivilegeError) if !CurrentUser.user.is_moderator? && @user_feedback.is_deleted? respond_with(@user_feedback) end def index - @user_feedbacks = UserFeedback.search(search_params).paginate(params[:page], limit: params[:limit]) + @user_feedbacks = UserFeedback.visible(CurrentUser.user).search(search_params).paginate(params[:page], limit: params[:limit]) respond_with(@user_feedbacks) end @@ -32,7 +33,7 @@ class UserFeedbacksController < ApplicationController def update @user_feedback = UserFeedback.find(params[:id]) - check_privilege(@user_feedback) + check_edit_privilege(@user_feedback) params_update = user_feedback_params(:update) @user_feedback.update(params_update) @@ -41,17 +42,47 @@ class UserFeedbacksController < ApplicationController respond_with(@user_feedback) end + def delete + @user_feedback = UserFeedback.find(params[:id]) + check_delete_privilege(@user_feedback) + @user_feedback.update(is_deleted: true) + flash[:notice] = @user_feedback.errors.any? ? @user_feedback.errors.full_messages.join("; ") : "Feedback deleted" + respond_with(@user_feedback) do |format| + format.html { redirect_back(fallback_location: user_feedbacks_path(search: { user_id: @user_feedback.user_id })) } + end + end + + def undelete + @user_feedback = UserFeedback.find(params[:id]) + check_delete_privilege(@user_feedback) + @user_feedback.update(is_deleted: false) + flash[:notice] = @user_feedback.errors.any? ? @user_feedback.errors.full_messages.join("; ") : "Feedback undeleted" + respond_with(@user_feedback) do |format| + format.html { redirect_back(fallback_location: user_feedbacks_path(search: { user_id: @user_feedback.user_id })) } + end + end + def destroy @user_feedback = UserFeedback.find(params[:id]) - check_privilege(@user_feedback) + check_destroy_privilege(@user_feedback) @user_feedback.destroy - redirect_back fallback_location: user_feedbacks_path + respond_with(@user_feedback) do |format| + format.html { redirect_back(fallback_location: user_feedbacks_path(search: { user_id: @user_feedback.user_id })) } + end end private - def check_privilege(user_feedback) - raise User::PrivilegeError unless user_feedback.editable_by?(CurrentUser.user) + def check_edit_privilege(user_feedback) + raise(User::PrivilegeError) unless user_feedback.editable_by?(CurrentUser.user) + end + + def check_delete_privilege(user_feedback) + raise(User::PrivilegeError) unless user_feedback.deletable_by?(CurrentUser.user) + end + + def check_destroy_privilege(user_feedback) + raise(User::PrivilegeError) unless user_feedback.destroyable_by?(CurrentUser.user) end def user_feedback_params(context) @@ -61,4 +92,8 @@ class UserFeedbacksController < ApplicationController params.fetch(:user_feedback, {}).permit(permitted_params) end + + def search_params + permit_search_params(%i[deleted body_matches user_id user_name creator_id creator_name category]) + end end diff --git a/app/decorators/mod_action_decorator.rb b/app/decorators/mod_action_decorator.rb index 43388d79a..40cb0a8b3 100644 --- a/app/decorators/mod_action_decorator.rb +++ b/app/decorators/mod_action_decorator.rb @@ -130,6 +130,10 @@ class ModActionDecorator < ApplicationDecorator end when "user_feedback_delete" "Deleted #{vals['type']} record ##{vals['record_id']} for #{user} with reason: #{vals['reason']}" + when "user_feedback_undelete" + "Undeleted #{vals['type']} record ##{vals['record_id']} for #{user} with reason: #{vals['reason']}" + when "user_feedback_destroy" + "Destroyed #{vals['type']} record ##{vals['record_id']} for #{user} with reason: #{vals['reason']}" ### Legacy User Record ### when "created_positive_record" "Created positive record ##{vals['record_id']} for #{user} with reason: #{vals['reason']}" diff --git a/app/javascript/src/styles/specific/user_feedback.scss b/app/javascript/src/styles/specific/user_feedback.scss index 5bfb372c4..af8046155 100644 --- a/app/javascript/src/styles/specific/user_feedback.scss +++ b/app/javascript/src/styles/specific/user_feedback.scss @@ -1,5 +1,3 @@ - - .user-feedback-positive { color: $positive-record-color; } @@ -25,7 +23,18 @@ div#c-user-feedbacks, div#c-moderator-dashboards .activity-container { background: $neutral-record-background; } + tr.user-feedback[data-is-deleted="true"] { + background: #827428; + } + blockquote { padding: 0.5em; } + + .show-all-user-feedbacks-link { + font-size: 1.5em; + width: 100%; + text-align: center; + padding: 0.5em 0; + } } diff --git a/app/models/mod_action.rb b/app/models/mod_action.rb index 2cdb03a08..6ac0a579d 100644 --- a/app/models/mod_action.rb +++ b/app/models/mod_action.rb @@ -72,6 +72,8 @@ class ModAction < ApplicationRecord :user_feedback_create, :user_feedback_update, :user_feedback_delete, + :user_feedback_undelete, + :user_feedback_destroy, :wiki_page_rename, :wiki_page_delete, :wiki_page_lock, diff --git a/app/models/user.rb b/app/models/user.rb index 6c72e9f4f..6cf13feb9 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -96,7 +96,7 @@ class User < ApplicationRecord has_many :bans, -> { order("bans.id desc") } has_many :dmails, -> { order("dmails.id desc") }, foreign_key: "owner_id" has_many :favorites, -> { order(id: :desc) } - has_many :feedback, class_name: "UserFeedback", dependent: :destroy + has_many :feedback, -> { active }, class_name: "UserFeedback", dependent: :destroy has_many :forum_posts, -> { order("forum_posts.created_at, forum_posts.id") }, foreign_key: "creator_id" has_many :forum_topic_visits has_many :note_versions, foreign_key: "updater_id" diff --git a/app/models/user_feedback.rb b/app/models/user_feedback.rb index 5b13b12cb..bede15147 100644 --- a/app/models/user_feedback.rb +++ b/app/models/user_feedback.rb @@ -10,22 +10,39 @@ class UserFeedback < ApplicationRecord validates :body, length: { minimum: 1, maximum: Danbooru.config.user_feedback_max_size } validate :creator_is_moderator, on: :create validate :user_is_not_creator + after_create :log_create + after_update :log_update + after_destroy :log_destroy after_save :create_dmail - after_create do |rec| - ModAction.log(:user_feedback_create, { user_id: rec.user_id, reason: rec.body, type: rec.category, record_id: rec.id }) - end - after_update do |rec| - ModAction.log(:user_feedback_update, { user_id: rec.user_id, reason: rec.body, reason_was: rec.body_before_last_save, type: rec.category, type_was: rec.category_before_last_save, record_id: rec.id }) - end - after_destroy do |rec| - ModAction.log(:user_feedback_delete, { user_id: rec.user_id, reason: rec.body, type: rec.category, record_id: rec.id }) - deletion_user = "\"#{CurrentUser.name}\":/users/#{CurrentUser.id}" - creator_user = "\"#{creator.name}\":/users/#{creator.id}" - StaffNote.create(body: "#{deletion_user} deleted #{rec.category} feedback, created #{created_at.to_date} by #{creator_user}: #{rec.body}", user_id: rec.user_id, creator: User.system) - end attr_accessor :send_update_dmail + scope :active, -> { where(is_deleted: false) } + scope :deleted, -> { where(is_deleted: true) } + + module LogMethods + def log_create + ModAction.log(:user_feedback_create, { user_id: user_id, reason: body, type: category, record_id: id }) + end + + def log_update + details = { user_id: user_id, reason: body, reason_was: body_before_last_save, type: category, type_was: category_before_last_save, record_id: id } + if saved_change_to_is_deleted? + action = is_deleted? ? :user_feedback_delete : :user_feedback_undelete + ModAction.log(action, details) + return unless saved_change_to_category? || saved_change_to_body? + end + ModAction.log(:user_feedback_update, details) + end + + def log_destroy + ModAction.log(:user_feedback_de, { user_id: user_id, reason: body, type: category, record_id: id }) + deletion_user = "\"#{CurrentUser.name}\":/users/#{CurrentUser.id}" + creator_user = "\"#{creator.name}\":/users/#{creator.id}" + StaffNote.create(body: "#{deletion_user} deleted #{category} feedback, created #{created_at.to_date} by #{creator_user}: #{body}", user_id: user_id, creator: User.system) + end + end + module SearchMethods def positive where("category = ?", "positive") @@ -47,11 +64,22 @@ class UserFeedback < ApplicationRecord order(created_at: :desc) end + def visible(user) + if user.is_moderator? + all + else + active + end + end + def search(params) q = super - q = q.attribute_matches(:body, params[:body_matches]) + deleted = (params[:deleted].presence || "excluded").downcase + q = q.active if deleted == "excluded" + q = q.deleted if deleted == "only" + q = q.attribute_matches(:body, params[:body_matches]) q = q.where_user(:user_id, :user, params) q = q.where_user(:creator_id, :creator, params) @@ -63,6 +91,7 @@ class UserFeedback < ApplicationRecord end end + include LogMethods extend SearchMethods def user_name @@ -93,4 +122,12 @@ class UserFeedback < ApplicationRecord def editable_by?(editor) editor.is_moderator? && editor != user end + + def deletable_by?(deleter) + editable_by?(deleter) + end + + def destroyable_by?(destroyer) + deletable_by?(destroyer) && (destroyer.is_admin? || destroyer == creator) + end end diff --git a/app/views/user_feedbacks/_search.html.erb b/app/views/user_feedbacks/_search.html.erb index 4774b8aaa..a8b1b00b7 100644 --- a/app/views/user_feedbacks/_search.html.erb +++ b/app/views/user_feedbacks/_search.html.erb @@ -2,5 +2,8 @@ <%= f.user :user %> <%= f.user :creator %> <%= f.input :body_matches, label: "Message" %> + <% if CurrentUser.is_moderator? %> + <%= f.input :deleted, label: "Deleted?", collection: [%w[Excluded excluded], %w[Included included], %w[Only only]], include_blank: true %> + <% end %> <%= f.input :category, collection: %w[positive negative neutral], include_blank: true %> <% end %> diff --git a/app/views/user_feedbacks/index.html.erb b/app/views/user_feedbacks/index.html.erb index 1e4f27fe3..dd33a6964 100644 --- a/app/views/user_feedbacks/index.html.erb +++ b/app/views/user_feedbacks/index.html.erb @@ -6,19 +6,24 @@
User | -Creator | -When | +User | +Creator | +When | Message | -+ | |
---|---|---|---|---|---|---|---|---|
<%= link_to_user feedback.user %> | <%= link_to_user feedback.creator %> | -<%= compact_time(feedback.created_at) %> | ++ <%= compact_time(feedback.created_at) %> + <% if feedback.is_deleted? %> + (deleted) + <% end %> + |
<%= format_text(feedback.body) %>
@@ -28,7 +33,16 @@
<% if feedback.editable_by?(CurrentUser.user) %>
<%= link_to "edit", edit_user_feedback_path(feedback) %>
- | <%= link_to "delete", user_feedback_path(feedback), :method => :delete, :data => {:confirm => "Are you sure you want to delete this user feedback?"} %>
+ <% end %>
+ <% if feedback.deletable_by?(CurrentUser.user) %>
+ <% if feedback.is_deleted? %>
+ | <%= link_to "undelete", undelete_user_feedback_path(feedback), method: :put, data: { confirm: "Are you sure you want to undelete this user feedback?" } %>
+ <% else %>
+ | <%= link_to "delete", delete_user_feedback_path(feedback), method: :put, data: { confirm: "Are you sure you want to delete this user feedback?" } %>
+ <% end %>
+ <% end %>
+ <% if feedback.destroyable_by?(CurrentUser.user) %>
+ | <%= link_to "destroy", user_feedback_path(feedback), method: :delete, data: { confirm: "Are you sure you want to destroy this user feedback? This cannot be undone." } %>
<% end %>
|
|