rubocop: fix various Rubocop warnings.

This commit is contained in:
evazion
2021-06-16 18:24:42 -05:00
parent cfe471e0b5
commit 07e23204b6
99 changed files with 412 additions and 374 deletions

View File

@@ -18,6 +18,9 @@ Layout/CaseIndentation:
Layout/EmptyLineAfterGuardClause: Layout/EmptyLineAfterGuardClause:
Enabled: false Enabled: false
Layout/EmptyLineBetweenDefs:
AllowAdjacentOneLineDefs: true
Layout/EndAlignment: Layout/EndAlignment:
EnforcedStyleAlignWith: variable EnforcedStyleAlignWith: variable
@@ -44,7 +47,7 @@ Metrics/AbcSize:
Metrics/BlockLength: Metrics/BlockLength:
Max: 50 Max: 50
ExcludedMethods: IgnoredMethods:
- concerning - concerning
- context - context
- should - should
@@ -66,7 +69,7 @@ Metrics/ModuleLength:
Max: 500 Max: 500
Metrics/ParameterLists: Metrics/ParameterLists:
Max: 4 Max: 6
Metrics/PerceivedComplexity: Metrics/PerceivedComplexity:
Max: 20 Max: 20
@@ -74,18 +77,43 @@ Metrics/PerceivedComplexity:
Lint/InheritException: Lint/InheritException:
EnforcedStyle: standard_error EnforcedStyle: standard_error
Naming/HeredocDelimiterNaming:
Enabled: false
Naming/MethodParameterName: Naming/MethodParameterName:
Enabled: false Enabled: false
Naming/PredicateName:
Enabled: false
Rails/Blank:
UnlessPresent: false
Rails/DynamicFindBy:
Enabled: false
Rails/HasManyOrHasOneDependent:
Enabled: false
Rails/HttpStatus: Rails/HttpStatus:
EnforcedStyle: numeric EnforcedStyle: numeric
Rails/InverseOf:
Enabled: false
Style/Alias:
EnforcedStyle: prefer_alias_method
Style/AsciiComments: Style/AsciiComments:
Enabled: false Enabled: false
Style/CommentAnnotation: Style/CommentAnnotation:
Enabled: false Enabled: false
Style/ConditionalAssignment:
EnforcedStyle: assign_inside_condition
IncludeTernaryExpressions: false
Style/Documentation: Style/Documentation:
Enabled: false Enabled: false
@@ -104,6 +132,9 @@ Style/FloatDivision:
Style/FrozenStringLiteralComment: Style/FrozenStringLiteralComment:
Enabled: false Enabled: false
Style/GuardClause:
MinBodyLength: 20
Style/HashSyntax: Style/HashSyntax:
Enabled: false Enabled: false
@@ -113,12 +144,20 @@ Style/IfUnlessModifier:
Style/MutableConstant: Style/MutableConstant:
Enabled: false Enabled: false
Style/NegatedIf:
Enabled: false
Style/NumericPredicate: Style/NumericPredicate:
Enabled: false Enabled: false
Style/PercentLiteralDelimiters: Style/PercentLiteralDelimiters:
PreferredDelimiters: PreferredDelimiters:
"default": "[]" "default": "{}"
"%i": "[]"
"%I": "[]"
"%w": "[]"
"%W": "[]"
"%r": "{}"
Style/ParallelAssignment: Style/ParallelAssignment:
Enabled: false Enabled: false
@@ -134,7 +173,7 @@ Style/SpecialGlobalVars:
Enabled: false Enabled: false
Style/StringLiterals: Style/StringLiterals:
Enabled: false EnforcedStyle: double_quotes
Style/StringLiteralsInInterpolation: Style/StringLiteralsInInterpolation:
Enabled: false Enabled: false
@@ -142,8 +181,18 @@ Style/StringLiteralsInInterpolation:
Style/SymbolArray: Style/SymbolArray:
MinSize: 10 MinSize: 10
Style/SymbolProc:
IgnoredMethods:
- respond_with
Style/TernaryParentheses: Style/TernaryParentheses:
EnforcedStyle: require_parentheses_when_complex EnforcedStyle: require_parentheses_when_complex
Style/TrailingCommaInArrayLiteral:
EnforcedStyleForMultiline: consistent_comma
Style/TrailingCommaInHashLiteral:
EnforcedStyleForMultiline: consistent_comma
Style/WordArray: Style/WordArray:
MinSize: 10 MinSize: 10

View File

@@ -1,7 +1,6 @@
class ApplicationComponent < ViewComponent::Base class ApplicationComponent < ViewComponent::Base
delegate :link_to_user, :time_ago_in_words_tagged, :format_text, :external_link_to, :tag_class, to: :helpers delegate :link_to_user, :time_ago_in_words_tagged, :format_text, :external_link_to, :tag_class, to: :helpers
delegate :edit_icon, :delete_icon, :undelete_icon, :flag_icon, :upvote_icon, delegate :edit_icon, :delete_icon, :undelete_icon, :flag_icon, :upvote_icon, :downvote_icon, :link_icon, :sticky_icon, :unsticky_icon, to: :helpers
:downvote_icon, :link_icon, :sticky_icon, :unsticky_icon, to: :helpers
def policy(subject) def policy(subject)
Pundit.policy!(current_user, subject) Pundit.policy!(current_user, subject)

View File

@@ -4,6 +4,7 @@ class CommentComponent < ApplicationComponent
attr_reader :comment, :context, :dtext_data, :current_user attr_reader :comment, :context, :dtext_data, :current_user
def initialize(comment:, current_user:, context: nil, dtext_data: nil) def initialize(comment:, current_user:, context: nil, dtext_data: nil)
super
@comment = comment @comment = comment
@context = context @context = context
@dtext_data = dtext_data @dtext_data = dtext_data
@@ -11,7 +12,7 @@ class CommentComponent < ApplicationComponent
end end
def dimmed? def dimmed?
comment.is_deleted? || (!comment.is_sticky? && comment.score <= current_user.comment_threshold/2.0) comment.is_deleted? || (!comment.is_sticky? && comment.score <= current_user.comment_threshold / 2.0)
end end
def thresholded? def thresholded?

View File

@@ -4,6 +4,7 @@ class CommentSectionComponent < ApplicationComponent
attr_reader :post, :comments, :current_user, :limit, :dtext_data attr_reader :post, :comments, :current_user, :limit, :dtext_data
def initialize(post:, current_user:, limit: nil) def initialize(post:, current_user:, limit: nil)
super
@post = post @post = post
@current_user = current_user @current_user = current_user
@limit = limit @limit = limit

View File

@@ -2,6 +2,7 @@
class ForumPostComponent < ApplicationComponent class ForumPostComponent < ApplicationComponent
attr_reader :forum_post, :original_forum_post_id, :dtext_data, :moderation_reports, :current_user attr_reader :forum_post, :original_forum_post_id, :dtext_data, :moderation_reports, :current_user
delegate :link_to_user, :time_ago_in_words_tagged, :format_text, :policy, to: :helpers delegate :link_to_user, :time_ago_in_words_tagged, :format_text, :policy, to: :helpers
with_collection_parameter :forum_post with_collection_parameter :forum_post
@@ -17,6 +18,7 @@ class ForumPostComponent < ApplicationComponent
end end
def initialize(forum_post:, original_forum_post_id: nil, dtext_data: nil, current_user: User.anonymous) def initialize(forum_post:, original_forum_post_id: nil, dtext_data: nil, current_user: User.anonymous)
super
@forum_post = forum_post @forum_post = forum_post
@original_forum_post_id = original_forum_post_id @original_forum_post_id = original_forum_post_id
@dtext_data = dtext_data @dtext_data = dtext_data

View File

@@ -23,6 +23,7 @@
<% if policy(forum_post).create? %> <% if policy(forum_post).create? %>
<li><%= link_to "Reply", new_forum_post_path(post_id: forum_post.id), method: :get, remote: true %></li> <li><%= link_to "Reply", new_forum_post_path(post_id: forum_post.id), method: :get, remote: true %></li>
<% end %> <% end %>
<% if policy(forum_post).destroy? && !forum_post.is_original_post?(original_forum_post_id) %> <% if policy(forum_post).destroy? && !forum_post.is_original_post?(original_forum_post_id) %>
<% if forum_post.is_deleted %> <% if forum_post.is_deleted %>
<li><%= link_to "Undelete", undelete_forum_post_path(forum_post.id), method: :post, remote: true %></li> <li><%= link_to "Undelete", undelete_forum_post_path(forum_post.id), method: :post, remote: true %></li>
@@ -30,6 +31,7 @@
<li><%= link_to "Delete", forum_post_path(forum_post.id), "data-confirm": "Are you sure you want to delete this forum post?", method: :delete, remote: true %></li> <li><%= link_to "Delete", forum_post_path(forum_post.id), "data-confirm": "Are you sure you want to delete this forum post?", method: :delete, remote: true %></li>
<% end %> <% end %>
<% end %> <% end %>
<% if policy(forum_post).update? %> <% if policy(forum_post).update? %>
<% if forum_post.is_original_post?(original_forum_post_id) %> <% if forum_post.is_original_post?(original_forum_post_id) %>
<li><%= link_to "Edit", edit_forum_topic_path(forum_post.topic), id: "edit_forum_topic_link_#{forum_post.topic.id}", class: "edit_forum_topic_link" %></li> <li><%= link_to "Edit", edit_forum_topic_path(forum_post.topic), id: "edit_forum_topic_link_#{forum_post.topic.id}", class: "edit_forum_topic_link" %></li>
@@ -37,12 +39,15 @@
<li><%= link_to "Edit", edit_forum_post_path(forum_post.id), id: "edit_forum_post_link_#{forum_post.id}", class: "edit_forum_post_link" %></li> <li><%= link_to "Edit", edit_forum_post_path(forum_post.id), id: "edit_forum_post_link_#{forum_post.id}", class: "edit_forum_post_link" %></li>
<% end %> <% end %>
<% end %> <% end %>
<% if policy(forum_post).reportable? %> <% if policy(forum_post).reportable? %>
<li><%= link_to "Report", new_moderation_report_path(moderation_report: { model_type: "ForumPost", model_id: forum_post.id }), remote: true, title: "Report this forum post to the moderators" %></li> <li><%= link_to "Report", new_moderation_report_path(moderation_report: { model_type: "ForumPost", model_id: forum_post.id }), remote: true, title: "Report this forum post to the moderators" %></li>
<% end %> <% end %>
<% if has_moderation_reports? %> <% if has_moderation_reports? %>
<li class="moderation-report-notice">Reported (<%= link_to pluralize(forum_post.moderation_reports.length, "report"), moderation_reports_path(search: { model_type: "ForumPost", model_id: forum_post.id }) %>)</li> <li class="moderation-report-notice">Reported (<%= link_to pluralize(forum_post.moderation_reports.length, "report"), moderation_reports_path(search: { model_type: "ForumPost", model_id: forum_post.id }) %>)</li>
<% end %> <% end %>
<% if forum_post.bulk_update_request.present? %> <% if forum_post.bulk_update_request.present? %>
<menu class="votes" id="forum-post-votes-for-<%= forum_post.id %>"> <menu class="votes" id="forum-post-votes-for-<%= forum_post.id %>">
<%= render "forum_post_votes/list", votes: forum_post.votes, forum_post: forum_post %> <%= render "forum_post_votes/list", votes: forum_post.votes, forum_post: forum_post %>

View File

@@ -2,10 +2,12 @@
class PaginatorComponent < ApplicationComponent class PaginatorComponent < ApplicationComponent
attr_reader :records, :window, :params attr_reader :records, :window, :params
delegate :current_page, :prev_page, :next_page, :total_pages, :paginator_mode, :paginator_page_limit, to: :records delegate :current_page, :prev_page, :next_page, :total_pages, :paginator_mode, :paginator_page_limit, to: :records
delegate :ellipsis_icon, :chevron_left_icon, :chevron_right_icon, to: :helpers delegate :ellipsis_icon, :chevron_left_icon, :chevron_right_icon, to: :helpers
def initialize(records:, params:, window: 4) def initialize(records:, params:, window: 4)
super
@records = records @records = records
@window = window @window = window
@params = params @params = params
@@ -25,7 +27,7 @@ class PaginatorComponent < ApplicationComponent
("..." unless left == 2), ("..." unless left == 2),
(left..right).to_a, (left..right).to_a,
("..." unless right == last_page - 1), ("..." unless right == last_page - 1),
(last_page unless last_page == 1) (last_page unless last_page == 1),
].flatten.compact ].flatten.compact
end end

View File

@@ -4,6 +4,7 @@ class PostNavbarComponent < ApplicationComponent
attr_reader :post, :current_user, :search attr_reader :post, :current_user, :search
def initialize(post:, current_user:, search: nil) def initialize(post:, current_user:, search: nil)
super
@post = post @post = post
@current_user = current_user @current_user = current_user
@search = search.presence || "status:any" @search = search.presence || "status:any"

View File

@@ -4,9 +4,11 @@ class PostPreviewComponent < ApplicationComponent
with_collection_parameter :post with_collection_parameter :post
attr_reader :post, :tags, :show_deleted, :show_cropped, :link_target, :pool, :similarity, :recommended, :compact, :size, :current_user, :options attr_reader :post, :tags, :show_deleted, :show_cropped, :link_target, :pool, :similarity, :recommended, :compact, :size, :current_user, :options
delegate :external_link_to, :time_ago_in_words_tagged, :empty_heart_icon, to: :helpers delegate :external_link_to, :time_ago_in_words_tagged, :empty_heart_icon, to: :helpers
def initialize(post:, tags: "", show_deleted: false, show_cropped: true, link_target: post, pool: nil, similarity: nil, recommended: nil, compact: nil, size: nil, current_user: CurrentUser.user, **options) def initialize(post:, tags: "", show_deleted: false, show_cropped: true, link_target: post, pool: nil, similarity: nil, recommended: nil, compact: nil, size: nil, current_user: CurrentUser.user, **options)
super
@post = post @post = post
@tags = tags.presence @tags = tags.presence
@show_deleted = show_deleted @show_deleted = show_deleted
@@ -44,7 +46,7 @@ class PostPreviewComponent < ApplicationComponent
{ {
width: [(downscale_ratio * post.image_width).floor, post.image_width].min, width: [(downscale_ratio * post.image_width).floor, post.image_width].min,
height: [(downscale_ratio * post.image_height).floor, post.image_height].min height: [(downscale_ratio * post.image_height).floor, post.image_height].min,
} }
else else
{ width: 0, height: 0 } { width: 0, height: 0 }
@@ -70,7 +72,7 @@ class PostPreviewComponent < ApplicationComponent
def data_attributes def data_attributes
attributes = { attributes = {
"data-id" => post.id, "data-id" => post.id,
"data-has-sound" => post.has_tag?('video_with_sound|flash_with_sound'), "data-has-sound" => post.has_tag?("video_with_sound|flash_with_sound"),
"data-tags" => post.tag_string, "data-tags" => post.tag_string,
"data-pools" => post.pool_string, "data-pools" => post.pool_string,
"data-approver-id" => post.approver_id, "data-approver-id" => post.approver_id,

View File

@@ -5,6 +5,7 @@ class PostVotesComponent < ApplicationComponent
attr_reader :post, :current_user attr_reader :post, :current_user
def initialize(post:, current_user:) def initialize(post:, current_user:)
super
@post = post @post = post
@current_user = current_user @current_user = current_user
end end

View File

@@ -2,9 +2,11 @@
class SourceDataComponent < ApplicationComponent class SourceDataComponent < ApplicationComponent
attr_reader :source attr_reader :source
delegate :spinner_icon, :external_site_icon, to: :helpers delegate :spinner_icon, :external_site_icon, to: :helpers
def initialize(source:) def initialize(source:)
super
@source = source @source = source
end end

View File

@@ -2,16 +2,18 @@
class TagListComponent < ApplicationComponent class TagListComponent < ApplicationComponent
attr_reader :tags, :current_query, :show_extra_links attr_reader :tags, :current_query, :show_extra_links
delegate :humanized_number, to: :helpers delegate :humanized_number, to: :helpers
def initialize(tags: [], current_query: nil, show_extra_links: false) def initialize(tags: [], current_query: nil, show_extra_links: false)
super
@tags = tags @tags = tags
@current_query = current_query @current_query = current_query
@show_extra_links = show_extra_links @show_extra_links = show_extra_links
end end
def self.tags_from_names(tag_names) def self.tags_from_names(tag_names)
names_to_tags = Tag.where(name: tag_names).map { |tag| [tag.name, tag] }.to_h names_to_tags = Tag.where(name: tag_names).index_by(&:name)
tag_names.map do |name| tag_names.map do |name|
names_to_tags.fetch(name) { Tag.new(name: name).freeze } names_to_tags.fetch(name) { Tag.new(name: name).freeze }

View File

@@ -90,9 +90,9 @@ class ApplicationController < ActionController::Base
render_error_page(401, exception, template: "sessions/new") render_error_page(401, exception, template: "sessions/new")
when ActionController::InvalidAuthenticityToken, ActionController::UnpermittedParameters, ActionController::InvalidCrossOriginRequest when ActionController::InvalidAuthenticityToken, ActionController::UnpermittedParameters, ActionController::InvalidCrossOriginRequest
render_error_page(403, exception) render_error_page(403, exception)
when ActiveSupport::MessageVerifier::InvalidSignature # raised by `find_signed!` when ActiveSupport::MessageVerifier::InvalidSignature, # raised by `find_signed!`
render_error_page(403, exception, template: "static/access_denied", message: "Access denied") User::PrivilegeError,
when User::PrivilegeError, Pundit::NotAuthorizedError Pundit::NotAuthorizedError
render_error_page(403, exception, template: "static/access_denied", message: "Access denied") render_error_page(403, exception, template: "static/access_denied", message: "Access denied")
when ActiveRecord::RecordNotFound when ActiveRecord::RecordNotFound
render_error_page(404, exception, message: "That record was not found.") render_error_page(404, exception, message: "That record was not found.")
@@ -183,7 +183,7 @@ class ApplicationController < ActionController::Base
return if CurrentUser.user.is_anonymous? return if CurrentUser.user.is_anonymous?
last_authenticated_at = session[:last_authenticated_at] last_authenticated_at = session[:last_authenticated_at]
if last_authenticated_at.blank? || Time.parse(last_authenticated_at) < 60.minutes.ago if last_authenticated_at.blank? || Time.zone.parse(last_authenticated_at) < 60.minutes.ago
redirect_to confirm_password_session_path(url: request.fullpath) redirect_to confirm_password_session_path(url: request.fullpath)
end end
end end
@@ -197,7 +197,7 @@ class ApplicationController < ActionController::Base
params[:search] ||= ActionController::Parameters.new params[:search] ||= ActionController::Parameters.new
deep_reject_blank = lambda do |hash| deep_reject_blank = lambda do |hash|
hash.reject { |k, v| v.blank? || (v.is_a?(Hash) && deep_reject_blank.call(v).blank?) } hash.reject { |_k, v| v.blank? || (v.is_a?(Hash) && deep_reject_blank.call(v).blank?) }
end end
nonblank_search_params = deep_reject_blank.call(params[:search]) nonblank_search_params = deep_reject_blank.call(params[:search])

View File

@@ -56,7 +56,7 @@ class ArtistsController < ApplicationController
def destroy def destroy
@artist = authorize Artist.find(params[:id]) @artist = authorize Artist.find(params[:id])
@artist.update_attribute(:is_deleted, true) @artist.update(is_deleted: true)
redirect_to(artist_path(@artist), :notice => "Artist deleted") redirect_to(artist_path(@artist), :notice => "Artist deleted")
end end

View File

@@ -3,7 +3,7 @@ class CommentVotesController < ApplicationController
def index def index
@comment_votes = authorize CommentVote.visible(CurrentUser.user).paginated_search(params, count_pages: true) @comment_votes = authorize CommentVote.visible(CurrentUser.user).paginated_search(params, count_pages: true)
@comment_votes = @comment_votes.includes(:user, comment: [:creator, post: [:uploader]]) if request.format.html? @comment_votes = @comment_votes.includes(:user, comment: [:creator, { post: [:uploader] }]) if request.format.html?
respond_with(@comment_votes) respond_with(@comment_votes)
end end

View File

@@ -82,7 +82,7 @@ class CommentsController < ApplicationController
def index_by_post def index_by_post
@limit = params.fetch(:limit, 20) @limit = params.fetch(:limit, 20)
@posts = Post.where("last_comment_bumped_at IS NOT NULL").user_tag_match(params[:tags]).reorder("last_comment_bumped_at DESC NULLS LAST").paginate(params[:page], limit: @limit, search_count: params[:search]) @posts = Post.where.not(last_comment_bumped_at: nil).user_tag_match(params[:tags]).reorder("last_comment_bumped_at DESC NULLS LAST").paginate(params[:page], limit: @limit, search_count: params[:search])
if request.format.html? if request.format.html?
@posts = @posts.includes(comments: [:creator]) @posts = @posts.includes(comments: [:creator])

View File

@@ -8,33 +8,25 @@ class DelayedJobsController < ApplicationController
def cancel def cancel
@job = authorize Delayed::Job.find(params[:id]), policy_class: DelayedJobPolicy @job = authorize Delayed::Job.find(params[:id]), policy_class: DelayedJobPolicy
if !@job.locked_at? @job.fail! unless @job.locked_at?
@job.fail!
end
respond_with(@job) respond_with(@job)
end end
def retry def retry
@job = authorize Delayed::Job.find(params[:id]), policy_class: DelayedJobPolicy @job = authorize Delayed::Job.find(params[:id]), policy_class: DelayedJobPolicy
if !@job.locked_at? @job.update(failed_at: nil, attempts: 0) unless @job.locked_at?
@job.update(failed_at: nil, attempts: 0)
end
respond_with(@job) respond_with(@job)
end end
def run def run
@job = authorize Delayed::Job.find(params[:id]), policy_class: DelayedJobPolicy @job = authorize Delayed::Job.find(params[:id]), policy_class: DelayedJobPolicy
if !@job.locked_at? @job.update(run_at: Time.zone.now) unless @job.locked_at?
@job.update(run_at: Time.now)
end
respond_with(@job) respond_with(@job)
end end
def destroy def destroy
@job = authorize Delayed::Job.find(params[:id]), policy_class: DelayedJobPolicy @job = authorize Delayed::Job.find(params[:id]), policy_class: DelayedJobPolicy
if !@job.locked_at? @job.destroy unless @job.locked_at?
@job.destroy
end
respond_with(@job) respond_with(@job)
end end
end end

View File

@@ -2,7 +2,8 @@ class DtextPreviewsController < ApplicationController
def create def create
@inline = params[:inline].to_s.truthy? @inline = params[:inline].to_s.truthy?
@disable_mentions = params[:disable_mentions].to_s.truthy? @disable_mentions = params[:disable_mentions].to_s.truthy?
@html = helpers.format_text(params[:body], inline: @inline, disable_mentions: @disable_mentions)
render inline: "<%= format_text(params[:body], inline: @inline, disable_mentions: @disable_mentions) %>" render html: @html
end end
end end

View File

@@ -79,7 +79,7 @@ class ForumTopicsController < ApplicationController
def mark_all_as_read def mark_all_as_read
authorize ForumTopic authorize ForumTopic
CurrentUser.user.update_attribute(:last_forum_read_at, Time.now) CurrentUser.user.update(last_forum_read_at: Time.zone.now)
ForumTopicVisit.prune!(CurrentUser.user) ForumTopicVisit.prune!(CurrentUser.user)
redirect_to forum_topics_path, :notice => "All topics marked as read" redirect_to forum_topics_path, :notice => "All topics marked as read"
end end

View File

@@ -4,9 +4,10 @@ class IpAddressesController < ApplicationController
def index def index
@ip_addresses = authorize IpAddress.visible(CurrentUser.user).paginated_search(params) @ip_addresses = authorize IpAddress.visible(CurrentUser.user).paginated_search(params)
if search_params[:group_by] == "ip_addr" case search_params[:group_by]
when "ip_addr"
@ip_addresses = @ip_addresses.group_by_ip_addr(search_params[:ipv4_masklen], search_params[:ipv6_masklen]) @ip_addresses = @ip_addresses.group_by_ip_addr(search_params[:ipv4_masklen], search_params[:ipv6_masklen])
elsif search_params[:group_by] == "user" when "user"
@ip_addresses = @ip_addresses.group_by_user.includes(:user) @ip_addresses = @ip_addresses.group_by_user.includes(:user)
else else
@ip_addresses = @ip_addresses.includes(:user, :model) @ip_addresses = @ip_addresses.includes(:user, :model)

View File

@@ -4,7 +4,7 @@ module Maintenance
class VerificationError < StandardError; end class VerificationError < StandardError; end
before_action :validate_sig, :only => [:destroy] before_action :validate_sig, :only => [:destroy]
rescue_from VerificationError, :with => :render_403 rescue_from VerificationError, with: :render_verification_error
def show def show
end end
@@ -17,15 +17,15 @@ module Maintenance
private private
def render_403 def render_verification_error
render plain: "", :status => 403 render plain: "", status: 403
end end
def validate_sig def validate_sig
verifier = ActiveSupport::MessageVerifier.new(Danbooru.config.email_key, digest: "SHA256", serializer: JSON) verifier = ActiveSupport::MessageVerifier.new(Danbooru.config.email_key, digest: "SHA256", serializer: JSON)
calculated_sig = verifier.generate(params[:user_id].to_s) calculated_sig = verifier.generate(params[:user_id].to_s)
if calculated_sig != params[:sig] if calculated_sig != params[:sig]
raise VerificationError.new raise VerificationError, "Invalid signature"
end end
end end
end end

View File

@@ -35,8 +35,6 @@ class PoolVersionsController < ApplicationController
end end
def check_availabililty def check_availabililty
if !PoolVersion.enabled? raise NotImplementedError, "Archive service is not configured. Pool versions are not saved." unless PoolVersion.enabled?
raise NotImplementedError.new("Archive service is not configured. Pool versions are not saved.")
end
end end
end end

View File

@@ -54,7 +54,7 @@ class PoolsController < ApplicationController
def destroy def destroy
@pool = authorize Pool.find(params[:id]) @pool = authorize Pool.find(params[:id])
@pool.update_attribute(:is_deleted, true) @pool.update(is_deleted: true)
@pool.create_mod_action_for_delete @pool.create_mod_action_for_delete
flash[:notice] = "Pool deleted" flash[:notice] = "Pool deleted"
respond_with(@pool) respond_with(@pool)
@@ -62,7 +62,7 @@ class PoolsController < ApplicationController
def undelete def undelete
@pool = authorize Pool.find(params[:id]) @pool = authorize Pool.find(params[:id])
@pool.update_attribute(:is_deleted, false) @pool.update(is_deleted: false)
@pool.create_mod_action_for_undelete @pool.create_mod_action_for_undelete
flash[:notice] = "Pool undeleted" flash[:notice] = "Pool undeleted"
respond_with(@pool) respond_with(@pool)

View File

@@ -37,8 +37,7 @@ class PostVersionsController < ApplicationController
end end
def check_availabililty def check_availabililty
if !PostVersion.enabled? return if PostVersion.enabled?
raise NotImplementedError.new("Archive service is not configured. Post versions are not saved.") raise NotImplementedError, "Archive service is not configured. Post versions are not saved."
end
end end
end end

View File

@@ -116,7 +116,7 @@ class PostsController < ApplicationController
render :template => "static/error", :status => 500 render :template => "static/error", :status => 500
else else
response_params = {:q => params[:tags_query], :pool_id => params[:pool_id], :favgroup_id => params[:favgroup_id]} response_params = {:q => params[:tags_query], :pool_id => params[:pool_id], :favgroup_id => params[:favgroup_id]}
response_params.reject! {|key, value| value.blank?} response_params.reject! {|_key, value| value.blank?}
redirect_to post_path(post, response_params) redirect_to post_path(post, response_params)
end end
end end

View File

@@ -4,7 +4,7 @@ class RecommendedPostsController < ApplicationController
def index def index
limit = params.fetch(:limit, 100).to_i.clamp(0, 200) limit = params.fetch(:limit, 100).to_i.clamp(0, 200)
@recs = RecommenderService.search(search_params).take(limit) @recs = RecommenderService.search(search_params).take(limit)
@posts = @recs.map { |rec| rec[:post] } @posts = @recs.pluck(:post)
respond_with(@recs) respond_with(@recs)
end end

View File

@@ -33,7 +33,7 @@ class StaticController < ApplicationController
def sitemap_index def sitemap_index
@sitemap = params[:sitemap] @sitemap = params[:sitemap]
@limit = params.fetch(:limit, 10000).to_i @limit = params.fetch(:limit, 10_000).to_i
case @sitemap case @sitemap
when "artists" when "artists"

View File

@@ -45,7 +45,7 @@ class UploadsController < ApplicationController
def preprocess def preprocess
authorize Upload authorize Upload
@upload, @remote_size = UploadService::ControllerHelper.prepare( @upload, @remote_size = UploadService::ControllerHelper.prepare(
url: params.dig(:upload, :source), file: params.dig(:upload, :file), ref: params.dig(:upload, :referer_url), url: params.dig(:upload, :source), file: params.dig(:upload, :file), ref: params.dig(:upload, :referer_url)
) )
render body: nil render body: nil
end end

View File

@@ -1,5 +1,3 @@
require 'dtext'
module ApplicationHelper module ApplicationHelper
def listing_type(*fields, member_check: true, types: [:revert, :standard]) def listing_type(*fields, member_check: true, types: [:revert, :standard])
(fields.reduce(false) { |acc, field| acc || params.dig(:search, field).present? } && (!member_check || CurrentUser.is_member?) ? types[0] : types[1]) (fields.reduce(false) { |acc, field| acc || params.dig(:search, field).present? } && (!member_check || CurrentUser.is_member?) ? types[0] : types[1])
@@ -11,8 +9,7 @@ module ApplicationHelper
end end
def diff_name_html(this_name, other_name) def diff_name_html(this_name, other_name)
pattern = Regexp.new('.') DiffBuilder.new(this_name, other_name, /./).build
DiffBuilder.new(this_name, other_name, pattern).build
end end
def diff_body_html(record, other, field) def diff_body_html(record, other, field)
@@ -21,7 +18,7 @@ module ApplicationHelper
return h(diff_record[field]).gsub(/\r?\n/, '<span class="paragraph-mark">¶</span><br>').html_safe return h(diff_record[field]).gsub(/\r?\n/, '<span class="paragraph-mark">¶</span><br>').html_safe
end end
pattern = Regexp.new('(?:<.+?>)|(?:\w+)|(?:[ \t]+)|(?:\r?\n)|(?:.+?)') pattern = /(?:<.+?>)|(?:\w+)|(?:[ \t]+)|(?:\r?\n)|(?:.+?)/
DiffBuilder.new(record[field], other[field], pattern).build DiffBuilder.new(record[field], other[field], pattern).build
end end
@@ -32,18 +29,17 @@ module ApplicationHelper
return type == "previous" ? "New" : "" return type == "previous" ? "New" : ""
end end
statuses = [] changed_fields = record.class.status_fields.select do |field, status|
record.class.status_fields.each do |field, status| (record.has_attribute?(field) && record[field] != other[field]) ||
if record.has_attribute?(field) (!record.has_attribute?(field) && record.send(field, type))
statuses += [status] if record[field] != other[field]
else
statuses += [status] if record.send(field, type)
end
end end
statuses = changed_fields.map { |field, status| status }
altered = record.updater_id != other.updater_id altered = record.updater_id != other.updater_id
%(<div class="version-statuses" data-altered="#{altered}">#{statuses.join("<br>")}</div>).html_safe tag.div(class: "version-statuses", "data-altered": altered) do
safe_join(statuses, tag.br)
end
end end
def wordbreakify(string) def wordbreakify(string)

View File

@@ -4,7 +4,7 @@ module ForumTopicsHelper
end end
def available_min_user_levels def available_min_user_levels
ForumTopic::MIN_LEVELS.select { |name, level| level <= CurrentUser.level }.to_a ForumTopic::MIN_LEVELS.select { |_name, level| level <= CurrentUser.level }.to_a
end end
def new_forum_topic?(topic, read_forum_topics) def new_forum_topic?(topic, read_forum_topics)

View File

@@ -22,11 +22,12 @@ module PopularPostsHelper
end end
def date_range_description(date, scale, min_date, max_date) def date_range_description(date, scale, min_date, max_date)
if scale == "day" case scale
when "day"
date.strftime("%B %d, %Y") date.strftime("%B %d, %Y")
elsif scale == "week" when "week"
"#{min_date.strftime("%B %d, %Y")} - #{max_date.strftime("%B %d, %Y")}" "#{min_date.strftime("%B %d, %Y")} - #{max_date.strftime("%B %d, %Y")}"
elsif scale == "month" when "month"
date.strftime("%B %Y") date.strftime("%B %Y")
end end
end end

View File

@@ -40,12 +40,12 @@ module PostVersionsHelper
def post_version_field(post_version, field) def post_version_field(post_version, field)
value = post_version_value(post_version.send(field)) value = post_version_value(post_version.send(field))
prefix = (field == :parent_id ? "parent" : field.to_s) prefix = (field == :parent_id ? "parent" : field.to_s)
search = prefix + ":" + value.to_s search = "#{prefix}:#{value}"
display = (field == :rating ? post_version.pretty_rating : value) display = (field == :rating ? post_version.pretty_rating : value)
%(<b>#{field.to_s.titleize}:</b> #{link_to(display, posts_path(:tags => search))}).html_safe %(<b>#{field.to_s.titleize}:</b> #{link_to(display, posts_path(:tags => search))}).html_safe
end end
def post_version_value(value) def post_version_value(value)
return (value.present? ? value : "none") value.presence || "none"
end end
end end

View File

@@ -1,6 +1,9 @@
module WikiPagesHelper module WikiPagesHelper
def wiki_page_other_names_list(wiki_page) def wiki_page_other_names_list(wiki_page)
names_html = wiki_page.other_names.map {|name| link_to(name, "http://www.pixiv.net/search.php?s_mode=s_tag_full&word=#{u(name)}", :class => "wiki-other-name")} names_html = wiki_page.other_names.map do |name|
names_html.join(" ").html_safe link_to(name, "https://www.pixiv.net/tags/#{u(name)}/artworks", class: "wiki-other-name")
end
safe_join(names_html, " ")
end end
end end

View File

@@ -2,7 +2,7 @@ class ApplicationJob < ActiveJob::Base
queue_as :default queue_as :default
queue_with_priority 0 queue_with_priority 0
discard_on ActiveJob::DeserializationError do |job, error| discard_on ActiveJob::DeserializationError do |_job, error|
DanbooruLogger.log(error) DanbooruLogger.log(error)
end end
end end

View File

@@ -3,7 +3,8 @@ module Moderator
module Queries module Queries
class Artist < ::Struct.new(:user, :count) class Artist < ::Struct.new(:user, :count)
def self.all(min_date, max_level) def self.all(min_date, max_level)
::ArtistVersion.joins(:updater) ::ArtistVersion
.joins(:updater)
.where("artist_versions.created_at > ?", min_date) .where("artist_versions.created_at > ?", min_date)
.where("users.level <= ?", max_level) .where("users.level <= ?", max_level)
.group(:updater) .group(:updater)

View File

@@ -3,7 +3,8 @@ module Moderator
module Queries module Queries
class Comment < ::Struct.new(:comment, :count) class Comment < ::Struct.new(:comment, :count)
def self.all(min_date, max_level) def self.all(min_date, max_level)
::CommentVote.joins(comment: [:creator]) ::CommentVote
.joins(comment: [:creator])
.where("comments.score < 0") .where("comments.score < 0")
.where("comment_votes.created_at > ?", min_date) .where("comment_votes.created_at > ?", min_date)
.where("users.level <= ?", max_level) .where("users.level <= ?", max_level)

View File

@@ -3,7 +3,8 @@ module Moderator
module Queries module Queries
class Note < ::Struct.new(:user, :count) class Note < ::Struct.new(:user, :count)
def self.all(min_date, max_level) def self.all(min_date, max_level)
::NoteVersion.joins(:updater) ::NoteVersion
.joins(:updater)
.where("note_versions.created_at > ?", min_date) .where("note_versions.created_at > ?", min_date)
.where("users.level <= ?", max_level) .where("users.level <= ?", max_level)
.group(:updater) .group(:updater)

View File

@@ -3,7 +3,8 @@ module Moderator
module Queries module Queries
class PostAppeal class PostAppeal
def self.all(min_date) def self.all(min_date)
::Post.joins(:appeals).includes(:uploader, :flags, appeals: [:creator]) ::Post
.joins(:appeals).includes(:uploader, :flags, appeals: [:creator])
.deleted .deleted
.where("post_appeals.created_at > ?", min_date) .where("post_appeals.created_at > ?", min_date)
.group(:id) .group(:id)

View File

@@ -3,7 +3,8 @@ module Moderator
module Queries module Queries
class Upload < ::Struct.new(:user, :count) class Upload < ::Struct.new(:user, :count)
def self.all(min_date, max_level) def self.all(min_date, max_level)
::Post.joins(:uploader) ::Post
.joins(:uploader)
.where("posts.created_at > ?", min_date) .where("posts.created_at > ?", min_date)
.where("users.level <= ?", max_level) .where("users.level <= ?", max_level)
.group(:uploader) .group(:uploader)

View File

@@ -3,7 +3,8 @@ module Moderator
module Queries module Queries
class WikiPage < ::Struct.new(:user, :count) class WikiPage < ::Struct.new(:user, :count)
def self.all(min_date, max_level) def self.all(min_date, max_level)
::WikiPageVersion.joins(:updater) ::WikiPageVersion
.joins(:updater)
.where("wiki_page_versions.created_at > ?", min_date) .where("wiki_page_versions.created_at > ?", min_date)
.where("users.level <= ?", max_level) .where("users.level <= ?", max_level)
.group(:updater) .group(:updater)

View File

@@ -62,7 +62,7 @@ module Moderator
end end
def add_row(sums, counts) def add_row(sums, counts)
sums.merge!(counts) { |key, oldcount, newcount| oldcount + newcount } sums.merge!(counts) { |_key, oldcount, newcount| oldcount + newcount }
end end
def add_row_id(sums, counts) def add_row_id(sums, counts)

View File

@@ -11,9 +11,10 @@ class NicoSeigaApiClient
end end
def image_ids def image_ids
if @work_type == "illust" case @work_type
when "illust"
[api_response["id"]] [api_response["id"]]
elsif @work_type == "manga" when "manga"
manga_api_response.map do |x| manga_api_response.map do |x|
case x["meta"]["source_url"] case x["meta"]["source_url"]
when %r{/thumb/(\d+)\w}i then Regexp.last_match(1) when %r{/thumb/(\d+)\w}i then Regexp.last_match(1)
@@ -40,20 +41,22 @@ class NicoSeigaApiClient
end end
def user_name def user_name
if @work_type == "illust" case @work_type
when "illust"
api_response["nickname"] api_response["nickname"]
elsif @work_type == "manga" when "manga"
user_api_response(user_id)["nickname"] user_api_response(user_id)["nickname"]
end end
end end
def api_response def api_response
if @work_type == "illust" case @work_type
when "illust"
resp = get("https://sp.seiga.nicovideo.jp/ajax/seiga/im#{@work_id}") resp = get("https://sp.seiga.nicovideo.jp/ajax/seiga/im#{@work_id}")
return {} if resp.blank? || resp.code.to_i == 404 return {} if resp.blank? || resp.code.to_i == 404
api_response = JSON.parse(resp)["target_image"] api_response = JSON.parse(resp)["target_image"]
elsif @work_type == "manga" when "manga"
resp = http.cache(1.minute).get("#{XML_API}/theme/info?id=#{@work_id}") resp = http.cache(1.minute).get("#{XML_API}/theme/info?id=#{@work_id}")
return {} if resp.blank? || resp.code.to_i == 404 return {} if resp.blank? || resp.code.to_i == 404
api_response = Hash.from_xml(resp.to_s)["response"]["theme"] api_response = Hash.from_xml(resp.to_s)["response"]["theme"]
@@ -86,16 +89,13 @@ class NicoSeigaApiClient
# XXX should fail gracefully instead of raising exception # XXX should fail gracefully instead of raising exception
resp = http.cache(1.hour).post("https://account.nicovideo.jp/login/redirector?site=seiga", form: form) resp = http.cache(1.hour).post("https://account.nicovideo.jp/login/redirector?site=seiga", form: form)
raise RuntimeError, "NicoSeiga login failed (status=#{resp.status} url=#{url})" if resp.status != 200 raise "NicoSeiga login failed (status=#{resp.status} url=#{url})" if resp.status != 200
http http
end end
def get(url) def get(url)
resp = login.cache(1.minute).get(url) login.cache(1.minute).get(url)
#raise RuntimeError, "NicoSeiga get failed (status=#{resp.status} url=#{url})" if resp.status != 200
resp
end end
memoize :api_response, :manga_api_response, :user_api_response memoize :api_response, :manga_api_response, :user_api_response

View File

@@ -1,19 +1,19 @@
module NoteSanitizer module NoteSanitizer
ALLOWED_ELEMENTS = %w( ALLOWED_ELEMENTS = %w[
code center tn h1 h2 h3 h4 h5 h6 a span div blockquote br p ul li ol em code center tn h1 h2 h3 h4 h5 h6 a span div blockquote br p ul li ol em
strong small big b i font u s pre ruby rb rt rp rtc sub sup hr wbr strong small big b i font u s pre ruby rb rt rp rtc sub sup hr wbr
) ]
ALLOWED_ATTRIBUTES = { ALLOWED_ATTRIBUTES = {
:all => %w(style title), :all => %w[style title],
"a" => %w(href), "a" => %w[href],
"span" => %w(class), "span" => %w[class],
"div" => %w(class align), "div" => %w[class align],
"p" => %w(class align), "p" => %w[class align],
"font" => %w(color size) "font" => %w[color size]
} }
ALLOWED_PROPERTIES = %w( ALLOWED_PROPERTIES = %w[
align-items align-items
background background-color background background-color
border border-color border-image border-radius border-style border-width border border-color border-image border-radius border-style border-width
@@ -48,7 +48,7 @@ module NoteSanitizer
word-wrap overflow-wrap word-wrap overflow-wrap
writing-mode writing-mode
vertical-align vertical-align
) ]
def self.sanitize(text) def self.sanitize(text)
text.gsub!(/<( |-|3|:|>|\Z)/, "&lt;\\1") text.gsub!(/<( |-|3|:|>|\Z)/, "&lt;\\1")

View File

@@ -46,21 +46,23 @@ module PaginationExtension
end end
def is_first_page? def is_first_page?
if paginator_mode == :numbered case paginator_mode
when :numbered
current_page == 1 current_page == 1
elsif paginator_mode == :sequential_before when :sequential_before
false false
elsif paginator_mode == :sequential_after when :sequential_after
size <= records_per_page size <= records_per_page
end end
end end
def is_last_page? def is_last_page?
if paginator_mode == :numbered case paginator_mode
when :numbered
current_page >= total_pages current_page >= total_pages
elsif paginator_mode == :sequential_before when :sequential_before
size <= records_per_page size <= records_per_page
elsif paginator_mode == :sequential_after when :sequential_after
false false
end end
end end
@@ -98,11 +100,12 @@ module PaginationExtension
# we override a rails internal method to discard that extra record. See # we override a rails internal method to discard that extra record. See
# #2044, #3642. # #2044, #3642.
def records def records
if paginator_mode == :sequential_before case paginator_mode
when :sequential_before
super.first(records_per_page) super.first(records_per_page)
elsif paginator_mode == :sequential_after when :sequential_after
super.first(records_per_page).reverse super.first(records_per_page).reverse
elsif paginator_mode == :numbered when :numbered
super super
end end
end end

View File

@@ -20,7 +20,7 @@ module PostSets
end end
def has_blank_wiki? def has_blank_wiki?
tag.present? && !wiki_page.present? tag.present? && wiki_page.nil?
end end
def wiki_page def wiki_page
@@ -94,7 +94,7 @@ module PostSets
end end
def get_post_count def get_post_count
if %w(json atom xml).include?(format.downcase) if %w[json atom xml].include?(format.downcase)
# no need to get counts for formats that don't use a paginator # no need to get counts for formats that don't use a paginator
nil nil
else else

View File

@@ -17,14 +17,14 @@ class RateLimiter
case action case action
when "users:create" when "users:create"
rate, burst = 1.0/5.minutes, 10 rate, burst = 1.0 / 5.minutes, 10
when "emails:update", "sessions:create", "moderation_reports:create" when "emails:update", "sessions:create", "moderation_reports:create"
rate, burst = 1.0/1.minute, 10 rate, burst = 1.0 / 1.minute, 10
when "dmails:create", "comments:create", "forum_posts:create", "forum_topics:create" when "dmails:create", "comments:create", "forum_posts:create", "forum_topics:create"
rate, burst = 1.0/1.minute, 50 rate, burst = 1.0 / 1.minute, 50
when "comment_votes:create", "comment_votes:destroy", "post_votes:create", when "comment_votes:create", "comment_votes:destroy", "post_votes:create",
"post_votes:destroy", "favorites:create", "favorites:destroy", "post_disapprovals:create" "post_votes:destroy", "favorites:create", "favorites:destroy", "post_disapprovals:create"
rate, burst = 1.0/1.second, 200 rate, burst = 1.0 / 1.second, 200
else else
rate = user.api_regen_multiplier rate = user.api_regen_multiplier
burst = 200 burst = 200

View File

@@ -55,7 +55,7 @@ module RecommenderService
if user.present? if user.present?
raise User::PrivilegeError unless Pundit.policy!(CurrentUser.user, user).can_see_favorites? raise User::PrivilegeError unless Pundit.policy!(CurrentUser.user, user).can_see_favorites?
max_recommendations = params.fetch(:max_recommendations, user.favorite_count + 500).to_i.clamp(0, 50000) max_recommendations = params.fetch(:max_recommendations, user.favorite_count + 500).to_i.clamp(0, 50_000)
recs = RecommenderService.recommend_for_user(user, tags: params[:post_tags_match], limit: max_recommendations) recs = RecommenderService.recommend_for_user(user, tags: params[:post_tags_match], limit: max_recommendations)
elsif post.present? elsif post.present?
max_recommendations = params.fetch(:max_recommendations, 100).to_i.clamp(0, 1000) max_recommendations = params.fetch(:max_recommendations, 100).to_i.clamp(0, 1000)

View File

@@ -10,7 +10,7 @@ class ReportbooruService
reportbooru_server.present? reportbooru_server.present?
end end
def missed_search_rankings(expires_in: 1.minutes) def missed_search_rankings(expires_in: 1.minute)
return [] unless enabled? return [] unless enabled?
response = http.cache(expires_in).get("#{reportbooru_server}/missed_searches") response = http.cache(expires_in).get("#{reportbooru_server}/missed_searches")
@@ -20,11 +20,11 @@ class ReportbooruService
body.lines.map(&:split).map { [_1, _2.to_i] } body.lines.map(&:split).map { [_1, _2.to_i] }
end end
def post_search_rankings(date, expires_in: 1.minutes) def post_search_rankings(date, expires_in: 1.minute)
request("#{reportbooru_server}/post_searches/rank?date=#{date}", expires_in) request("#{reportbooru_server}/post_searches/rank?date=#{date}", expires_in)
end end
def post_view_rankings(date, expires_in: 1.minutes) def post_view_rankings(date, expires_in: 1.minute)
request("#{reportbooru_server}/post_views/rank?date=#{date}", expires_in) request("#{reportbooru_server}/post_views/rank?date=#{date}", expires_in)
end end

View File

@@ -156,12 +156,12 @@ module Sources::Strategies
"https://twitter.com/i/web/status/#{status_id}" "https://twitter.com/i/web/status/#{status_id}"
elsif url =~ %r{\Ahttps?://(?:o|image-proxy-origin)\.twimg\.com/\d/proxy\.jpg\?t=(\w+)&}i elsif url =~ %r{\Ahttps?://(?:o|image-proxy-origin)\.twimg\.com/\d/proxy\.jpg\?t=(\w+)&}i
str = Base64.decode64($1) str = Base64.decode64($1)
source = URI.extract(str, ['http', 'https']) source = URI.extract(str, %w[http https])
if source.any? if source.any?
source = source[0] source = source[0]
if source =~ %r{^https?://twitpic.com/show/large/[a-z0-9]+}i if source =~ %r{^https?://twitpic.com/show/large/[a-z0-9]+}i
source.gsub!(%r{show/large/}, "") source.gsub!(%r{show/large/}, "")
index = source.rindex('.') index = source.rindex(".")
source = source[0..index - 1] source = source[0..index - 1]
end end
source source

View File

@@ -68,7 +68,7 @@ class TagCategory
end end
def category_ids_regex def category_ids_regex
@@category_ids_regex ||= "[#{category_ids.join("")}]" @@category_ids_regex ||= "[#{category_ids.join}]"
end end
end end

View File

@@ -82,7 +82,7 @@ class TagMover
old_cosplay_tag = "#{old_tag.name}_(cosplay)" old_cosplay_tag = "#{old_tag.name}_(cosplay)"
new_cosplay_tag = "#{new_tag.name}_(cosplay)" new_cosplay_tag = "#{new_tag.name}_(cosplay)"
if Tag.nonempty.where(name: old_cosplay_tag).exists? if Tag.nonempty.exists?(name: old_cosplay_tag)
TagMover.new(old_cosplay_tag, new_cosplay_tag).move! TagMover.new(old_cosplay_tag, new_cosplay_tag).move!
end end
end end

View File

@@ -16,7 +16,7 @@ module TagRelationshipRetirementService
if topic.nil? if topic.nil?
CurrentUser.as(User.system) do CurrentUser.as(User.system) do
topic = ForumTopic.create!(creator: User.system, title: forum_topic_title, category_id: 1) topic = ForumTopic.create!(creator: User.system, title: forum_topic_title, category_id: 1)
forum_post = ForumPost.create!(creator: User.system, body: forum_topic_body, topic: topic) ForumPost.create!(creator: User.system, body: forum_topic_body, topic: topic)
end end
end end
topic topic
@@ -45,6 +45,6 @@ module TagRelationshipRetirementService
end end
def is_unused?(name) def is_unused?(name)
!Post.raw_tag_match(name).where("created_at > ?", THRESHOLD.ago).exists? !Post.raw_tag_match(name).exists?(["created_at > ?", THRESHOLD.ago])
end end
end end

View File

@@ -1,8 +1,3 @@
require 'upload_service/controller_helper'
require 'upload_service/preprocessor'
require 'upload_service/replacer'
require 'upload_service/utils'
class UploadService class UploadService
attr_reader :params, :post, :upload attr_reader :params, :post, :upload

View File

@@ -34,15 +34,13 @@ class UploadService
def in_progress? def in_progress?
if md5.present? if md5.present?
return Upload.where(status: "preprocessing", md5: md5).exists? Upload.exists?(status: "preprocessing", md5: md5)
end elsif Utils.is_downloadable?(source)
Upload.exists?(status: "preprocessing", source: source)
if Utils.is_downloadable?(source) else
return Upload.where(status: "preprocessing", source: source).exists?
end
false false
end end
end
def predecessor def predecessor
if md5.present? if md5.present?

View File

@@ -11,7 +11,7 @@ class UploadService
end end
def comment_replacement_message(post, replacement) def comment_replacement_message(post, replacement)
%("#{replacement.creator.name}":[#{Routes.user_path(replacement.creator)}] replaced this post with a new file:\n\n#{replacement_message(post, replacement)}) %{"#{replacement.creator.name}":[#{Routes.user_path(replacement.creator)}] replaced this post with a new file:\n\n#{replacement_message(post, replacement)}}
end end
def replacement_message(post, replacement) def replacement_message(post, replacement)
@@ -49,7 +49,7 @@ class UploadService
truncated_source = source.gsub(%r{\Ahttps?://}, "").truncate(64, omission: "...#{source.last(32)}") truncated_source = source.gsub(%r{\Ahttps?://}, "").truncate(64, omission: "...#{source.last(32)}")
if source =~ %r{\Ahttps?://}i if source =~ %r{\Ahttps?://}i
%("#{truncated_source}":[#{source}]) %{"#{truncated_source}":[#{source}]}
else else
truncated_source truncated_source
end end
@@ -70,7 +70,7 @@ class UploadService
return "file://#{repl.replacement_file.original_filename}" return "file://#{repl.replacement_file.original_filename}"
end end
if !upload.source.present? if upload.source.blank?
raise "No source found in upload for replacement" raise "No source found in upload for replacement"
end end

View File

@@ -14,7 +14,7 @@ class UploadService
end end
def is_downloadable?(source) def is_downloadable?(source)
source =~ /^https?:\/\// source =~ %r{\Ahttps?://}
end end
def generate_resizes(media_file) def generate_resizes(media_file)

View File

@@ -42,8 +42,8 @@ class UserDeletion
user.email_address = nil user.email_address = nil
user.last_logged_in_at = nil user.last_logged_in_at = nil
user.last_forum_read_at = nil user.last_forum_read_at = nil
user.favorite_tags = '' user.favorite_tags = ""
user.blacklisted_tags = '' user.blacklisted_tags = ""
user.hide_deleted_posts = false user.hide_deleted_posts = false
user.show_deleted_children = false user.show_deleted_children = false
user.time_zone = "Eastern Time (US & Canada)" user.time_zone = "Eastern Time (US & Canada)"

View File

@@ -32,22 +32,18 @@ class ArtistVersion < ApplicationRecord
extend SearchMethods extend SearchMethods
def previous def previous
@previous ||= begin @previous ||= ArtistVersion.where("artist_id = ? and created_at < ?", artist_id, created_at).order("created_at desc").limit(1).to_a
ArtistVersion.where("artist_id = ? and created_at < ?", artist_id, created_at).order("created_at desc").limit(1).to_a
end
@previous.first @previous.first
end end
def subsequent def subsequent
@subsequent ||= begin @subsequent ||= ArtistVersion.where("artist_id = ? and created_at > ?", artist_id, created_at).order("created_at asc").limit(1).to_a
ArtistVersion.where("artist_id = ? and created_at > ?", artist_id, created_at).order("created_at asc").limit(1).to_a
end
@subsequent.first @subsequent.first
end end
def current def current
@previous ||= begin @previous ||= begin
ArtistVersion.where("artist_id = ?", artist_id).order("created_at desc").limit(1).to_a ArtistVersion.where(artist_id: artist_id).order("created_at desc").limit(1).to_a
end end
@previous.first @previous.first
end end
@@ -66,17 +62,17 @@ class ArtistVersion < ApplicationRecord
end end
def other_names_changed(type) def other_names_changed(type)
other = self.send(type) other = send(type)
((other_names - other.other_names) | (other.other_names - other_names)).length.positive? ((other_names - other.other_names) | (other.other_names - other_names)).length.positive?
end end
def urls_changed(type) def urls_changed(type)
other = self.send(type) other = send(type)
((urls - other.urls) | (other.urls - urls)).length.positive? ((urls - other.urls) | (other.urls - urls)).length.positive?
end end
def was_deleted(type) def was_deleted(type)
other = self.send(type) other = send(type)
if type == "previous" if type == "previous"
is_deleted && !other.is_deleted is_deleted && !other.is_deleted
else else
@@ -85,7 +81,7 @@ class ArtistVersion < ApplicationRecord
end end
def was_undeleted(type) def was_undeleted(type)
other = self.send(type) other = send(type)
if type == "previous" if type == "previous"
!is_deleted && other.is_deleted !is_deleted && other.is_deleted
else else
@@ -94,7 +90,7 @@ class ArtistVersion < ApplicationRecord
end end
def was_banned(type) def was_banned(type)
other = self.send(type) other = send(type)
if type == "previous" if type == "previous"
is_banned && !other.is_banned is_banned && !other.is_banned
else else
@@ -103,7 +99,7 @@ class ArtistVersion < ApplicationRecord
end end
def was_unbanned(type) def was_unbanned(type)
other = self.send(type) other = send(type)
if type == "previous" if type == "previous"
!is_banned && other.is_banned !is_banned && other.is_banned
else else

View File

@@ -12,8 +12,8 @@ class Ban < ApplicationRecord
validates :reason, presence: true validates :reason, presence: true
validate :user, :validate_user_is_bannable, on: :create validate :user, :validate_user_is_bannable, on: :create
scope :unexpired, -> { where("bans.created_at + bans.duration > ?", Time.now) } scope :unexpired, -> { where("bans.created_at + bans.duration > ?", Time.zone.now) }
scope :expired, -> { where("bans.created_at + bans.duration <= ?", Time.now) } scope :expired, -> { where("bans.created_at + bans.duration <= ?", Time.zone.now) }
scope :active, -> { unexpired } scope :active, -> { unexpired }
def self.search(params) def self.search(params)
@@ -48,7 +48,7 @@ class Ban < ApplicationRecord
end end
def update_user_on_destroy def update_user_on_destroy
user.update_attribute(:is_banned, false) user.update!(is_banned: false)
end end
def user_name def user_name
@@ -68,7 +68,7 @@ class Ban < ApplicationRecord
end end
def expired? def expired?
persisted? && expires_at < Time.now persisted? && expires_at < Time.zone.now
end end
def create_feedback def create_feedback

View File

@@ -1,17 +1,16 @@
class BulkUpdateRequest < ApplicationRecord class BulkUpdateRequest < ApplicationRecord
attr_accessor :title attr_accessor :title, :reason
attr_accessor :reason
belongs_to :user belongs_to :user
belongs_to :forum_topic, optional: true belongs_to :forum_topic, optional: true
belongs_to :forum_post, optional: true belongs_to :forum_post, optional: true
belongs_to :approver, optional: true, class_name: "User" belongs_to :approver, optional: true, class_name: "User"
validates_presence_of :reason, on: :create validates :reason, presence: true, on: :create
validates_presence_of :script validates :script, presence: true
validates_presence_of :title, if: ->(rec) {rec.forum_topic_id.blank?} validates :title, presence: true, if: ->(rec) { rec.forum_topic_id.blank? }
validates_presence_of :forum_topic, if: ->(rec) {rec.forum_topic_id.present?} validates :forum_topic, presence: true, if: ->(rec) { rec.forum_topic_id.present? }
validates_inclusion_of :status, :in => %w(pending approved rejected) validates :status, inclusion: { in: %w[pending approved rejected] }
validate :validate_script, if: :script_changed? validate :validate_script, if: :script_changed?
before_save :update_tags, if: :script_changed? before_save :update_tags, if: :script_changed?

View File

@@ -3,8 +3,8 @@ class Comment < ApplicationRecord
belongs_to :creator, class_name: "User" belongs_to :creator, class_name: "User"
belongs_to_updater belongs_to_updater
has_many :moderation_reports, as: :model has_many :moderation_reports, as: :model, dependent: :destroy
has_many :votes, :class_name => "CommentVote", :dependent => :destroy has_many :votes, class_name: "CommentVote", dependent: :destroy
validates :body, presence: true, length: { maximum: 15_000 }, if: :body_changed? validates :body, presence: true, length: { maximum: 15_000 }, if: :body_changed?
@@ -20,9 +20,9 @@ class Comment < ApplicationRecord
deletable deletable
mentionable( mentionable(
:message_field => :body, message_field: :body,
:title => ->(user_name) {"#{creator.name} mentioned you in a comment on post ##{post_id}"}, title: ->(_user_name) {"#{creator.name} mentioned you in a comment on post ##{post_id}"},
:body => ->(user_name) {"@#{creator.name} mentioned you in comment ##{id} on post ##{post_id}:\n\n[quote]\n#{DText.extract_mention(body, "@" + user_name)}\n[/quote]\n"} body: ->(user_name) {"@#{creator.name} mentioned you in comment ##{id} on post ##{post_id}:\n\n[quote]\n#{DText.extract_mention(body, "@#{user_name}")}\n[/quote]\n"}
) )
module SearchMethods module SearchMethods
@@ -55,7 +55,7 @@ class Comment < ApplicationRecord
def update_last_commented_at_on_create def update_last_commented_at_on_create
Post.where(:id => post_id).update_all(:last_commented_at => created_at) Post.where(:id => post_id).update_all(:last_commented_at => created_at)
if Comment.where("post_id = ?", post_id).count <= Danbooru.config.comment_threshold && !do_not_bump_post? if Comment.where(post_id: post_id).count <= Danbooru.config.comment_threshold && !do_not_bump_post?
Post.where(:id => post_id).update_all(:last_comment_bumped_at => created_at) Post.where(:id => post_id).update_all(:last_comment_bumped_at => created_at)
end end
end end

View File

@@ -7,8 +7,8 @@ class CommentVote < ApplicationRecord
validate :validate_vote_is_unique, if: :is_deleted_changed? validate :validate_vote_is_unique, if: :is_deleted_changed?
validates :score, inclusion: { in: [-1, 1], message: "must be 1 or -1" } validates :score, inclusion: { in: [-1, 1], message: "must be 1 or -1" }
before_create :update_score_on_create
before_save :update_score_on_delete_or_undelete, if: -> { !new_record? && is_deleted_changed? } before_save :update_score_on_delete_or_undelete, if: -> { !new_record? && is_deleted_changed? }
before_create :update_score_on_create
deletable deletable

View File

@@ -1,5 +1,3 @@
require 'digest/sha1'
class Dmail < ApplicationRecord class Dmail < ApplicationRecord
validate :validate_sender_is_not_limited, on: :create validate :validate_sender_is_not_limited, on: :create
validates :title, presence: true, length: { maximum: 200 }, if: :title_changed? validates :title, presence: true, length: { maximum: 200 }, if: :title_changed?

View File

@@ -30,9 +30,9 @@ class ForumPost < ApplicationRecord
deletable deletable
mentionable( mentionable(
:message_field => :body, message_field: :body,
:title => ->(user_name) {%{#{creator.name} mentioned you in topic ##{topic_id} (#{topic.title})}}, title: ->(_user_name) {%{#{creator.name} mentioned you in topic ##{topic_id} (#{topic.title})}},
:body => ->(user_name) {%{@#{creator.name} mentioned you in topic ##{topic_id} ("#{topic.title}":[#{Routes.forum_topic_path(topic, page: forum_topic_page)}]):\n\n[quote]\n#{DText.extract_mention(body, "@" + user_name)}\n[/quote]\n}} body: ->(user_name) {%{@#{creator.name} mentioned you in topic ##{topic_id} ("#{topic.title}":[#{Routes.forum_topic_path(topic, page: forum_topic_page)}]):\n\n[quote]\n#{DText.extract_mention(body, "@#{user_name}")}\n[/quote]\n}}
) )
module SearchMethods module SearchMethods
@@ -74,7 +74,7 @@ class ForumPost < ApplicationRecord
end end
def voted?(user, score) def voted?(user, score)
votes.where(creator_id: user.id, score: score).exists? votes.exists?(creator_id: user.id, score: score)
end end
def autoreport_spam def autoreport_spam
@@ -149,7 +149,7 @@ class ForumPost < ApplicationRecord
def is_original_post?(original_post_id = nil) def is_original_post?(original_post_id = nil)
if original_post_id if original_post_id
return id == original_post_id id == original_post_id
else else
ForumPost.exists?(["id = ? and id = (select _.id from forum_posts _ where _.topic_id = ? order by _.id asc limit 1)", id, topic_id]) ForumPost.exists?(["id = ? and id = (select _.id from forum_posts _ where _.topic_id = ? order by _.id asc limit 1)", id, topic_id])
end end

View File

@@ -7,7 +7,7 @@ class ForumPostVote < ApplicationRecord
scope :up, -> {where(score: 1)} scope :up, -> {where(score: 1)}
scope :down, -> {where(score: -1)} scope :down, -> {where(score: -1)}
scope :by, ->(user_id) {where(creator_id: user_id)} scope :by, ->(user_id) {where(creator_id: user_id)}
scope :excluding_user, ->(user_id) {where("creator_id <> ?", user_id)} scope :excluding_user, ->(user_id) { where.not(creator_id: user_id) }
def self.visible(user) def self.visible(user)
where(forum_post: ForumPost.visible(user)) where(forum_post: ForumPost.visible(user))
@@ -37,14 +37,13 @@ class ForumPostVote < ApplicationRecord
end end
def vote_type def vote_type
if score == 1 case score
return "up" when 1
elsif score == -1 "up"
return "down" when -1
elsif score == 0 "down"
return "meh" when 0
else "meh"
raise
end end
end end

View File

@@ -2,13 +2,13 @@ class ForumTopic < ApplicationRecord
CATEGORIES = { CATEGORIES = {
0 => "General", 0 => "General",
1 => "Tags", 1 => "Tags",
2 => "Bugs & Features" 2 => "Bugs & Features",
} }
MIN_LEVELS = { MIN_LEVELS = {
None: 0, None: 0,
Moderator: User::Levels::MODERATOR, Moderator: User::Levels::MODERATOR,
Admin: User::Levels::ADMIN Admin: User::Levels::ADMIN,
} }
belongs_to :creator, class_name: "User" belongs_to :creator, class_name: "User"
@@ -17,14 +17,14 @@ class ForumTopic < ApplicationRecord
has_many :forum_topic_visits has_many :forum_topic_visits
has_one :forum_topic_visit_by_current_user, -> { where(user_id: CurrentUser.id) }, class_name: "ForumTopicVisit" has_one :forum_topic_visit_by_current_user, -> { where(user_id: CurrentUser.id) }, class_name: "ForumTopicVisit"
has_one :original_post, -> { order(id: :asc) }, class_name: "ForumPost", foreign_key: "topic_id", inverse_of: :topic has_one :original_post, -> { order(id: :asc) }, class_name: "ForumPost", foreign_key: "topic_id", inverse_of: :topic
has_many :bulk_update_requests, :foreign_key => "forum_topic_id" has_many :bulk_update_requests
has_many :tag_aliases, :foreign_key => "forum_topic_id" has_many :tag_aliases
has_many :tag_implications, :foreign_key => "forum_topic_id" has_many :tag_implications
validates :title, presence: true, length: { maximum: 200 }, if: :title_changed? validates :title, presence: true, length: { maximum: 200 }, if: :title_changed?
validates_associated :original_post validates_associated :original_post
validates_inclusion_of :category_id, :in => CATEGORIES.keys validates :category_id, inclusion: { in: CATEGORIES.keys }
validates_inclusion_of :min_level, :in => MIN_LEVELS.values validates :min_level, inclusion: { in: MIN_LEVELS.values }
accepts_nested_attributes_for :original_post accepts_nested_attributes_for :original_post
after_update :update_orignal_post after_update :update_orignal_post
@@ -129,9 +129,9 @@ class ForumTopic < ApplicationRecord
def mark_as_read!(user = CurrentUser.user) def mark_as_read!(user = CurrentUser.user)
return if user.is_anonymous? return if user.is_anonymous?
match = ForumTopicVisit.where(:user_id => user.id, :forum_topic_id => id).first visit = ForumTopicVisit.find_by(user_id: user.id, forum_topic_id: id)
if match if visit
match.update_attribute(:last_read_at, updated_at) visit.update!(last_read_at: updated_at)
else else
ForumTopicVisit.create(:user_id => user.id, :forum_topic_id => id, :last_read_at => updated_at) ForumTopicVisit.create(:user_id => user.id, :forum_topic_id => id, :last_read_at => updated_at)
end end

View File

@@ -9,7 +9,7 @@ class IpBan < ApplicationRecord
deletable deletable
enum category: { enum category: {
full: 0, full: 0,
partial: 100 partial: 100,
}, _suffix: "ban" }, _suffix: "ban"
def self.visible(user) def self.visible(user)

View File

@@ -53,7 +53,7 @@ class ModAction < ApplicationRecord
ip_ban_undelete: 163, ip_ban_undelete: 163,
mass_update: 1000, # XXX unused mass_update: 1000, # XXX unused
bulk_revert: 1001, # XXX unused bulk_revert: 1001, # XXX unused
other: 2000 other: 2000,
} }
def self.visible(user) def self.visible(user)

View File

@@ -2,9 +2,14 @@ class Note < ApplicationRecord
class RevertError < StandardError; end class RevertError < StandardError; end
attr_accessor :html_id attr_accessor :html_id
belongs_to :post belongs_to :post
has_many :versions, -> {order("note_versions.id ASC")}, :class_name => "NoteVersion", :dependent => :destroy has_many :versions, -> {order("note_versions.id ASC")}, :class_name => "NoteVersion", :dependent => :destroy
validates_presence_of :x, :y, :width, :height, :body validates :x, presence: true
validates :y, presence: true
validates :width, presence: true
validates :height, presence: true
validates :body, presence: true
validate :note_within_image validate :note_within_image
after_save :update_post after_save :update_post
after_save :create_version after_save :create_version
@@ -95,7 +100,7 @@ class Note < ApplicationRecord
def revert_to(version) def revert_to(version)
if id != version.note_id if id != version.note_id
raise RevertError.new("You cannot revert to a previous version of another note.") raise RevertError, "You cannot revert to a previous version of another note."
end end
self.x = version.x self.x = version.x

View File

@@ -11,23 +11,17 @@ class NoteVersion < ApplicationRecord
end end
def previous def previous
@previous ||= begin @previous ||= NoteVersion.where("note_id = ? and version < ?", note_id, version).order("updated_at desc").limit(1).to_a
NoteVersion.where("note_id = ? and version < ?", note_id, version).order("updated_at desc").limit(1).to_a
end
@previous.first @previous.first
end end
def subsequent def subsequent
@subsequent ||= begin @subsequent ||= NoteVersion.where("note_id = ? and version > ?", note_id, version).order("updated_at asc").limit(1).to_a
NoteVersion.where("note_id = ? and version > ?", note_id, version).order("updated_at asc").limit(1).to_a
end
@subsequent.first @subsequent.first
end end
def current def current
@current ||= begin @current ||= NoteVersion.where(note_id: note_id).order("updated_at desc").limit(1).to_a
NoteVersion.where("note_id = ?", note_id).order("updated_at desc").limit(1).to_a
end
@current.first @current.first
end end
@@ -42,17 +36,17 @@ class NoteVersion < ApplicationRecord
end end
def was_moved(type) def was_moved(type)
other = self.send(type) other = send(type)
x != other.x || y != other.y x != other.x || y != other.y
end end
def was_resized(type) def was_resized(type)
other = self.send(type) other = send(type)
width != other.width || height != other.height width != other.width || height != other.height
end end
def was_deleted(type) def was_deleted(type)
other = self.send(type) other = send(type)
if type == "previous" if type == "previous"
!is_active && other.is_active !is_active && other.is_active
else else
@@ -61,7 +55,7 @@ class NoteVersion < ApplicationRecord
end end
def was_undeleted(type) def was_undeleted(type)
other = self.send(type) other = send(type)
if type == "previous" if type == "previous"
is_active && !other.is_active is_active && !other.is_active
else else

View File

@@ -4,14 +4,14 @@ class Pool < ApplicationRecord
array_attribute :post_ids, parse: /\d+/, cast: :to_i array_attribute :post_ids, parse: /\d+/, cast: :to_i
validates_uniqueness_of :name, case_sensitive: false, if: :name_changed? validates :name, uniqueness: { case_sensitive: false }, if: :name_changed?
validate :validate_name, if: :name_changed? validate :validate_name, if: :name_changed?
validates_inclusion_of :category, :in => %w(series collection) validates :category, inclusion: { in: %w[series collection] }
validate :updater_can_edit_deleted validate :updater_can_edit_deleted
before_validation :normalize_post_ids before_validation :normalize_post_ids
before_validation :normalize_name before_validation :normalize_name
after_save :create_version
after_create :synchronize! after_create :synchronize!
after_save :create_version
deletable deletable
@@ -47,9 +47,10 @@ class Pool < ApplicationRecord
q = q.name_matches(params[:name_matches]) q = q.name_matches(params[:name_matches])
end end
if params[:category] == "series" case params[:category]
when "series"
q = q.series q = q.series
elsif params[:category] == "collection" when "collection"
q = q.collection q = q.collection
end end
@@ -80,7 +81,7 @@ class Pool < ApplicationRecord
def self.named(name) def self.named(name)
if name =~ /^\d+$/ if name =~ /^\d+$/
where("pools.id = ?", name.to_i) where(id: name.to_i)
elsif name elsif name
where_ilike(:name, normalize_name_for_search(name)) where_ilike(:name, normalize_name_for_search(name))
else else
@@ -93,11 +94,8 @@ class Pool < ApplicationRecord
end end
def versions def versions
if PoolVersion.enabled? raise NotImplementedError, "Archive service not configured" unless PoolVersion.enabled?
PoolVersion.where("pool_id = ?", id).order("id asc") PoolVersion.where(pool_id: id).order("id asc")
else
raise "Archive service not configured"
end
end end
def is_series? def is_series?
@@ -126,7 +124,7 @@ class Pool < ApplicationRecord
def revert_to!(version) def revert_to!(version)
if id != version.pool_id if id != version.pool_id
raise RevertError.new("You cannot revert to a previous version of another pool.") raise RevertError, "You cannot revert to a previous version of another pool."
end end
self.post_ids = version.post_ids self.post_ids = version.post_ids

View File

@@ -18,7 +18,7 @@ class PoolVersion < ApplicationRecord
end end
def for_user(user_id) def for_user(user_id)
where("updater_id = ?", user_id) where(updater_id: user_id)
end end
def for_post_id(post_id) def for_post_id(post_id)
@@ -65,7 +65,7 @@ class PoolVersion < ApplicationRecord
def self.queue(pool, updater, updater_ip_addr) def self.queue(pool, updater, updater_ip_addr)
# queue updates to sqs so that if archives goes down for whatever reason it won't # queue updates to sqs so that if archives goes down for whatever reason it won't
# block pool updates # block pool updates
raise NotImplementedError.new("Archive service is not configured.") if !enabled? raise NotImplementedError, "Archive service is not configured." if !enabled?
json = { json = {
pool_id: pool.id, pool_id: pool.id,
@@ -93,23 +93,17 @@ class PoolVersion < ApplicationRecord
end end
def previous def previous
@previous ||= begin @previous ||= PoolVersion.where("pool_id = ? and version < ?", pool_id, version).order("version desc").limit(1).to_a
PoolVersion.where("pool_id = ? and version < ?", pool_id, version).order("version desc").limit(1).to_a
end
@previous.first @previous.first
end end
def subsequent def subsequent
@subsequent ||= begin @subsequent ||= PoolVersion.where("pool_id = ? and version > ?", pool_id, version).order("version asc").limit(1).to_a
PoolVersion.where("pool_id = ? and version > ?", pool_id, version).order("version asc").limit(1).to_a
end
@subsequent.first @subsequent.first
end end
def current def current
@current ||= begin @current ||= PoolVersion.where(pool_id: pool_id).order("version desc").limit(1).to_a
PoolVersion.where("pool_id = ?", pool_id).order("version desc").limit(1).to_a
end
@current.first @current.first
end end
@@ -126,12 +120,12 @@ class PoolVersion < ApplicationRecord
end end
def posts_changed(type) def posts_changed(type)
other = self.send(type) other = send(type)
((post_ids - other.post_ids) | (other.post_ids - post_ids)).length.positive? ((post_ids - other.post_ids) | (other.post_ids - post_ids)).length.positive?
end end
def was_deleted(type) def was_deleted(type)
other = self.send(type) other = send(type)
if type == "previous" if type == "previous"
is_deleted && !other.is_deleted is_deleted && !other.is_deleted
else else
@@ -140,7 +134,7 @@ class PoolVersion < ApplicationRecord
end end
def was_undeleted(type) def was_undeleted(type)
other = self.send(type) other = send(type)
if type == "previous" if type == "previous"
!is_deleted && other.is_deleted !is_deleted && other.is_deleted
else else
@@ -149,7 +143,7 @@ class PoolVersion < ApplicationRecord
end end
def was_activated(type) def was_activated(type)
other = self.send(type) other = send(type)
if type == "previous" if type == "previous"
is_active && !other.is_active is_active && !other.is_active
else else
@@ -158,7 +152,7 @@ class PoolVersion < ApplicationRecord
end end
def was_deactivated(type) def was_deactivated(type)
other = self.send(type) other = send(type)
if type == "previous" if type == "previous"
!is_active && other.is_active !is_active && other.is_active
else else

View File

@@ -18,8 +18,8 @@ class Post < ApplicationRecord
before_validation :parse_pixiv_id before_validation :parse_pixiv_id
before_validation :blank_out_nonexistent_parents before_validation :blank_out_nonexistent_parents
before_validation :remove_parent_loops before_validation :remove_parent_loops
validates_uniqueness_of :md5, :on => :create, message: ->(obj, data) { "duplicate: #{Post.find_by_md5(obj.md5).id}"} validates :md5, uniqueness: { message: ->(post, _data) { "duplicate: #{Post.find_by_md5(post.md5).id}" }}, on: :create
validates_inclusion_of :rating, in: %w(s q e), message: "rating must be s, q, or e" validates :rating, inclusion: { in: %w[s q e], message: "rating must be s, q, or e" }
validates :source, length: { maximum: 1200 } validates :source, length: { maximum: 1200 }
validate :added_tags_are_valid validate :added_tags_are_valid
validate :removed_tags_are_valid validate :removed_tags_are_valid
@@ -79,8 +79,8 @@ class Post < ApplicationRecord
module ClassMethods module ClassMethods
def delete_files(post_id, md5, file_ext, force: false) def delete_files(post_id, md5, file_ext, force: false)
if Post.where(md5: md5).exists? && !force if Post.exists?(md5: md5) && !force
raise DeletionError.new("Files still in use; skipping deletion.") raise DeletionError, "Files still in use; skipping deletion."
end end
Danbooru.config.storage_manager.delete_file(post_id, md5, file_ext, :original) Danbooru.config.storage_manager.delete_file(post_id, md5, file_ext, :original)
@@ -302,7 +302,7 @@ class Post < ApplicationRecord
flag = flags.create(reason: reason, is_deletion: is_deletion, creator: CurrentUser.user) flag = flags.create(reason: reason, is_deletion: is_deletion, creator: CurrentUser.user)
if flag.errors.any? if flag.errors.any?
raise PostFlag::Error.new(flag.errors.full_messages.join("; ")) raise PostFlag::Error, flag.errors.full_messages.join("; ")
end end
end end
@@ -311,7 +311,7 @@ class Post < ApplicationRecord
end end
def disapproved_by?(user) def disapproved_by?(user)
PostDisapproval.where(:user_id => user.id, :post_id => id).exists? PostDisapproval.exists?(user_id: user.id, post_id: id)
end end
def autoban def autoban
@@ -353,7 +353,7 @@ class Post < ApplicationRecord
end end
def source_domain def source_domain
return "" unless source =~ %r!\Ahttps?://!i return "" unless source =~ %r{\Ahttps?://}i
url = Addressable::URI.parse(normalized_source) url = Addressable::URI.parse(normalized_source)
url.domain url.domain
@@ -400,11 +400,11 @@ class Post < ApplicationRecord
end end
def set_tag_count(category, tagcount) def set_tag_count(category, tagcount)
self.send("tag_count_#{category}=", tagcount) send("tag_count_#{category}=", tagcount)
end end
def inc_tag_count(category) def inc_tag_count(category)
set_tag_count(category, self.send("tag_count_#{category}") + 1) set_tag_count(category, send("tag_count_#{category}") + 1)
end end
def set_tag_counts def set_tag_counts
@@ -469,7 +469,7 @@ class Post < ApplicationRecord
normalized_tags = filter_metatags(normalized_tags) normalized_tags = filter_metatags(normalized_tags)
normalized_tags = TagAlias.to_aliased(normalized_tags) normalized_tags = TagAlias.to_aliased(normalized_tags)
normalized_tags = remove_negated_tags(normalized_tags) normalized_tags = remove_negated_tags(normalized_tags)
normalized_tags = %w(tagme) if normalized_tags.empty? normalized_tags = %w[tagme] if normalized_tags.empty?
normalized_tags = add_automatic_tags(normalized_tags) normalized_tags = add_automatic_tags(normalized_tags)
normalized_tags = remove_invalid_tags(normalized_tags) normalized_tags = remove_invalid_tags(normalized_tags)
normalized_tags = Tag.convert_cosplay_tags(normalized_tags) normalized_tags = Tag.convert_cosplay_tags(normalized_tags)
@@ -496,11 +496,11 @@ class Post < ApplicationRecord
@negated_tags, tags = tags.partition {|x| x =~ /\A-/i} @negated_tags, tags = tags.partition {|x| x =~ /\A-/i}
@negated_tags = @negated_tags.map {|x| x[1..-1]} @negated_tags = @negated_tags.map {|x| x[1..-1]}
@negated_tags = TagAlias.to_aliased(@negated_tags) @negated_tags = TagAlias.to_aliased(@negated_tags)
return tags - @negated_tags tags - @negated_tags
end end
def add_automatic_tags(tags) def add_automatic_tags(tags)
tags -= %w(incredibly_absurdres absurdres highres lowres huge_filesize flash) tags -= %w[incredibly_absurdres absurdres highres lowres huge_filesize flash]
if has_dimensions? if has_dimensions?
if image_width >= 10_000 || image_height >= 10_000 if image_width >= 10_000 || image_height >= 10_000
@@ -549,7 +549,7 @@ class Post < ApplicationRecord
tags -= ["animated_png"] tags -= ["animated_png"]
end end
return tags tags
end end
def apply_casesensitive_metatags(tags) def apply_casesensitive_metatags(tags)
@@ -574,7 +574,8 @@ class Post < ApplicationRecord
end end
end end
end end
return tags
tags
end end
def filter_metatags(tags) def filter_metatags(tags)
@@ -582,7 +583,7 @@ class Post < ApplicationRecord
tags = apply_categorization_metatags(tags) tags = apply_categorization_metatags(tags)
@post_metatags, tags = tags.partition {|x| x =~ /\A(?:-pool|pool|newpool|fav|-fav|child|-child|-favgroup|favgroup|upvote|downvote|status|-status|disapproved):/i} @post_metatags, tags = tags.partition {|x| x =~ /\A(?:-pool|pool|newpool|fav|-fav|child|-child|-favgroup|favgroup|upvote|downvote|status|-status|disapproved):/i}
apply_pre_metatags apply_pre_metatags
return tags tags
end end
def apply_categorization_metatags(tags) def apply_categorization_metatags(tags)
@@ -1043,7 +1044,7 @@ class Post < ApplicationRecord
def revert_to(target) def revert_to(target)
if id != target.post_id if id != target.post_id
raise RevertError.new("You cannot revert to a previous version of another post.") raise RevertError, "You cannot revert to a previous version of another post."
end end
self.tag_string = target.tags self.tag_string = target.tags
@@ -1359,13 +1360,11 @@ class Post < ApplicationRecord
end end
def updater_can_change_rating def updater_can_change_rating
if rating_changed? && is_rating_locked?
# Don't forbid changes if the rating lock was just now set in the same update. # Don't forbid changes if the rating lock was just now set in the same update.
if !is_rating_locked_changed? if rating_changed? && is_rating_locked? && !is_rating_locked_changed?
errors.add(:rating, "is locked and cannot be changed. Unlock the post first.") errors.add(:rating, "is locked and cannot be changed. Unlock the post first.")
end end
end end
end
def uploader_is_not_limited def uploader_is_not_limited
errors.add(:uploader, "have reached your upload limit") if uploader.upload_limit.limited? errors.add(:uploader, "have reached your upload limit") if uploader.upload_limit.limited?
@@ -1401,7 +1400,7 @@ class Post < ApplicationRecord
def has_artist_tag def has_artist_tag
return if !new_record? return if !new_record?
return if source !~ %r!\Ahttps?://! return if source !~ %r{\Ahttps?://}
return if has_tag?("artist_request") || has_tag?("official_art") return if has_tag?("artist_request") || has_tag?("official_art")
return if tags.any?(&:artist?) return if tags.any?(&:artist?)
return if Sources::Strategies.find(source).is_a?(Sources::Strategies::Null) return if Sources::Strategies.find(source).is_a?(Sources::Strategies::Null)

View File

@@ -10,7 +10,7 @@ class PostAppeal < ApplicationRecord
enum status: { enum status: {
pending: 0, pending: 0,
succeeded: 1, succeeded: 1,
rejected: 2 rejected: 2,
} }
scope :expired, -> { pending.where("post_appeals.created_at < ?", Danbooru.config.moderation_period.ago) } scope :expired, -> { pending.where("post_appeals.created_at < ?", Danbooru.config.moderation_period.ago) }

View File

@@ -20,7 +20,7 @@ class PostApproval < ApplicationRecord
errors.add(:base, "You cannot approve a post you uploaded") errors.add(:base, "You cannot approve a post you uploaded")
end end
if post.approver == user || post.approvals.where(user: user).exists? if post.approver == user || post.approvals.exists?(user: user)
errors.add(:base, "You have previously approved this post and cannot approve it again") errors.add(:base, "You have previously approved this post and cannot approve it again")
end end
end end

View File

@@ -5,7 +5,7 @@ class PostDisapproval < ApplicationRecord
belongs_to :post belongs_to :post
belongs_to :user belongs_to :user
validates :user, uniqueness: { scope: :post, message: "have already hidden this post" } validates :user, uniqueness: { scope: :post, message: "have already hidden this post" }
validates_inclusion_of :reason, in: REASONS validates :reason, inclusion: { in: REASONS }
validate :validate_disapproval validate :validate_disapproval
scope :with_message, -> { where.not(message: nil) } scope :with_message, -> { where.not(message: nil) }

View File

@@ -4,6 +4,7 @@ class PostEvent
include ActiveModel::Serializers::Xml include ActiveModel::Serializers::Xml
attr_accessor :event attr_accessor :event
delegate :created_at, to: :event delegate :created_at, to: :event
def self.find_for_post(post_id) def self.find_for_post(post_id)
@@ -62,11 +63,11 @@ class PostEvent
def attributes def attributes
{ {
"creator_id": nil, creator_id: nil,
"created_at": nil, created_at: nil,
"reason": nil, reason: nil,
"status": nil, status: nil,
"type": nil type: nil,
} }
end end

View File

@@ -18,7 +18,7 @@ class PostFlag < ApplicationRecord
enum status: { enum status: {
pending: 0, pending: 0,
succeeded: 1, succeeded: 1,
rejected: 2 rejected: 2,
} }
scope :by_users, -> { where.not(creator: User.system) } scope :by_users, -> { where.not(creator: User.system) }

View File

@@ -9,7 +9,7 @@ class PostReplacement < ApplicationRecord
def initialize_fields def initialize_fields
self.creator = CurrentUser.user self.creator = CurrentUser.user
self.original_url = post.source self.original_url = post.source
self.tags = post.tag_string + " " + self.tags.to_s self.tags = "#{post.tag_string} #{tags}"
self.old_file_ext = post.file_ext self.old_file_ext = post.file_ext
self.old_file_size = post.file_size self.old_file_size = post.file_size

View File

@@ -81,7 +81,7 @@ class PostVersion < ApplicationRecord
def queue(post) def queue(post)
# queue updates to sqs so that if archives goes down for whatever reason it won't # queue updates to sqs so that if archives goes down for whatever reason it won't
# block post updates # block post updates
raise NotImplementedError.new("Archive service is not configured") if !enabled? raise NotImplementedError, "Archive service is not configured" if !enabled?
json = { json = {
"post_id" => post.id, "post_id" => post.id,
@@ -92,7 +92,7 @@ class PostVersion < ApplicationRecord
"updater_ip_addr" => CurrentUser.ip_addr.to_s, "updater_ip_addr" => CurrentUser.ip_addr.to_s,
"updated_at" => post.updated_at.try(:iso8601), "updated_at" => post.updated_at.try(:iso8601),
"created_at" => post.created_at.try(:iso8601), "created_at" => post.created_at.try(:iso8601),
"tags" => post.tag_string "tags" => post.tag_string,
} }
msg = "add post version\n#{json.to_json}" msg = "add post version\n#{json.to_json}"
sqs_service.send_message(msg, message_group_id: "post:#{post.id}") sqs_service.send_message(msg, message_group_id: "post:#{post.id}")
@@ -117,25 +117,21 @@ class PostVersion < ApplicationRecord
# HACK: if all the post versions for this post have already been preloaded, # HACK: if all the post versions for this post have already been preloaded,
# we can use that to avoid a SQL query. # we can use that to avoid a SQL query.
if association(:post).loaded? && post && post.association(:versions).loaded? if association(:post).loaded? && post && post.association(:versions).loaded?
ver = [post.versions.sort_by(&:version).reverse.find { |v| v.version < version }] [post.versions.sort_by(&:version).reverse.find { |v| v.version < version }]
else else
ver = PostVersion.where("post_id = ? and version < ?", post_id, version).order("version desc").limit(1).to_a PostVersion.where("post_id = ? and version < ?", post_id, version).order("version desc").limit(1).to_a
end end
end end
@previous.first @previous.first
end end
def subsequent def subsequent
@subsequent ||= begin @subsequent ||= PostVersion.where("post_id = ? and version > ?", post_id, version).order("version asc").limit(1).to_a
PostVersion.where("post_id = ? and version > ?", post_id, version).order("version asc").limit(1).to_a
end
@subsequent.first @subsequent.first
end end
def current def current
@current ||= begin @current ||= PostVersion.where(post_id: post_id).order("version desc").limit(1).to_a
PostVersion.where("post_id = ?", post_id).order("version desc").limit(1).to_a
end
@current.first @current.first
end end
@@ -167,11 +163,11 @@ class PostVersion < ApplicationRecord
def changes def changes
delta = { delta = {
:added_tags => added_tags, added_tags: added_tags,
:removed_tags => removed_tags, removed_tags: removed_tags,
:obsolete_removed_tags => [], obsolete_removed_tags: [],
:obsolete_added_tags => [], obsolete_added_tags: [],
:unchanged_tags => [] unchanged_tags: [],
} }
return delta if post.nil? return delta if post.nil?
@@ -252,9 +248,10 @@ class PostVersion < ApplicationRecord
removed = changes[:removed_tags] - changes[:obsolete_removed_tags] removed = changes[:removed_tags] - changes[:obsolete_removed_tags]
added.each do |tag| added.each do |tag|
if tag =~ /^source:/ case tag
when /^source:/
post.source = "" post.source = ""
elsif tag =~ /^parent:/ when /^parent:/
post.parent_id = nil post.parent_id = nil
else else
escaped_tag = Regexp.escape(tag) escaped_tag = Regexp.escape(tag)

View File

@@ -3,6 +3,7 @@ class SavedSearch < ApplicationRecord
QUERY_LIMIT = 1000 QUERY_LIMIT = 1000
attr_reader :disable_labels attr_reader :disable_labels
belongs_to :user belongs_to :user
normalize :query, :normalize_query normalize :query, :normalize_query
@@ -146,7 +147,7 @@ class SavedSearch < ApplicationRecord
PostQueryBuilder.new(query.to_s).normalized_query(sort: false).to_s PostQueryBuilder.new(query.to_s).normalized_query(sort: false).to_s
end end
def queries_for(user_id, label: nil, options: {}) def queries_for(user_id, label: nil)
searches = SavedSearch.where(user_id: user_id) searches = SavedSearch.where(user_id: user_id)
searches = searches.labeled(label) if label.present? searches = searches.labeled(label) if label.present?
queries = searches.map(&:normalized_query) queries = searches.map(&:normalized_query)
@@ -167,8 +168,8 @@ class SavedSearch < ApplicationRecord
end end
def rewrite_query(old_name, new_name) def rewrite_query(old_name, new_name)
self.query.gsub!(/(?:\A| )([-~])?#{Regexp.escape(old_name)}(?: |\z)/i) { " #{$1}#{new_name} " } query.gsub!(/(?:\A| )([-~])?#{Regexp.escape(old_name)}(?: |\z)/i) { " #{$1}#{new_name} " }
self.query.strip! query.strip!
end end
end end

View File

@@ -11,7 +11,7 @@ class Tag < ApplicationRecord
validates :name, tag_name: true, uniqueness: true, on: :create validates :name, tag_name: true, uniqueness: true, on: :create
validates :name, tag_name: true, on: :name validates :name, tag_name: true, on: :name
validates_inclusion_of :category, in: TagCategory.category_ids validates :category, inclusion: { in: TagCategory.category_ids }
after_save :update_category_cache, if: :saved_change_to_category? after_save :update_category_cache, if: :saved_change_to_category?
after_save :update_category_post_counts, if: :saved_change_to_category? after_save :update_category_post_counts, if: :saved_change_to_category?
@@ -21,13 +21,13 @@ class Tag < ApplicationRecord
module ApiMethods module ApiMethods
def to_legacy_json def to_legacy_json
return { {
"name" => name, name: name,
"id" => id, id: id,
"created_at" => created_at.try(:strftime, "%Y-%m-%d %H:%M"), created_at: created_at.try(:strftime, "%Y-%m-%d %H:%M"),
"count" => post_count, count: post_count,
"type" => category, type: category,
"ambiguous" => false ambiguous: false,
}.to_json }.to_json
end end
end end
@@ -255,7 +255,7 @@ class Tag < ApplicationRecord
def abbreviation_matches(abbrev) def abbreviation_matches(abbrev)
abbrev = abbrev.downcase.delete_prefix("/") abbrev = abbrev.downcase.delete_prefix("/")
return none if abbrev !~ /\A[a-z0-9\*]*\z/ return none if abbrev !~ /\A[a-z0-9*]*\z/
where("regexp_replace(tags.name, ?, '\\1', 'g') LIKE ?", ABBREVIATION_REGEXP.source, abbrev.to_escaped_for_sql_like) where("regexp_replace(tags.name, ?, '\\1', 'g') LIKE ?", ABBREVIATION_REGEXP.source, abbrev.to_escaped_for_sql_like)
end end
@@ -309,7 +309,7 @@ class Tag < ApplicationRecord
def names_matches_with_aliases(name, limit) def names_matches_with_aliases(name, limit)
name = normalize_name(name) name = normalize_name(name)
wildcard_name = name + '*' wildcard_name = "#{name}*"
query1 = query1 =
Tag Tag

View File

@@ -21,7 +21,8 @@ class TagRelationship < ApplicationRecord
before_validation :normalize_names before_validation :normalize_names
validates :status, inclusion: { in: %w[active deleted retired] } validates :status, inclusion: { in: %w[active deleted retired] }
validates_presence_of :antecedent_name, :consequent_name validates :antecedent_name, presence: true
validates :consequent_name, presence: true
validates :approver, presence: { message: "must exist" }, if: -> { approver_id.present? } validates :approver, presence: { message: "must exist" }, if: -> { approver_id.present? }
validates :forum_topic, presence: { message: "must exist" }, if: -> { forum_topic_id.present? } validates :forum_topic, presence: { message: "must exist" }, if: -> { forum_topic_id.present? }
validate :antecedent_and_consequent_are_different validate :antecedent_and_consequent_are_different
@@ -110,7 +111,7 @@ class TagRelationship < ApplicationRecord
end end
def self.approve!(antecedent_name:, consequent_name:, approver:, forum_topic: nil) def self.approve!(antecedent_name:, consequent_name:, approver:, forum_topic: nil)
ProcessTagRelationshipJob.perform_later(class_name: self.name, approver: approver, antecedent_name: antecedent_name, consequent_name: consequent_name, forum_topic: forum_topic) ProcessTagRelationshipJob.perform_later(class_name: name, approver: approver, antecedent_name: antecedent_name, consequent_name: consequent_name, forum_topic: forum_topic)
end end
def self.model_restriction(table) def self.model_restriction(table)

View File

@@ -62,13 +62,14 @@ class Upload < ApplicationRecord
end end
attr_accessor :as_pending, :replaced_post, :file attr_accessor :as_pending, :replaced_post, :file
belongs_to :uploader, :class_name => "User" belongs_to :uploader, :class_name => "User"
belongs_to :post, optional: true belongs_to :post, optional: true
before_validation :initialize_attributes, on: :create before_validation :initialize_attributes, on: :create
before_validation :assign_rating_from_tags before_validation :assign_rating_from_tags
# validates :source, format: { with: /\Ahttps?/ }, if: ->(record) {record.file.blank?}, on: :create # validates :source, format: { with: /\Ahttps?/ }, if: ->(record) {record.file.blank?}, on: :create
validates :rating, inclusion: { in: %w(q e s) }, allow_nil: true validates :rating, inclusion: { in: %w[q e s] }, allow_nil: true
validates :md5, confirmation: true, if: ->(rec) { rec.md5_confirmation.present? } validates :md5, confirmation: true, if: ->(rec) { rec.md5_confirmation.present? }
validates_with FileValidator, on: :file validates_with FileValidator, on: :file
serialize :context, JSON serialize :context, JSON
@@ -109,7 +110,7 @@ class Upload < ApplicationRecord
def delete_files def delete_files
# md5 is blank if the upload errored out before downloading the file. # md5 is blank if the upload errored out before downloading the file.
if is_completed? || md5.blank? || Upload.where(md5: md5).exists? || Post.where(md5: md5).exists? if is_completed? || md5.blank? || Upload.exists?(md5: md5) || Post.exists?(md5: md5)
return return
end end
@@ -170,7 +171,7 @@ class Upload < ApplicationRecord
source = source.unicode_normalize(:nfc) source = source.unicode_normalize(:nfc)
# percent encode unicode characters in urls # percent encode unicode characters in urls
if source =~ %r!\Ahttps?://!i if source =~ %r{\Ahttps?://}i
source = Addressable::URI.normalized_encode(source) rescue source source = Addressable::URI.normalized_encode(source) rescue source
end end
@@ -178,7 +179,7 @@ class Upload < ApplicationRecord
end end
def source_url def source_url
return nil unless source =~ %r!\Ahttps?://!i return nil unless source =~ %r{\Ahttps?://}i
Addressable::URI.heuristic_parse(source) rescue nil Addressable::URI.heuristic_parse(source) rescue nil
end end
end end

View File

@@ -1,5 +1,3 @@
require 'digest/sha1'
class User < ApplicationRecord class User < ApplicationRecord
class Error < StandardError; end class Error < StandardError; end
class PrivilegeError < StandardError; end class PrivilegeError < StandardError; end
@@ -17,10 +15,7 @@ class User < ApplicationRecord
end end
# Used for `before_action :<role>_only`. Must have a corresponding `is_<role>?` method. # Used for `before_action :<role>_only`. Must have a corresponding `is_<role>?` method.
Roles = Levels.constants.map(&:downcase) + [ Roles = Levels.constants.map(&:downcase) + %i[banned approver]
:banned,
:approver
]
# candidates for removal: # candidates for removal:
# - enable_post_navigation (disabled by 700) # - enable_post_navigation (disabled by 700)
@@ -36,7 +31,7 @@ class User < ApplicationRecord
# - enable_recommended_posts # - enable_recommended_posts
# - has_mail # - has_mail
# - is_super_voter # - is_super_voter
BOOLEAN_ATTRIBUTES = %w( BOOLEAN_ATTRIBUTES = %w[
is_banned is_banned
has_mail has_mail
receive_email_notifications receive_email_notifications
@@ -67,7 +62,7 @@ class User < ApplicationRecord
no_feedback no_feedback
requires_verification requires_verification
is_verified is_verified
) ]
DEFAULT_BLACKLIST = ["spoilers", "guro", "scat", "furry -rating:s"].join("\n") DEFAULT_BLACKLIST = ["spoilers", "guro", "scat", "furry -rating:s"].join("\n")
@@ -104,10 +99,10 @@ class User < ApplicationRecord
after_initialize :initialize_attributes, if: :new_record? after_initialize :initialize_attributes, if: :new_record?
validates :name, user_name: true, on: :create validates :name, user_name: true, on: :create
validates_length_of :password, :minimum => 5, :if => ->(rec) { rec.new_record? || rec.password.present?} validates :password, length: { minimum: 5 }, if: ->(rec) { rec.new_record? || rec.password.present? }
validates_inclusion_of :default_image_size, :in => %w(large original) validates :default_image_size, inclusion: { in: %w[large original] }
validates_inclusion_of :per_page, in: (1..PostSets::Post::MAX_PER_PAGE) validates :per_page, inclusion: { in: (1..PostSets::Post::MAX_PER_PAGE) }
validates_confirmation_of :password validates :password, confirmation: true
validates :comment_threshold, inclusion: { in: (-100..5) } validates :comment_threshold, inclusion: { in: (-100..5) }
before_validation :normalize_blacklisted_tags before_validation :normalize_blacklisted_tags
before_create :promote_to_owner_if_first_user before_create :promote_to_owner_if_first_user
@@ -233,13 +228,13 @@ class User < ApplicationRecord
end end
def anonymous def anonymous
user = User.new(name: "Anonymous", level: Levels::ANONYMOUS, created_at: Time.now) user = User.new(name: "Anonymous", level: Levels::ANONYMOUS, created_at: Time.zone.now)
user.freeze.readonly! user.freeze.readonly!
user user
end end
def level_hash def level_hash
return { {
"Restricted" => Levels::RESTRICTED, "Restricted" => Levels::RESTRICTED,
"Member" => Levels::MEMBER, "Member" => Levels::MEMBER,
"Gold" => Levels::GOLD, "Gold" => Levels::GOLD,
@@ -247,7 +242,7 @@ class User < ApplicationRecord
"Builder" => Levels::BUILDER, "Builder" => Levels::BUILDER,
"Moderator" => Levels::MODERATOR, "Moderator" => Levels::MODERATOR,
"Admin" => Levels::ADMIN, "Admin" => Levels::ADMIN,
"Owner" => Levels::OWNER "Owner" => Levels::OWNER,
} }
end end
@@ -293,7 +288,7 @@ class User < ApplicationRecord
def promote_to_owner_if_first_user def promote_to_owner_if_first_user
return if Rails.env.test? return if Rails.env.test?
if name != Danbooru.config.system_user && !User.where(level: Levels::OWNER).exists? if name != Danbooru.config.system_user && !User.exists?(level: Levels::OWNER)
self.level = Levels::OWNER self.level = Levels::OWNER
self.can_approve_posts = true self.can_approve_posts = true
self.can_upload_free = true self.can_upload_free = true
@@ -386,12 +381,12 @@ class User < ApplicationRecord
end end
def rewrite_blacklist(old_name, new_name) def rewrite_blacklist(old_name, new_name)
self.blacklisted_tags.gsub!(/(?:^| )([-~])?#{Regexp.escape(old_name)}(?: |$)/i) { " #{$1}#{new_name} " } blacklisted_tags.gsub!(/(?:^| )([-~])?#{Regexp.escape(old_name)}(?: |$)/i) { " #{$1}#{new_name} " }
end end
def normalize_blacklisted_tags def normalize_blacklisted_tags
return unless blacklisted_tags.present? return unless blacklisted_tags.present?
self.blacklisted_tags = self.blacklisted_tags.lines.map(&:strip).join("\n") self.blacklisted_tags = blacklisted_tags.lines.map(&:strip).join("\n")
end end
end end
@@ -615,7 +610,8 @@ class User < ApplicationRecord
params = params.dup params = params.dup
params[:name_matches] = params.delete(:name) if params[:name].present? params[:name_matches] = params.delete(:name) if params[:name].present?
q = search_attributes(params, q = search_attributes(
params,
:id, :created_at, :updated_at, :name, :level, :post_upload_count, :id, :created_at, :updated_at, :name, :level, :post_upload_count,
:post_update_count, :note_update_count, :favorite_count, :posts, :post_update_count, :note_update_count, :favorite_count, :posts,
:note_versions, :artist_commentary_versions, :post_appeals, :note_versions, :artist_commentary_versions, :post_appeals,

View File

@@ -1,11 +1,12 @@
class UserFeedback < ApplicationRecord class UserFeedback < ApplicationRecord
self.table_name = "user_feedback" self.table_name = "user_feedback"
attr_accessor :disable_dmail_notification
belongs_to :user belongs_to :user
belongs_to :creator, class_name: "User" belongs_to :creator, class_name: "User"
attr_accessor :disable_dmail_notification validates :body, presence: true
validates_presence_of :body, :category validates :category, presence: true, inclusion: { in: %w[positive negative neutral] }
validates_inclusion_of :category, :in => %w(positive negative neutral)
after_create :create_dmail, unless: :disable_dmail_notification after_create :create_dmail, unless: :disable_dmail_notification
after_update(:if => ->(rec) { CurrentUser.id != rec.creator_id}) do |rec| after_update(:if => ->(rec) { CurrentUser.id != rec.creator_id}) do |rec|
ModAction.log(%{#{CurrentUser.user.name} updated user feedback for "#{rec.user.name}":#{Routes.user_path(rec.user)}}, :user_feedback_update) ModAction.log(%{#{CurrentUser.user.name} updated user feedback for "#{rec.user.name}":#{Routes.user_path(rec.user)}}, :user_feedback_update)

View File

@@ -4,7 +4,8 @@ class UserNameChangeRequest < ApplicationRecord
validate :not_limited, on: :create validate :not_limited, on: :create
validates :desired_name, user_name: true, confirmation: true, on: :create validates :desired_name, user_name: true, confirmation: true, on: :create
validates_presence_of :original_name, :desired_name validates :original_name, presence: true
validates :desired_name, presence: true
after_create :update_name! after_create :update_name!
@@ -28,7 +29,7 @@ class UserNameChangeRequest < ApplicationRecord
end end
def not_limited def not_limited
if UserNameChangeRequest.unscoped.where(user: user).where("created_at >= ?", 1.week.ago).exists? if UserNameChangeRequest.unscoped.where(user: user).exists?(["created_at >= ?", 1.week.ago])
errors.add(:base, "You can only submit one name change request per week") errors.add(:base, "You can only submit one name change request per week")
end end
end end

View File

@@ -5,7 +5,7 @@ class UserUpgrade < ApplicationRecord
enum upgrade_type: { enum upgrade_type: {
gold: 0, gold: 0,
platinum: 10, platinum: 10,
gold_to_platinum: 20 gold_to_platinum: 20,
}, _suffix: "upgrade" }, _suffix: "upgrade"
enum status: { enum status: {
@@ -175,7 +175,7 @@ class UserUpgrade < ApplicationRecord
country: country, country: country,
is_gift: is_gift?, is_gift: is_gift?,
level: level, level: level,
}, }
) )
update!(stripe_id: checkout.id) update!(stripe_id: checkout.id)

View File

@@ -118,13 +118,13 @@ class WikiPage < ApplicationRecord
tag_was = Tag.find_by_name(Tag.normalize_name(title_was)) tag_was = Tag.find_by_name(Tag.normalize_name(title_was))
if tag_was.present? && !tag_was.empty? if tag_was.present? && !tag_was.empty?
warnings.add(:base, %!Warning: {{#{title_was}}} still has #{tag_was.post_count} #{"post".pluralize(tag_was.post_count)}. Be sure to move the posts!) warnings.add(:base, %{Warning: {{#{title_was}}} still has #{tag_was.post_count} #{"post".pluralize(tag_was.post_count)}. Be sure to move the posts})
end end
broken_wikis = WikiPage.linked_to(title_was) broken_wikis = WikiPage.linked_to(title_was)
if broken_wikis.count > 0 if broken_wikis.count > 0
broken_wiki_search = Routes.wiki_pages_path(search: { linked_to: title_was }) broken_wiki_search = Routes.wiki_pages_path(search: { linked_to: title_was })
warnings.add(:base, %!Warning: [[#{title_was}]] is still linked from "#{broken_wikis.count} #{"other wiki page".pluralize(broken_wikis.count)}":[#{broken_wiki_search}]. Update #{(broken_wikis.count > 1) ? "these wikis" : "this wiki"} to link to [[#{title}]] instead!) warnings.add(:base, %{Warning: [[#{title_was}]] is still linked from "#{broken_wikis.count} #{"other wiki page".pluralize(broken_wikis.count)}":[#{broken_wiki_search}]. Update #{(broken_wikis.count > 1) ? "these wikis" : "this wiki"} to link to [[#{title}]] instead})
end end
end end
@@ -136,7 +136,7 @@ class WikiPage < ApplicationRecord
def revert_to(version) def revert_to(version)
if id != version.wiki_page_id if id != version.wiki_page_id
raise RevertError.new("You cannot revert to a previous version of another wiki page.") raise RevertError, "You cannot revert to a previous version of another wiki page."
end end
self.title = version.title self.title = version.title

View File

@@ -21,23 +21,17 @@ class WikiPageVersion < ApplicationRecord
end end
def previous def previous
@previous ||= begin @previous ||= WikiPageVersion.where("wiki_page_id = ? and id < ?", wiki_page_id, id).order("id desc").limit(1).to_a
WikiPageVersion.where("wiki_page_id = ? and id < ?", wiki_page_id, id).order("id desc").limit(1).to_a
end
@previous.first @previous.first
end end
def subsequent def subsequent
@subsequent ||= begin @subsequent ||= WikiPageVersion.where("wiki_page_id = ? and id > ?", wiki_page_id, id).order("id asc").limit(1).to_a
WikiPageVersion.where("wiki_page_id = ? and id > ?", wiki_page_id, id).order("id asc").limit(1).to_a
end
@subsequent.first @subsequent.first
end end
def current def current
@current ||= begin @current ||= WikiPageVersion.where(wiki_page_id: wiki_page_id).order("id desc").limit(1).to_a
WikiPageVersion.where("wiki_page_id = ?", wiki_page_id).order("id desc").limit(1).to_a
end
@current.first @current.first
end end
@@ -52,12 +46,12 @@ class WikiPageVersion < ApplicationRecord
end end
def other_names_changed(type) def other_names_changed(type)
other = self.send(type) other = send(type)
((other_names - other.other_names) | (other.other_names - other_names)).length.positive? ((other_names - other.other_names) | (other.other_names - other_names)).length.positive?
end end
def was_deleted(type) def was_deleted(type)
other = self.send(type) other = send(type)
if type == "previous" if type == "previous"
is_deleted && !other.is_deleted is_deleted && !other.is_deleted
else else
@@ -66,7 +60,7 @@ class WikiPageVersion < ApplicationRecord
end end
def was_undeleted(type) def was_undeleted(type)
other = self.send(type) other = send(type)
if type == "previous" if type == "previous"
!is_deleted && other.is_deleted !is_deleted && other.is_deleted
else else

View File

@@ -24,7 +24,7 @@ class ApiKeyPolicy < ApplicationPolicy
end end
def permitted_attributes def permitted_attributes
[:name, :permitted_ip_addresses, permissions: []] [:name, :permitted_ip_addresses, { permissions: [] }]
end end
def api_attributes def api_attributes

View File

@@ -69,7 +69,7 @@ class ApplicationPolicy
# The list of attributes that are permitted to be returned by the API. # The list of attributes that are permitted to be returned by the API.
def api_attributes def api_attributes
# XXX allow inet # XXX allow inet
record.class.attribute_types.reject { |name, attr| attr.type.in?([:inet, :tsvector]) }.keys.map(&:to_sym) record.class.attribute_types.reject { |_name, attr| attr.type.in?([:inet, :tsvector]) }.keys.map(&:to_sym)
end end
# The list of attributes that are permitted to be used as data-* attributes # The list of attributes that are permitted to be used as data-* attributes

View File

@@ -16,6 +16,6 @@ class FavoriteGroupPolicy < ApplicationPolicy
end end
def permitted_attributes def permitted_attributes
[:name, :post_ids_string, :is_public, :post_ids, post_ids: []] [:name, :post_ids_string, :is_public, :post_ids, { post_ids: [] }]
end end
end end

View File

@@ -34,7 +34,7 @@ class ForumTopicPolicy < ApplicationPolicy
def permitted_attributes def permitted_attributes
[ [
:title, :category_id, { original_post_attributes: [:id, :body] }, :title, :category_id, { original_post_attributes: [:id, :body] },
([:is_sticky, :is_locked, :min_level] if moderate?) ([:is_sticky, :is_locked, :min_level] if moderate?),
].compact.flatten ].compact.flatten
end end

View File

@@ -20,7 +20,7 @@ class PoolPolicy < ApplicationPolicy
end end
def permitted_attributes def permitted_attributes
[:name, :description, :category, :post_ids, :post_ids_string, post_ids: []] [:name, :description, :category, :post_ids, :post_ids_string, { post_ids: [] }]
end end
def api_attributes def api_attributes

View File

@@ -8,12 +8,14 @@ class PostReplacementPolicy < ApplicationPolicy
end end
def permitted_attributes_for_create def permitted_attributes_for_create
[:replacement_url, :replacement_file, :final_source, :tags] %i[replacement_url replacement_file final_source tags]
end end
def permitted_attributes_for_update def permitted_attributes_for_update
[:old_file_ext, :old_file_size, :old_image_width, :old_image_height, %i[
:old_md5, :file_ext, :file_size, :image_width, :image_height, :md5, old_file_ext old_file_size old_image_width old_image_height old_md5
:original_url, :replacement_url] file_ext file_size image_width image_height md5 original_url
replacement_url
]
end end
end end

View File

@@ -36,15 +36,15 @@ class UserPolicy < ApplicationPolicy
end end
def permitted_attributes_for_update def permitted_attributes_for_update
[ %i[
:comment_threshold, :default_image_size, :favorite_tags, comment_threshold default_image_size favorite_tags
:blacklisted_tags, :time_zone, :per_page, :custom_style, :theme, blacklisted_tags time_zone per_page custom_style theme
:receive_email_notifications, :always_resize_images, receive_email_notifications always_resize_images
:new_post_navigation_layout, :enable_private_favorites, new_post_navigation_layout enable_private_favorites
:hide_deleted_posts, :style_usernames, :show_deleted_children, hide_deleted_posts style_usernames show_deleted_children
:disable_categorized_saved_searches, :disable_tagged_filenames, disable_categorized_saved_searches disable_tagged_filenames
:disable_cropped_thumbnails, :disable_mobile_gestures, :enable_safe_mode, disable_cropped_thumbnails disable_mobile_gestures enable_safe_mode
:enable_desktop_mode, :disable_post_tooltips, enable_desktop_mode disable_post_tooltips
].compact ].compact
end end

View File

@@ -1,5 +1,6 @@
class PostPresenter class PostPresenter
attr_reader :pool, :next_post_in_pool attr_reader :pool, :next_post_in_pool
delegate :split_tag_list_text, to: :tag_set_presenter delegate :split_tag_list_text, to: :tag_set_presenter
def initialize(post) def initialize(post)

View File

@@ -55,7 +55,7 @@ class TagSetPresenter
end end
def ordered_tags def ordered_tags
names_to_tags = tags.map { |tag| [tag.name, tag] }.to_h names_to_tags = tags.index_by(&:name)
tag_names.map do |name| tag_names.map do |name|
names_to_tags[name] || Tag.new(name: name).freeze names_to_tags[name] || Tag.new(name: name).freeze