add title support

This commit is contained in:
edshot99 2024-10-30 18:52:53 -05:00
parent a3e00b591f
commit b7fee5fe2f
26 changed files with 177 additions and 9 deletions

View File

@ -168,6 +168,7 @@ class PostsController < ApplicationController
tag_string_diff source_diff
parent_id old_parent_id
source old_source
title old_title
description old_description
rating old_rating
edit_reason

View File

@ -72,7 +72,7 @@ class UploadsController < ApplicationController
def upload_params
permitted_params = %i[
file direct_url source tag_string rating parent_id description description as_pending
file direct_url source tag_string rating parent_id title description description as_pending
]
permitted_params << :locked_tags if CurrentUser.is_admin?

View File

@ -50,13 +50,15 @@ class PostsDecorator < ApplicationDecorator
status_flags << 'U' if post.is_pending?
status_flags << 'F' if post.is_flagged?
title = t.tag.span(post.title, class: "post-score-title")
title = title + t.tag.br if post.title.present?
post_score_icon = "#{'↑' if post.score > 0}#{'↓' if post.score < 0}#{'↕' if post.score == 0}"
score = t.tag.span("#{post_score_icon}#{post.score}", class: "post-score-score #{score_class(post.score)}")
favs = t.tag.span("#{post.fav_count}", class: "post-score-faves")
comments = t.tag.span "C#{post.visible_comment_count(CurrentUser)}", class: 'post-score-comments'
rating = t.tag.span(post.rating.upcase, class: "post-score-rating")
status = t.tag.span(status_flags.join(''), class: 'post-score-extras')
t.tag.div score + favs + comments + rating + status, class: 'post-score', id: "post-score-#{post.id}"
t.tag.div title + score + favs + comments + rating + status, class: 'post-score', id: "post-score-#{post.id}"
end
def preview_html(t, options = {})

View File

@ -61,6 +61,7 @@ module PostIndex
rating: { type: "keyword" },
file_ext: { type: "keyword" },
source: { type: "keyword" },
title: { type: "text" },
description: { type: "text" },
notes: { type: "text" },
del_reason: { type: "keyword" },
@ -273,6 +274,7 @@ module PostIndex
rating: rating,
file_ext: file_ext,
source: source_array,
title: title.present? ? title : nil,
description: description.present? ? description : nil,
rating_locked: is_rating_locked,

View File

@ -19,9 +19,11 @@ module PostVersionIndex
parent_id: { type: "integer" },
rating: { type: "keyword" },
source: { type: "keyword" },
title: { type: "text" },
description: { type: "text" },
reason: { type: "text" },
title_changed: { type: "boolean" },
description_changed: { type: "boolean" },
parent_id_changed: { type: "boolean" },
source_changed: { type: "boolean" },
@ -80,9 +82,11 @@ module PostVersionIndex
parent_id: parent_id,
rating: rating,
source: source,
title: title,
description: description,
reason: reason,
title_changed: title_changed,
description_changed: description_changed,
parent_id_changed: parent_changed,
source_changed: source_changed,

View File

@ -199,6 +199,14 @@
<label><input type="checkbox" v-model="ratingLocked"/> Lock Rating</label>
</div>
</div>
<div class="flex-grid border-bottom">
<div class="col">
<label class="section-label" for="post_title">Title</label>
</div>
<div class="col2">
<textarea spellcheck="true" class="tag-textarea" v-model="title" id="post_title"></textarea>
</div>
</div>
<div class="flex-grid border-bottom">
<div class="col">
<label class="section-label" for="post_description">Description</label>
@ -371,6 +379,7 @@
loadingRelated: false,
parentID: '',
title: '',
description: '',
rating: '',
error: '',
@ -426,6 +435,7 @@
};
fillField('parentID', 'parent');
fillField('title', 'title');
fillField('description', 'description');
fillTags();
fillRating();
@ -459,6 +469,7 @@
data.append('upload[tag_string]', this.tags);
data.append('upload[rating]', this.rating);
data.append('upload[source]', this.sources.join('\n'));
data.append('upload[title]', this.title);
data.append('upload[description]', this.description);
data.append('upload[parent_id]', this.parentID);
if (this.allowLockedTags)

View File

@ -106,14 +106,25 @@ div#c-post-versions {
@include grid-border(righ);
}
.pv-title-label {
grid-row: 1;
@include grid-col(7, 8);
}
.pv-title {
grid-row: 2;
@include grid-col(7, 8);
@include grid-border(right);
}
.pv-description-label {
grid-row: 1;
@include grid-col(7, 9);
@include grid-col(8, 9);
}
.pv-description {
grid-row: 2;
@include grid-col(7, 9);
@include grid-col(8, 9);
@include grid-border(right);
}

View File

@ -108,6 +108,7 @@ class ElasticPostQueryBuilder < ElasticQueryBuilder
add_array_relation(:rating, :rating)
add_array_relation(:filetype, :file_ext)
add_array_relation(:delreason, :del_reason, action: :wildcard)
add_array_relation(:title, :title, action: :match_phrase_prefix)
add_array_relation(:description, :description, action: :match_phrase_prefix)
add_array_relation(:note, :notes, action: :match_phrase_prefix)
add_array_relation(:sources, :source, any_none_key: :source, action: :wildcard)
@ -149,6 +150,10 @@ class ElasticPostQueryBuilder < ElasticQueryBuilder
(q[:hassource] ? must : must_not).push({exists: {field: :source}})
end
if q.include?(:hastitle)
(q[:hastitle] ? must : must_not).push({exists: {field: :title}})
end
if q.include?(:hasdescription)
(q[:hasdescription] ? must : must_not).push({exists: {field: :description}})
end

View File

@ -8,11 +8,11 @@ class TagQuery
].freeze
BOOLEAN_METATAGS = %w[
hassource hasdescription isparent ischild inpool pending_replacements artverified
hassource hastitle hasdescription isparent ischild inpool pending_replacements artverified
].freeze
NEGATABLE_METATAGS = %w[
id filetype type rating description parent user user_id approver flagger deletedby delreason
id filetype type rating title description parent user user_id approver flagger deletedby delreason
source status pool set fav favoritedby note locked upvote votedup downvote voteddown voted
width height mpixels ratio filesize duration score favcount date age change tagcount
commenter comm noter noteupdater
@ -290,6 +290,9 @@ class TagQuery
when "filetype", "-filetype", "~filetype", "type", "-type", "~type"
add_to_query(type, :filetype) { g2.downcase }
when "title", "-title", "~title"
add_to_query(type, :title) { g2 }
when "description", "-description", "~description"
add_to_query(type, :description) { g2 }

View File

@ -51,6 +51,7 @@ class UploadService
p.tag_string = upload.tag_string
p.locked_tags = upload.locked_tags
p.is_rating_locked = upload.locked_rating if upload.locked_rating.present?
p.title = upload.title.strip
p.description = upload.description.strip
p.md5 = upload.md5
p.file_ext = upload.file_ext

View File

@ -21,6 +21,7 @@ class Post < ApplicationRecord
validates :md5, uniqueness: { :on => :create, message: ->(obj, data) {"duplicate: #{Post.find_by_md5(obj.md5).id}"} }
validates :rating, inclusion: { in: %w(s q e), message: "rating must be s, q, or e" }
validates :bg_color, format: { with: /\A[A-Fa-f0-9]{6}\z/ }, allow_nil: true
validates :title, length: { maximum: Danbooru.config.post_title_max_size }, if: :title_changed?
validates :description, length: { maximum: Danbooru.config.post_descr_max_size }, if: :description_changed?
validate :added_tags_are_valid, if: :should_process_tags?
validate :removed_tags_are_valid, if: :should_process_tags?
@ -1174,6 +1175,7 @@ class Post < ApplicationRecord
def backup_post_data_destroy(reason: "")
post_data = {
id: id,
title: title,
description: description,
md5: md5,
tags: tag_string,
@ -1324,7 +1326,7 @@ class Post < ApplicationRecord
end
def saved_change_to_watched_attributes?
saved_change_to_rating? || saved_change_to_source? || saved_change_to_parent_id? || saved_change_to_tag_string? || saved_change_to_locked_tags? || saved_change_to_description?
saved_change_to_rating? || saved_change_to_source? || saved_change_to_parent_id? || saved_change_to_tag_string? || saved_change_to_locked_tags? || saved_change_to_title? || saved_change_to_description?
end
def create_new_version
@ -1342,6 +1344,7 @@ class Post < ApplicationRecord
self.rating = target.rating
self.source = target.source
self.parent_id = target.parent_id
self.title = target.title
self.description = target.description
self.edit_reason = "Revert to version #{target.version}"
end

View File

@ -247,6 +247,7 @@ class PostReplacement < ApplicationRecord
rating: post.rating,
source: "#{self.source}\n" + post.source,
parent_id: post.id,
title: post.title,
description: post.description,
locked_tags: post.locked_tags,
replacement_id: self.id

View File

@ -94,10 +94,15 @@ class PostVersion < ApplicationRecord
must << { match: { reason: params[:reason] } }
end
if params[:title].present?
must << { match: { title: params[:title] } }
end
if params[:description].present?
must << { match: { description: params[:description] } }
end
must = boolean_match(:title_changed, params[:title_changed], must)
must = boolean_match(:description_changed, params[:description_changed], must)
must = boolean_match(:source_changed, params[:source_changed], must)
@ -172,6 +177,7 @@ class PostVersion < ApplicationRecord
updater_ip_addr: CurrentUser.ip_addr,
tags: post.tag_string,
locked_tags: post.locked_tags,
title: post.title,
description: post.description,
reason: post.edit_reason
})
@ -203,6 +209,7 @@ class PostVersion < ApplicationRecord
self.rating_changed = prev.nil? || rating != prev.try(:rating)
self.parent_changed = prev.nil? || parent_id != prev.try(:parent_id)
self.source_changed = prev.nil? || source != prev.try(:source)
self.title_changed = prev.nil? || title != prev.try(:title)
self.description_changed = prev.nil? || description != prev.try(:description)
end
@ -346,6 +353,10 @@ class PostVersion < ApplicationRecord
def undo
raise UndoError, "Version 1 is not undoable" unless undoable?
if title_changed
post.title = previous.title
end
if description_changed
post.description = previous.description
end

View File

@ -148,6 +148,7 @@ class PostPresenter < Presenter
comment_count: post.visible_comment_count(CurrentUser),
change_seq: post.change_seq,
uploader_id: post.uploader_id,
title: post.title,
description: post.description,
flags: {
pending: post.is_pending,

View File

@ -138,6 +138,6 @@ class PostSerializer < ActiveModel::Serializer
end
attributes :id, :created_at, :updated_at, :file, :preview, :sample, :score, :tags, :locked_tags, :change_seq, :flags,
:rating, :fav_count, :sources, :pools, :relationships, :approver_id, :uploader_id, :description,
:rating, :fav_count, :sources, :pools, :relationships, :approver_id, :uploader_id, :title, :description,
:comment_count, :is_favorited, :has_notes, :duration
end

View File

@ -15,6 +15,9 @@
<div class="pv-reason-label pv-label">
Reason
</div>
<div class="pv-title-label pv-label">
Title
</div>
<div class="pv-description-label pv-label">
Description
</div>
@ -37,6 +40,21 @@
<div class="pv-reason pv-content">
<%= post_version.reason %>
</div>
<div class="pv-title pv-content">
<% if post_version.title.present? %>
<div class="desc-show">
<%= post_version.title_changed ? "Show Title" : "No change" %></div>
<div id='title-<%= post_version.id %>' class='desc-popup box-section'>
<h2>Title</h2>
<div class="closebutton">X</div>
<div class='desc-popup-inner'>
<p class="dtext-container"><%= format_text(post_version.title) %></p>
</div>
</div>
<% elsif post_version.title_changed && post_version.version != 1%>
<em>Cleared</em>
<% end %>
</div>
<div class="pv-description pv-content">
<% if post_version.description.present? %>
<div class="desc-show">

View File

@ -2,6 +2,8 @@
<%= f.user :updater, label: "User" %>
<%= f.input :post_id, label: "Post #" %>
<%= f.input :reason, label: "Reason" %>
<%= f.input :title, label: "Title" %>
<%= f.input :title_changed, label: "Title Changed", collection: [%w[Yes true], %w[No false]], include_blank: true %>
<%= f.input :description, label: "Description" %>
<%= f.input :description_changed, label: "Description Changed", collection: [%w[Yes true], %w[No false]], include_blank: true %>
<%= f.input :rating_changed, label: "Rating Changed To", collection: rating_collection + [%w[Any any]], include_blank: true %>

View File

@ -40,6 +40,7 @@
<%= f.input :parent_id, as: :string, label: "Parent", input_html: { size: 5 } %>
<%= f.input :source, as: :text, label: "Sources", input_html: { size: "60x5", spellcheck: false } %>
<%= f.input :title, as: :text, label: "Title", input_html: { size: "60x5", spellcheck: true } %>
<div class="input">
<%= f.input :description, as: :dtext, limit: Danbooru.config.post_descr_max_size, allow_color: true %>

View File

@ -172,6 +172,17 @@
<% end %>
</section>
<% if @post.title.present? %>
<div id="post-title-container" class="styled-dtext">
<details id="title" <%= 'open' %>>
<summary>Title</summary>
<div>
<%= format_text(@post.title, max_thumbs: 0) %>
</div>
</details>
</div>
<% end %>
<% if @post.description.present? %>
<div id="post-description-container" class="styled-dtext">
<details id="description" <%= 'open' unless CurrentUser.description_collapsed_initially? %>>

View File

@ -317,6 +317,10 @@ module Danbooru
10_000
end
def post_title_max_size
128
end
def post_descr_max_size
50_000
end

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddTitleToPosts < ActiveRecord::Migration[7.1]
def change
add_column(:posts, :title, :text, null: false, default: '')
end
end

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddTitleToPostVersions < ActiveRecord::Migration[7.1]
def change
add_column :post_versions, :title, :text
end
end

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddTitleChangedToPostVersions < ActiveRecord::Migration[7.1]
def change
add_column(:post_versions, :title_changed, :boolean, null: false, default: false)
end
end

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddTitleToUploads < ActiveRecord::Migration[7.1]
def change
add_column(:uploads, :title, :text, null: false, default: '')
end
end

View File

@ -0,0 +1,39 @@
# frozen_string_literal: true
class UpdatePostsTriggerChangeSeq < ActiveRecord::Migration[7.1]
def up
execute <<-SQL
CREATE OR REPLACE FUNCTION public.posts_trigger_change_seq() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF NEW.tag_string != OLD.tag_string OR NEW.parent_id != OLD.parent_id OR NEW.source != OLD.source OR NEW.approver_id != OLD.approver_id OR NEW.rating != OLD.rating OR NEW.title != OLD.title OR NEW.description != OLD.description OR NEW.md5 != OLD.md5 OR NEW.is_deleted != OLD.is_deleted OR NEW.is_pending != OLD.is_pending OR NEW.is_flagged != OLD.is_flagged OR NEW.is_rating_locked != OLD.is_rating_locked OR NEW.is_status_locked != OLD.is_status_locked OR NEW.is_note_locked != OLD.is_note_locked OR NEW.bit_flags != OLD.bit_flags OR NEW.has_active_children != OLD.has_active_children OR NEW.last_noted_at != OLD.last_noted_at
THEN
NEW.change_seq = nextval('public.posts_change_seq_seq');
END IF;
RETURN NEW;
END;
$$;
SQL
end
def down
execute <<-SQL
CREATE OR REPLACE FUNCTION public.posts_trigger_change_seq() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF NEW.tag_string != OLD.tag_string OR NEW.parent_id != OLD.parent_id OR NEW.source != OLD.source OR NEW.approver_id != OLD.approver_id OR NEW.rating != OLD.rating OR NEW.description != OLD.description OR NEW.md5 != OLD.md5 OR NEW.is_deleted != OLD.is_deleted OR NEW.is_pending != OLD.is_pending OR NEW.is_flagged != OLD.is_flagged OR NEW.is_rating_locked != OLD.is_rating_locked OR NEW.is_status_locked != OLD.is_status_locked OR NEW.is_note_locked != OLD.is_note_locked OR NEW.bit_flags != OLD.bit_flags OR NEW.has_active_children != OLD.has_active_children OR NEW.last_noted_at != OLD.last_noted_at
THEN
NEW.change_seq = nextval('public.posts_change_seq_seq');
END IF;
RETURN NEW;
END;
$$;
SQL
end
end

View File

@ -31,7 +31,7 @@ CREATE FUNCTION public.posts_trigger_change_seq() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF NEW.tag_string != OLD.tag_string OR NEW.parent_id != OLD.parent_id OR NEW.source != OLD.source OR NEW.approver_id != OLD.approver_id OR NEW.rating != OLD.rating OR NEW.description != OLD.description OR NEW.md5 != OLD.md5 OR NEW.is_deleted != OLD.is_deleted OR NEW.is_pending != OLD.is_pending OR NEW.is_flagged != OLD.is_flagged OR NEW.is_rating_locked != OLD.is_rating_locked OR NEW.is_status_locked != OLD.is_status_locked OR NEW.is_note_locked != OLD.is_note_locked OR NEW.bit_flags != OLD.bit_flags OR NEW.has_active_children != OLD.has_active_children OR NEW.last_noted_at != OLD.last_noted_at
IF NEW.tag_string != OLD.tag_string OR NEW.parent_id != OLD.parent_id OR NEW.source != OLD.source OR NEW.approver_id != OLD.approver_id OR NEW.rating != OLD.rating OR NEW.title != OLD.title OR NEW.description != OLD.description OR NEW.md5 != OLD.md5 OR NEW.is_deleted != OLD.is_deleted OR NEW.is_pending != OLD.is_pending OR NEW.is_flagged != OLD.is_flagged OR NEW.is_rating_locked != OLD.is_rating_locked OR NEW.is_status_locked != OLD.is_status_locked OR NEW.is_note_locked != OLD.is_note_locked OR NEW.bit_flags != OLD.bit_flags OR NEW.has_active_children != OLD.has_active_children OR NEW.last_noted_at != OLD.last_noted_at
THEN
NEW.change_seq = nextval('public.posts_change_seq_seq');
END IF;
@ -1570,6 +1570,8 @@ CREATE TABLE public.post_versions (
parent_changed boolean DEFAULT false NOT NULL,
source text,
source_changed boolean DEFAULT false NOT NULL,
title text,
title_changed boolean DEFAULT false NOT NULL,
description text,
description_changed boolean DEFAULT false NOT NULL,
version integer DEFAULT 1 NOT NULL,
@ -1678,6 +1680,7 @@ CREATE TABLE public.posts (
locked_tags text,
tag_count_species integer DEFAULT 0 NOT NULL,
tag_count_invalid integer DEFAULT 0 NOT NULL,
title text DEFAULT ''::text NOT NULL,
description text DEFAULT ''::text NOT NULL,
comment_count integer DEFAULT 0 NOT NULL,
change_seq bigint NOT NULL,
@ -2136,6 +2139,7 @@ CREATE TABLE public.uploads (
file_size integer,
image_width integer,
image_height integer,
title text DEFAULT ''::text NOT NULL,
description text DEFAULT ''::text NOT NULL
);
@ -4677,6 +4681,11 @@ ALTER TABLE ONLY public.avoid_postings
SET search_path TO "$user", public;
INSERT INTO "schema_migrations" (version) VALUES
('20241029202902'),
('20241010174014'),
('20241009155325'),
('20241009155301'),
('20241009023749'),
('20241001045543'),
('20240726170041'),
('20240709134926'),