forked from e621ng/e621ng
[AvoidPosting] Integrate the avoid posting list into the site (#582)
This commit is contained in:
parent
516e3391be
commit
8a3e70e5ca
@ -185,7 +185,7 @@ class ApplicationController < ActionController::Base
|
||||
end
|
||||
end
|
||||
|
||||
%i[is_bd_staff can_view_staff_notes can_handle_takedowns].each do |role|
|
||||
%i[is_bd_staff can_view_staff_notes can_handle_takedowns can_edit_avoid_posting_entries].each do |role|
|
||||
define_method("#{role}_only") do
|
||||
user_access_check("#{role}?")
|
||||
end
|
||||
|
@ -64,7 +64,7 @@ class ArtistsController < ApplicationController
|
||||
@artist.destroy
|
||||
respond_with(@artist) do |format|
|
||||
format.html do
|
||||
redirect_to(artists_path, notice: "Artist deleted")
|
||||
redirect_to(artists_path, notice: @artist.valid? ? "Artist deleted" : @artist.errors.full_messages.join("; "))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
16
app/controllers/avoid_posting_versions_controller.rb
Normal file
16
app/controllers/avoid_posting_versions_controller.rb
Normal file
@ -0,0 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class AvoidPostingVersionsController < ApplicationController
|
||||
respond_to :html, :json
|
||||
|
||||
def index
|
||||
@avoid_posting_versions = AvoidPostingVersion.search(search_params).paginate(params[:page], limit: params[:limit])
|
||||
respond_with(@avoid_posting_versions)
|
||||
end
|
||||
|
||||
def search_params
|
||||
permitted_params = %i[updater_name updater_id any_name_matches artist_name artist_id any_other_name_matches group_name is_active]
|
||||
permitted_params += %i[updater_ip_addr] if CurrentUser.is_admin?
|
||||
permit_search_params permitted_params
|
||||
end
|
||||
end
|
109
app/controllers/avoid_postings_controller.rb
Normal file
109
app/controllers/avoid_postings_controller.rb
Normal file
@ -0,0 +1,109 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class AvoidPostingsController < ApplicationController
|
||||
respond_to :html, :json
|
||||
before_action :can_edit_avoid_posting_entries_only, except: %i[index show]
|
||||
before_action :load_avoid_posting, only: %i[edit update destroy show delete undelete]
|
||||
helper_method :search_params
|
||||
|
||||
def index
|
||||
@avoid_postings = AvoidPosting.search(search_params).paginate(params[:page], limit: params[:limit])
|
||||
respond_with(@avoid_postings)
|
||||
end
|
||||
|
||||
def show
|
||||
respond_with(@avoid_posting)
|
||||
end
|
||||
|
||||
def new
|
||||
@avoid_posting = AvoidPosting.new(avoid_posting_params)
|
||||
@avoid_posting.artist = Artist.new(avoid_posting_params[:artist_attributes])
|
||||
respond_with(@artist)
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def create
|
||||
@avoid_posting = AvoidPosting.new(avoid_posting_params)
|
||||
artparams = avoid_posting_params.try(:[], :artist_attributes)
|
||||
if artparams.present? && (artist = Artist.find_by(name: Artist.normalize_name(artparams[:name])))
|
||||
@avoid_posting.artist = artist
|
||||
notices = []
|
||||
if artist.other_names.present? && (artparams.key?(:other_names_string) || artparams.key?(:other_names))
|
||||
on = artparams[:other_names_string].try(:split) || artparams[:other_names]
|
||||
artparams.delete(:other_names_string)
|
||||
artparams.delete(:other_names)
|
||||
if on.present?
|
||||
artparams[:other_names] = (artist.other_names + on).uniq
|
||||
notices << "Artist already had other names, the provided names were merged into the existing names."
|
||||
end
|
||||
end
|
||||
if artist.group_name.present? && artparams.key?(:group_name)
|
||||
if artparams[:group_name].blank?
|
||||
artparams.delete(:group_name)
|
||||
else
|
||||
notices << "Artist's original group name was replaced."
|
||||
end
|
||||
end
|
||||
if artist.linked_user_id.present? && artparams.key?(:linked_user_id)
|
||||
if artparams[:linked_user_id].present?
|
||||
notices << "Artist is already linked to \"#{artist.linked_user.name}\":/users/#{artist.linked_user_id}, no change was made."
|
||||
end
|
||||
artparams.delete(:linked_user_id)
|
||||
end
|
||||
notices = notices.join("\n")
|
||||
# Remove period from last notice
|
||||
flash[:notice] = notices[0..-2] if notices.present?
|
||||
artist.update(artparams)
|
||||
end
|
||||
@avoid_posting.save
|
||||
respond_with(@avoid_posting)
|
||||
end
|
||||
|
||||
def update
|
||||
@avoid_posting.update(avoid_posting_params)
|
||||
flash[:notice] = @avoid_posting.valid? ? "Avoid posting entry updated" : @avoid_posting.errors.full_messages.join("; ")
|
||||
respond_with(@avoid_posting)
|
||||
end
|
||||
|
||||
def destroy
|
||||
@avoid_posting.destroy
|
||||
redirect_to artist_path(@avoid_posting.artist), notice: "Avoid posting entry destroyed"
|
||||
end
|
||||
|
||||
def delete
|
||||
@avoid_posting.update(is_active: false)
|
||||
redirect_to avoid_posting_path(@avoid_posting), notice: "Avoid posting entry deleted"
|
||||
end
|
||||
|
||||
def undelete
|
||||
@avoid_posting.update(is_active: true)
|
||||
redirect_to avoid_posting_path(@avoid_posting), notice: "Avoid posting entry undeleted"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_avoid_posting
|
||||
id = params[:id]
|
||||
if id =~ /\A\d+\z/
|
||||
@avoid_posting = AvoidPosting.find(id)
|
||||
else
|
||||
@avoid_posting = AvoidPosting.find_by!(artist_name: id)
|
||||
end
|
||||
end
|
||||
|
||||
def search_params
|
||||
permitted_params = %i[creator_name creator_id any_name_matches artist_id artist_name any_other_name_matches group_name details is_active]
|
||||
permitted_params += %i[staff_notes] if CurrentUser.is_staff?
|
||||
permitted_params += %i[creator_ip_addr] if CurrentUser.is_admin?
|
||||
permit_search_params permitted_params
|
||||
end
|
||||
|
||||
def avoid_posting_params
|
||||
permitted_params = %i[details staff_notes is_active]
|
||||
permitted_params += [artist_attributes: [:id, :name, :other_names_string, :group_name, :linked_user_id, { other_names: [] }]]
|
||||
|
||||
params.fetch(:avoid_posting, {}).permit(permitted_params)
|
||||
end
|
||||
end
|
@ -2,19 +2,23 @@
|
||||
|
||||
class StaticController < ApplicationController
|
||||
def privacy
|
||||
@page = WikiPage.find_by(title: "e621:privacy_policy")
|
||||
@page = format_wiki_page("e621:privacy_policy")
|
||||
end
|
||||
|
||||
def terms_of_service
|
||||
@page = WikiPage.find_by(title: "e621:terms_of_service")
|
||||
@page = format_wiki_page("e621:terms_of_service")
|
||||
end
|
||||
|
||||
def contact
|
||||
@page = WikiPage.find_by(title: "e621:contact")
|
||||
@page = format_wiki_page("e621:contact")
|
||||
end
|
||||
|
||||
def takedown
|
||||
@page = WikiPage.find_by(title: "e621:takedown")
|
||||
@page = format_wiki_page("e621:takedown")
|
||||
end
|
||||
|
||||
def avoid_posting
|
||||
@page = format_wiki_page("e621:avoid_posting_notice")
|
||||
end
|
||||
|
||||
def not_found
|
||||
@ -64,4 +68,12 @@ class StaticController < ApplicationController
|
||||
redirect_to(Danbooru.config.discord_site + user_hash, allow_other_host: true)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def format_wiki_page(name)
|
||||
wiki = WikiPage.find_by(title: name)
|
||||
return WikiPage.new(body: "Wiki page \"#{name}\" not found.") if wiki.blank?
|
||||
wiki
|
||||
end
|
||||
end
|
||||
|
@ -65,6 +65,18 @@ class ModActionDecorator < ApplicationDecorator
|
||||
when "artist_user_unlinked"
|
||||
"Unlinked #{user} from artist ##{vals['artist_page']}"
|
||||
|
||||
### Avoid Posting ###
|
||||
when "avoid_posting_create"
|
||||
"Created avoid posting entry for artist \"#{vals['artist_name']}\":/artists/show_or_new?name=#{vals['artist_name']}"
|
||||
when "avoid_posting_update"
|
||||
"Updated avoid posting entry for artist \"#{vals['artist_name']}\":/artists/show_or_new?name=#{vals['artist_name']}"
|
||||
when "avoid_posting_destroy"
|
||||
"Destroyed avoid posting entry for artist \"#{vals['artist_name']}\":/artists/show_or_new?name=#{vals['artist_name']}"
|
||||
when "avoid_posting_delete"
|
||||
"Deleted avoid posting entry for artist \"#{vals['artist_name']}\":/artists/show_or_new?name=#{vals['artist_name']}"
|
||||
when "avoid_posting_undelete"
|
||||
"Undeleted avoid posting entry for artist \"#{vals['artist_name']}\":/artists/show_or_new?name=#{vals['artist_name']}"
|
||||
|
||||
### User ###
|
||||
|
||||
when "user_delete"
|
||||
|
@ -1,21 +1,22 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module ArtistsHelper
|
||||
def link_to_artist(name)
|
||||
def link_to_artist(name, hide_new_notice: false)
|
||||
artist = Artist.find_by(name: name)
|
||||
|
||||
if artist
|
||||
link_to(artist.name, artist_path(artist))
|
||||
else
|
||||
link = link_to(name, new_artist_path(artist: { name: name }))
|
||||
return link.html_safe if hide_new_notice
|
||||
notice = tag.span("*", class: "new-artist", title: "No artist with this name currently exists.")
|
||||
"#{link} #{notice}".html_safe
|
||||
end
|
||||
end
|
||||
|
||||
def link_to_artists(names)
|
||||
def link_to_artists(names, hide_new_notice: false)
|
||||
names.map do |name|
|
||||
link_to_artist(name.downcase)
|
||||
link_to_artist(name.downcase, hide_new_notice: hide_new_notice)
|
||||
end.join(", ").html_safe
|
||||
end
|
||||
end
|
||||
|
33
app/helpers/avoid_posting_helper.rb
Normal file
33
app/helpers/avoid_posting_helper.rb
Normal file
@ -0,0 +1,33 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module AvoidPostingHelper
|
||||
def format_avoid_posting_list
|
||||
avoid_postings = AvoidPosting.active.joins(:artist).order("artists.name ASC").group_by(&:header)
|
||||
text = ""
|
||||
avoid_postings.each do |header, entries|
|
||||
text += "h2. #{header} [##{anchor(header)}]\n"
|
||||
entries.each do |dnp|
|
||||
text += "* #{dnp.all_names}"
|
||||
if dnp.pretty_details.present?
|
||||
text += " - #{dnp.pretty_details}"
|
||||
end
|
||||
text += "\n"
|
||||
end
|
||||
text += "\n"
|
||||
end
|
||||
format_text(text)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def anchor(header)
|
||||
case header
|
||||
when "#"
|
||||
"number"
|
||||
when "?"
|
||||
"other"
|
||||
else
|
||||
header.downcase
|
||||
end
|
||||
end
|
||||
end
|
@ -38,6 +38,7 @@
|
||||
@import "specific/admin_dashboards.scss";
|
||||
@import "specific/api_keys.scss";
|
||||
@import "specific/artists.scss";
|
||||
@import "specific/avoid_posting.scss";
|
||||
@import "specific/bans.scss";
|
||||
@import "specific/blips.scss";
|
||||
@import "specific/comments.scss";
|
||||
|
87
app/javascript/src/styles/specific/avoid_posting.scss
Normal file
87
app/javascript/src/styles/specific/avoid_posting.scss
Normal file
@ -0,0 +1,87 @@
|
||||
#c-static #a-avoid-posting {
|
||||
margin-left: 0.25em;
|
||||
|
||||
#avoid-posting-list {
|
||||
h2 {
|
||||
margin-top: 1.25em;
|
||||
font-size: 1.8em;
|
||||
line-height: 1em;
|
||||
margin-bottom: .25em;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-left: 1em;
|
||||
|
||||
li {
|
||||
list-style-type: disc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#c-avoid-postings #a-index, #c-avoid-posting-versions #a-index {
|
||||
|
||||
table.dnp-list {
|
||||
td.dnp-artist {
|
||||
grid-area: artist;
|
||||
|
||||
.dnp-artist-names {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25em 0.5em;
|
||||
span { text-wrap: pretty; }
|
||||
}
|
||||
}
|
||||
td.dnp-details {
|
||||
grid-area: details;
|
||||
width: 60%;
|
||||
|
||||
span.avoid-posting-staff-notes {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
}
|
||||
td.dnp-creator {
|
||||
grid-area: creator;
|
||||
text-wrap: nowrap;
|
||||
}
|
||||
td.dnp-status {
|
||||
grid-area: status;
|
||||
}
|
||||
td.dnp-links {
|
||||
grid-area: links;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
table.dnp-list {
|
||||
thead {
|
||||
display: block;
|
||||
tr {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
th.dnp-links { display: none; }
|
||||
}
|
||||
}
|
||||
tbody {
|
||||
display: block;
|
||||
tr {
|
||||
display: grid;
|
||||
width: 100%;
|
||||
grid-template-columns: 1fr min-content min-content;
|
||||
grid-template-areas:
|
||||
"artist status creator links"
|
||||
"details details details details";
|
||||
grid-column-gap: 1em;
|
||||
|
||||
td.dnp-details {
|
||||
width: unset;
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -328,6 +328,34 @@ div#c-posts {
|
||||
}
|
||||
}
|
||||
|
||||
div#avoid-posting-notice {
|
||||
font-size: 1.25rem;
|
||||
line-height: 1.5rem;
|
||||
padding: $padding-025 $padding-050;
|
||||
|
||||
background-color: themed("color-section");
|
||||
border: 1px solid themed("color-foreground");
|
||||
|
||||
/*.artist-separator {
|
||||
color: var(--color-text-muted);
|
||||
}*/
|
||||
|
||||
ul {
|
||||
list-style: disc;
|
||||
}
|
||||
|
||||
li {
|
||||
.artist, .separator, .details {
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.separator {
|
||||
color: var(--color-text-muted);
|
||||
padding: 0 0.3rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.quick-mod {
|
||||
|
||||
.quick-mod-group {
|
||||
|
@ -65,7 +65,7 @@ class UploadService
|
||||
p.has_cropped = upload.is_image?
|
||||
p.duration = upload.video_duration(upload.file.path)
|
||||
|
||||
if !upload.uploader.can_upload_free? || upload.upload_as_pending?
|
||||
if !upload.uploader.can_upload_free? || (!upload.uploader.can_approve_posts? && p.avoid_posting_artists.any?) || upload.upload_as_pending?
|
||||
p.is_pending = true
|
||||
end
|
||||
end
|
||||
|
@ -7,8 +7,9 @@ class Artist < ApplicationRecord
|
||||
array_attribute :other_names
|
||||
|
||||
belongs_to_creator
|
||||
before_validation :normalize_name
|
||||
before_validation :normalize_other_names
|
||||
before_validation :normalize_name, unless: :destroyed?
|
||||
before_validation :normalize_other_names, unless: :destroyed?
|
||||
before_validation :validate_protected_properties_not_changed, if: :dnp_restricted?
|
||||
validate :validate_user_can_edit
|
||||
validate :wiki_page_not_locked
|
||||
validate :user_not_limited
|
||||
@ -28,6 +29,8 @@ class Artist < ApplicationRecord
|
||||
has_one :wiki_page, foreign_key: "title", primary_key: "name"
|
||||
has_one :tag_alias, foreign_key: "antecedent_name", primary_key: "name"
|
||||
has_one :tag, foreign_key: "name", primary_key: "name"
|
||||
has_one :avoid_posting, -> { active }
|
||||
has_one :inactive_dnp, -> { deleted }, class_name: "AvoidPosting"
|
||||
belongs_to :linked_user, class_name: "User", optional: true
|
||||
attribute :notes, :string
|
||||
|
||||
@ -496,6 +499,29 @@ class Artist < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
module AvoidPostingMethods
|
||||
def validate_protected_properties_not_changed
|
||||
errors.add(:name, "cannot be changed while the artist is on the avoid posting list") if will_save_change_to_name?
|
||||
errors.add(:group_name, "cannot be changed while the artist is on the avoid posting list") if will_save_change_to_group_name?
|
||||
errors.add(:other_names, "cannot be changed while the artist is on the avoid posting list") if will_save_change_to_other_names?
|
||||
throw(:abort) if errors.any?
|
||||
end
|
||||
|
||||
def is_dnp?
|
||||
avoid_posting.present?
|
||||
end
|
||||
|
||||
def has_any_dnp?
|
||||
is_dnp? || inactive_dnp.present?
|
||||
end
|
||||
|
||||
def dnp_restricted?
|
||||
is_dnp? && !CurrentUser.can_edit_avoid_posting_entries?
|
||||
end
|
||||
end
|
||||
|
||||
include AvoidPostingMethods
|
||||
|
||||
include UrlMethods
|
||||
include NameMethods
|
||||
include GroupMethods
|
||||
@ -505,8 +531,10 @@ class Artist < ApplicationRecord
|
||||
include LockMethods
|
||||
extend SearchMethods
|
||||
|
||||
# due to technical limitations (foreign keys), artists with any
|
||||
# dnp entry (active or inactive) cannot be deleted
|
||||
def deletable_by?(user)
|
||||
user.is_admin?
|
||||
!has_any_dnp? && user.is_admin?
|
||||
end
|
||||
|
||||
def editable_by?(user)
|
||||
|
133
app/models/avoid_posting.rb
Normal file
133
app/models/avoid_posting.rb
Normal file
@ -0,0 +1,133 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class AvoidPosting < ApplicationRecord
|
||||
belongs_to_creator
|
||||
belongs_to_updater
|
||||
belongs_to :artist
|
||||
has_many :versions, -> { order("avoid_posting_versions.id ASC") }, class_name: "AvoidPostingVersion", dependent: :destroy
|
||||
validates :artist_id, uniqueness: { message: "already has an avoid posting entry" }
|
||||
after_create :log_create
|
||||
after_create :create_version
|
||||
after_update :log_update, if: :saved_change_to_watched_attributes?
|
||||
after_update :create_version, if: :saved_change_to_watched_attributes?
|
||||
after_destroy :log_destroy
|
||||
validates_associated :artist
|
||||
accepts_nested_attributes_for :artist
|
||||
|
||||
scope :active, -> { where(is_active: true) }
|
||||
scope :deleted, -> { where(is_active: false) }
|
||||
|
||||
module LogMethods
|
||||
def log_create
|
||||
ModAction.log(:avoid_posting_create, { id: id, artist_name: artist_name })
|
||||
end
|
||||
|
||||
def saved_change_to_watched_attributes?
|
||||
saved_change_to_is_active? || saved_change_to_details? || saved_change_to_staff_notes?
|
||||
end
|
||||
|
||||
def log_update
|
||||
entry = { id: id, artist_name: artist_name }
|
||||
if saved_change_to_is_active?
|
||||
action = is_active? ? :avoid_posting_undelete : :avoid_posting_delete
|
||||
ModAction.log(action, entry)
|
||||
# only log delete/undelete if only is_active changed (checking for 2 because of updated_at)
|
||||
return if previous_changes.length == 2
|
||||
end
|
||||
entry = entry.merge({ details: details, old_details: details_before_last_save }) if saved_change_to_details?
|
||||
entry = entry.merge({ staff_notes: staff_notes, old_staff_notes: staff_notes_before_last_save }) if saved_change_to_staff_notes?
|
||||
|
||||
ModAction.log(:avoid_posting_update, entry)
|
||||
end
|
||||
|
||||
def log_destroy
|
||||
ModAction.log(:avoid_posting_destroy, { id: id, artist_name: artist_name })
|
||||
end
|
||||
end
|
||||
|
||||
def create_version
|
||||
AvoidPostingVersion.create({
|
||||
avoid_posting: self,
|
||||
details: details,
|
||||
staff_notes: staff_notes,
|
||||
is_active: is_active,
|
||||
})
|
||||
end
|
||||
|
||||
def status
|
||||
if is_active?
|
||||
"Active"
|
||||
else
|
||||
"Deleted"
|
||||
end
|
||||
end
|
||||
|
||||
module ArtistMethods
|
||||
delegate :group_name, :other_names, :other_names_string, :linked_user_id, :linked_user, :any_name_matches, to: :artist
|
||||
delegate :name, to: :artist, prefix: true, allow_nil: true
|
||||
end
|
||||
|
||||
module ApiMethods
|
||||
def hidden_attributes
|
||||
attr = super
|
||||
attr += %i[staff_notes] unless CurrentUser.is_staff?
|
||||
attr
|
||||
end
|
||||
end
|
||||
|
||||
module SearchMethods
|
||||
def for_artist(name)
|
||||
active.find_by(artist_name: name)
|
||||
end
|
||||
|
||||
def artist_search(params)
|
||||
Artist.search(params.slice(:any_name_matches, :any_other_name_matches).merge({ id: params[:artist_id], name: params[:artist_name] }))
|
||||
end
|
||||
|
||||
def search(params)
|
||||
q = super
|
||||
artist_keys = %i[artist_id artist_name any_name_matches any_other_name_matches]
|
||||
q = q.joins(:artist).merge(artist_search(params)) if artist_keys.any? { |key| params.key?(key) }
|
||||
|
||||
if params[:is_active].present?
|
||||
q = q.active if params[:is_active].to_s.truthy?
|
||||
q = q.deleted if params[:is_active].to_s.falsy?
|
||||
else
|
||||
q = q.active
|
||||
end
|
||||
|
||||
q = q.attribute_matches(:details, params[:details])
|
||||
q = q.attribute_matches(:staff_notes, params[:staff_notes])
|
||||
q = q.where_user(:creator_id, :creator, params)
|
||||
q = q.where("creator_ip_addr <<= ?", params[:creator_ip_addr]) if params[:creator_ip_addr].present?
|
||||
q.apply_basic_order(params)
|
||||
end
|
||||
end
|
||||
|
||||
def header
|
||||
first = artist_name[0]
|
||||
if first =~ /\d/
|
||||
"#"
|
||||
elsif first =~ /[a-z]/
|
||||
first.upcase
|
||||
else
|
||||
"?"
|
||||
end
|
||||
end
|
||||
|
||||
def all_names
|
||||
return artist_name.tr("_", " ") if other_names.blank?
|
||||
"#{artist_name} / #{other_names.join(' / ')}".tr("_", " ")
|
||||
end
|
||||
|
||||
def pretty_details
|
||||
return details if details.present?
|
||||
return "Only the artist is allowed to post." if linked_user_id.present?
|
||||
""
|
||||
end
|
||||
|
||||
include LogMethods
|
||||
include ApiMethods
|
||||
include ArtistMethods
|
||||
extend SearchMethods
|
||||
end
|
48
app/models/avoid_posting_version.rb
Normal file
48
app/models/avoid_posting_version.rb
Normal file
@ -0,0 +1,48 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class AvoidPostingVersion < ApplicationRecord
|
||||
belongs_to_updater
|
||||
belongs_to :avoid_posting
|
||||
has_one :artist, through: :avoid_posting
|
||||
delegate :artist_id, :artist_name, to: :avoid_posting
|
||||
|
||||
def status
|
||||
if is_active?
|
||||
"Active"
|
||||
else
|
||||
"Deleted"
|
||||
end
|
||||
end
|
||||
|
||||
def previous
|
||||
AvoidPostingVersion.joins(:avoid_posting).where(id: ...id).order(id: :desc).first
|
||||
end
|
||||
|
||||
module ApiMethods
|
||||
def hidden_attributes
|
||||
attr = super
|
||||
attr += %i[staff_notes] unless CurrentUser.is_janitor?
|
||||
attr
|
||||
end
|
||||
end
|
||||
|
||||
module SearchMethods
|
||||
def artist_search(params)
|
||||
Artist.search(params.slice(:any_name_matches, :any_other_name_matches).merge({ id: params[:artist_id], name: params[:artist_name] }))
|
||||
end
|
||||
|
||||
def search(params)
|
||||
q = super
|
||||
artist_keys = %i[artist_id artist_name any_name_matches any_other_name_matches]
|
||||
q = q.joins(:artist).merge(artist_search(params)) if artist_keys.any? { |key| params.key?(key) }
|
||||
|
||||
q = q.attribute_matches(:is_active, params[:is_active])
|
||||
q = q.where_user(:updater_id, :updater, params)
|
||||
q = q.where("updater_ip_addr <<= ?", params[:updater_ip_addr]) if params[:updater_ip_addr].present?
|
||||
q.apply_basic_order(params)
|
||||
end
|
||||
end
|
||||
|
||||
include ApiMethods
|
||||
extend SearchMethods
|
||||
end
|
@ -11,6 +11,11 @@ class ModAction < ApplicationRecord
|
||||
:artist_page_unlock,
|
||||
:artist_user_linked,
|
||||
:artist_user_unlinked,
|
||||
:avoid_posting_create,
|
||||
:avoid_posting_update,
|
||||
:avoid_posting_delete,
|
||||
:avoid_posting_undelete,
|
||||
:avoid_posting_destroy,
|
||||
:blip_delete,
|
||||
:blip_hide,
|
||||
:blip_unhide,
|
||||
|
@ -1754,9 +1754,12 @@ class Post < ApplicationRecord
|
||||
save
|
||||
end
|
||||
|
||||
def artist_tags
|
||||
tags.select { |t| t.category == Tag.categories.artist }
|
||||
end
|
||||
|
||||
def uploader_linked_artists
|
||||
linked_artists ||= tags.select { |t| t.category == Tag.categories.artist }.filter_map(&:artist)
|
||||
linked_artists.select { |artist| artist.linked_user_id == uploader_id }
|
||||
artist_tags.filter_map(&:artist).select { |artist| artist.linked_user_id == uploader_id }
|
||||
end
|
||||
|
||||
def flaggable_for_guidelines?
|
||||
@ -1768,4 +1771,8 @@ class Post < ApplicationRecord
|
||||
def visible_comment_count(_user)
|
||||
comment_count
|
||||
end
|
||||
|
||||
def avoid_posting_artists
|
||||
AvoidPosting.active.joins(:artist).where("artists.name": artist_tags.map(&:name))
|
||||
end
|
||||
end
|
||||
|
@ -319,6 +319,10 @@ class User < ApplicationRecord
|
||||
is_bd_staff
|
||||
end
|
||||
|
||||
def is_staff?
|
||||
is_janitor?
|
||||
end
|
||||
|
||||
def is_approver?
|
||||
can_approve_posts?
|
||||
end
|
||||
@ -508,13 +512,17 @@ class User < ApplicationRecord
|
||||
end
|
||||
|
||||
def can_view_staff_notes?
|
||||
is_janitor?
|
||||
is_staff?
|
||||
end
|
||||
|
||||
def can_handle_takedowns?
|
||||
is_bd_staff?
|
||||
end
|
||||
|
||||
def can_edit_avoid_posting_entries?
|
||||
is_bd_staff?
|
||||
end
|
||||
|
||||
def can_undo_post_versions?
|
||||
is_member?
|
||||
end
|
||||
|
@ -2,18 +2,23 @@
|
||||
<% if @artist.new_record? %>
|
||||
<%# FIXME: Probably wrong type in the production database %>
|
||||
<%= f.input :name, as: :string, autocomplete: "tag" %>
|
||||
<% elsif CurrentUser.user.is_janitor? %>
|
||||
<%= f.input :name, autocomplete: "tag", hint: "Change to rename this artist entry and its wiki page" %>
|
||||
<% elsif !@artist.dnp_restricted? && CurrentUser.user.is_janitor? %>
|
||||
<%= f.input :name, autocomplete: "tag", hint: "Change to rename this artist entry and its wiki page." %>
|
||||
<% else %>
|
||||
<p><%= @artist.name %></p>
|
||||
<% if @artist.dnp_restricted? %>
|
||||
<p>Name, other names, and group name cannot be edited for artists on the <%= link_to "Avoid Posting", avoid_postings_path %> list.</p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% if CurrentUser.is_janitor? %>
|
||||
<%= f.input :linked_user_id, label: "Linked User ID" %>
|
||||
<%= f.input :is_locked, label: "Locked" %>
|
||||
<% end %>
|
||||
<% if @artist.new_record? || !@artist.dnp_restricted? %>
|
||||
<%= f.input :other_names_string, label: "Other names", hint: 'Separate names with spaces, not commas. Use underscores for spaces inside names. Limit 25.', input_html: { size: "80" } %>
|
||||
<%= f.input :group_name %>
|
||||
<%= f.input :url_string, :label => "URLs", as: :text, input_html: { size: "80x10", value: params.dig(:artist, :url_string) || @artist.urls.join("\n")}, hint: "You can prefix a URL with - to mark it as dead." %>
|
||||
<% end %>
|
||||
<%= f.input :url_string, label: "URLs", as: :text, input_html: { size: "80x10", value: params.dig(:artist, :url_string) || @artist.urls.join("\n")}, hint: "You can prefix a URL with - to mark it as dead." %>
|
||||
|
||||
<% if @artist.is_note_locked? %>
|
||||
<p>Artist is note locked. Notes cannot be edited.</p>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<% content_for(:secondary_links) do %>
|
||||
<li><%= render "artists/quick_search" %></li>
|
||||
<%= subnav_link_to "Listing", artists_path %>
|
||||
<%= subnav_link_to "Avoid Posting", wiki_page_path(id: "avoid_posting") %>
|
||||
<%= subnav_link_to "Avoid Posting", avoid_postings_path %>
|
||||
<% if CurrentUser.is_member? %>
|
||||
<%= subnav_link_to "New", new_artist_path %>
|
||||
<% end %>
|
||||
@ -18,5 +18,10 @@
|
||||
<% if @artist.deletable_by?(CurrentUser.user) %>
|
||||
<%= subnav_link_to "Delete", artist_path(@artist), method: :delete, data: { confirm: "Are you sure you want to delete this artist? This cannot be undone." } %>
|
||||
<% end %>
|
||||
<% if @artist.is_dnp? %>
|
||||
<li>|</li>
|
||||
<%= subnav_link_to "DNP", avoid_posting_path(@artist.avoid_posting) %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
@ -7,6 +7,18 @@
|
||||
<% end %>
|
||||
</h1>
|
||||
|
||||
<% if @artist.is_dnp? %>
|
||||
<div id="avoid-posting">
|
||||
<h2>This artist is on the <%= link_to "Avoid Posting", avoid_postings_path %> list.</h2>
|
||||
<% if @artist.avoid_posting.pretty_details.present? %>
|
||||
<div class="dtext-container">
|
||||
<%= format_text(@artist.avoid_posting.pretty_details, inline: true) %>
|
||||
</div>
|
||||
<% end %>
|
||||
<p><%= link_to "Open Avoid Posting entry", avoid_posting_path(@artist.avoid_posting) %></p>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if @artist.notes.present? && @artist.visible? %>
|
||||
<div class="dtext-container">
|
||||
<%= format_text(@artist.notes, allow_color: true) %>
|
||||
|
11
app/views/avoid_posting_versions/_search.html.erb
Normal file
11
app/views/avoid_posting_versions/_search.html.erb
Normal file
@ -0,0 +1,11 @@
|
||||
<%= form_search(path: avoid_posting_versions_path) do |f| %>
|
||||
<%= f.user :updater %>
|
||||
<% if CurrentUser.is_admin? %>
|
||||
<%= f.input :updater_ip_addr, label: "Updater IP Address" %>
|
||||
<% end %>
|
||||
<%= f.input :any_name_matches, label: "Name", hint: "Use * for wildcard", autocomplete: "artist" %>
|
||||
<%= f.input :artist_name, label: "Artist Name", hide_unless_value: true %>
|
||||
<%= f.input :artist_id, label: "Artist ID", hide_unless_value: true %>
|
||||
<%= f.input :any_other_name_matches, label: "Other Names", hide_unless_value: true %>
|
||||
<%= f.input :is_active, label: "Active?", collection: [%w[Yes true], %w[No false], %w[Any any]] %>
|
||||
<% end %>
|
@ -0,0 +1,4 @@
|
||||
<% content_for(:secondary_links) do %>
|
||||
<%= subnav_link_to "Listing", avoid_posting_versions_path %>
|
||||
<%= subnav_link_to "Avoid Postings", avoid_postings_path %>
|
||||
<% end %>
|
84
app/views/avoid_posting_versions/index.html.erb
Normal file
84
app/views/avoid_posting_versions/index.html.erb
Normal file
@ -0,0 +1,84 @@
|
||||
<div id="c-avoid-posting-versions">
|
||||
<div id="a-index">
|
||||
<h1>Avoid Posting Versions</h1>
|
||||
|
||||
<%= render "search" %>
|
||||
|
||||
<table class="striped dnp-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="dnp-artist">Artist</th>
|
||||
<th class="dnp-details" width="60%">Details</th>
|
||||
<th class="dnp-status">Status</th>
|
||||
<th class="dnp-creator">Updater</th>
|
||||
<th class="dnp-links"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @avoid_posting_versions.each do |avoid_posting_version| %>
|
||||
<% previous = avoid_posting_version.previous %>
|
||||
<tr id="avoid-posting-version-<%= avoid_posting_version.id %>" data-artist="<%= avoid_posting_version.artist_name %>">
|
||||
<td class="dnp-artist">
|
||||
<%= link_to avoid_posting_version.artist_name, artist_path(avoid_posting_version.artist) %>
|
||||
</td>
|
||||
<td class="dnp-details">
|
||||
<span class="avoid-posting-details">
|
||||
<% if previous.present? %>
|
||||
<% if previous.details == avoid_posting_version.details %>
|
||||
(no changes)
|
||||
<% elsif avoid_posting_version.details.blank? %>
|
||||
(cleared)
|
||||
<% else %>
|
||||
<%= avoid_posting_version.details %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= avoid_posting_version.details %>
|
||||
<% end %>
|
||||
</span>
|
||||
<% if CurrentUser.is_staff? %>
|
||||
<span class="avoid-posting-staff-notes">
|
||||
<% if previous.present? && previous.staff_notes != avoid_posting_version.staff_notes %>
|
||||
<b>Staff Notes</b>
|
||||
<span>
|
||||
<% if avoid_posting_version.staff_notes.blank? %>
|
||||
(cleared)
|
||||
<% else %>
|
||||
<%= avoid_posting_version.staff_notes %>
|
||||
<% end %>
|
||||
</span>
|
||||
<% end %>
|
||||
</span>
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="dnp-status">
|
||||
<%= avoid_posting_version.status %>
|
||||
</td>
|
||||
<td class="dnp-creator">
|
||||
<%= link_to_user avoid_posting_version.updater %>
|
||||
<%= link_to "»", avoid_posting_versions_path(search: { updater_name: avoid_posting_version.updater_name }) %>
|
||||
<p>
|
||||
<%= compact_time(avoid_posting_version.updated_at) %>
|
||||
<% if CurrentUser.is_admin? %>
|
||||
(<%= link_to_ip avoid_posting_version.updater_ip_addr %>)
|
||||
<% end %>
|
||||
</p>
|
||||
</td>
|
||||
<td class="dnp-links">
|
||||
<%= link_to "Show", avoid_posting_path(avoid_posting_version.avoid_posting) %>
|
||||
<% if CurrentUser.can_edit_avoid_posting_entries? %>
|
||||
| <%= link_to "Edit", edit_avoid_posting_path(avoid_posting_version.avoid_posting) %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%= numbered_paginator(@avoid_posting_versions) %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render "secondary_links" %>
|
||||
<% content_for(:page_title) do %>
|
||||
Avoid Posting Versions
|
||||
<% end %>
|
11
app/views/avoid_postings/_form.html.erb
Normal file
11
app/views/avoid_postings/_form.html.erb
Normal file
@ -0,0 +1,11 @@
|
||||
<%= custom_form_for(@avoid_posting) do |f| %>
|
||||
<%= f.simple_fields_for(:artist) do |af| %>
|
||||
<%= af.input :name, label: "Artist name", autocomplete: "artist", hint: params[:action] == "new" ? "An artist will be created if one does not exist." : "The artist will be renamed." %>
|
||||
<%= af.input :other_names_string, label: "Other names", hint: "Separate names with spaces, not commas. Use underscores for spaces inside names. Limit 25.", input_html: { size: "80" } %>
|
||||
<%= af.input :group_name %>
|
||||
<%= af.input :linked_user_id, label: "Linked User ID" %>
|
||||
<% end %>
|
||||
<%= f.input :details, label: "Details", as: :dtext, hint: "Details shown to all users. Conditions should be listed here." %>
|
||||
<%= f.input :staff_notes, label: "Staff Notes", as: :dtext, hint: "Notes shown only to staff members." %>
|
||||
<%= f.button :submit, "Submit" %>
|
||||
<% end %>
|
16
app/views/avoid_postings/_search.html.erb
Normal file
16
app/views/avoid_postings/_search.html.erb
Normal file
@ -0,0 +1,16 @@
|
||||
<%= form_search(path: avoid_postings_path, always_display: true) do |f| %>
|
||||
<%= f.user :creator %>
|
||||
<% if CurrentUser.is_admin? %>
|
||||
<%= f.input :creator_ip_addr, label: "Creator IP Address" %>
|
||||
<% end %>
|
||||
<%= f.input :any_name_matches, label: "Name", hint: "Use * for wildcard", autocomplete: "artist" %>
|
||||
<%= f.input :artist_name, label: "Artist Name", hide_unless_value: true %>
|
||||
<%= f.input :artist_id, label: "Artist ID", hide_unless_value: true %>
|
||||
<%= f.input :any_other_name_matches, label: "Other Names", hide_unless_value: true %>
|
||||
<%= f.input :group_name, label: "Group Name", hide_unless_value: true %>
|
||||
<%= f.input :details, label: "Details" %>
|
||||
<% if CurrentUser.is_staff? %>
|
||||
<%= f.input :staff_notes %>
|
||||
<% end %>
|
||||
<%= f.input :is_active, label: "Active?", collection: [%w[Yes true], %w[No false], %w[Any any]] %>
|
||||
<% end %>
|
23
app/views/avoid_postings/_secondary_links.html.erb
Normal file
23
app/views/avoid_postings/_secondary_links.html.erb
Normal file
@ -0,0 +1,23 @@
|
||||
<% content_for(:secondary_links) do %>
|
||||
<%= subnav_link_to "Listing", avoid_postings_path %>
|
||||
<% if CurrentUser.can_edit_avoid_posting_entries? %>
|
||||
<%= subnav_link_to "New", new_avoid_posting_path %>
|
||||
<% end %>
|
||||
<% if params[:action] == "show" %>
|
||||
<% if CurrentUser.can_edit_avoid_posting_entries? %>
|
||||
<%= subnav_link_to "Edit", edit_avoid_posting_path(@avoid_posting) %>
|
||||
<% if @avoid_posting.is_active? %>
|
||||
<%= subnav_link_to "Delete", delete_avoid_posting_path(@avoid_posting), method: :put, data: { confirm: "Are you sure you want to delete this avoid posting entry?" } %>
|
||||
<% else %>
|
||||
<%= subnav_link_to "Undelete", undelete_avoid_posting_path(@avoid_posting), method: :put, data: { confirm: "Are you sure you want to undelete this avoid posting entry?" } %>
|
||||
<% end %>
|
||||
<%= subnav_link_to "Destroy", avoid_posting_path(@avoid_posting), method: :delete, data: { confirm: "Are you sure you want to destroy this avoid posting entry? This will remove all related history, and cannot be undone." } %>
|
||||
<% end %>
|
||||
<%= subnav_link_to "Implications", tag_implications_path(search: { antecedent_name: @avoid_posting.artist_name }) %>
|
||||
<%= subnav_link_to "History", avoid_posting_versions_path(search: { artist_name: @avoid_posting.artist_name }) %>
|
||||
<% else %>
|
||||
<%= subnav_link_to "History", avoid_posting_versions_path %>
|
||||
<% end %>
|
||||
<li>|</li>
|
||||
<%= subnav_link_to "Static", avoid_posting_static_path %>
|
||||
<% end %>
|
13
app/views/avoid_postings/edit.html.erb
Normal file
13
app/views/avoid_postings/edit.html.erb
Normal file
@ -0,0 +1,13 @@
|
||||
<div class="c-avoid-postings">
|
||||
<div class="a-edit">
|
||||
<h1>Edit Avoid Posting for <%= link_to @avoid_posting.artist_name, avoid_posting_path(@avoid_posting), class: "tag-type-1" %></h1>
|
||||
|
||||
<%= error_messages_for :avoid_posting %>
|
||||
<%= render "form" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render "secondary_links" %>
|
||||
<% content_for(:page_title) do %>
|
||||
Edit Avoid Posting for <%= @avoid_posting.artist_name %>
|
||||
<% end %>
|
70
app/views/avoid_postings/index.html.erb
Normal file
70
app/views/avoid_postings/index.html.erb
Normal file
@ -0,0 +1,70 @@
|
||||
<div id="c-avoid-postings">
|
||||
<div id="a-index">
|
||||
<h1>Avoid Postings</h1>
|
||||
|
||||
<%= render "search" %>
|
||||
|
||||
<table class="striped dnp-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="dnp-artist">Artist</th>
|
||||
<th class="dnp-details">Details</th>
|
||||
<% if search_params.key?(:is_active) %>
|
||||
<th class="dnp-status">Status</th>
|
||||
<% end %>
|
||||
<% if search_params.key?(:creator_id) || search_params.key?(:creator_name) %>
|
||||
<th class="dnp-creator">Creator</th>
|
||||
<% end %>
|
||||
<th class="dnp-links"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @avoid_postings.each do |avoid_posting| %>
|
||||
<tr id="avoid-posting-<%= avoid_posting.id %>" data-artist="<%= avoid_posting.artist_name %>">
|
||||
<td class="dnp-artist">
|
||||
<span class="dnp-artist-names">
|
||||
<%= link_to avoid_posting.artist_name, artist_path(avoid_posting.artist) %>
|
||||
<% if avoid_posting.other_names.present? %>
|
||||
<span>(<%= link_to_artists(avoid_posting.other_names, hide_new_notice: true) %>)</span>
|
||||
<% end %>
|
||||
</span>
|
||||
</td>
|
||||
<td class="dnp-details">
|
||||
<span class="avoid-posting-details"><%= format_text(avoid_posting.details, inline: true) %></span>
|
||||
<% if CurrentUser.is_staff? && avoid_posting.staff_notes.present? %>
|
||||
<span class="avoid-posting-staff-notes">
|
||||
<b>Staff Notes</b>
|
||||
<span><%= format_text(avoid_posting.staff_notes, inline: true) %></span>
|
||||
</span>
|
||||
<% end %>
|
||||
</td>
|
||||
<% if search_params.key?(:is_active) %>
|
||||
<td class="dnp-status">
|
||||
<%= avoid_posting.status %>
|
||||
</td>
|
||||
<% end %>
|
||||
<% if search_params.key?(:creator_id) || search_params.key?(:creator_name) %>
|
||||
<td class="dnp-creator">
|
||||
<%= link_to_user avoid_posting.creator %>
|
||||
</td>
|
||||
<% end %>
|
||||
<td class="dnp-links">
|
||||
<%= link_to "Show", avoid_posting_path(avoid_posting) %>
|
||||
<% if CurrentUser.can_edit_avoid_posting_entries? %>
|
||||
| <%= link_to "Edit", edit_avoid_posting_path(avoid_posting) %>
|
||||
| <%= link_to "Delete", delete_avoid_posting_path(avoid_posting), method: :put, data: { confirm: "Are you sure you want to delete this avoid posting?" } %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%= numbered_paginator(@avoid_postings) %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render "secondary_links" %>
|
||||
<% content_for(:page_title) do %>
|
||||
Avoid Postings
|
||||
<% end %>
|
13
app/views/avoid_postings/new.html.erb
Normal file
13
app/views/avoid_postings/new.html.erb
Normal file
@ -0,0 +1,13 @@
|
||||
<div class="c-avoid-postings">
|
||||
<div class="a-new">
|
||||
<h1>New Avoid Posting</h1>
|
||||
|
||||
<%= error_messages_for :avoid_posting %>
|
||||
<%= render "form" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render "secondary_links" %>
|
||||
<% content_for(:page_title) do %>
|
||||
New Avoid Posting
|
||||
<% end %>
|
46
app/views/avoid_postings/show.html.erb
Normal file
46
app/views/avoid_postings/show.html.erb
Normal file
@ -0,0 +1,46 @@
|
||||
<div id="c-avoid-postings">
|
||||
<div id="a-index">
|
||||
<h1>Avoid Posting: <%= link_to @avoid_posting.artist_name, show_or_new_artists_path(name: @avoid_posting.artist_name), class: "tag-type-1" %><%= " (inactive)" unless @avoid_posting.is_active? %></h1>
|
||||
<ul>
|
||||
<li><strong>Status</strong> <%= @avoid_posting.status %></li>
|
||||
|
||||
<% if @avoid_posting.linked_user_id && @avoid_posting.linked_user %>
|
||||
<li><strong>User</strong> <%= link_to_user(@avoid_posting.linked_user) %></li>
|
||||
<% end %>
|
||||
<li><strong>Created</strong> <%= compact_time @avoid_posting.created_at %> by <%= link_to_user(@avoid_posting.creator) %><% if CurrentUser.is_admin? %> (<%= link_to_ip @avoid_posting.creator_ip_addr %>)<% end %></li>
|
||||
<% if @avoid_posting.updater.present? %>
|
||||
<li><strong>Updated</strong> <%= compact_time @avoid_posting.updated_at %> by <%= link_to_user(@avoid_posting.updater) %><% if CurrentUser.is_admin? %> (<%= link_to_ip @avoid_posting.updater_ip_addr %>)<% end %></li>
|
||||
<% end %>
|
||||
<% if @avoid_posting.other_names.present? %>
|
||||
<li><strong>Other Names</strong> <%= link_to_artists(@avoid_posting.other_names) %></li>
|
||||
<% end %>
|
||||
<% if @avoid_posting.group_name.present? %>
|
||||
<li><strong>Group</strong> <%= link_to_artist(@avoid_posting.group_name) %></li>
|
||||
<% end %>
|
||||
<% if @avoid_posting.group_name.present? && @avoid_posting.artist.members.present? %>
|
||||
<li><strong>Members</strong> <%= link_to_artists(@avoid_posting.artist.members.limit(25).map(&:name)) %></li>
|
||||
<% end %>
|
||||
<% if @avoid_posting.details.present? %>
|
||||
<li>
|
||||
<strong>Details</strong>
|
||||
<div class="dtext-container">
|
||||
<%= format_text(@avoid_posting.details) %>
|
||||
</div>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if CurrentUser.is_staff? && @avoid_posting.staff_notes.present? %>
|
||||
<li>
|
||||
<strong>Staff Notes</strong>
|
||||
<div class="dtext-container">
|
||||
<%= format_text(@avoid_posting.staff_notes, inline: true) %>
|
||||
</div>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render "secondary_links" %>
|
||||
<% content_for(:page_title) do %>
|
||||
Avoid Posting for <%= @avoid_posting.artist_name %>
|
||||
<% end %>
|
27
app/views/posts/partials/show/_avoid_posting.html.erb
Normal file
27
app/views/posts/partials/show/_avoid_posting.html.erb
Normal file
@ -0,0 +1,27 @@
|
||||
<% if post.avoid_posting_artists.any? %>
|
||||
<div class="notice" id="avoid-posting-notice">
|
||||
<div class="avoid-posting">
|
||||
<h3>Avoid Posting</h3>
|
||||
<ul>
|
||||
<% post.avoid_posting_artists.each do |dnp| %>
|
||||
<li>
|
||||
<% if dnp.pretty_details.blank? %>
|
||||
<span class="artist"><%= link_to dnp.artist_name, avoid_posting_path(dnp) %></span>
|
||||
<span class="separator">-</span>
|
||||
<span class="details">Avoid posting.</span>
|
||||
<% else %>
|
||||
<span class="artist">
|
||||
<%= link_to dnp.artist_name, avoid_posting_path(dnp) %>
|
||||
<% if dnp.artist.try(:linked_user_id) == post.uploader_id %>
|
||||
<i class="uploader-is-artist fa-regular fa-circle-check" title="The uploader is linked to this artist."></i>
|
||||
<% end %>
|
||||
</span>
|
||||
<span class="separator">-</span>
|
||||
<span class="details"><%= format_text(dnp.pretty_details, inline: true) %></span>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
@ -49,6 +49,10 @@
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if post.is_pending? || (post.is_flagged? && post.flags.any?) %>
|
||||
<%= render "posts/partials/show/avoid_posting", post: post %>
|
||||
<% end %>
|
||||
|
||||
<% if post.replacements.pending.any? %>
|
||||
<div class="notice notice-flagged">
|
||||
<p>This post has <%= link_to "pending replacements.", post_replacements_path(search: {post_id: @post.id}) %></p>
|
||||
|
15
app/views/static/avoid_posting.html.erb
Normal file
15
app/views/static/avoid_posting.html.erb
Normal file
@ -0,0 +1,15 @@
|
||||
<div id="c-static">
|
||||
<div id="a-avoid-posting">
|
||||
|
||||
<div class="dtext-container">
|
||||
<%= format_text(@page.body, allow_color: true) %>
|
||||
<%= format_avoid_posting_list %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render "avoid_postings/secondary_links" %>
|
||||
|
||||
<% content_for(:page_title) do %>
|
||||
Avoid Posting List
|
||||
<% end %>
|
@ -37,7 +37,7 @@
|
||||
<ul>
|
||||
<li><h1>Artists</h1></li>
|
||||
<li><%= link_to("Listing", artists_path) %></li>
|
||||
<li><%= link_to("Avoid Posting", help_page_path(id: "avoid_posting")) %></li>
|
||||
<li><%= link_to("Avoid Posting", avoid_postings_path) %></li>
|
||||
<li><%= link_to("Changes", artist_versions_path) %></li>
|
||||
<li><%= link_to("Help", help_page_path(id: "artists")) %></li>
|
||||
</ul>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<h2>Before uploading, read
|
||||
the <%= link_to "how to upload guide", wiki_page_path(id: "howto:upload") %>.</h2>
|
||||
<p>Make sure you're not posting something on
|
||||
the <%= link_to "Avoid Posting List", help_page_path(id: 'avoid_posting') %><br>
|
||||
the <%= link_to "Avoid Posting List", avoid_postings_path %><br>
|
||||
Review the <%= link_to "Uploading Guidelines", help_page_path(id: "uploading_guidelines") %>
|
||||
<br>
|
||||
Unsure what to tag your post
|
||||
|
@ -460,7 +460,7 @@ module Danbooru
|
||||
},
|
||||
{
|
||||
name: "dnp_artist",
|
||||
reason: "The artist of this post is on the [[avoid_posting|avoid posting list]]",
|
||||
reason: "The artist of this post is on the \"avoid posting list\":/avoid_postings",
|
||||
text: "Certain artists have requested that their work is not to be published on this site, and were granted [[avoid_posting|Do Not Post]] status.\nSometimes, that status comes with conditions; see [[conditional_dnp]] for more information",
|
||||
},
|
||||
{
|
||||
@ -527,7 +527,7 @@ module Danbooru
|
||||
"Traced artwork",
|
||||
"Traced artwork (post #%PARENT_ID%)",
|
||||
"Takedown #%OTHER_ID%",
|
||||
"The artist of this post is on the [[avoid_posting|avoid posting list]]",
|
||||
"The artist of this post is on the \"avoid posting list\":/avoid_postings",
|
||||
"[[conditional_dnp|Conditional DNP]] (Only the artist is allowed to post)",
|
||||
"[[conditional_dnp|Conditional DNP]] (%OTHER_ID%)",
|
||||
]
|
||||
|
@ -76,6 +76,16 @@ Rails.application.routes.draw do
|
||||
end
|
||||
end
|
||||
|
||||
resources :avoid_postings, constraints: id_name_constraint do
|
||||
member do
|
||||
put :delete
|
||||
put :undelete
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
resources :avoid_posting_versions, only: %i[index]
|
||||
|
||||
resources :tickets, except: %i[destroy] do
|
||||
member do
|
||||
post :claim
|
||||
@ -448,6 +458,7 @@ Rails.application.routes.draw do
|
||||
post "/static/discord" => "static#discord", as: "discord_post"
|
||||
get "/static/toggle_mobile_mode" => "static#disable_mobile_mode", as: "disable_mobile_mode"
|
||||
get "/static/theme" => "static#theme", as: "theme"
|
||||
get "/static/avoid_posting" => "static#avoid_posting", as: "avoid_posting_static"
|
||||
get "/meta_searches/tags" => "meta_searches#tags", :as => "meta_searches_tags"
|
||||
|
||||
root :to => "static#home"
|
||||
|
19
db/fixes/118_create_avoid_postings_from_implications.rb
Executable file
19
db/fixes/118_create_avoid_postings_from_implications.rb
Executable file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "config", "environment"))
|
||||
|
||||
CurrentUser.as_system do
|
||||
TagImplication.order(created_at: :asc).approved.where(consequent_name: %w[avoid_posting conditional_dnp]).find_each do |implication|
|
||||
artist = Artist.find_or_create_by!(name: implication.antecedent_name)
|
||||
dnp = CurrentUser.scoped(implication.creator, implication.creator_ip_addr) do
|
||||
AvoidPosting.create(artist: artist, created_at: implication.created_at, updated_at: implication.created_at)
|
||||
end
|
||||
if dnp.valid?
|
||||
puts artist.name
|
||||
else
|
||||
puts "Failed to create dnp for #{artist.name}"
|
||||
puts dnp.errors.full_messages
|
||||
end
|
||||
end
|
||||
end
|
17
db/migrate/20240103002040_create_avoid_postings.rb
Normal file
17
db/migrate/20240103002040_create_avoid_postings.rb
Normal file
@ -0,0 +1,17 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class CreateAvoidPostings < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
create_table(:avoid_postings) do |t|
|
||||
t.references(:creator, foreign_key: { to_table: :users }, null: false)
|
||||
t.references(:updater, foreign_key: { to_table: :users }, null: false)
|
||||
t.references(:artist, foreign_key: true, null: false, index: { unique: true })
|
||||
t.inet(:creator_ip_addr, null: false)
|
||||
t.inet(:updater_ip_addr, null: false)
|
||||
t.string(:details, null: false, default: "")
|
||||
t.string(:staff_notes, null: false, default: "")
|
||||
t.boolean(:is_active, null: false, default: true)
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
15
db/migrate/20240103002049_create_avoid_posting_versions.rb
Normal file
15
db/migrate/20240103002049_create_avoid_posting_versions.rb
Normal file
@ -0,0 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class CreateAvoidPostingVersions < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
create_table(:avoid_posting_versions) do |t|
|
||||
t.references(:updater, foreign_key: { to_table: :users }, null: false)
|
||||
t.references(:avoid_posting, foreign_key: { to_table: :avoid_postings }, null: false)
|
||||
t.inet(:updater_ip_addr, null: false)
|
||||
t.string(:details, null: false, default: "")
|
||||
t.string(:staff_notes, null: false, default: "")
|
||||
t.boolean(:is_active, null: false, default: true)
|
||||
t.datetime(:updated_at, null: false)
|
||||
end
|
||||
end
|
||||
end
|
180
db/structure.sql
180
db/structure.sql
@ -202,6 +202,79 @@ CREATE SEQUENCE public.artists_id_seq
|
||||
ALTER SEQUENCE public.artists_id_seq OWNED BY public.artists.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: avoid_posting_versions; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.avoid_posting_versions (
|
||||
id bigint NOT NULL,
|
||||
updater_id bigint NOT NULL,
|
||||
avoid_posting_id bigint NOT NULL,
|
||||
updater_ip_addr inet NOT NULL,
|
||||
details character varying DEFAULT ''::character varying NOT NULL,
|
||||
staff_notes character varying DEFAULT ''::character varying NOT NULL,
|
||||
is_active boolean DEFAULT true NOT NULL,
|
||||
updated_at timestamp(6) without time zone NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: avoid_posting_versions_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.avoid_posting_versions_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: avoid_posting_versions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.avoid_posting_versions_id_seq OWNED BY public.avoid_posting_versions.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: avoid_postings; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.avoid_postings (
|
||||
id bigint NOT NULL,
|
||||
creator_id bigint NOT NULL,
|
||||
updater_id bigint NOT NULL,
|
||||
artist_id bigint NOT NULL,
|
||||
creator_ip_addr inet NOT NULL,
|
||||
updater_ip_addr inet NOT NULL,
|
||||
details character varying DEFAULT ''::character varying NOT NULL,
|
||||
staff_notes character varying DEFAULT ''::character varying NOT NULL,
|
||||
is_active boolean DEFAULT true NOT NULL,
|
||||
created_at timestamp(6) without time zone NOT NULL,
|
||||
updated_at timestamp(6) without time zone NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: avoid_postings_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.avoid_postings_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: avoid_postings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.avoid_postings_id_seq OWNED BY public.avoid_postings.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: bans; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
@ -2408,6 +2481,20 @@ ALTER TABLE ONLY public.artist_versions ALTER COLUMN id SET DEFAULT nextval('pub
|
||||
ALTER TABLE ONLY public.artists ALTER COLUMN id SET DEFAULT nextval('public.artists_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: avoid_posting_versions id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.avoid_posting_versions ALTER COLUMN id SET DEFAULT nextval('public.avoid_posting_versions_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: avoid_postings id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.avoid_postings ALTER COLUMN id SET DEFAULT nextval('public.avoid_postings_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: bans id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
@ -2840,6 +2927,22 @@ ALTER TABLE ONLY public.artists
|
||||
ADD CONSTRAINT artists_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: avoid_posting_versions avoid_posting_versions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.avoid_posting_versions
|
||||
ADD CONSTRAINT avoid_posting_versions_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: avoid_postings avoid_postings_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.avoid_postings
|
||||
ADD CONSTRAINT avoid_postings_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: bans bans_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
@ -3410,6 +3513,41 @@ CREATE INDEX index_artists_on_name_trgm ON public.artists USING gin (name public
|
||||
CREATE INDEX index_artists_on_other_names ON public.artists USING gin (other_names);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_avoid_posting_versions_on_avoid_posting_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_avoid_posting_versions_on_avoid_posting_id ON public.avoid_posting_versions USING btree (avoid_posting_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_avoid_posting_versions_on_updater_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_avoid_posting_versions_on_updater_id ON public.avoid_posting_versions USING btree (updater_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_avoid_postings_on_artist_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE UNIQUE INDEX index_avoid_postings_on_artist_id ON public.avoid_postings USING btree (artist_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_avoid_postings_on_creator_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_avoid_postings_on_creator_id ON public.avoid_postings USING btree (creator_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_avoid_postings_on_updater_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_avoid_postings_on_updater_id ON public.avoid_postings USING btree (updater_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_bans_on_banner_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
@ -4427,6 +4565,14 @@ ALTER TABLE ONLY public.staff_audit_logs
|
||||
ADD CONSTRAINT fk_rails_02329e5ef9 FOREIGN KEY (user_id) REFERENCES public.users(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: avoid_posting_versions fk_rails_1d1f54e17a; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.avoid_posting_versions
|
||||
ADD CONSTRAINT fk_rails_1d1f54e17a FOREIGN KEY (updater_id) REFERENCES public.users(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: blips fk_rails_23e7479aac; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
@ -4443,6 +4589,14 @@ ALTER TABLE ONLY public.tickets
|
||||
ADD CONSTRAINT fk_rails_45cd696dba FOREIGN KEY (accused_id) REFERENCES public.users(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: avoid_posting_versions fk_rails_4c48affea5; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.avoid_posting_versions
|
||||
ADD CONSTRAINT fk_rails_4c48affea5 FOREIGN KEY (avoid_posting_id) REFERENCES public.avoid_postings(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: user_feedback fk_rails_9329a36823; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
@ -4467,6 +4621,14 @@ ALTER TABLE ONLY public.favorites
|
||||
ADD CONSTRAINT fk_rails_a7668ef613 FOREIGN KEY (user_id) REFERENCES public.users(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: avoid_postings fk_rails_b2ebf2bc30; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.avoid_postings
|
||||
ADD CONSTRAINT fk_rails_b2ebf2bc30 FOREIGN KEY (artist_id) REFERENCES public.artists(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: staff_notes fk_rails_bab7e2d92a; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
@ -4483,6 +4645,14 @@ ALTER TABLE ONLY public.post_events
|
||||
ADD CONSTRAINT fk_rails_bd327ccee6 FOREIGN KEY (creator_id) REFERENCES public.users(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: avoid_postings fk_rails_cccc6419c8; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.avoid_postings
|
||||
ADD CONSTRAINT fk_rails_cccc6419c8 FOREIGN KEY (updater_id) REFERENCES public.users(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: favorites fk_rails_d20e53bb68; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
@ -4491,6 +4661,14 @@ ALTER TABLE ONLY public.favorites
|
||||
ADD CONSTRAINT fk_rails_d20e53bb68 FOREIGN KEY (post_id) REFERENCES public.posts(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: avoid_postings fk_rails_d45cc0f1a1; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.avoid_postings
|
||||
ADD CONSTRAINT fk_rails_d45cc0f1a1 FOREIGN KEY (creator_id) REFERENCES public.users(id);
|
||||
|
||||
|
||||
--
|
||||
-- PostgreSQL database dump complete
|
||||
--
|
||||
@ -4501,6 +4679,8 @@ INSERT INTO "schema_migrations" (version) VALUES
|
||||
('20240726170041'),
|
||||
('20240709134926'),
|
||||
('20240706061122'),
|
||||
('20240103002049'),
|
||||
('20240103002040'),
|
||||
('20240101042716'),
|
||||
('20230531080817'),
|
||||
('20230518182034'),
|
||||
|
169
test/controllers/avoid_postings_controller_test.rb
Normal file
169
test/controllers/avoid_postings_controller_test.rb
Normal file
@ -0,0 +1,169 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
|
||||
class AvoidPostingsControllerTest < ActionDispatch::IntegrationTest
|
||||
context "The avoid postings controller" do
|
||||
setup do
|
||||
@user = create(:user)
|
||||
@bd_user = create(:bd_staff_user)
|
||||
CurrentUser.user = @user
|
||||
|
||||
as(@bd_user) do
|
||||
@avoid_posting = create(:avoid_posting)
|
||||
@artist = @avoid_posting.artist
|
||||
end
|
||||
end
|
||||
|
||||
context "index action" do
|
||||
should "render" do
|
||||
get_auth avoid_postings_path, @user
|
||||
assert_response :success
|
||||
end
|
||||
end
|
||||
|
||||
context "show action" do
|
||||
should "render" do
|
||||
get_auth avoid_posting_path(@avoid_posting), @user
|
||||
assert_response :success
|
||||
end
|
||||
end
|
||||
|
||||
context "edit action" do
|
||||
should "render" do
|
||||
get_auth edit_avoid_posting_path(@avoid_posting), @bd_user
|
||||
assert_response :success
|
||||
end
|
||||
end
|
||||
|
||||
context "new action" do
|
||||
should "render" do
|
||||
get_auth new_avoid_posting_path, @bd_user
|
||||
assert_response :success
|
||||
end
|
||||
end
|
||||
|
||||
context "create action" do
|
||||
should "work and create artist" do
|
||||
assert_difference(%w[AvoidPosting.count AvoidPostingVersion.count Artist.count], 1) do
|
||||
post_auth avoid_postings_path, @bd_user, params: { avoid_posting: { artist_attributes: { name: "another_artist" } } }
|
||||
end
|
||||
|
||||
artist = Artist.find_by(name: "another_artist")
|
||||
assert_not_nil(artist)
|
||||
avoid_posting = AvoidPosting.find_by(artist: artist)
|
||||
assert_not_nil(avoid_posting)
|
||||
assert_redirected_to(avoid_posting_path(avoid_posting))
|
||||
end
|
||||
|
||||
should "work with existing artist" do
|
||||
@artist = create(:artist)
|
||||
assert_difference(%w[AvoidPosting.count AvoidPostingVersion.count], 1) do
|
||||
post_auth avoid_postings_path, @bd_user, params: { avoid_posting: { artist_attributes: { name: @artist.name } } }
|
||||
end
|
||||
|
||||
avoid_posting = AvoidPosting.find_by(artist: @artist)
|
||||
assert_not_nil(avoid_posting)
|
||||
assert_redirected_to(avoid_posting_path(avoid_posting))
|
||||
end
|
||||
|
||||
should "merge other_names if already set" do
|
||||
@artist = create(:artist, other_names: %w[test1 test2])
|
||||
assert_difference(%w[AvoidPosting.count AvoidPostingVersion.count], 1) do
|
||||
post_auth avoid_postings_path, @bd_user, params: { avoid_posting: { artist_attributes: { name: @artist.name, other_names_string: "test2 test3" } } }
|
||||
end
|
||||
|
||||
@artist.reload
|
||||
avoid_posting = AvoidPosting.find_by(artist: @artist)
|
||||
assert_not_nil(avoid_posting)
|
||||
assert_equal(%w[test1 test2 test3], @artist.other_names)
|
||||
assert_redirected_to(avoid_posting_path(avoid_posting))
|
||||
end
|
||||
|
||||
should "reject linked_user_id if already set" do
|
||||
@artist = create(:artist, linked_user: @bd_user)
|
||||
assert_difference(%w[AvoidPosting.count AvoidPostingVersion.count], 1) do
|
||||
post_auth avoid_postings_path, @bd_user, params: { avoid_posting: { artist_attributes: { name: @artist.name, linked_user_id: create(:user).id } } }
|
||||
end
|
||||
|
||||
@artist.reload
|
||||
avoid_posting = AvoidPosting.find_by(artist: @artist)
|
||||
assert_not_nil(avoid_posting)
|
||||
assert_equal(@bd_user, @artist.linked_user)
|
||||
assert_redirected_to(avoid_posting_path(avoid_posting))
|
||||
end
|
||||
|
||||
should "not override existing artist properties with empty fields" do
|
||||
@artist = create(:artist, other_names: %w[test1 test2], group_name: "foobar", linked_user: @bd_user)
|
||||
assert_difference(%w[AvoidPosting.count AvoidPostingVersion.count], 1) do
|
||||
post_auth avoid_postings_path, @bd_user, params: { avoid_posting: { artist_attributes: { name: @artist.name, other_names: [], other_names_string: "", group_name: "", linked_user_id: "" } } }
|
||||
end
|
||||
|
||||
@artist.reload
|
||||
avoid_posting = AvoidPosting.find_by(artist: @artist)
|
||||
assert_not_nil(avoid_posting)
|
||||
assert_equal(%w[test1 test2], @artist.other_names)
|
||||
assert_equal("foobar", @artist.group_name)
|
||||
assert_equal(@bd_user, @artist.linked_user)
|
||||
assert_redirected_to(avoid_posting_path(avoid_posting))
|
||||
end
|
||||
end
|
||||
|
||||
context "update action" do
|
||||
should "work" do
|
||||
assert_difference(%w[ModAction.count AvoidPostingVersion.count], 1) do
|
||||
put_auth avoid_posting_path(@avoid_posting), @bd_user, params: { avoid_posting: { details: "test" } }
|
||||
end
|
||||
|
||||
assert_redirected_to(avoid_posting_path(@avoid_posting))
|
||||
assert_equal("avoid_posting_update", ModAction.last.action)
|
||||
assert_equal("test", @avoid_posting.reload.details)
|
||||
end
|
||||
|
||||
should "work with nested attributes" do
|
||||
assert_difference({ "ModAction.count" => 1, "AvoidPostingVersion.count" => 0 }) do
|
||||
put_auth avoid_posting_path(@avoid_posting), @bd_user, params: { avoid_posting: { artist_attributes: { id: @avoid_posting.artist.id, name: "foobar" } } }
|
||||
end
|
||||
|
||||
assert_redirected_to(avoid_posting_path(@avoid_posting))
|
||||
assert_equal("artist_page_rename", ModAction.last.action)
|
||||
assert_equal("foobar", @avoid_posting.artist.reload.name)
|
||||
end
|
||||
end
|
||||
|
||||
context "delete action" do
|
||||
should "work" do
|
||||
assert_difference(%w[ModAction.count AvoidPostingVersion.count], 1) do
|
||||
put_auth delete_avoid_posting_path(@avoid_posting), @bd_user
|
||||
end
|
||||
|
||||
assert_equal(false, @avoid_posting.reload.is_active?)
|
||||
assert_equal("avoid_posting_delete", ModAction.last.action)
|
||||
end
|
||||
end
|
||||
|
||||
context "undelete action" do
|
||||
should "work" do
|
||||
@avoid_posting.update_column(:is_active, false)
|
||||
|
||||
assert_difference(%w[ModAction.count AvoidPostingVersion.count], 1) do
|
||||
put_auth undelete_avoid_posting_path(@avoid_posting), @bd_user
|
||||
end
|
||||
|
||||
assert_equal(true, @avoid_posting.reload.is_active?)
|
||||
assert_equal("avoid_posting_undelete", ModAction.last.action)
|
||||
end
|
||||
end
|
||||
|
||||
context "destroy action" do
|
||||
should "work" do
|
||||
assert_difference({ "ModAction.count" => 1, "AvoidPosting.count" => -1 }) do
|
||||
delete_auth avoid_posting_path(@avoid_posting), @bd_user
|
||||
end
|
||||
|
||||
assert_nil(AvoidPosting.find_by(id: @avoid_posting.id))
|
||||
assert_equal("avoid_posting_destroy", ModAction.last.action)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
10
test/factories/avoid_posting.rb
Normal file
10
test/factories/avoid_posting.rb
Normal file
@ -0,0 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory(:avoid_posting) do
|
||||
association :artist
|
||||
is_active { true }
|
||||
association :creator, factory: :bd_staff_user
|
||||
creator_ip_addr { "127.0.0.1" }
|
||||
end
|
||||
end
|
@ -44,16 +44,19 @@ class ArtistsControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
should "create an artist" do
|
||||
context "when creating an artist" do
|
||||
should "work" do
|
||||
attributes = attributes_for(:artist)
|
||||
assert_difference("Artist.count", 1) do
|
||||
attributes.delete(:is_active)
|
||||
post_auth artists_path, @user, params: {artist: attributes}
|
||||
post_auth artists_path, @user, params: { artist: attributes }
|
||||
end
|
||||
|
||||
artist = Artist.find_by_name(attributes[:name])
|
||||
assert_not_nil(artist)
|
||||
assert_redirected_to(artist_path(artist.id))
|
||||
end
|
||||
end
|
||||
|
||||
context "with an artist that has notes" do
|
||||
setup do
|
||||
@ -134,5 +137,44 @@ class ArtistsControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_redirected_to(artist_path(@artist.id))
|
||||
end
|
||||
end
|
||||
|
||||
context "with a dnp entry" do
|
||||
setup do
|
||||
@bd_user = create(:bd_staff_user)
|
||||
CurrentUser.user = @bd_user
|
||||
@avoid_posting = create(:avoid_posting, artist: @artist)
|
||||
end
|
||||
|
||||
should "not allow destroying" do
|
||||
assert_no_difference("Artist.count") do
|
||||
delete_auth artist_path(@artist), @bd_user
|
||||
end
|
||||
end
|
||||
|
||||
# technical restriction
|
||||
should "not allow destroying even if the dnp is inactive" do
|
||||
@avoid_posting.update(is_active: false)
|
||||
assert_no_difference("Artist.count") do
|
||||
delete_auth artist_path(@artist), @bd_user
|
||||
end
|
||||
end
|
||||
|
||||
should "not allow editing protected properties" do
|
||||
@janitor = create(:janitor_user)
|
||||
name = @artist.name
|
||||
group_name = @artist.group_name
|
||||
other_names = @artist.other_names
|
||||
assert_no_difference("ModAction.count") do
|
||||
put_auth artist_path(@artist), @janitor, params: { artist: { name: "another_name", group_name: "some_group", other_names: "some other names" } }
|
||||
end
|
||||
|
||||
@artist.reload
|
||||
assert_equal(name, @artist.name)
|
||||
assert_equal(group_name, @artist.group_name)
|
||||
assert_equal(other_names, @artist.other_names)
|
||||
assert_equal(name, @artist.wiki_page.reload.title)
|
||||
assert_equal(name, @avoid_posting.reload.artist_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
69
test/unit/avoid_posting_test.rb
Normal file
69
test/unit/avoid_posting_test.rb
Normal file
@ -0,0 +1,69 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
|
||||
class AvoidPostingTest < ActiveSupport::TestCase
|
||||
context "An avoid posting entry" do
|
||||
setup do
|
||||
@bd_user = create(:bd_staff_user)
|
||||
CurrentUser.user = @bd_user
|
||||
@avoid_posting = create(:avoid_posting)
|
||||
end
|
||||
|
||||
should "create an artist" do
|
||||
assert_difference("Artist.count", 1) do
|
||||
create(:avoid_posting)
|
||||
end
|
||||
end
|
||||
|
||||
should "create a create modaction" do
|
||||
assert_difference("ModAction.count", 1) do
|
||||
create(:avoid_posting)
|
||||
end
|
||||
|
||||
assert_equal("avoid_posting_create", ModAction.last.action)
|
||||
end
|
||||
|
||||
should "create an update modaction" do
|
||||
assert_difference("ModAction.count", 1) do
|
||||
@avoid_posting.update(details: "test")
|
||||
end
|
||||
|
||||
assert_equal("avoid_posting_update", ModAction.last.action)
|
||||
end
|
||||
|
||||
should "create a delete modaction" do
|
||||
assert_difference("ModAction.count", 1) do
|
||||
@avoid_posting.update(is_active: false)
|
||||
end
|
||||
|
||||
assert_equal("avoid_posting_delete", ModAction.last.action)
|
||||
end
|
||||
|
||||
should "create an undelete modaction" do
|
||||
@avoid_posting.update_column(:is_active, false)
|
||||
|
||||
assert_difference("ModAction.count", 1) do
|
||||
@avoid_posting.update(is_active: true)
|
||||
end
|
||||
|
||||
assert_equal("avoid_posting_undelete", ModAction.last.action)
|
||||
end
|
||||
|
||||
should "create a destroy modaction" do
|
||||
assert_difference("ModAction.count", 1) do
|
||||
@avoid_posting.destroy
|
||||
end
|
||||
|
||||
assert_equal("avoid_posting_destroy", ModAction.last.action)
|
||||
end
|
||||
|
||||
should "create a version when updated" do
|
||||
assert_difference("AvoidPostingVersion.count", 1) do
|
||||
@avoid_posting.update(details: "test")
|
||||
end
|
||||
|
||||
assert_equal("test", AvoidPostingVersion.last.details)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user