forked from e621ng/e621ng
[StaffNotes] Add updating and deleting (#823)
This commit is contained in:
parent
afce6b614c
commit
29b98e5002
@ -156,3 +156,6 @@ Style/TrailingCommaInArrayLiteral:
|
||||
|
||||
Style/TrailingCommaInHashLiteral:
|
||||
EnforcedStyleForMultiline: consistent_comma
|
||||
|
||||
Rails/NotNullColumn:
|
||||
Enabled: false
|
||||
|
@ -498,7 +498,7 @@ Layout/SpaceInsideBlockBraces:
|
||||
# SupportedStylesForEmptyBraces: space, no_space
|
||||
Layout/SpaceInsideHashLiteralBraces:
|
||||
Exclude:
|
||||
- 'app/controllers/admin/staff_notes_controller.rb'
|
||||
- 'app/controllers/staff_notes_controller.rb'
|
||||
- 'app/controllers/admin/users_controller.rb'
|
||||
- 'app/controllers/application_controller.rb'
|
||||
- 'app/controllers/comment_votes_controller.rb'
|
||||
@ -2416,7 +2416,7 @@ Style/StringLiterals:
|
||||
Exclude:
|
||||
- 'Gemfile'
|
||||
- 'Rakefile'
|
||||
- 'app/controllers/admin/staff_notes_controller.rb'
|
||||
- 'app/controllers/staff_notes_controller.rb'
|
||||
- 'app/controllers/blips_controller.rb'
|
||||
- 'app/controllers/comments_controller.rb'
|
||||
- 'app/controllers/edit_histories_controller.rb'
|
||||
|
@ -1,41 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Admin
|
||||
class StaffNotesController < ApplicationController
|
||||
before_action :can_view_staff_notes_only
|
||||
respond_to :html
|
||||
|
||||
def index
|
||||
@user = User.find_by(id: params[:user_id])
|
||||
@notes = StaffNote.search(search_params.merge({ user_id: params[:user_id] })).includes(:user, :creator).paginate(params[:page], limit: params[:limit])
|
||||
respond_with(@notes)
|
||||
end
|
||||
|
||||
def new
|
||||
@user = User.find(params[:user_id])
|
||||
@staff_note = StaffNote.new(note_params)
|
||||
respond_with(@note)
|
||||
end
|
||||
|
||||
def create
|
||||
@user = User.find(params[:user_id])
|
||||
@staff_note = StaffNote.create(note_params.merge({creator: CurrentUser.user, user_id: @user.id}))
|
||||
flash[:notice] = @staff_note.valid? ? "Staff Note added" : @staff_note.errors.full_messages.join("; ")
|
||||
respond_with(@staff_note) do |format|
|
||||
format.html do
|
||||
redirect_back fallback_location: admin_staff_notes_path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def search_params
|
||||
permit_search_params(%i[creator_id creator_name user_id user_name resolved body_matches without_system_user])
|
||||
end
|
||||
|
||||
def note_params
|
||||
params.fetch(:staff_note, {}).permit(%i[body])
|
||||
end
|
||||
end
|
||||
end
|
@ -5,19 +5,20 @@ class ModActionsController < ApplicationController
|
||||
|
||||
def index
|
||||
@mod_actions = ModActionDecorator.decorate_collection(
|
||||
ModAction.includes(:creator).search(search_params).paginate(params[:page], limit: params[:limit]),
|
||||
ModAction.visible(CurrentUser.user).includes(:creator).search(search_params).paginate(params[:page], limit: params[:limit]),
|
||||
)
|
||||
respond_with(@mod_actions) do |format|
|
||||
format.json do
|
||||
render json: @mod_actions.to_json
|
||||
end
|
||||
end
|
||||
respond_with(@mod_actions)
|
||||
end
|
||||
|
||||
def show
|
||||
@mod_action = ModAction.find(params[:id])
|
||||
check_permission(@mod_action)
|
||||
respond_with(@mod_action) do |fmt|
|
||||
fmt.html { redirect_to mod_actions_path(search: { id: @mod_action.id }) }
|
||||
end
|
||||
end
|
||||
|
||||
def check_permission(mod_action)
|
||||
raise(User::PrivilegeError) unless mod_action.can_view?(CurrentUser.user)
|
||||
end
|
||||
end
|
||||
|
77
app/controllers/staff_notes_controller.rb
Normal file
77
app/controllers/staff_notes_controller.rb
Normal file
@ -0,0 +1,77 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class StaffNotesController < ApplicationController
|
||||
before_action :can_view_staff_notes_only
|
||||
before_action :load_staff_note, only: %i[show edit update delete undelete]
|
||||
before_action :check_edit_privilege, only: %i[update]
|
||||
before_action :check_delete_privilege, only: %i[delete undelete]
|
||||
respond_to :html, :json
|
||||
|
||||
def index
|
||||
@user = User.find_by(id: params[:user_id])
|
||||
@notes = StaffNote.search(search_params.merge({ user_id: params[:user_id] })).includes(:user, :creator).paginate(params[:page], limit: params[:limit])
|
||||
respond_with(@notes)
|
||||
end
|
||||
|
||||
def show
|
||||
respond_with(@staff_note)
|
||||
end
|
||||
|
||||
def new
|
||||
@user = User.find(params[:user_id])
|
||||
@staff_note = StaffNote.new(staff_note_params)
|
||||
respond_with(@note)
|
||||
end
|
||||
|
||||
def edit
|
||||
respond_with(@staff_note)
|
||||
end
|
||||
|
||||
def create
|
||||
@user = User.find(params[:user_id])
|
||||
@staff_note = StaffNote.create(staff_note_params.merge({ user_id: @user.id }))
|
||||
flash[:notice] = @staff_note.valid? ? "Staff Note added" : @staff_note.errors.full_messages.join("; ")
|
||||
respond_with(@staff_note) do |format|
|
||||
format.html do
|
||||
redirect_back fallback_location: staff_notes_path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
@staff_note.update(staff_note_params)
|
||||
redirect_back(fallback_location: staff_notes_path)
|
||||
end
|
||||
|
||||
def delete
|
||||
@staff_note.update(is_deleted: true)
|
||||
redirect_back(fallback_location: staff_notes_path)
|
||||
end
|
||||
|
||||
def undelete
|
||||
@staff_note.update(is_deleted: false)
|
||||
redirect_back(fallback_location: staff_notes_path)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def search_params
|
||||
permit_search_params(%i[creator_id creator_name updater_id updater_name user_id user_name body_matches without_system_user include_deleted])
|
||||
end
|
||||
|
||||
def staff_note_params
|
||||
params.fetch(:staff_note, {}).permit(%i[body])
|
||||
end
|
||||
|
||||
def load_staff_note
|
||||
@staff_note = StaffNote.find(params[:id])
|
||||
end
|
||||
|
||||
def check_edit_privilege
|
||||
raise User::PrivilegeError unless @staff_note.can_edit?(CurrentUser.user)
|
||||
end
|
||||
|
||||
def check_delete_privilege
|
||||
raise User::PrivilegeError unless @staff_note.can_delete?(CurrentUser.user)
|
||||
end
|
||||
end
|
@ -55,7 +55,7 @@ class ModActionDecorator < ApplicationDecorator
|
||||
when "artist_delete"
|
||||
"Deleted artist ##{vals['artist_id']} (#{vals['artist_name']})"
|
||||
when "artist_page_rename"
|
||||
"Renamed artist page (\"#{vals['old_name']}\":/artists/show_or_new?name=#{vals['old_name']} -> \"#{vals['new_name']}\":/artists/show_or_new?name=#{vals['new_name']})"
|
||||
"Renamed artist page (\"#{vals['old_name']}\":/artists/show_or_new?name=#{vals['old_name']} → \"#{vals['new_name']}\":/artists/show_or_new?name=#{vals['new_name']})"
|
||||
when "artist_page_lock"
|
||||
"Locked artist page artist ##{vals['artist_page']}"
|
||||
when "artist_page_unlock"
|
||||
@ -77,6 +77,16 @@ class ModActionDecorator < ApplicationDecorator
|
||||
when "avoid_posting_undelete"
|
||||
"Undeleted \"avoid posting ##{vals['id']}\":/avoid_postings/#{vals['id']} for [[#{vals['artist_name']}]]"
|
||||
|
||||
### Staff Note ###
|
||||
when "staff_note_create"
|
||||
"Created \"staff note ##{vals['id']}\":/staff_notes/#{vals['id']} for #{user}\n#{vals['body']}"
|
||||
when "staff_note_update"
|
||||
"Updated \"staff note ##{vals['id']}\":/staff_notes/#{vals['id']} for #{user}\n#{vals['body']}"
|
||||
when "staff_note_delete"
|
||||
"Deleted \"staff note ##{vals['id']}\":/staff_notes/#{vals['id']} for #{user}"
|
||||
when "staff_note_undelete"
|
||||
"Undeleted \"staff note ##{vals['id']}\":/staff_notes/#{vals['id']} for #{user}"
|
||||
|
||||
### User ###
|
||||
|
||||
when "user_delete"
|
||||
@ -276,7 +286,7 @@ class ModActionDecorator < ApplicationDecorator
|
||||
### BURs ###
|
||||
|
||||
when "mass_update"
|
||||
"Mass updated [[#{vals['antecedent']}]] -> [[#{vals['consequent']}]]"
|
||||
"Mass updated [[#{vals['antecedent']}]] → [[#{vals['consequent']}]]"
|
||||
when "nuke_tag"
|
||||
"Nuked tag [[#{vals['tag_name']}]]"
|
||||
|
||||
@ -319,7 +329,7 @@ class ModActionDecorator < ApplicationDecorator
|
||||
"Edited whitelist entry"
|
||||
else
|
||||
if vals['old_pattern'] && vals['old_pattern'] != vals['pattern'] && CurrentUser.is_admin?
|
||||
"Edited whitelist entry '#{vals['old_pattern']}' -> '#{vals['pattern']}'"
|
||||
"Edited whitelist entry '#{vals['old_pattern']}' → '#{vals['pattern']}'"
|
||||
else
|
||||
"Edited whitelist entry '#{CurrentUser.is_admin? ? vals['pattern'] : vals['note']}'"
|
||||
end
|
||||
|
@ -47,6 +47,7 @@ export { default as PostReplacement } from '../src/javascripts/post_replacement.
|
||||
export { default as PostVersions } from '../src/javascripts/post_versions.js';
|
||||
export { default as Replacer } from '../src/javascripts/replacer.js';
|
||||
export { default as Shortcuts } from '../src/javascripts/shortcuts.js';
|
||||
export { default as StaffNote } from '../src/javascripts/staff_notes.js';
|
||||
export { default as Utility } from '../src/javascripts/utility.js';
|
||||
export { default as TagRelationships } from '../src/javascripts/tag_relationships.js';
|
||||
export { default as Takedown } from '../src/javascripts/takedowns.js';
|
||||
|
25
app/javascript/src/javascripts/staff_notes.js
Normal file
25
app/javascript/src/javascripts/staff_notes.js
Normal file
@ -0,0 +1,25 @@
|
||||
const StaffNote = {};
|
||||
|
||||
StaffNote.initialize_all = function () {
|
||||
$(".expand-new-staff-note").on("click", StaffNote.show_new_note_form);
|
||||
$(".edit-staff-note-link").on("click", StaffNote.show_edit_form);
|
||||
};
|
||||
|
||||
StaffNote.show_new_note_form = function (e) {
|
||||
e.preventDefault();
|
||||
$(e.target).hide();
|
||||
var $form = $(e.target).closest("div.new-staff-note").find("form");
|
||||
$form.show();
|
||||
$form[0].scrollIntoView(false);
|
||||
};
|
||||
|
||||
StaffNote.show_edit_form = function (e) {
|
||||
e.preventDefault();
|
||||
$(this).closest(".staff-note").find(".edit_staff_note").show();
|
||||
};
|
||||
|
||||
$(document).ready(function () {
|
||||
StaffNote.initialize_all();
|
||||
});
|
||||
|
||||
export default StaffNote;
|
@ -1,11 +1,15 @@
|
||||
.staff-note-list {
|
||||
.staff-note {
|
||||
margin-bottom: $padding-050;
|
||||
}
|
||||
|
||||
// This is getting overwritten through DText styling on user profiles,
|
||||
// because the whole list is wrapped in a collapsable section.
|
||||
h4.author-name {
|
||||
font-size: $h4-size;
|
||||
}
|
||||
}
|
||||
|
||||
.staff-note {
|
||||
margin-bottom: $padding-050;
|
||||
|
||||
&[data-is-deleted="true"] {
|
||||
background: $background-article-hidden;
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,10 @@ class ModAction < ApplicationRecord
|
||||
avoid_posting_delete: %i[id artist_name],
|
||||
avoid_posting_undelete: %i[id artist_name],
|
||||
avoid_posting_destroy: %i[id artist_name],
|
||||
staff_note_create: %i[id user_id body],
|
||||
staff_note_update: %i[id user_id body old_body],
|
||||
staff_note_delete: %i[id user_id],
|
||||
staff_note_undelete: %i[id user_id],
|
||||
blip_delete: %i[blip_id user_id],
|
||||
blip_hide: %i[blip_id user_id],
|
||||
blip_unhide: %i[blip_id user_id],
|
||||
@ -91,9 +95,20 @@ class ModAction < ApplicationRecord
|
||||
takedown_process: %i[takedown_id],
|
||||
}.freeze
|
||||
|
||||
ProtectedActionKeys = %w[staff_note_create staff_note_update staff_note_delete staff_note_undelete ip_ban_create ip_ban_delete].freeze
|
||||
|
||||
KnownActionKeys = KnownActions.keys.freeze
|
||||
|
||||
def self.search(params)
|
||||
module SearchMethods
|
||||
def visible(user)
|
||||
if user.is_staff?
|
||||
all
|
||||
else
|
||||
where.not(action: ProtectedActionKeys)
|
||||
end
|
||||
end
|
||||
|
||||
def search(params)
|
||||
q = super
|
||||
|
||||
q = q.where_user(:creator_id, :creator, params)
|
||||
@ -104,6 +119,15 @@ class ModAction < ApplicationRecord
|
||||
|
||||
q.apply_basic_order(params)
|
||||
end
|
||||
end
|
||||
|
||||
def can_view?(user)
|
||||
if user.is_staff?
|
||||
true
|
||||
else
|
||||
ProtectedActionKeys.exclude?(action)
|
||||
end
|
||||
end
|
||||
|
||||
def values
|
||||
original_values = self[:values]
|
||||
@ -131,7 +155,7 @@ class ModAction < ApplicationRecord
|
||||
end
|
||||
|
||||
def hidden_attributes
|
||||
super + [:values]
|
||||
super + %i[values values_old]
|
||||
end
|
||||
|
||||
def method_attributes
|
||||
@ -145,4 +169,6 @@ class ModAction < ApplicationRecord
|
||||
def initialize_creator
|
||||
self.creator_id = CurrentUser.id
|
||||
end
|
||||
|
||||
extend SearchMethods
|
||||
end
|
||||
|
@ -1,8 +1,33 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class StaffNote < ApplicationRecord
|
||||
belongs_to :creator, class_name: "User"
|
||||
belongs_to_creator
|
||||
belongs_to_updater
|
||||
belongs_to :user
|
||||
after_create :log_create
|
||||
after_update :log_update
|
||||
|
||||
scope :active, -> { where(is_deleted: false) }
|
||||
|
||||
module LogMethods
|
||||
def log_create
|
||||
ModAction.log(:staff_note_create, { id: id, user_id: user_id, body: body })
|
||||
end
|
||||
|
||||
def log_update
|
||||
if saved_change_to_body?
|
||||
ModAction.log(:staff_note_update, { id: id, user_id: user_id, body: body, old_body: body_before_last_save })
|
||||
end
|
||||
|
||||
if saved_change_to_is_deleted?
|
||||
if is_deleted?
|
||||
ModAction.log(:staff_note_delete, { id: id, user_id: user_id })
|
||||
else
|
||||
ModAction.log(:staff_note_undelete, { id: id, user_id: user_id })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module SearchMethods
|
||||
def search(params)
|
||||
@ -12,28 +37,45 @@ class StaffNote < ApplicationRecord
|
||||
q = q.attribute_matches(:body, params[:body_matches])
|
||||
q = q.where_user(:user_id, :user, params)
|
||||
q = q.where_user(:creator_id, :creator, params)
|
||||
q = q.where_user(:updater_id, :updater, params)
|
||||
|
||||
if params[:without_system_user]&.truthy?
|
||||
q = q.where.not(creator: User.system)
|
||||
end
|
||||
|
||||
if params[:is_deleted].present?
|
||||
q = q.attribute_matches(:is_deleted, params[:is_deleted])
|
||||
elsif !params[:include_deleted]&.truthy?
|
||||
q = q.active
|
||||
end
|
||||
|
||||
q.apply_basic_order(params)
|
||||
end
|
||||
|
||||
def default_order
|
||||
order("resolved asc, id desc")
|
||||
order("id desc")
|
||||
end
|
||||
end
|
||||
|
||||
include LogMethods
|
||||
extend SearchMethods
|
||||
|
||||
def resolve!
|
||||
self.resolved = true
|
||||
save
|
||||
def user_name
|
||||
User.id_to_name(user_id)
|
||||
end
|
||||
|
||||
def unresolve!
|
||||
self.resolved = false
|
||||
save
|
||||
def user_name=(name)
|
||||
self.user_id = User.name_to_id(name)
|
||||
end
|
||||
|
||||
def can_edit?(user)
|
||||
return false unless user.is_staff?
|
||||
user.id == creator_id || user.is_admin?
|
||||
end
|
||||
|
||||
def can_delete?(user)
|
||||
return false unless user.is_staff?
|
||||
return true if creator_id == user.id || user.is_admin?
|
||||
user_id != user.id
|
||||
end
|
||||
end
|
||||
|
@ -111,7 +111,7 @@ class User < ApplicationRecord
|
||||
has_many :post_sets, -> { order(name: :asc) }, foreign_key: :creator_id
|
||||
has_many :post_versions
|
||||
has_many :post_votes
|
||||
has_many :staff_notes, -> { order("staff_notes.id desc") }
|
||||
has_many :staff_notes, -> { active.order("staff_notes.id desc") }
|
||||
has_many :user_name_change_requests, -> { order(id: :asc) }
|
||||
|
||||
belongs_to :avatar, class_name: 'Post', optional: true
|
||||
|
@ -1,13 +0,0 @@
|
||||
<% if CurrentUser.can_view_staff_notes? %>
|
||||
<div class="staff-notes-section styled-dtext">
|
||||
<details>
|
||||
<summary>Staff Notes (<%= user.staff_notes.count %>)</summary>
|
||||
<div>
|
||||
<h4><%= link_to "Staff Notes", user_staff_notes_path(user_id: user.id) %></h4>
|
||||
<%= render "admin/staff_notes/partials/list_of_notes", staff_notes: user.staff_notes.limit(15), show_receiver_name: false %>
|
||||
<h4>New Staff Note</h4>
|
||||
<%= render "admin/staff_notes/partials/new", user: user, staff_note: StaffNote.new(user_id: user.id) %>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
<% end %>
|
@ -1,3 +0,0 @@
|
||||
<div id="p-staff-notes-list" class="staff-note-list">
|
||||
<%= render partial: "admin/staff_notes/partials/staff_note", collection: staff_notes, locals: { show_receiver_name: show_receiver_name } %>
|
||||
</div>
|
@ -1,6 +0,0 @@
|
||||
<%= error_messages_for :staff_note %>
|
||||
|
||||
<%= custom_form_for(staff_note, url: user_staff_notes_path(user_id: user.id), method: :post) do |f| %>
|
||||
<%= f.input :body, as: :dtext, label: false, allow_color: true %>
|
||||
<%= f.button :submit, "Submit" %>
|
||||
<% end %>
|
@ -1,19 +0,0 @@
|
||||
<article class="staff-note comment-post-grid" id="staff-note-<%= staff_note.id %>">
|
||||
<div class="author-info">
|
||||
<div class="name-rank">
|
||||
<h4 class="author-name"><%= link_to_user staff_note.creator %></h4>
|
||||
<%= staff_note.creator.level_string %>
|
||||
</div>
|
||||
<div class="post-time">
|
||||
<%= link_to time_ago_in_words_tagged(staff_note.created_at), user_staff_notes_path(user_id: staff_note.user_id, anchor: "staff-note-#{staff_note.id}") %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<% if show_receiver_name %>
|
||||
<h4>On <%= link_to_user staff_note.user %></h4>
|
||||
<% end %>
|
||||
<div class="body dtext-container">
|
||||
<%= format_text(staff_note.body, allow_color: true) %>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
@ -1,4 +1,4 @@
|
||||
<%= form_search(path: mod_actions_path) do |f| %>
|
||||
<%= f.user :creator %>
|
||||
<%= f.input :action, label: "Action", collection: ModAction::KnownActionKeys.map {|k| [k.to_s.capitalize.tr("_"," "), k.to_s]}, include_blank: true %>
|
||||
<%= f.input :action, label: "Action", collection: ModAction::KnownActionKeys.reject { |k| !CurrentUser.is_staff? && ModAction::ProtectedActionKeys.include?(k) }.map { |k| [k.to_s.capitalize.tr("_", " "), k.to_s] }, include_blank: true %>
|
||||
<% end %>
|
||||
|
@ -1,6 +1,8 @@
|
||||
<%= form_search path: admin_staff_notes_path, always_display: true do |f| %>
|
||||
<%= form_search path: staff_notes_path do |f| %>
|
||||
<%= f.user :creator %>
|
||||
<%= f.user :updater %>
|
||||
<%= f.user :user %>
|
||||
<%= f.input :body_matches, label: "Body" %>
|
||||
<%= f.input :without_system_user, as: :boolean, label: "Hide automated?" %>
|
||||
<%= f.input :include_deleted, as: :boolean, label: "Show deleted?" %>
|
||||
<% end %>
|
4
app/views/staff_notes/_secondary_links.html.erb
Normal file
4
app/views/staff_notes/_secondary_links.html.erb
Normal file
@ -0,0 +1,4 @@
|
||||
<% content_for(:secondary_links) do %>
|
||||
<%= subnav_link_to "Listing", staff_notes_path %>
|
||||
<%= subnav_link_to "Search", search_staff_notes_path %>
|
||||
<% end %>
|
13
app/views/staff_notes/edit.html.erb
Normal file
13
app/views/staff_notes/edit.html.erb
Normal file
@ -0,0 +1,13 @@
|
||||
<div id="c-staff-notes">
|
||||
<div id="a-edit">
|
||||
<h1>Edit Staff Note For <%= link_to_user @staff_note.user %></h1>
|
||||
|
||||
<%= render "staff_notes/partials/edit", staff_note: @staff_note %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render "secondary_links" %>
|
||||
|
||||
<% content_for(:page_title) do %>
|
||||
Edit Staff Note
|
||||
<% end %>
|
@ -7,12 +7,12 @@
|
||||
<% end %>
|
||||
<%= render "search" %>
|
||||
|
||||
<%= render "admin/staff_notes/partials/list_of_notes", staff_notes: @notes, show_receiver_name: @user.blank? %>
|
||||
<%= render "staff_notes/partials/list_of_notes", staff_notes: @notes, show_receiver_name: @user.blank? %>
|
||||
<%= numbered_paginator(@notes) %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render "users/secondary_links" %>
|
||||
<%= render "secondary_links" %>
|
||||
|
||||
<% content_for(:page_title) do %>
|
||||
<%= @user ? "#{@user.name} - Staff Notes" : "Staff Notes" %>
|
@ -2,11 +2,11 @@
|
||||
<div id="a-new">
|
||||
<h1>New Staff Note for <%= link_to_user(@user) %></h1>
|
||||
|
||||
<%= render "admin/staff_notes/partials/new", staff_note: @staff_note, user: @user %>
|
||||
<%= render "staff_notes/partials/new", staff_note: @staff_note, user: @user %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render "users/secondary_links" %>
|
||||
<%= render "secondary_links" %>
|
||||
|
||||
<% content_for(:page_title) do %>
|
||||
New Staff Note
|
6
app/views/staff_notes/partials/_edit.html.erb
Normal file
6
app/views/staff_notes/partials/_edit.html.erb
Normal file
@ -0,0 +1,6 @@
|
||||
<%= error_messages_for :staff_note %>
|
||||
|
||||
<%= custom_form_for(staff_note, html: { style: ("display: none;" if local_assigns[:hidden]) }, url: staff_note_path(staff_note, user_id: staff_note.user_id), method: :patch) do |f| %>
|
||||
<%= f.input :body, as: :dtext, label: false %>
|
||||
<%= f.button :submit, "Submit" %>
|
||||
<% end %>
|
15
app/views/staff_notes/partials/_for_user.html.erb
Normal file
15
app/views/staff_notes/partials/_for_user.html.erb
Normal file
@ -0,0 +1,15 @@
|
||||
<% if CurrentUser.can_view_staff_notes? %>
|
||||
<div class="staff-notes-section styled-dtext">
|
||||
<details>
|
||||
<summary>Staff Notes (<%= user.staff_notes.count %>)</summary>
|
||||
<div>
|
||||
<h4><%= link_to "Staff Notes", staff_notes_path(search: { user_id: user.id }) %></h4>
|
||||
<%= render "staff_notes/partials/list_of_notes", staff_notes: user.staff_notes.limit(15), show_receiver_name: false %>
|
||||
<div class="new-staff-note">
|
||||
<p><%= link_to "Create »", new_staff_note_path(search: { user_id: user.id }), class: "expand-new-staff-note" %></p>
|
||||
<%= render "staff_notes/partials/new", user: user, staff_note: StaffNote.new(user_id: user.id), hidden: true %>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
<% end %>
|
3
app/views/staff_notes/partials/_list_of_notes.html.erb
Normal file
3
app/views/staff_notes/partials/_list_of_notes.html.erb
Normal file
@ -0,0 +1,3 @@
|
||||
<div id="p-staff-notes-list" class="staff-note-list">
|
||||
<%= render partial: "staff_notes/partials/staff_note", collection: staff_notes, locals: { show_receiver_name: show_receiver_name } %>
|
||||
</div>
|
6
app/views/staff_notes/partials/_new.html.erb
Normal file
6
app/views/staff_notes/partials/_new.html.erb
Normal file
@ -0,0 +1,6 @@
|
||||
<%= error_messages_for :staff_note %>
|
||||
|
||||
<%= custom_form_for(staff_note, html: { style: ("display: none;" if local_assigns[:hidden]) }, url: staff_notes_path(user_id: user.id), method: :post) do |f| %>
|
||||
<%= f.input :body, as: :dtext, label: false, allow_color: true %>
|
||||
<%= f.button :submit, "Submit" %>
|
||||
<% end %>
|
39
app/views/staff_notes/partials/_staff_note.html.erb
Normal file
39
app/views/staff_notes/partials/_staff_note.html.erb
Normal file
@ -0,0 +1,39 @@
|
||||
<article class="staff-note comment-post-grid" data-is-deleted="<%= staff_note.is_deleted %>" id="staff-note-<%= staff_note.id %>">
|
||||
<div class="author-info">
|
||||
<div class="name-rank">
|
||||
<h4 class="author-name"><%= link_to_user staff_note.creator %></h4>
|
||||
<%= staff_note.creator.level_string %>
|
||||
</div>
|
||||
<div class="post-time">
|
||||
<%= link_to time_ago_in_words_tagged(staff_note.created_at), staff_notes_path(search: { user_id: staff_note.user_id }, anchor: "staff-note-#{staff_note.id}") %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<% if show_receiver_name %>
|
||||
<h4>On <%= link_to_user staff_note.user %></h4>
|
||||
<% end %>
|
||||
<div class="body dtext-container">
|
||||
<%= format_text(staff_note.body, allow_color: true) %>
|
||||
</div>
|
||||
|
||||
<%= render "application/update_notice", record: staff_note %>
|
||||
<div class="content-menu">
|
||||
<menu>
|
||||
<% if staff_note.can_edit?(CurrentUser.user) %>
|
||||
<li><%= link_to "Edit", edit_staff_note_path(staff_note), id: "edit-staff-note-link-#{staff_note.id}", class: "edit-staff-note-link" %></li>
|
||||
<% end %>
|
||||
<% if staff_note.can_delete?(CurrentUser.user) %>
|
||||
<% if staff_note.is_deleted? %>
|
||||
<li><%= link_to "Undelete", undelete_staff_note_path(staff_note), method: :put %></li>
|
||||
<% else %>
|
||||
<li><%= link_to "Delete", delete_staff_note_path(staff_note), method: :put %></li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</menu>
|
||||
</div>
|
||||
|
||||
<% if staff_note.can_edit?(CurrentUser.user) %>
|
||||
<%= render "staff_notes/partials/edit", staff_note: staff_note, hidden: true %>
|
||||
<% end %>
|
||||
</div>
|
||||
</article>
|
13
app/views/staff_notes/search.html.erb
Normal file
13
app/views/staff_notes/search.html.erb
Normal file
@ -0,0 +1,13 @@
|
||||
<div id="c-staff-notes">
|
||||
<div id="a-search">
|
||||
<h1>Search Staff Notes</h1>
|
||||
|
||||
<%= render "search" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render "secondary_links" %>
|
||||
|
||||
<% content_for(:page_title) do %>
|
||||
Search Staff Notes
|
||||
<% end %>
|
13
app/views/staff_notes/show.html.erb
Normal file
13
app/views/staff_notes/show.html.erb
Normal file
@ -0,0 +1,13 @@
|
||||
<div id="c-staff-notes">
|
||||
<div id="a-show">
|
||||
<h1>Staff Note For <%= link_to_user @staff_note.user %></h1>
|
||||
|
||||
<%= render "staff_notes/partials/staff_note", staff_note: @staff_note, show_receiver_name: true %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render "secondary_links" %>
|
||||
|
||||
<% content_for(:page_title) do %>
|
||||
Staff Note - <%= @staff_note.user_name %>
|
||||
<% end %>
|
@ -119,6 +119,9 @@
|
||||
<li><%= link_to("Stuck DNP tags", new_admin_stuck_dnp_path) %></li>
|
||||
<li><%= link_to("Destroyed Posts", admin_destroyed_posts_path) %></li>
|
||||
<% end %>
|
||||
<% if CurrentUser.is_staff? %>
|
||||
<li><%= link_to("Staff Notes", staff_notes_path) %></li>
|
||||
<% end %>
|
||||
<li><%= link_to("Upload Whitelist", upload_whitelists_path) %></li>
|
||||
<li><%= link_to("Mod Actions", mod_actions_path) %></li>
|
||||
<li><%= link_to("Bulk Update Requests", bulk_update_requests_path) %></li>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<div id="c-users">
|
||||
<div id="a-show">
|
||||
<%= render "statistics", :presenter => @presenter, :user => @user %>
|
||||
<%= render "admin/staff_notes/partials/for_user", user: @user %>
|
||||
<%= render "staff_notes/partials/for_user", user: @user %>
|
||||
<%= render "posts/partials/common/inline_blacklist" %>
|
||||
<%= render "post_summary", presenter: @presenter, user: @user %>
|
||||
<%= render "about", presenter: @presenter, user: @user %>
|
||||
|
@ -25,7 +25,6 @@ Rails.application.routes.draw do
|
||||
resource :reowner, controller: 'reowner', only: [:new, :create]
|
||||
resource :stuck_dnp, controller: "stuck_dnp", only: %i[new create]
|
||||
resources :destroyed_posts, only: %i[index show update]
|
||||
resources :staff_notes, only: [:index]
|
||||
end
|
||||
|
||||
namespace :security do
|
||||
@ -95,6 +94,16 @@ Rails.application.routes.draw do
|
||||
|
||||
resources :avoid_posting_versions, only: %i[index]
|
||||
|
||||
resources :staff_notes, except: %i[destroy] do
|
||||
collection do
|
||||
get :search
|
||||
end
|
||||
member do
|
||||
put :delete
|
||||
put :undelete
|
||||
end
|
||||
end
|
||||
|
||||
resources :tickets, except: %i[destroy] do
|
||||
member do
|
||||
post :claim
|
||||
@ -294,7 +303,6 @@ Rails.application.routes.draw do
|
||||
resources :users do
|
||||
resource :password, :only => [:edit], :controller => "maintenance/user/passwords"
|
||||
resource :api_key, only: %i[show update destroy], controller: "maintenance/user/api_keys"
|
||||
resources :staff_notes, only: [:index, :new, :create], controller: "admin/staff_notes"
|
||||
|
||||
collection do
|
||||
get :home
|
||||
|
9
db/migrate/20240205174652_soft_deletable_staff_notes.rb
Normal file
9
db/migrate/20240205174652_soft_deletable_staff_notes.rb
Normal file
@ -0,0 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class SoftDeletableStaffNotes < ActiveRecord::Migration[7.1]
|
||||
def change
|
||||
add_column :staff_notes, :is_deleted, :boolean, null: false, default: false
|
||||
add_reference :staff_notes, :updater, foreign_key: { to_table: :users }, null: false
|
||||
remove_column :staff_notes, :resolved, :boolean, null: false, default: false
|
||||
end
|
||||
end
|
@ -1783,7 +1783,8 @@ CREATE TABLE public.staff_notes (
|
||||
user_id bigint NOT NULL,
|
||||
creator_id integer NOT NULL,
|
||||
body character varying,
|
||||
resolved boolean DEFAULT false NOT NULL
|
||||
is_deleted boolean DEFAULT false NOT NULL,
|
||||
updater_id bigint NOT NULL
|
||||
);
|
||||
|
||||
|
||||
@ -4230,6 +4231,13 @@ CREATE INDEX index_staff_audit_logs_on_user_id ON public.staff_audit_logs USING
|
||||
CREATE INDEX index_staff_notes_on_creator_id ON public.staff_notes USING btree (creator_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_staff_notes_on_updater_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_staff_notes_on_updater_id ON public.staff_notes USING btree (updater_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_staff_notes_on_user_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
@ -4671,6 +4679,14 @@ ALTER TABLE ONLY public.avoid_postings
|
||||
ADD CONSTRAINT fk_rails_d45cc0f1a1 FOREIGN KEY (creator_id) REFERENCES public.users(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: staff_notes fk_rails_eaa7223eea; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.staff_notes
|
||||
ADD CONSTRAINT fk_rails_eaa7223eea FOREIGN KEY (updater_id) REFERENCES public.users(id);
|
||||
|
||||
|
||||
--
|
||||
-- PostgreSQL database dump complete
|
||||
--
|
||||
@ -4683,6 +4699,7 @@ INSERT INTO "schema_migrations" (version) VALUES
|
||||
('20240726170041'),
|
||||
('20240709134926'),
|
||||
('20240706061122'),
|
||||
('20240205174652'),
|
||||
('20240103002049'),
|
||||
('20240103002040'),
|
||||
('20240101042716'),
|
||||
|
@ -93,7 +93,7 @@ class UserFeedbacksControllerTest < ActionDispatch::IntegrationTest
|
||||
end
|
||||
|
||||
should "delete a feedback" do
|
||||
assert_difference({ "UserFeedback.count" => -1, "ModAction.count" => 1 }) do
|
||||
assert_difference({ "UserFeedback.count" => -1, "ModAction.count" => 2 }) do
|
||||
delete_auth user_feedback_path(@user_feedback), @critic
|
||||
end
|
||||
end
|
||||
@ -101,7 +101,7 @@ class UserFeedbacksControllerTest < ActionDispatch::IntegrationTest
|
||||
context "by a moderator" do
|
||||
should "allow destroying feedbacks they created" do
|
||||
as(@mod) { @user_feedback = create(:user_feedback, user: @user) }
|
||||
assert_difference({ "UserFeedback.count" => -1, "ModAction.count" => 1 }) do
|
||||
assert_difference({ "UserFeedback.count" => -1, "ModAction.count" => 2 }) do
|
||||
delete_auth user_feedback_path(@user_feedback), @mod
|
||||
end
|
||||
end
|
||||
@ -126,13 +126,13 @@ class UserFeedbacksControllerTest < ActionDispatch::IntegrationTest
|
||||
context "by an admin" do
|
||||
should "allow destroying feedbacks they created" do
|
||||
as(@admin) { @user_feedback = create(:user_feedback, user: @user) }
|
||||
assert_difference({ "UserFeedback.count" => -1, "ModAction.count" => 1 }) do
|
||||
assert_difference({ "UserFeedback.count" => -1, "ModAction.count" => 2 }) do
|
||||
delete_auth user_feedback_path(@user_feedback), @admin
|
||||
end
|
||||
end
|
||||
|
||||
should "allow destroying feedbacks they did not create" do
|
||||
assert_difference({ "UserFeedback.count" => -1, "ModAction.count" => 1 }) do
|
||||
assert_difference({ "UserFeedback.count" => -1, "ModAction.count" => 2 }) do
|
||||
delete_auth user_feedback_path(@user_feedback, format: :json), @admin
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user