bump gems except commonmarker (#1234)

lot of irritating churn out of standardrb here
This commit is contained in:
Peter Bhat Harkins 2023-12-28 18:35:30 -06:00
parent 623f8f851a
commit 2332d28022
61 changed files with 223 additions and 222 deletions

View File

@ -1 +1 @@
3.2.2
3.3.0

View File

@ -1,10 +1,17 @@
ignore:
- '**/*':
# there's no "don't delete these records or shit will be on fire" option,
# just various "sure automatically destroy lots of data yolo" options
- Rails/HasManyOrHasOneDependent
# is a multimaster db while needing microsecond accurate sorting really 'standard'
- Rails/OrderById
# it's mad about the class variables and I don't want to risk the refactor now
- 'extras/**/*':
- Naming/VariableName
# migrations are not live code; ignore those before standardrb
# migrations are not live code
- 'db/migrate/201*'
- 'db/migrate/2020*'
- 'db/migrate/2022*'
- 'db/migrate/202309*'
plugins:

View File

@ -26,7 +26,7 @@ gem "rotp"
gem "rqrcode"
# parsing
gem "commonmarker"
gem "commonmarker", "<1"
gem "htmlentities"
gem "pdf-reader"
gem "nokogiri"

View File

@ -80,13 +80,13 @@ GEM
minitest (>= 5.1)
mutex_m
tzinfo (~> 2.0)
addressable (2.8.5)
addressable (2.8.6)
public_suffix (>= 2.0.2, < 6.0)
afm (0.2.2)
ast (2.4.2)
attr_extras (7.1.0)
base64 (0.1.1)
bcrypt (3.1.19)
base64 (0.2.0)
bcrypt (3.1.20)
benchmark-perf (0.6.0)
bigdecimal (3.1.5)
brakeman (6.1.1)
@ -124,19 +124,19 @@ GEM
exception_notification (4.5.0)
actionmailer (>= 5.2, < 8)
activesupport (>= 5.2, < 8)
execjs (2.9.0)
factory_bot (6.2.1)
execjs (2.9.1)
factory_bot (6.4.4)
activesupport (>= 5.0.0)
factory_bot_rails (6.2.0)
factory_bot (~> 6.2.0)
factory_bot_rails (6.4.2)
factory_bot (~> 6.4)
railties (>= 5.0.0)
faker (3.2.1)
faker (3.2.2)
i18n (>= 1.8.11, < 2)
ffi (1.15.5)
ffi (1.16.3)
flamegraph (0.9.5)
globalid (1.2.1)
activesupport (>= 6.1)
hashdiff (1.0.1)
hashdiff (1.1.0)
hashery (2.1.2)
hashie (5.0.0)
htmlentities (4.3.4)
@ -146,7 +146,7 @@ GEM
irb (1.11.0)
rdoc
reline (>= 0.3.8)
json (2.6.3)
json (2.7.1)
language_server-protocol (3.17.0.3)
lint_roller (1.1.0)
listen (3.8.0)
@ -168,7 +168,7 @@ GEM
minitest (5.20.0)
mutex_m (0.2.0)
mysql2 (0.5.5)
net-imap (0.4.8)
net-imap (0.4.9)
date
net-protocol
net-pop (0.1.2)
@ -178,10 +178,10 @@ GEM
net-smtp (0.4.0)
net-protocol
nio4r (2.7.0)
nokogiri (1.15.5)
nokogiri (1.16.0)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
nokogiri (1.15.5-x86_64-linux)
nokogiri (1.16.0-x86_64-linux)
racc (~> 1.4)
oauth (1.1.0)
oauth-tty (~> 1.0, >= 1.0.1)
@ -190,14 +190,14 @@ GEM
oauth-tty (1.0.5)
version_gem (~> 1.1, >= 1.1.1)
optimist (3.1.0)
parallel (1.23.0)
parser (3.2.2.3)
parallel (1.24.0)
parser (3.2.2.4)
ast (~> 2.4.1)
racc
parslet (2.0.0)
patience_diff (1.2.0)
optimist (~> 3.0)
pdf-reader (2.11.0)
pdf-reader (2.12.0)
Ascii85 (~> 1.0)
afm (~> 0.2.1)
hashery (~> 2.0)
@ -205,14 +205,14 @@ GEM
ttfunk
psych (5.1.2)
stringio
public_suffix (5.0.3)
puma (6.3.1)
public_suffix (5.0.4)
puma (6.4.0)
nio4r (~> 2.0)
racc (1.7.3)
rack (3.0.8)
rack-attack (6.7.0)
rack (>= 1.0, < 4)
rack-mini-profiler (3.1.1)
rack-mini-profiler (3.3.0)
rack (>= 1.2.0)
rack-session (2.0.0)
rack (>= 3.0.0)
@ -258,9 +258,9 @@ GEM
rb-readline (0.5.5)
rdoc (6.6.2)
psych (>= 4.0.0)
redis-client (0.17.0)
redis-client (0.19.1)
connection_pool
regexp_parser (2.8.1)
regexp_parser (2.8.3)
reline (0.4.1)
io-console (~> 0.5)
rexml (3.2.6)
@ -277,7 +277,7 @@ GEM
rspec-mocks (3.12.6)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-rails (6.0.3)
rspec-rails (6.1.0)
actionpack (>= 6.1)
activesupport (>= 6.1)
railties (>= 6.1)
@ -286,28 +286,28 @@ GEM
rspec-mocks (~> 3.12)
rspec-support (~> 3.12)
rspec-support (3.12.1)
rubocop (1.56.3)
base64 (~> 0.1.1)
rubocop (1.59.0)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.2.2.3)
parser (>= 3.2.2.4)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.28.1, < 2.0)
rubocop-ast (>= 1.30.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.29.0)
rubocop-ast (1.30.0)
parser (>= 3.2.1.0)
rubocop-performance (1.19.0)
rubocop (>= 1.7.0, < 2.0)
rubocop-ast (>= 0.4.0)
rubocop-rails (2.20.2)
rubocop-performance (1.20.1)
rubocop (>= 1.48.1, < 2.0)
rubocop-ast (>= 1.30.0, < 2.0)
rubocop-rails (2.23.1)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.33.0, < 2.0)
rubocop-sorbet (0.7.3)
rubocop-ast (>= 1.30.0, < 2.0)
rubocop-sorbet (0.7.6)
rubocop (>= 0.90.0)
ruby-progressbar (1.13.0)
ruby-rc4 (0.1.5)
@ -318,7 +318,7 @@ GEM
scenic-mysql_adapter (1.0.1)
mysql2
scenic (>= 1.4.0)
sidekiq (7.1.4)
sidekiq (7.2.0)
concurrent-ruby (< 2)
connection_pool (>= 2.3.0)
rack (>= 2.2.4)
@ -342,21 +342,21 @@ GEM
activesupport (>= 5.2)
sprockets (>= 3.0.0)
stackprof (0.2.25)
standard (1.31.1)
standard (1.33.0)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.0)
rubocop (~> 1.56.2)
rubocop (~> 1.59.0)
standard-custom (~> 1.0.0)
standard-performance (~> 1.2)
standard-performance (~> 1.3)
standard-custom (1.0.2)
lint_roller (~> 1.0)
rubocop (~> 1.50)
standard-performance (1.2.0)
standard-performance (1.3.0)
lint_roller (~> 1.1)
rubocop-performance (~> 1.19.0)
standard-rails (0.2.0)
rubocop-performance (~> 1.20.1)
standard-rails (1.0.0)
lint_roller (~> 1.0)
rubocop-rails (~> 2.20.2)
rubocop-rails (~> 2.23.1)
standard-sorbet (0.0.2)
lint_roller (~> 1.1)
rubocop-sorbet (~> 0.7.0)
@ -373,7 +373,7 @@ GEM
concurrent-ruby (~> 1.0)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
unicode-display_width (2.4.2)
unicode-display_width (2.5.0)
vcr (6.2.0)
version_gem (1.1.3)
webmock (3.19.1)
@ -400,7 +400,7 @@ DEPENDENCIES
brakeman
byebug
capybara
commonmarker
commonmarker (< 1)
database_cleaner
exception_notification
factory_bot_rails

View File

@ -31,7 +31,7 @@ class ApplicationController < ActionController::Base
def agent_is_spider?
ua = request.env["HTTP_USER_AGENT"].to_s
(ua == "" || ua.match(/(Google|bing|Slack|Twitter)bot|Slurp|crawler|Feedly|FeedParser|RSS/))
ua == "" || ua.match(/(Google|bing|Slack|Twitter)bot|Slurp|crawler|Feedly|FeedParser|RSS/)
end
def authenticate_user

View File

@ -5,7 +5,7 @@ class AvatarsController < ApplicationController
ALLOWED_SIZES = [16, 32, 100, 200].freeze
CACHE_DIR = "#{Rails.root}/public/avatars/".freeze
CACHE_DIR = Rails.public_path.join("avatars/").to_s.freeze
def expire
expired = 0
@ -13,7 +13,7 @@ class AvatarsController < ApplicationController
Dir.entries(CACHE_DIR).select { |f|
f.match(/\A#{@user.username}-(\d+)\.png\z/)
}.each do |f|
Rails.logger.debug "Expiring #{f}"
Rails.logger.debug { "Expiring #{f}" }
File.unlink("#{CACHE_DIR}/#{f}")
expired += 1
rescue => e

View File

@ -9,7 +9,7 @@ class CategoriesController < ApplicationController
end
def create
category = Category.create(category_params)
category = Category.create!(category_params)
if category.valid?
flash[:success] = "Category #{category.category} has been created"
redirect_to tags_path

View File

@ -16,7 +16,7 @@ class HatsController < ApplicationController
@hat_groups = {}
Hat.active.includes(:user).each do |h|
Hat.active.includes(:user).find_each do |h|
@hat_groups[h.hat] ||= []
@hat_groups[h.hat].push h
end

View File

@ -63,7 +63,7 @@ class LoginController < ApplicationController
if !user.password_digest.to_s.match(/^\$2a\$#{BCrypt::Engine::DEFAULT_COST}\$/o)
user.password = user.password_confirmation = params[:password].to_s
user.save
user.save!
end
if user.has_2fa? && !Rails.env.development?

View File

@ -86,7 +86,7 @@ class MessagesController < ApplicationController
if @message.recipient_user_id == @user.id
@message.has_been_read = true
@message.save
@message.save!
end
Rails.cache.delete("user:#{@user.id}:unread_replies")
end
@ -144,7 +144,7 @@ class MessagesController < ApplicationController
def keep_as_new
@message.has_been_read = false
@message.save
@message.save!
redirect_to "/messages"
end

View File

@ -61,7 +61,7 @@ class SignupController < ApplicationController
end
if @new_user.save
@invitation&.update(used_at: Time.current, new_user: @new_user)
@invitation&.update!(used_at: Time.current, new_user: @new_user)
session[:u] = @new_user.session_token
flash[:success] = "Welcome to #{Rails.application.name}, " \
"#{@new_user.username}!"

View File

@ -21,7 +21,7 @@ class StoriesController < ApplicationController
if @story.valid? && !(@story.already_posted_recently? && !@story.seen_previous)
if @story.save
ReadRibbon.where(user: @user, story: @story).first_or_create
ReadRibbon.where(user: @user, story: @story).first_or_create!
return redirect_to @story.comments_path
end
end
@ -437,7 +437,7 @@ class StoriesController < ApplicationController
@story = if @user.is_moderator?
Story.where(short_id: params[:story_id] || params[:id]).first
else
Story.where(user_id: @user.id, short_id: (params[:story_id] || params[:id])).first
Story.where(user_id: @user.id, short_id: params[:story_id] || params[:id]).first
end
if !@story
@ -471,7 +471,7 @@ class StoriesController < ApplicationController
def track_story_reads
@story = Story.where(short_id: params[:id]).first!
@ribbon = ReadRibbon.where(user: @user, story: @story).first_or_create
@ribbon = ReadRibbon.where(user: @user, story: @story).first_or_create!
yield
@ribbon.bump
end

View File

@ -30,7 +30,7 @@ class TagsController < ApplicationController
def create
@title = "Create Tag"
tag = Tag.create(tag_params)
if tag.valid?
if tag.persisted?
flash[:success] = "Tag #{tag.tag} has been created"
redirect_to tags_path
else

View File

@ -1,19 +1,19 @@
# typed: false
module StoriesHelper
def show_guidelines?
if !@user
def show_guidelines?(user)
if !user
return true
end
if @user.stories_submitted_count <= 5
if user.stories_submitted_count <= 5
return true
end
if Moderation.joins(:story)
.where(
"stories.user_id = ? AND moderations.created_at > ?",
@user.id,
user.id,
5.days.ago
).exists?
return true
@ -21,12 +21,4 @@ module StoriesHelper
false
end
def is_unread?(comment)
if !@user || !@ribbon
return false
end
(comment.created_at > @ribbon.updated_at) && (comment.user_id != @user.id)
end
end

View File

@ -1,7 +1,7 @@
# typed: false
module UsersHelper
def stories_submitted_content(showing_user)
def stories_submitted_content(user, showing_user)
tag = showing_user.most_common_story_tag
stories_submitted = showing_user.stories_submitted_count
@ -11,7 +11,7 @@ module UsersHelper
capture do
concat link_to(stories_displayed, newest_by_user_path(showing_user))
concat(" (+#{stories_deleted} deleted)") if user_is_moderator? && stories_deleted > 0
concat(" (+#{stories_deleted} deleted)") if user&.is_moderator? && stories_deleted > 0
if tag
concat ", most commonly tagged "
@ -20,13 +20,13 @@ module UsersHelper
end
end
def comments_posted_content(showing_user)
def comments_posted_content(user, showing_user)
comments_deleted = showing_user.comments_deleted_count
capture do
concat link_to(showing_user.comments_posted_count, user_threads_path(showing_user))
if user_is_moderator? && comments_deleted > 0
if user&.is_moderator? && comments_deleted > 0
concat " (+#{comments_deleted} deleted)"
end
end
@ -62,10 +62,4 @@ module UsersHelper
"(#{user.karma})"
end
end
private
def user_is_moderator?
@user&.is_moderator?
end
end

View File

@ -1,6 +1,6 @@
# typed: false
class BanNotification < ApplicationMailer
class BanNotificationMailer < ApplicationMailer
def notify(user, banner, reason)
@banner = banner
@reason = reason

View File

@ -1,6 +1,6 @@
# typed: false
class EmailMessage < ApplicationMailer
class EmailMessageMailer < ApplicationMailer
def notify(message, user)
@message = message
@user = user

View File

@ -1,6 +1,6 @@
# typed: false
class EmailReply < ApplicationMailer
class EmailReplyMailer < ApplicationMailer
def reply(comment, user)
@comment = comment
@user = user

View File

@ -1,6 +1,6 @@
# typed: false
class PasswordReset < ApplicationMailer
class PasswordResetMailer < ApplicationMailer
def password_reset_link(user, ip)
@user = user
@ip = ip

View File

@ -109,7 +109,7 @@ class Comment < ApplicationRecord
Comment.all.find_each do |c|
c.markeddown_comment = c.generated_markeddown_comment
c.save(validate: false)
c.save!(validate: false)
end
Comment.record_timestamps = true
@ -194,7 +194,7 @@ class Comment < ApplicationRecord
return false unless parent_comment_id
return false if user.is_moderator?
parent_comment_ids = parent_comment.parents.pluck(:id).append(parent_comment.id)
parent_comment_ids = parent_comment.parents.ids.append(parent_comment.id)
flag_count = Vote.comments_flags(parent_comment_ids).count
commenter_flag_count = Vote.comments_flags(parent_comment_ids, user).count # double-count author
delay = (2 + flag_count + commenter_flag_count).minutes
@ -205,7 +205,7 @@ class Comment < ApplicationRecord
return false if recent.blank?
wait = ActionController::Base.helpers
.distance_of_time_in_words(Time.now, (recent.created_at + delay))
.distance_of_time_in_words(Time.zone.now, (recent.created_at + delay))
Rails.logger.info "breaks_speed_limit: #{user.username} replying to https://lobste.rs/c/#{parent_comment.short_id} parent_comment_ids (#{parent_comment_ids.join(" ")}) flags #{flag_count} commenter_flag_count #{commenter_flag_count} delay #{delay} delay.ago #{delay.ago} recent #{recent.id}"
errors.add(
:comment,
@ -247,12 +247,12 @@ class Comment < ApplicationRecord
m.reason = reason
end
m.save
m.save!
User.update_counters user_id, karma: (votes.count * -2)
end
save(validate: false)
save!(validate: false)
Comment.record_timestamps = true
story.update_cached_columns
@ -268,7 +268,7 @@ class Comment < ApplicationRecord
if u.email_mentions?
begin
EmailReply.mention(self, u).deliver_now
EmailReplyMailer.mention(self, u).deliver_now
rescue => e
Rails.logger.error "error e-mailing #{u.email}: #{e}"
end
@ -307,7 +307,7 @@ class Comment < ApplicationRecord
users_following_thread.each do |u|
if u.email_replies?
begin
EmailReply.reply(self, u).deliver_now
EmailReplyMailer.reply(self, u).deliver_now
rescue => e
Rails.logger.error "error e-mailing #{u.email}: #{e}"
end
@ -581,11 +581,11 @@ class Comment < ApplicationRecord
m.comment_id = id
m.moderator_user_id = user.id
m.action = "undeleted comment"
m.save
m.save!
end
end
save(validate: false)
save!(validate: false)
Comment.record_timestamps = true
story.update_cached_columns

View File

@ -29,11 +29,11 @@ class Hat < ApplicationRecord
m.action = "Revoked hat \"#{hat}\": #{reason}"
m.save!
destroy
destroy!
end
def to_html_label
hl = (link.present? && link.match(/^https?:\/\//))
hl = link.present? && link.match(/^https?:\/\//)
h = "<span class=\"hat " \
"hat_#{hat.gsub(/[^A-Za-z0-9]/, "_").downcase}\" " \
@ -72,7 +72,7 @@ class Hat < ApplicationRecord
m.moderator_user_id = granted_by_user_id
m.action = "Granted hat \"#{hat}\"" + (link.present? ?
" (#{link})" : "")
m.save
m.save!
end
def sanitized_link

View File

@ -25,7 +25,7 @@ class HatRequest < ApplicationRecord
m.body = reason
m.save!
destroy
destroy!
end
end
@ -38,7 +38,7 @@ class HatRequest < ApplicationRecord
m.body = reason
m.save!
destroy
destroy!
end
end
end

View File

@ -12,7 +12,7 @@ class Keystore < ApplicationRecord
end
def self.value_for(key)
where(key: key).limit(1).pluck(:value).first
where(key: key).limit(1).pick(:value)
end
def self.put(key, value)

View File

@ -78,7 +78,7 @@ class Message < ApplicationRecord
def check_for_both_deleted
if deleted_by_author? && deleted_by_recipient?
destroy
destroy!
end
end
@ -91,7 +91,7 @@ class Message < ApplicationRecord
if recipient.email_messages?
begin
EmailMessage.notify(self, recipient).deliver_now
EmailMessageMailer.notify(self, recipient).deliver_now
rescue => e
Rails.logger.error "error e-mailing #{recipient.email}: #{e}"
end

View File

@ -11,7 +11,7 @@ class ModNote < ApplicationRecord
inverse_of: :mod_notes
scope :recent, -> { where("created_at >= ?", 1.week.ago).order("created_at desc") }
scope :for, ->(user) { includes(:moderator).where("user_id = ?", user).order("created_at desc") }
scope :for, ->(user) { includes(:moderator).where(user_id: user).order("created_at desc") }
validates :note, :markeddown_note, presence: true, length: {maximum: 65_535}

View File

@ -84,7 +84,7 @@ class Moderation < ApplicationRecord
m.body << "\n" \
"*This is an automated message.*"
m.save
m.save!
end
protected

View File

@ -4,6 +4,12 @@ class ReadRibbon < ApplicationRecord
belongs_to :user
belongs_to :story
def is_unread? comment
return false if !user
(comment.created_at > updated_at) && (comment.user_id != user.id)
end
# don't add callbacks to this model; for performance the read tracking in
# StoriesController uses .bump and RepliesController uses update_all, etc.
@ -28,7 +34,7 @@ class ReadRibbon < ApplicationRecord
# save without callbacks, validation, or transaction
def bump
if new_record?
save
save!
else
update_column(:updated_at, Time.now.utc)
end

View File

@ -13,7 +13,7 @@ class ReplyingComment < ApplicationRecord
scope :unread_replies_for, ->(user_id) { for_user(user_id).where(is_unread: true) }
scope :comment_replies_for,
->(user_id) { for_user(user_id).where.not(parent_comment_id: nil) }
scope :story_replies_for, ->(user_id) { for_user(user_id).where("parent_comment_id is null") }
scope :story_replies_for, ->(user_id) { for_user(user_id).where(parent_comment_id: nil) }
protected

View File

@ -99,7 +99,7 @@ class Story < ApplicationRecord
user.nil? ? none : joins(:savings).merge(SavedStory.by(user))
}
scope :to_tweet, -> {
hottest(nil, Tag.where(tag: "meta").pluck(:id))
hottest(nil, Tag.where(tag: "meta").ids)
.where(twitter_id: nil)
.where("score >= 2")
.where("created_at >= ?", 2.days.ago)
@ -153,9 +153,9 @@ class Story < ApplicationRecord
attr_writer :fetched_response
before_validation :assign_short_id_and_score, on: :create
before_create :assign_initial_hotness
before_save :log_moderation
before_save :fix_bogus_chars
before_create :assign_initial_hotness
after_create :mark_submitter, :record_initial_upvote
after_save :update_cached_columns, :update_story_text
@ -591,7 +591,7 @@ class Story < ApplicationRecord
}.join(", ")
m.reason = moderation_reason
m.save
m.save!
self.is_moderated = true
end
@ -614,7 +614,7 @@ class Story < ApplicationRecord
end
def merge_story_short_id=(sid)
self.merged_story_id = sid.present? ? Story.where(short_id: sid).pluck(:id).first : nil
self.merged_story_id = sid.present? ? Story.where(short_id: sid).pick(:id) : nil
end
def merge_story_short_id
@ -676,7 +676,7 @@ class Story < ApplicationRecord
st.each do |tagging|
if !new_tag_names_a.include?(tagging.tag.tag)
tagging.destroy
tagging.destroy!
end
end

View File

@ -7,7 +7,7 @@ class StoryRepository
end
def categories(cats)
tagged_story_ids = Tagging.select(:story_id).where(tag_id: Tag.where(category: cats).pluck(:id))
tagged_story_ids = Tagging.select(:story_id).where(tag_id: Tag.where(category: cats).select(:id))
Story.base(@user).positive_ranked.where(id: tagged_story_ids).order(created_at: :desc)
end
@ -28,7 +28,7 @@ class StoryRepository
def active
Story.base(@user)
.where.not(id: Story.hidden_by(@user).pluck(:id))
.where.not(id: Story.hidden_by(@user).select(:id))
.filter_tags(@params[:exclude_tags] || [])
.select('stories.*, (
select max(comments.id)

View File

@ -52,7 +52,7 @@ class User < ApplicationRecord
through: :votes,
source: :story
has_many :hats, dependent: :destroy
has_many :wearable_hats, -> { where("doffed_at is null") },
has_many :wearable_hats, -> { where(doffed_at: nil) },
class_name: "Hat",
inverse_of: :user
@ -184,7 +184,7 @@ class User < ApplicationRecord
h = super(only: attrs)
h[:avatar_url] = avatar_url
h[:invited_by_user] = User.where(id: invited_by_user_id).pluck(:username).first
h[:invited_by_user] = User.where(id: invited_by_user_id).pick(:username)
if github_username.present?
h[:github_username] = github_username
@ -264,7 +264,7 @@ class User < ApplicationRecord
self.banned_by_user_id = banner.id
self.banned_reason = reason
BanNotification.notify(self, banner, reason) unless deleted_at?
BanNotificationMailer.notify(self, banner, reason) unless deleted_at?
delete!
m = Moderation.new
@ -375,11 +375,11 @@ class User < ApplicationRecord
sent_messages.each do |m|
m.deleted_by_author = true
m.save
m.save!
end
received_messages.each do |m|
m.deleted_by_recipient = true
m.save
m.save!
end
invitations.destroy_all
@ -396,11 +396,11 @@ class User < ApplicationRecord
User.transaction do
sent_messages.each do |m|
m.deleted_by_author = false
m.save
m.save!
end
received_messages.each do |m|
m.deleted_by_recipient = false
m.save
m.save!
end
self.deleted_at = nil
@ -449,7 +449,7 @@ class User < ApplicationRecord
self.password_reset_token = "#{Time.current.to_i}-#{Utils.random_str(30)}"
save!
PasswordReset.password_reset_link(self, ip).deliver_now
PasswordResetMailer.password_reset_link(self, ip).deliver_now
end
def has_2fa?

View File

@ -27,7 +27,7 @@
show_story ||= @story.try(:id) != comment.story_id
# show merge icon only on story page when merged
was_merged = @story && (@story.id != comment.story_id)
is_unread = is_unread?(comment)
is_unread = @ribbon&.is_unread?(comment)
%>
<%#heinous_inline_partial(comments/_comment.html.erb)%>

View File

@ -76,7 +76,7 @@ Please don't use this to promote the story, summarize the post, or explain why y
See the guidelines below for more." %>
</div>
<%= tag.details class: "boxline actions", open: show_guidelines? ? true : nil do %>
<%= tag.details class: "boxline actions", open: show_guidelines?(@user) ? true : nil do %>
<summary>Story submission guidelines</summary>
<ul>

View File

@ -78,12 +78,12 @@
<label class="required">Stories Submitted:</label>
<span class="d">
<%= stories_submitted_content(@showing_user) %>
<%= stories_submitted_content(@user, @showing_user) %>
</span>
<br>
<label class="required">Comments Posted:</label>
<span class="d"><%= comments_posted_content(@showing_user) %></span>
<span class="d"><%= comments_posted_content(@user, @showing_user) %></span>
<br>
<% if @showing_user.hats.any? %>

View File

@ -39,7 +39,7 @@ module Lobsters
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
config.time_zone = "Central Time (US & Canada)"
# config.eager_load_paths << Rails.root.join("extras")
config.autoload_paths << "#{root}/extras"
# Raise an exception when using mass assignment with unpermitted attributes
config.action_controller.action_on_unpermitted_parameters = :raise
@ -56,8 +56,8 @@ module Lobsters
config.skip_yarn = true
config.after_initialize do
require "#{Rails.root}/lib/monkey.rb"
require "#{Rails.root}/lib/time_series.rb"
require Rails.root.join("lib/monkey.rb").to_s
require Rails.root.join("lib/time_series.rb").to_s
end
config.generators do |g|

View File

@ -148,6 +148,29 @@
],
"note": "Rendered markdown"
},
{
"warning_type": "File Access",
"warning_code": 16,
"fingerprint": "438821a8545ab06b9a347e6e1307042b8c6c837b3325e4d0f932dbff7beb6228",
"check_name": "FileAccess",
"message": "Model attribute used in file name",
"file": "app/controllers/avatars_controller.rb",
"line": 53,
"link": "https://brakemanscanner.org/docs/warning_types/file_access/",
"code": "File.rename(\"#{Rails.public_path.join(\"avatars/\").to_s}/.#{User.where(:username => username).first!.username}-#{:BRAKEMAN_SAFE_LITERAL}.png\", \"#{Rails.public_path.join(\"avatars/\").to_s}/#{User.where(:username => username).first!.username}-#{:BRAKEMAN_SAFE_LITERAL}.png\")",
"render_path": null,
"location": {
"type": "method",
"class": "AvatarsController",
"method": "show"
},
"user_input": "User.where(:username => username).first!.username",
"confidence": "Medium",
"cwe_id": [
22
],
"note": "User#username validated by User::VALID_USERNAME"
},
{
"warning_type": "SQL Injection",
"warning_code": 0,
@ -171,29 +194,6 @@
],
"note": "Search.flatten_title is a security control"
},
{
"warning_type": "File Access",
"warning_code": 16,
"fingerprint": "6b060ef0bd512b993bd2411b4e284fbc90bd7d7cd47fbfd7e3f01d8b2815a317",
"check_name": "FileAccess",
"message": "Model attribute used in file name",
"file": "app/controllers/avatars_controller.rb",
"line": 53,
"link": "https://brakemanscanner.org/docs/warning_types/file_access/",
"code": "File.rename(\"#{\"#{Rails.root}/public/avatars/\"}/.#{User.where(:username => username).first!.username}-#{:BRAKEMAN_SAFE_LITERAL}.png\", \"#{\"#{Rails.root}/public/avatars/\"}/#{User.where(:username => username).first!.username}-#{:BRAKEMAN_SAFE_LITERAL}.png\")",
"render_path": null,
"location": {
"type": "method",
"class": "AvatarsController",
"method": "show"
},
"user_input": "User.where(:username => username).first!.username",
"confidence": "Medium",
"cwe_id": [
22
],
"note": "User#username validated by User::VALID_USERNAME"
},
{
"warning_type": "Cross-Site Scripting",
"warning_code": 2,
@ -297,6 +297,29 @@
],
"note": "calculated_hotness returns float; id is an integer"
},
{
"warning_type": "File Access",
"warning_code": 16,
"fingerprint": "a49c5ada804d39509938a1b7737994d697c646342f3ba6745571665724944958",
"check_name": "FileAccess",
"message": "Model attribute used in file name",
"file": "app/controllers/avatars_controller.rb",
"line": 49,
"link": "https://brakemanscanner.org/docs/warning_types/file_access/",
"code": "File.open(\"#{Rails.public_path.join(\"avatars/\").to_s}/.#{User.where(:username => username).first!.username}-#{:BRAKEMAN_SAFE_LITERAL}.png\", \"wb+\")",
"render_path": null,
"location": {
"type": "method",
"class": "AvatarsController",
"method": "show"
},
"user_input": "User.where(:username => username).first!.username",
"confidence": "Medium",
"cwe_id": [
22
],
"note": "User#username validated by User::VALID_USERNAME"
},
{
"warning_type": "SQL Injection",
"warning_code": 0,
@ -501,29 +524,6 @@
],
"note": "Search.strip_operators is a security control"
},
{
"warning_type": "File Access",
"warning_code": 16,
"fingerprint": "e50701db198ac5e2a90070b29ba5eee35ee4a2528d774c1176de2dc1516cc721",
"check_name": "FileAccess",
"message": "Model attribute used in file name",
"file": "app/controllers/avatars_controller.rb",
"line": 49,
"link": "https://brakemanscanner.org/docs/warning_types/file_access/",
"code": "File.open(\"#{\"#{Rails.root}/public/avatars/\"}/.#{User.where(:username => username).first!.username}-#{:BRAKEMAN_SAFE_LITERAL}.png\", \"wb+\")",
"render_path": null,
"location": {
"type": "method",
"class": "AvatarsController",
"method": "show"
},
"user_input": "User.where(:username => username).first!.username",
"confidence": "Medium",
"cwe_id": [
22
],
"note": "User#username validated by User::VALID_USERNAME"
},
{
"warning_type": "SQL Injection",
"warning_code": 0,
@ -571,6 +571,6 @@
"note": "IntervalHelper#time_interval is a security control"
}
],
"updated": "2023-12-17 20:12:30 -0600",
"brakeman_version": "6.1.0"
"updated": "2023-12-28 19:26:34 -0600",
"brakeman_version": "6.1.1"
}

View File

@ -99,7 +99,7 @@ Rails.application.configure do
# cache full pages for logged-out visitors without tag filters
config.action_controller.perform_caching = true
config.action_controller.page_cache_directory = "#{Rails.root}/public/cache"
config.action_controller.page_cache_directory = Rails.public_path.join("cache").to_s
# why help timing attacks?
config.middleware.delete(Rack::Runtime)

View File

@ -11,5 +11,5 @@ require Rails.root.join("lib/monkey.rb").to_s
%w[extras lib].each do |dir|
Rails.autoloaders.main.push_dir(Rails.root.join(dir))
Dir[File.join(Rails.root, dir, "*.rb")].sort.each { |l| require l }
Dir[Rails.root.join(dir, "*.rb").to_s].sort.each { |l| require l }
end

View File

@ -6,7 +6,7 @@ check_hourly = 4.days.ago
check_daily = 2.weeks.ago
top_score = Story.all.maximum("score")
SitemapGenerator::Sitemap.create do
SitemapGenerator::Sitemap.create! do
%w[/about /chat].each do |path|
add path, changefreq: "monthly", lastmod: nil
end

View File

@ -1,12 +1,12 @@
pwd = SecureRandom.base58
User.create(
User.create!(
username: "inactive-user",
email: "inactive-user@example.com",
password: pwd,
password_confirmation: pwd
)
User.create(
User.create!(
username: "test",
email: "test@example.com",
password: "test",
@ -23,12 +23,12 @@ User.create(
)
c = Category.create!(category: "Category")
Tag.create(category: c, tag: "test")
Tag.create!(category: c, tag: "test")
puts "created:"
puts " * an admin with username/password of test/test"
puts " * inactive-user for disowned comments by deleted users"
puts " * a test tag"
puts
puts "If this is a dev environment, you probably want to run `rails fake_data`"
puts "If this is production, you want to run `rails console` to rename your admin. Edit your category, and tag on-site."
Rails.logger.debug "created:"
Rails.logger.debug " * an admin with username/password of test/test"
Rails.logger.debug " * inactive-user for disowned comments by deleted users"
Rails.logger.debug " * a test tag"
Rails.logger.debug
Rails.logger.debug "If this is a dev environment, you probably want to run `rails fake_data`"
Rails.logger.debug "If this is production, you want to run `rails console` to rename your admin. Edit your category, and tag on-site."

View File

@ -1,5 +1,7 @@
# typed: false
require "commonmarker"
class Markdowner
# opts[:allow_images] allows <img> tags

View File

@ -218,7 +218,7 @@ class FakeDataGenerator
story.editor = User.moderators.sample
story.moderation_reason = Faker::Lorem.sentence(word_count: 5)
end
story.update(is_deleted: true)
story.update!(is_deleted: true)
end
puts
@ -253,7 +253,7 @@ class FakeDataGenerator
story.merged_story_id = second_story.id
story.editing_from_suggestions = true
story.moderation_reason = Faker::Lorem.sentence(word_count: 5)
story.save
story.save!
end
puts
@ -264,7 +264,7 @@ class FakeDataGenerator
story.title = Faker::Lorem.sentence(word_count: 4)
story.editing_from_suggestions = true
story.moderation_reason = Faker::Lorem.sentence(word_count: 5)
story.save
story.save!
end
puts
@ -275,7 +275,7 @@ class FakeDataGenerator
story.is_deleted = true
story.editing_from_suggestions = true
story.moderation_reason = Faker::Lorem.sentence(word_count: 5)
story.save
story.save!
end
puts
end

View File

@ -13,17 +13,17 @@ class String
q_encode_word = ->(w) { "=?UTF-8?Q?#{w}?=" }
string \
string
# Undo linebreaks from #pack("M") because we'll be adding characters
.gsub("=\n", "") \
.gsub("=\n", "")
# Question marks are delimiters in q-encoding so must be escaped
.gsub("?", "=3F") \
.gsub("?", "=3F")
# Spaces are insignificant in q-encoding so must be escaped
.gsub(/\s+/, " _") \
.gsub(/\s+/, " _")
# Take each space-separated word, then q-encode
.split(" ").map(&q_encode_word) \
.split(" ").map(&q_encode_word)
# Recombine words then word wrap at 75 characters
.join(" ").word_wrap(75) \
.join(" ").word_wrap(75)
# Compose final string, folding headers per rfc 2822 section 2.2.3
.lines.join("\t")
end

View File

@ -70,7 +70,7 @@ end
if __FILE__ == $PROGRAM_NAME
last_story_id = (
Keystore.value_for(LAST_STORY_KEY) ||
Story.order("id desc").limit(1).offset(1).pluck(:id).try(:first)
Story.order("id desc").limit(1).offset(1).ids.try(:first)
).to_i
Story.where("id > ? AND is_deleted = ?", last_story_id, false).order(:id).each do |s|

View File

@ -36,7 +36,7 @@ our_users = User.active.where("settings LIKE '%twitter_username:%'")
# ignore users that have previously been determined to have protected accounts,
# which cannot be added to a public list
Keystore.where("`key` LIKE 'user:%:twitter_private'").each do |ks|
Keystore.where("`key` LIKE 'user:%:twitter_private'").find_each do |ks|
our_users.reject! do |k, _v|
k.downcase == ks.key.scan(/:(.+):/).first.first.downcase
end

View File

@ -31,7 +31,7 @@ FactoryBot.define do
deleted_at { Time.current }
end
trait(:new) do
deleted_at { Time.current - 1.day }
deleted_at { 1.day.ago }
end
# users who were banned/deleted before a server move
# you must also add banned/deleted trait with this

View File

@ -97,7 +97,7 @@ RSpec.feature "Commenting" do
comment.reload
expect(comment.score).to eq(2)
story.update(merged_stories: [hot_take])
story.update!(merged_stories: [hot_take])
visit "/s/#{story.short_id}"
expect(page.find(:css, ".comment.upvoted .score")).to have_content("2")
end

View File

@ -24,8 +24,8 @@ RSpec.feature "Reading Homepage", type: :feature do
end
feature "browsing stories by tag" do
let(:tag_a) { Category.first.tags.create(tag: "A1").tag }
let(:tag_b) { Category.first.tags.create(tag: "B2").tag }
let(:tag_a) { Category.first.tags.create!(tag: "A1").tag }
let(:tag_b) { Category.first.tags.create!(tag: "B2").tag }
let!(:ab_story) { create(:story, tags_a: [tag_a, tag_b]) }
let!(:a_story) { create(:story, tags_a: [tag_a]) }
let!(:b_story) { create(:story, tags_a: [tag_b]) }

View File

@ -69,7 +69,7 @@ RSpec.feature "Submitting Stories", type: :feature do
scenario "new user submitting a never-before-seen domain" do
inactive_user # TODO: remove reference after satisfying rubocop RSpec/LetSetup properly
user.update(created_at: 1.day.ago)
user.update!(created_at: 1.day.ago)
refute(Domain.where(domain: "example.net").exists?)
expect {
visit "/stories/new"
@ -83,7 +83,7 @@ RSpec.feature "Submitting Stories", type: :feature do
end
scenario "new user resubmitting a link" do
user.update(created_at: 1.day.ago)
user.update!(created_at: 1.day.ago)
s = create(:story, created_at: 1.year.ago)
expect {
visit "/stories/new"
@ -100,7 +100,7 @@ RSpec.feature "Submitting Stories", type: :feature do
inactive_user # TODO: remove reference after satisfying rubocop RSpec/LetSetup properly
drama = create(:tag, tag: "drama", permit_by_new_users: false)
earlier_story = create(:story)
user.update(created_at: 1.day.ago)
user.update!(created_at: 1.day.ago)
expect {
visit "/stories/new"
fill_in "URL", with: "https://#{earlier_story.domain.domain}/story"

View File

@ -2,13 +2,13 @@
require "rails_helper"
RSpec.describe EmailReply, type: :mailer do
RSpec.describe EmailReplyMailer, type: :mailer do
it "has a stable message-id" do
comment = create(:comment)
user = comment.user
e1 = EmailReply.reply(comment, user)
e2 = EmailReply.reply(comment, user)
e1 = EmailReplyMailer.reply(comment, user)
e2 = EmailReplyMailer.reply(comment, user)
expect(e1["Message-ID"]).to_not be_nil
expect(e1["Message-ID"].to_s).to eq(e2["Message-ID"].to_s)
end
@ -18,7 +18,7 @@ RSpec.describe EmailReply, type: :mailer do
comment = create(:comment)
reply = create(:comment, parent_comment: comment)
email = EmailReply.reply(reply, user)
email = EmailReplyMailer.reply(reply, user)
expect(email["Message-ID"].to_s).to eq("<#{reply.mailing_list_message_id}>")
expect(email["In-Reply-To"].to_s).to eq("<#{comment.mailing_list_message_id}>")
expect(email["References"].to_s).to include(comment.mailing_list_message_id)
@ -31,7 +31,7 @@ RSpec.describe EmailReply, type: :mailer do
user = comment.user
reply = create(:comment, parent_comment: comment)
email = EmailReply.reply(reply, user)
email = EmailReplyMailer.reply(reply, user)
expect(email.body.encoded).to match("replied to you")
end
@ -39,7 +39,7 @@ RSpec.describe EmailReply, type: :mailer do
user = create(:story).user
comment = create(:comment)
email = EmailReply.reply(comment, user)
email = EmailReplyMailer.reply(comment, user)
expect(email.body.encoded).to match("replied to your story")
end
@ -48,7 +48,7 @@ RSpec.describe EmailReply, type: :mailer do
comment = create(:comment, user: create(:user, username: "alice"))
reply = create(:comment, parent_comment: comment)
email = EmailReply.reply(reply, user)
email = EmailReplyMailer.reply(reply, user)
expect(email.body.encoded).to match("replied to alice")
end
end

View File

@ -5,7 +5,7 @@ require "rails_helper"
describe Category do
context "validations" do
it "allows a valid category to be created" do
category = Category.create(
category = Category.create!(
category: Faker::Lorem.word
)
expect(category).to be_valid

View File

@ -13,7 +13,7 @@ describe EmailParser do
@emailer = create(:user, mailing_list_mode: 1)
@emails = {}
Dir.glob("#{Rails.root}/spec/fixtures/inbound_emails/*.eml")
Dir.glob(Rails.root.join("spec/fixtures/inbound_emails/*.eml").to_s)
.each do |f|
@emails[File.basename(f).gsub(/\..*/, "")] = File.read(f)
.gsub("##SHORTNAME##", Rails.application.shortname)

View File

@ -16,7 +16,7 @@ end
describe ReplyingComment do
def followed_parent
p = create(:comment)
ReadRibbon.create(user_id: p.user_id, story_id: p.story_id, updated_at: p.created_at - 1.second)
ReadRibbon.create!(user_id: p.user_id, story_id: p.story_id, updated_at: p.created_at - 1.second)
p
end

View File

@ -384,7 +384,7 @@ describe Story do
create(:comment, story: story, score: -9, flags: 10)
# stories stop accepting comments after a while, but this calculation is
# based on created_at, so set that to a known value after posting comments
story.update(created_at: Time.zone.at(0))
story.update!(created_at: Time.zone.at(0))
end
context "with positive base" do
@ -396,7 +396,7 @@ describe Story do
context "with negative base" do
before do
tag = create(:tag, hotness_mod: -10)
story.update(tags: [tag])
story.update!(tags: [tag])
end
it "return correct score" do

View File

@ -5,7 +5,7 @@ require "rails_helper"
describe Tag do
context "validations" do
it "allows a valid tag to be created" do
tag = Tag.create(
tag = Tag.create!(
category: Category.first,
tag: "tag_name",
hotness_mod: 0.25,

View File

@ -160,7 +160,7 @@ describe "login", type: :request do
end
it "doesn't reset if token expired" do
user.update(password_reset_token: "#{2.days.ago.to_i}-#{Utils.random_str(30)}")
user.update!(password_reset_token: "#{2.days.ago.to_i}-#{Utils.random_str(30)}")
expect {
post "/login/set_new_password", params: {
token: user.password_reset_token,