[Staff Notes] Add staff notes

This commit is contained in:
Kira 2021-04-30 09:14:47 -07:00
parent 2c9e2511f7
commit b3eb88405d
15 changed files with 365 additions and 3 deletions

View File

@ -0,0 +1,35 @@
module Admin
class StaffNotesController < ApplicationController
before_action :moderator_only
respond_to :html
def index
@user = User.where('id = ?', params[:user_id]).first
@notes = StaffNote.search(search_params).paginate(params[:page])
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 note_params
params.fetch(:staff_note, {}).permit([:body])
end
end
end

View File

@ -0,0 +1,7 @@
class StaffAuditLog < ApplicationRecord
belongs_to :user, :class_name => "User"
def self.log(category, user, details)
create(user: user, action: category.to_s, values: details)
end
end

62
app/models/staff_note.rb Normal file
View File

@ -0,0 +1,62 @@
class StaffNote < ApplicationRecord
belongs_to :creator, :class_name => "User"
belongs_to :user
after_create :add_audit_entry
module SearchMethods
def for_creator(user_id)
user_id.present? ? where("creator_id = ?", user_id) : none
end
def for_creator_name(user_name)
for_creator(User.name_to_id(user_name))
end
def for_user(user_id)
user_id.present? ? where('creator_id = ?', user_id) : none
end
def for_user_name(user_name)
for_user(User.name_to_id(user_name))
end
def search(params)
q = super
if params[:resolved]
q = q.attribute_matches(:resolved, params[:resolved])
end
if params[:user_name].present?
q = q.for_user_name(params[:user_name])
end
if params[:creator_name].present?
q = q.for_creator_name(params[:creator_name])
end
q.apply_default_order(params)
end
def default_order
order("resolved asc, id desc")
end
end
extend SearchMethods
def add_audit_entry
StaffAuditLog.log(:staff_note_add, creator, {user_id: user_id})
end
def resolve!
self.resolved = true
save
end
def unresolve!
self.resolved = false
save
end
end

View File

@ -183,4 +183,16 @@ class UserPresenter
return false if user.enable_privacy_mode? && !CurrentUser.is_admin?
true
end
def show_staff_notes?
CurrentUser.is_moderator?
end
def staff_notes
StaffNote.where(user_id: user.id).order(id: :desc).limit(15)
end
def new_staff_note
StaffNote.new(user_id: user.id)
end
end

View File

@ -0,0 +1,13 @@
<div id='searchform_hide'>
<%= search_show_link %>
</div>
<div class='section' id='searchform' style='width:400px;<% unless params[:show] %>display:none;
<% end %>'>
<%= simple_form_for(:search, :method => :get, url: admin_staff_notes_path, defaults: {required: false}, html: {class: "inline-form"}) do |f| %>
<%= f.input :creator_name, label: "Creator Name", input_html: {data: {autocomplete: "user"}} %>
<%= f.input :user_name, label: "User Name", input_html: {data: {autocomplete: "user"}} %>
<%= f.input :body_matches, label: "Body" %>
<%= f.submit "Search" %>
<% end %>
<%= search_hide_link %>
</div>

View File

@ -0,0 +1,15 @@
<div id="c-staff-notes">
<div id="a-index">
<h1><%= @user ? "Staff Notes for #{@user.name}" : "Staff Notes" %></h1>
<%= render "search" %>
<%= render "admin/staff_notes/partials/list_of_notes", staff_notes: @notes %>
<%= numbered_paginator(@notes) %>
</div>
</div>
<%= render "users/secondary_links" %>
<% content_for(:page_title) do %>
<%= @user ? "#{@user.name} - Staff Notes" : "Staff Notes" %>
<% end %>

View File

@ -0,0 +1,13 @@
<div id="c-staff-notes">
<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 %>
</div>
</div>
<%= render "users/secondary_links" %>
<% content_for(:page_title) do %>
New Staff Note
<% end %>

View File

@ -0,0 +1,3 @@
<div id="p-staff-notes-list" class="staff-note-list">
<%= render :partial => "admin/staff_notes/partials/staff_note", :collection => staff_notes %>
</div>

View File

@ -0,0 +1,7 @@
<%= error_messages_for :staff_note %>
<%= simple_form_for(staff_note, url: user_staff_notes_path(user_id: user.id), method: :post) do |f| %>
<%= dtext_field "staff_note", "body", name: "", :value => staff_note.body, :input_id => "staff_note_body_for_#{staff_note.id}", :preview_id => "dtext-preview-for-#{staff_note.id}" %>
<%= f.button :submit, "Submit" %>
<%= dtext_preview_button "staff_note", "body", :input_id => "staff_note_body_for_#{staff_note.id}", :preview_id => "dtext-preview-for-#{staff_note.id}" %>
<% end %>

View File

@ -0,0 +1,19 @@
<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="avatar">
<%= user_avatar(staff_note.creator) %>
</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">
<div class="body styled-dtext">
<%= format_text(staff_note.body, allow_color: true) %>
</div>
</div>
</article>

View File

@ -3,14 +3,31 @@
<div class="profile-container">
<%= render "statistics", :presenter => @presenter, :user => @user %>
<% if @presenter.show_staff_notes? %>
<div class="styled-dtext">
<div class="expandable">
<div class="expandable-header">
<span class="section-arrow"></span>
<span>Staff Notes (<%= @presenter.staff_notes.count %>)</span>
</div>
<div class="expandable-content">
<h4><%= link_to "Staff Notes", user_staff_notes_path(user_id: @user.id) %></h4>
<%= render "admin/staff_notes/partials/list_of_notes", staff_notes: @presenter.staff_notes %>
<h4>New Staff Note</h4>
<%= render "admin/staff_notes/partials/new", staff_note: @presenter.new_staff_note, user: @user %>
</div>
</div>
</div>
<% end %>
<div class="bottom-section">
<div class="posts-section">
<% if @presenter.can_view_favorites? %>
<div class="blacklist">
<%= render "posts/partials/common/inline_blacklist" %>
<%= render "posts/partials/common/inline_blacklist" %>
</div>
<div class="posts">
<%= render "post_summary", :presenter => @presenter, :user => @user %>
<%= render "post_summary", :presenter => @presenter, :user => @user %>
</div>
<% end %>
</div>

View File

@ -21,6 +21,7 @@ Rails.application.routes.draw do
resource :dashboard, :only => [:show]
resources :exceptions, only: [:index, :show]
resource :reowner, controller: 'reowner', only: [:new, :create]
resources :staff_notes, only: [:index]
end
resources :edit_histories
namespace :moderator do
@ -336,6 +337,7 @@ Rails.application.routes.draw do
resource :api_key, :only => [:show, :view, :update, :destroy], :controller => "maintenance/user/api_keys" do
post :view
end
resources :staff_notes, only: [:index, :new, :create], controller: "admin/staff_notes"
collection do
get :home

View File

@ -0,0 +1,11 @@
class AddStaffNotesTable < ActiveRecord::Migration[6.1]
def change
create_table :staff_notes do |t|
t.timestamps
t.references :user, null: false, foreign_key: true, index: true
t.integer :creator_id, null: false, index: true
t.string :body
t.boolean :resolved, null: false, default: false
end
end
end

View File

@ -0,0 +1,10 @@
class AddStaffAuditLogsTable < ActiveRecord::Migration[6.1]
def change
create_table :staff_audit_logs do |t|
t.timestamps
t.references :user, null: false, foreign_key: true, index: true
t.string :action, null: false, default: 'unknown_action'
t.json :values
end
end
end

View File

@ -2022,6 +2022,73 @@ CREATE TABLE public.schema_migrations (
);
--
-- Name: staff_audit_logs; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.staff_audit_logs (
id bigint NOT NULL,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL,
user_id bigint NOT NULL,
action character varying DEFAULT 'unknown_action'::character varying NOT NULL,
"values" json
);
--
-- Name: staff_audit_logs_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.staff_audit_logs_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: staff_audit_logs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.staff_audit_logs_id_seq OWNED BY public.staff_audit_logs.id;
--
-- Name: staff_notes; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.staff_notes (
id bigint NOT NULL,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL,
user_id bigint NOT NULL,
creator_id integer NOT NULL,
body character varying,
resolved boolean DEFAULT false NOT NULL
);
--
-- Name: staff_notes_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.staff_notes_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: staff_notes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.staff_notes_id_seq OWNED BY public.staff_notes.id;
--
-- Name: tag_aliases; Type: TABLE; Schema: public; Owner: -
--
@ -3025,6 +3092,20 @@ ALTER TABLE ONLY public.posts ALTER COLUMN change_seq SET DEFAULT nextval('publi
ALTER TABLE ONLY public.saved_searches ALTER COLUMN id SET DEFAULT nextval('public.saved_searches_id_seq'::regclass);
--
-- Name: staff_audit_logs id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.staff_audit_logs ALTER COLUMN id SET DEFAULT nextval('public.staff_audit_logs_id_seq'::regclass);
--
-- Name: staff_notes id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.staff_notes ALTER COLUMN id SET DEFAULT nextval('public.staff_notes_id_seq'::regclass);
--
-- Name: tag_aliases id; Type: DEFAULT; Schema: public; Owner: -
--
@ -3547,6 +3628,22 @@ ALTER TABLE ONLY public.schema_migrations
ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version);
--
-- Name: staff_audit_logs staff_audit_logs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.staff_audit_logs
ADD CONSTRAINT staff_audit_logs_pkey PRIMARY KEY (id);
--
-- Name: staff_notes staff_notes_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.staff_notes
ADD CONSTRAINT staff_notes_pkey PRIMARY KEY (id);
--
-- Name: tag_aliases tag_aliases_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@ -4522,6 +4619,27 @@ CREATE INDEX index_saved_searches_on_query ON public.saved_searches USING btree
CREATE INDEX index_saved_searches_on_user_id ON public.saved_searches USING btree (user_id);
--
-- Name: index_staff_audit_logs_on_user_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_staff_audit_logs_on_user_id ON public.staff_audit_logs USING btree (user_id);
--
-- Name: index_staff_notes_on_creator_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_staff_notes_on_creator_id ON public.staff_notes USING btree (creator_id);
--
-- Name: index_staff_notes_on_user_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_staff_notes_on_user_id ON public.staff_notes USING btree (user_id);
--
-- Name: index_tag_aliases_on_antecedent_name; Type: INDEX; Schema: public; Owner: -
--
@ -4865,6 +4983,14 @@ CREATE TRIGGER trigger_posts_on_tag_index_update BEFORE INSERT OR UPDATE ON publ
CREATE TRIGGER trigger_wiki_pages_on_update BEFORE INSERT OR UPDATE ON public.wiki_pages FOR EACH ROW EXECUTE PROCEDURE tsvector_update_trigger('body_index', 'public.danbooru', 'body', 'title');
--
-- Name: staff_audit_logs fk_rails_02329e5ef9; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.staff_audit_logs
ADD CONSTRAINT fk_rails_02329e5ef9 FOREIGN KEY (user_id) REFERENCES public.users(id);
--
-- Name: post_image_hashes fk_rails_2b7afcc2f0; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@ -4881,6 +5007,14 @@ ALTER TABLE ONLY public.favorites
ADD CONSTRAINT fk_rails_a7668ef613 FOREIGN KEY (user_id) REFERENCES public.users(id);
--
-- Name: staff_notes fk_rails_bab7e2d92a; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.staff_notes
ADD CONSTRAINT fk_rails_bab7e2d92a FOREIGN KEY (user_id) REFERENCES public.users(id);
--
-- Name: favorites fk_rails_d20e53bb68; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@ -5128,6 +5262,8 @@ INSERT INTO "schema_migrations" (version) VALUES
('20210117173030'),
('20210405040522'),
('20210425020131'),
('20210430201028');
('20210426025625'),
('20210430201028'),
('20210506235640');