bump gems except commonmarker (#1234)
lot of irritating churn out of standardrb here
This commit is contained in:
parent
623f8f851a
commit
2332d28022
|
@ -1 +1 @@
|
|||
3.2.2
|
||||
3.3.0
|
||||
|
|
|
@ -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:
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -26,7 +26,7 @@ gem "rotp"
|
|||
gem "rqrcode"
|
||||
|
||||
# parsing
|
||||
gem "commonmarker"
|
||||
gem "commonmarker", "<1"
|
||||
gem "htmlentities"
|
||||
gem "pdf-reader"
|
||||
gem "nokogiri"
|
||||
|
|
86
Gemfile.lock
86
Gemfile.lock
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}!"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# typed: false
|
||||
|
||||
class BanNotification < ApplicationMailer
|
||||
class BanNotificationMailer < ApplicationMailer
|
||||
def notify(user, banner, reason)
|
||||
@banner = banner
|
||||
@reason = reason
|
|
@ -1,6 +1,6 @@
|
|||
# typed: false
|
||||
|
||||
class EmailMessage < ApplicationMailer
|
||||
class EmailMessageMailer < ApplicationMailer
|
||||
def notify(message, user)
|
||||
@message = message
|
||||
@user = user
|
|
@ -1,6 +1,6 @@
|
|||
# typed: false
|
||||
|
||||
class EmailReply < ApplicationMailer
|
||||
class EmailReplyMailer < ApplicationMailer
|
||||
def reply(comment, user)
|
||||
@comment = comment
|
||||
@user = user
|
|
@ -1,6 +1,6 @@
|
|||
# typed: false
|
||||
|
||||
class PasswordReset < ApplicationMailer
|
||||
class PasswordResetMailer < ApplicationMailer
|
||||
def password_reset_link(user, ip)
|
||||
@user = user
|
||||
@ip = ip
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ class Moderation < ApplicationRecord
|
|||
m.body << "\n" \
|
||||
"*This is an automated message.*"
|
||||
|
||||
m.save
|
||||
m.save!
|
||||
end
|
||||
|
||||
protected
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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)%>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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? %>
|
||||
|
|
|
@ -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|
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
20
db/seeds.rb
20
db/seeds.rb
|
@ -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."
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# typed: false
|
||||
|
||||
require "commonmarker"
|
||||
|
||||
class Markdowner
|
||||
# opts[:allow_images] allows <img> tags
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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|
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]) }
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue