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:
|
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
|
# it's mad about the class variables and I don't want to risk the refactor now
|
||||||
- 'extras/**/*':
|
- 'extras/**/*':
|
||||||
- Naming/VariableName
|
- Naming/VariableName
|
||||||
# migrations are not live code; ignore those before standardrb
|
# migrations are not live code
|
||||||
- 'db/migrate/201*'
|
- 'db/migrate/201*'
|
||||||
- 'db/migrate/2020*'
|
- 'db/migrate/2020*'
|
||||||
|
- 'db/migrate/2022*'
|
||||||
- 'db/migrate/202309*'
|
- 'db/migrate/202309*'
|
||||||
|
|
||||||
plugins:
|
plugins:
|
||||||
|
|
2
Gemfile
2
Gemfile
|
@ -26,7 +26,7 @@ gem "rotp"
|
||||||
gem "rqrcode"
|
gem "rqrcode"
|
||||||
|
|
||||||
# parsing
|
# parsing
|
||||||
gem "commonmarker"
|
gem "commonmarker", "<1"
|
||||||
gem "htmlentities"
|
gem "htmlentities"
|
||||||
gem "pdf-reader"
|
gem "pdf-reader"
|
||||||
gem "nokogiri"
|
gem "nokogiri"
|
||||||
|
|
86
Gemfile.lock
86
Gemfile.lock
|
@ -80,13 +80,13 @@ GEM
|
||||||
minitest (>= 5.1)
|
minitest (>= 5.1)
|
||||||
mutex_m
|
mutex_m
|
||||||
tzinfo (~> 2.0)
|
tzinfo (~> 2.0)
|
||||||
addressable (2.8.5)
|
addressable (2.8.6)
|
||||||
public_suffix (>= 2.0.2, < 6.0)
|
public_suffix (>= 2.0.2, < 6.0)
|
||||||
afm (0.2.2)
|
afm (0.2.2)
|
||||||
ast (2.4.2)
|
ast (2.4.2)
|
||||||
attr_extras (7.1.0)
|
attr_extras (7.1.0)
|
||||||
base64 (0.1.1)
|
base64 (0.2.0)
|
||||||
bcrypt (3.1.19)
|
bcrypt (3.1.20)
|
||||||
benchmark-perf (0.6.0)
|
benchmark-perf (0.6.0)
|
||||||
bigdecimal (3.1.5)
|
bigdecimal (3.1.5)
|
||||||
brakeman (6.1.1)
|
brakeman (6.1.1)
|
||||||
|
@ -124,19 +124,19 @@ GEM
|
||||||
exception_notification (4.5.0)
|
exception_notification (4.5.0)
|
||||||
actionmailer (>= 5.2, < 8)
|
actionmailer (>= 5.2, < 8)
|
||||||
activesupport (>= 5.2, < 8)
|
activesupport (>= 5.2, < 8)
|
||||||
execjs (2.9.0)
|
execjs (2.9.1)
|
||||||
factory_bot (6.2.1)
|
factory_bot (6.4.4)
|
||||||
activesupport (>= 5.0.0)
|
activesupport (>= 5.0.0)
|
||||||
factory_bot_rails (6.2.0)
|
factory_bot_rails (6.4.2)
|
||||||
factory_bot (~> 6.2.0)
|
factory_bot (~> 6.4)
|
||||||
railties (>= 5.0.0)
|
railties (>= 5.0.0)
|
||||||
faker (3.2.1)
|
faker (3.2.2)
|
||||||
i18n (>= 1.8.11, < 2)
|
i18n (>= 1.8.11, < 2)
|
||||||
ffi (1.15.5)
|
ffi (1.16.3)
|
||||||
flamegraph (0.9.5)
|
flamegraph (0.9.5)
|
||||||
globalid (1.2.1)
|
globalid (1.2.1)
|
||||||
activesupport (>= 6.1)
|
activesupport (>= 6.1)
|
||||||
hashdiff (1.0.1)
|
hashdiff (1.1.0)
|
||||||
hashery (2.1.2)
|
hashery (2.1.2)
|
||||||
hashie (5.0.0)
|
hashie (5.0.0)
|
||||||
htmlentities (4.3.4)
|
htmlentities (4.3.4)
|
||||||
|
@ -146,7 +146,7 @@ GEM
|
||||||
irb (1.11.0)
|
irb (1.11.0)
|
||||||
rdoc
|
rdoc
|
||||||
reline (>= 0.3.8)
|
reline (>= 0.3.8)
|
||||||
json (2.6.3)
|
json (2.7.1)
|
||||||
language_server-protocol (3.17.0.3)
|
language_server-protocol (3.17.0.3)
|
||||||
lint_roller (1.1.0)
|
lint_roller (1.1.0)
|
||||||
listen (3.8.0)
|
listen (3.8.0)
|
||||||
|
@ -168,7 +168,7 @@ GEM
|
||||||
minitest (5.20.0)
|
minitest (5.20.0)
|
||||||
mutex_m (0.2.0)
|
mutex_m (0.2.0)
|
||||||
mysql2 (0.5.5)
|
mysql2 (0.5.5)
|
||||||
net-imap (0.4.8)
|
net-imap (0.4.9)
|
||||||
date
|
date
|
||||||
net-protocol
|
net-protocol
|
||||||
net-pop (0.1.2)
|
net-pop (0.1.2)
|
||||||
|
@ -178,10 +178,10 @@ GEM
|
||||||
net-smtp (0.4.0)
|
net-smtp (0.4.0)
|
||||||
net-protocol
|
net-protocol
|
||||||
nio4r (2.7.0)
|
nio4r (2.7.0)
|
||||||
nokogiri (1.15.5)
|
nokogiri (1.16.0)
|
||||||
mini_portile2 (~> 2.8.2)
|
mini_portile2 (~> 2.8.2)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.15.5-x86_64-linux)
|
nokogiri (1.16.0-x86_64-linux)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
oauth (1.1.0)
|
oauth (1.1.0)
|
||||||
oauth-tty (~> 1.0, >= 1.0.1)
|
oauth-tty (~> 1.0, >= 1.0.1)
|
||||||
|
@ -190,14 +190,14 @@ GEM
|
||||||
oauth-tty (1.0.5)
|
oauth-tty (1.0.5)
|
||||||
version_gem (~> 1.1, >= 1.1.1)
|
version_gem (~> 1.1, >= 1.1.1)
|
||||||
optimist (3.1.0)
|
optimist (3.1.0)
|
||||||
parallel (1.23.0)
|
parallel (1.24.0)
|
||||||
parser (3.2.2.3)
|
parser (3.2.2.4)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
racc
|
racc
|
||||||
parslet (2.0.0)
|
parslet (2.0.0)
|
||||||
patience_diff (1.2.0)
|
patience_diff (1.2.0)
|
||||||
optimist (~> 3.0)
|
optimist (~> 3.0)
|
||||||
pdf-reader (2.11.0)
|
pdf-reader (2.12.0)
|
||||||
Ascii85 (~> 1.0)
|
Ascii85 (~> 1.0)
|
||||||
afm (~> 0.2.1)
|
afm (~> 0.2.1)
|
||||||
hashery (~> 2.0)
|
hashery (~> 2.0)
|
||||||
|
@ -205,14 +205,14 @@ GEM
|
||||||
ttfunk
|
ttfunk
|
||||||
psych (5.1.2)
|
psych (5.1.2)
|
||||||
stringio
|
stringio
|
||||||
public_suffix (5.0.3)
|
public_suffix (5.0.4)
|
||||||
puma (6.3.1)
|
puma (6.4.0)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
racc (1.7.3)
|
racc (1.7.3)
|
||||||
rack (3.0.8)
|
rack (3.0.8)
|
||||||
rack-attack (6.7.0)
|
rack-attack (6.7.0)
|
||||||
rack (>= 1.0, < 4)
|
rack (>= 1.0, < 4)
|
||||||
rack-mini-profiler (3.1.1)
|
rack-mini-profiler (3.3.0)
|
||||||
rack (>= 1.2.0)
|
rack (>= 1.2.0)
|
||||||
rack-session (2.0.0)
|
rack-session (2.0.0)
|
||||||
rack (>= 3.0.0)
|
rack (>= 3.0.0)
|
||||||
|
@ -258,9 +258,9 @@ GEM
|
||||||
rb-readline (0.5.5)
|
rb-readline (0.5.5)
|
||||||
rdoc (6.6.2)
|
rdoc (6.6.2)
|
||||||
psych (>= 4.0.0)
|
psych (>= 4.0.0)
|
||||||
redis-client (0.17.0)
|
redis-client (0.19.1)
|
||||||
connection_pool
|
connection_pool
|
||||||
regexp_parser (2.8.1)
|
regexp_parser (2.8.3)
|
||||||
reline (0.4.1)
|
reline (0.4.1)
|
||||||
io-console (~> 0.5)
|
io-console (~> 0.5)
|
||||||
rexml (3.2.6)
|
rexml (3.2.6)
|
||||||
|
@ -277,7 +277,7 @@ GEM
|
||||||
rspec-mocks (3.12.6)
|
rspec-mocks (3.12.6)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.12.0)
|
rspec-support (~> 3.12.0)
|
||||||
rspec-rails (6.0.3)
|
rspec-rails (6.1.0)
|
||||||
actionpack (>= 6.1)
|
actionpack (>= 6.1)
|
||||||
activesupport (>= 6.1)
|
activesupport (>= 6.1)
|
||||||
railties (>= 6.1)
|
railties (>= 6.1)
|
||||||
|
@ -286,28 +286,28 @@ GEM
|
||||||
rspec-mocks (~> 3.12)
|
rspec-mocks (~> 3.12)
|
||||||
rspec-support (~> 3.12)
|
rspec-support (~> 3.12)
|
||||||
rspec-support (3.12.1)
|
rspec-support (3.12.1)
|
||||||
rubocop (1.56.3)
|
rubocop (1.59.0)
|
||||||
base64 (~> 0.1.1)
|
|
||||||
json (~> 2.3)
|
json (~> 2.3)
|
||||||
language_server-protocol (>= 3.17.0)
|
language_server-protocol (>= 3.17.0)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 3.2.2.3)
|
parser (>= 3.2.2.4)
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
regexp_parser (>= 1.8, < 3.0)
|
regexp_parser (>= 1.8, < 3.0)
|
||||||
rexml (>= 3.2.5, < 4.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)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 2.4.0, < 3.0)
|
unicode-display_width (>= 2.4.0, < 3.0)
|
||||||
rubocop-ast (1.29.0)
|
rubocop-ast (1.30.0)
|
||||||
parser (>= 3.2.1.0)
|
parser (>= 3.2.1.0)
|
||||||
rubocop-performance (1.19.0)
|
rubocop-performance (1.20.1)
|
||||||
rubocop (>= 1.7.0, < 2.0)
|
rubocop (>= 1.48.1, < 2.0)
|
||||||
rubocop-ast (>= 0.4.0)
|
rubocop-ast (>= 1.30.0, < 2.0)
|
||||||
rubocop-rails (2.20.2)
|
rubocop-rails (2.23.1)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
rack (>= 1.1)
|
rack (>= 1.1)
|
||||||
rubocop (>= 1.33.0, < 2.0)
|
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)
|
rubocop (>= 0.90.0)
|
||||||
ruby-progressbar (1.13.0)
|
ruby-progressbar (1.13.0)
|
||||||
ruby-rc4 (0.1.5)
|
ruby-rc4 (0.1.5)
|
||||||
|
@ -318,7 +318,7 @@ GEM
|
||||||
scenic-mysql_adapter (1.0.1)
|
scenic-mysql_adapter (1.0.1)
|
||||||
mysql2
|
mysql2
|
||||||
scenic (>= 1.4.0)
|
scenic (>= 1.4.0)
|
||||||
sidekiq (7.1.4)
|
sidekiq (7.2.0)
|
||||||
concurrent-ruby (< 2)
|
concurrent-ruby (< 2)
|
||||||
connection_pool (>= 2.3.0)
|
connection_pool (>= 2.3.0)
|
||||||
rack (>= 2.2.4)
|
rack (>= 2.2.4)
|
||||||
|
@ -342,21 +342,21 @@ GEM
|
||||||
activesupport (>= 5.2)
|
activesupport (>= 5.2)
|
||||||
sprockets (>= 3.0.0)
|
sprockets (>= 3.0.0)
|
||||||
stackprof (0.2.25)
|
stackprof (0.2.25)
|
||||||
standard (1.31.1)
|
standard (1.33.0)
|
||||||
language_server-protocol (~> 3.17.0.2)
|
language_server-protocol (~> 3.17.0.2)
|
||||||
lint_roller (~> 1.0)
|
lint_roller (~> 1.0)
|
||||||
rubocop (~> 1.56.2)
|
rubocop (~> 1.59.0)
|
||||||
standard-custom (~> 1.0.0)
|
standard-custom (~> 1.0.0)
|
||||||
standard-performance (~> 1.2)
|
standard-performance (~> 1.3)
|
||||||
standard-custom (1.0.2)
|
standard-custom (1.0.2)
|
||||||
lint_roller (~> 1.0)
|
lint_roller (~> 1.0)
|
||||||
rubocop (~> 1.50)
|
rubocop (~> 1.50)
|
||||||
standard-performance (1.2.0)
|
standard-performance (1.3.0)
|
||||||
lint_roller (~> 1.1)
|
lint_roller (~> 1.1)
|
||||||
rubocop-performance (~> 1.19.0)
|
rubocop-performance (~> 1.20.1)
|
||||||
standard-rails (0.2.0)
|
standard-rails (1.0.0)
|
||||||
lint_roller (~> 1.0)
|
lint_roller (~> 1.0)
|
||||||
rubocop-rails (~> 2.20.2)
|
rubocop-rails (~> 2.23.1)
|
||||||
standard-sorbet (0.0.2)
|
standard-sorbet (0.0.2)
|
||||||
lint_roller (~> 1.1)
|
lint_roller (~> 1.1)
|
||||||
rubocop-sorbet (~> 0.7.0)
|
rubocop-sorbet (~> 0.7.0)
|
||||||
|
@ -373,7 +373,7 @@ GEM
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
uglifier (4.2.0)
|
uglifier (4.2.0)
|
||||||
execjs (>= 0.3.0, < 3)
|
execjs (>= 0.3.0, < 3)
|
||||||
unicode-display_width (2.4.2)
|
unicode-display_width (2.5.0)
|
||||||
vcr (6.2.0)
|
vcr (6.2.0)
|
||||||
version_gem (1.1.3)
|
version_gem (1.1.3)
|
||||||
webmock (3.19.1)
|
webmock (3.19.1)
|
||||||
|
@ -400,7 +400,7 @@ DEPENDENCIES
|
||||||
brakeman
|
brakeman
|
||||||
byebug
|
byebug
|
||||||
capybara
|
capybara
|
||||||
commonmarker
|
commonmarker (< 1)
|
||||||
database_cleaner
|
database_cleaner
|
||||||
exception_notification
|
exception_notification
|
||||||
factory_bot_rails
|
factory_bot_rails
|
||||||
|
|
|
@ -31,7 +31,7 @@ class ApplicationController < ActionController::Base
|
||||||
|
|
||||||
def agent_is_spider?
|
def agent_is_spider?
|
||||||
ua = request.env["HTTP_USER_AGENT"].to_s
|
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
|
end
|
||||||
|
|
||||||
def authenticate_user
|
def authenticate_user
|
||||||
|
|
|
@ -5,7 +5,7 @@ class AvatarsController < ApplicationController
|
||||||
|
|
||||||
ALLOWED_SIZES = [16, 32, 100, 200].freeze
|
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
|
def expire
|
||||||
expired = 0
|
expired = 0
|
||||||
|
@ -13,7 +13,7 @@ class AvatarsController < ApplicationController
|
||||||
Dir.entries(CACHE_DIR).select { |f|
|
Dir.entries(CACHE_DIR).select { |f|
|
||||||
f.match(/\A#{@user.username}-(\d+)\.png\z/)
|
f.match(/\A#{@user.username}-(\d+)\.png\z/)
|
||||||
}.each do |f|
|
}.each do |f|
|
||||||
Rails.logger.debug "Expiring #{f}"
|
Rails.logger.debug { "Expiring #{f}" }
|
||||||
File.unlink("#{CACHE_DIR}/#{f}")
|
File.unlink("#{CACHE_DIR}/#{f}")
|
||||||
expired += 1
|
expired += 1
|
||||||
rescue => e
|
rescue => e
|
||||||
|
|
|
@ -9,7 +9,7 @@ class CategoriesController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
category = Category.create(category_params)
|
category = Category.create!(category_params)
|
||||||
if category.valid?
|
if category.valid?
|
||||||
flash[:success] = "Category #{category.category} has been created"
|
flash[:success] = "Category #{category.category} has been created"
|
||||||
redirect_to tags_path
|
redirect_to tags_path
|
||||||
|
|
|
@ -16,7 +16,7 @@ class HatsController < ApplicationController
|
||||||
|
|
||||||
@hat_groups = {}
|
@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] ||= []
|
||||||
@hat_groups[h.hat].push h
|
@hat_groups[h.hat].push h
|
||||||
end
|
end
|
||||||
|
|
|
@ -63,7 +63,7 @@ class LoginController < ApplicationController
|
||||||
|
|
||||||
if !user.password_digest.to_s.match(/^\$2a\$#{BCrypt::Engine::DEFAULT_COST}\$/o)
|
if !user.password_digest.to_s.match(/^\$2a\$#{BCrypt::Engine::DEFAULT_COST}\$/o)
|
||||||
user.password = user.password_confirmation = params[:password].to_s
|
user.password = user.password_confirmation = params[:password].to_s
|
||||||
user.save
|
user.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
if user.has_2fa? && !Rails.env.development?
|
if user.has_2fa? && !Rails.env.development?
|
||||||
|
|
|
@ -86,7 +86,7 @@ class MessagesController < ApplicationController
|
||||||
|
|
||||||
if @message.recipient_user_id == @user.id
|
if @message.recipient_user_id == @user.id
|
||||||
@message.has_been_read = true
|
@message.has_been_read = true
|
||||||
@message.save
|
@message.save!
|
||||||
end
|
end
|
||||||
Rails.cache.delete("user:#{@user.id}:unread_replies")
|
Rails.cache.delete("user:#{@user.id}:unread_replies")
|
||||||
end
|
end
|
||||||
|
@ -144,7 +144,7 @@ class MessagesController < ApplicationController
|
||||||
|
|
||||||
def keep_as_new
|
def keep_as_new
|
||||||
@message.has_been_read = false
|
@message.has_been_read = false
|
||||||
@message.save
|
@message.save!
|
||||||
|
|
||||||
redirect_to "/messages"
|
redirect_to "/messages"
|
||||||
end
|
end
|
||||||
|
|
|
@ -61,7 +61,7 @@ class SignupController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
if @new_user.save
|
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
|
session[:u] = @new_user.session_token
|
||||||
flash[:success] = "Welcome to #{Rails.application.name}, " \
|
flash[:success] = "Welcome to #{Rails.application.name}, " \
|
||||||
"#{@new_user.username}!"
|
"#{@new_user.username}!"
|
||||||
|
|
|
@ -21,7 +21,7 @@ class StoriesController < ApplicationController
|
||||||
|
|
||||||
if @story.valid? && !(@story.already_posted_recently? && !@story.seen_previous)
|
if @story.valid? && !(@story.already_posted_recently? && !@story.seen_previous)
|
||||||
if @story.save
|
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
|
return redirect_to @story.comments_path
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -437,7 +437,7 @@ class StoriesController < ApplicationController
|
||||||
@story = if @user.is_moderator?
|
@story = if @user.is_moderator?
|
||||||
Story.where(short_id: params[:story_id] || params[:id]).first
|
Story.where(short_id: params[:story_id] || params[:id]).first
|
||||||
else
|
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
|
end
|
||||||
|
|
||||||
if !@story
|
if !@story
|
||||||
|
@ -471,7 +471,7 @@ class StoriesController < ApplicationController
|
||||||
|
|
||||||
def track_story_reads
|
def track_story_reads
|
||||||
@story = Story.where(short_id: params[:id]).first!
|
@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
|
yield
|
||||||
@ribbon.bump
|
@ribbon.bump
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,7 +30,7 @@ class TagsController < ApplicationController
|
||||||
def create
|
def create
|
||||||
@title = "Create Tag"
|
@title = "Create Tag"
|
||||||
tag = Tag.create(tag_params)
|
tag = Tag.create(tag_params)
|
||||||
if tag.valid?
|
if tag.persisted?
|
||||||
flash[:success] = "Tag #{tag.tag} has been created"
|
flash[:success] = "Tag #{tag.tag} has been created"
|
||||||
redirect_to tags_path
|
redirect_to tags_path
|
||||||
else
|
else
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
# typed: false
|
# typed: false
|
||||||
|
|
||||||
module StoriesHelper
|
module StoriesHelper
|
||||||
def show_guidelines?
|
def show_guidelines?(user)
|
||||||
if !@user
|
if !user
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if @user.stories_submitted_count <= 5
|
if user.stories_submitted_count <= 5
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if Moderation.joins(:story)
|
if Moderation.joins(:story)
|
||||||
.where(
|
.where(
|
||||||
"stories.user_id = ? AND moderations.created_at > ?",
|
"stories.user_id = ? AND moderations.created_at > ?",
|
||||||
@user.id,
|
user.id,
|
||||||
5.days.ago
|
5.days.ago
|
||||||
).exists?
|
).exists?
|
||||||
return true
|
return true
|
||||||
|
@ -21,12 +21,4 @@ module StoriesHelper
|
||||||
|
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_unread?(comment)
|
|
||||||
if !@user || !@ribbon
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
(comment.created_at > @ribbon.updated_at) && (comment.user_id != @user.id)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# typed: false
|
# typed: false
|
||||||
|
|
||||||
module UsersHelper
|
module UsersHelper
|
||||||
def stories_submitted_content(showing_user)
|
def stories_submitted_content(user, showing_user)
|
||||||
tag = showing_user.most_common_story_tag
|
tag = showing_user.most_common_story_tag
|
||||||
|
|
||||||
stories_submitted = showing_user.stories_submitted_count
|
stories_submitted = showing_user.stories_submitted_count
|
||||||
|
@ -11,7 +11,7 @@ module UsersHelper
|
||||||
capture do
|
capture do
|
||||||
concat link_to(stories_displayed, newest_by_user_path(showing_user))
|
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
|
if tag
|
||||||
concat ", most commonly tagged "
|
concat ", most commonly tagged "
|
||||||
|
@ -20,13 +20,13 @@ module UsersHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def comments_posted_content(showing_user)
|
def comments_posted_content(user, showing_user)
|
||||||
comments_deleted = showing_user.comments_deleted_count
|
comments_deleted = showing_user.comments_deleted_count
|
||||||
|
|
||||||
capture do
|
capture do
|
||||||
concat link_to(showing_user.comments_posted_count, user_threads_path(showing_user))
|
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)"
|
concat " (+#{comments_deleted} deleted)"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -62,10 +62,4 @@ module UsersHelper
|
||||||
"(#{user.karma})"
|
"(#{user.karma})"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def user_is_moderator?
|
|
||||||
@user&.is_moderator?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# typed: false
|
# typed: false
|
||||||
|
|
||||||
class BanNotification < ApplicationMailer
|
class BanNotificationMailer < ApplicationMailer
|
||||||
def notify(user, banner, reason)
|
def notify(user, banner, reason)
|
||||||
@banner = banner
|
@banner = banner
|
||||||
@reason = reason
|
@reason = reason
|
|
@ -1,6 +1,6 @@
|
||||||
# typed: false
|
# typed: false
|
||||||
|
|
||||||
class EmailMessage < ApplicationMailer
|
class EmailMessageMailer < ApplicationMailer
|
||||||
def notify(message, user)
|
def notify(message, user)
|
||||||
@message = message
|
@message = message
|
||||||
@user = user
|
@user = user
|
|
@ -1,6 +1,6 @@
|
||||||
# typed: false
|
# typed: false
|
||||||
|
|
||||||
class EmailReply < ApplicationMailer
|
class EmailReplyMailer < ApplicationMailer
|
||||||
def reply(comment, user)
|
def reply(comment, user)
|
||||||
@comment = comment
|
@comment = comment
|
||||||
@user = user
|
@user = user
|
|
@ -1,6 +1,6 @@
|
||||||
# typed: false
|
# typed: false
|
||||||
|
|
||||||
class PasswordReset < ApplicationMailer
|
class PasswordResetMailer < ApplicationMailer
|
||||||
def password_reset_link(user, ip)
|
def password_reset_link(user, ip)
|
||||||
@user = user
|
@user = user
|
||||||
@ip = ip
|
@ip = ip
|
|
@ -109,7 +109,7 @@ class Comment < ApplicationRecord
|
||||||
|
|
||||||
Comment.all.find_each do |c|
|
Comment.all.find_each do |c|
|
||||||
c.markeddown_comment = c.generated_markeddown_comment
|
c.markeddown_comment = c.generated_markeddown_comment
|
||||||
c.save(validate: false)
|
c.save!(validate: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
Comment.record_timestamps = true
|
Comment.record_timestamps = true
|
||||||
|
@ -194,7 +194,7 @@ class Comment < ApplicationRecord
|
||||||
return false unless parent_comment_id
|
return false unless parent_comment_id
|
||||||
return false if user.is_moderator?
|
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
|
flag_count = Vote.comments_flags(parent_comment_ids).count
|
||||||
commenter_flag_count = Vote.comments_flags(parent_comment_ids, user).count # double-count author
|
commenter_flag_count = Vote.comments_flags(parent_comment_ids, user).count # double-count author
|
||||||
delay = (2 + flag_count + commenter_flag_count).minutes
|
delay = (2 + flag_count + commenter_flag_count).minutes
|
||||||
|
@ -205,7 +205,7 @@ class Comment < ApplicationRecord
|
||||||
return false if recent.blank?
|
return false if recent.blank?
|
||||||
|
|
||||||
wait = ActionController::Base.helpers
|
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}"
|
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(
|
errors.add(
|
||||||
:comment,
|
:comment,
|
||||||
|
@ -247,12 +247,12 @@ class Comment < ApplicationRecord
|
||||||
m.reason = reason
|
m.reason = reason
|
||||||
end
|
end
|
||||||
|
|
||||||
m.save
|
m.save!
|
||||||
|
|
||||||
User.update_counters user_id, karma: (votes.count * -2)
|
User.update_counters user_id, karma: (votes.count * -2)
|
||||||
end
|
end
|
||||||
|
|
||||||
save(validate: false)
|
save!(validate: false)
|
||||||
Comment.record_timestamps = true
|
Comment.record_timestamps = true
|
||||||
|
|
||||||
story.update_cached_columns
|
story.update_cached_columns
|
||||||
|
@ -268,7 +268,7 @@ class Comment < ApplicationRecord
|
||||||
|
|
||||||
if u.email_mentions?
|
if u.email_mentions?
|
||||||
begin
|
begin
|
||||||
EmailReply.mention(self, u).deliver_now
|
EmailReplyMailer.mention(self, u).deliver_now
|
||||||
rescue => e
|
rescue => e
|
||||||
Rails.logger.error "error e-mailing #{u.email}: #{e}"
|
Rails.logger.error "error e-mailing #{u.email}: #{e}"
|
||||||
end
|
end
|
||||||
|
@ -307,7 +307,7 @@ class Comment < ApplicationRecord
|
||||||
users_following_thread.each do |u|
|
users_following_thread.each do |u|
|
||||||
if u.email_replies?
|
if u.email_replies?
|
||||||
begin
|
begin
|
||||||
EmailReply.reply(self, u).deliver_now
|
EmailReplyMailer.reply(self, u).deliver_now
|
||||||
rescue => e
|
rescue => e
|
||||||
Rails.logger.error "error e-mailing #{u.email}: #{e}"
|
Rails.logger.error "error e-mailing #{u.email}: #{e}"
|
||||||
end
|
end
|
||||||
|
@ -581,11 +581,11 @@ class Comment < ApplicationRecord
|
||||||
m.comment_id = id
|
m.comment_id = id
|
||||||
m.moderator_user_id = user.id
|
m.moderator_user_id = user.id
|
||||||
m.action = "undeleted comment"
|
m.action = "undeleted comment"
|
||||||
m.save
|
m.save!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
save(validate: false)
|
save!(validate: false)
|
||||||
Comment.record_timestamps = true
|
Comment.record_timestamps = true
|
||||||
|
|
||||||
story.update_cached_columns
|
story.update_cached_columns
|
||||||
|
|
|
@ -29,11 +29,11 @@ class Hat < ApplicationRecord
|
||||||
m.action = "Revoked hat \"#{hat}\": #{reason}"
|
m.action = "Revoked hat \"#{hat}\": #{reason}"
|
||||||
m.save!
|
m.save!
|
||||||
|
|
||||||
destroy
|
destroy!
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_html_label
|
def to_html_label
|
||||||
hl = (link.present? && link.match(/^https?:\/\//))
|
hl = link.present? && link.match(/^https?:\/\//)
|
||||||
|
|
||||||
h = "<span class=\"hat " \
|
h = "<span class=\"hat " \
|
||||||
"hat_#{hat.gsub(/[^A-Za-z0-9]/, "_").downcase}\" " \
|
"hat_#{hat.gsub(/[^A-Za-z0-9]/, "_").downcase}\" " \
|
||||||
|
@ -72,7 +72,7 @@ class Hat < ApplicationRecord
|
||||||
m.moderator_user_id = granted_by_user_id
|
m.moderator_user_id = granted_by_user_id
|
||||||
m.action = "Granted hat \"#{hat}\"" + (link.present? ?
|
m.action = "Granted hat \"#{hat}\"" + (link.present? ?
|
||||||
" (#{link})" : "")
|
" (#{link})" : "")
|
||||||
m.save
|
m.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
def sanitized_link
|
def sanitized_link
|
||||||
|
|
|
@ -25,7 +25,7 @@ class HatRequest < ApplicationRecord
|
||||||
m.body = reason
|
m.body = reason
|
||||||
m.save!
|
m.save!
|
||||||
|
|
||||||
destroy
|
destroy!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ class HatRequest < ApplicationRecord
|
||||||
m.body = reason
|
m.body = reason
|
||||||
m.save!
|
m.save!
|
||||||
|
|
||||||
destroy
|
destroy!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,7 +12,7 @@ class Keystore < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.value_for(key)
|
def self.value_for(key)
|
||||||
where(key: key).limit(1).pluck(:value).first
|
where(key: key).limit(1).pick(:value)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.put(key, value)
|
def self.put(key, value)
|
||||||
|
|
|
@ -78,7 +78,7 @@ class Message < ApplicationRecord
|
||||||
|
|
||||||
def check_for_both_deleted
|
def check_for_both_deleted
|
||||||
if deleted_by_author? && deleted_by_recipient?
|
if deleted_by_author? && deleted_by_recipient?
|
||||||
destroy
|
destroy!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ class Message < ApplicationRecord
|
||||||
|
|
||||||
if recipient.email_messages?
|
if recipient.email_messages?
|
||||||
begin
|
begin
|
||||||
EmailMessage.notify(self, recipient).deliver_now
|
EmailMessageMailer.notify(self, recipient).deliver_now
|
||||||
rescue => e
|
rescue => e
|
||||||
Rails.logger.error "error e-mailing #{recipient.email}: #{e}"
|
Rails.logger.error "error e-mailing #{recipient.email}: #{e}"
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,7 +11,7 @@ class ModNote < ApplicationRecord
|
||||||
inverse_of: :mod_notes
|
inverse_of: :mod_notes
|
||||||
|
|
||||||
scope :recent, -> { where("created_at >= ?", 1.week.ago).order("created_at desc") }
|
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}
|
validates :note, :markeddown_note, presence: true, length: {maximum: 65_535}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ class Moderation < ApplicationRecord
|
||||||
m.body << "\n" \
|
m.body << "\n" \
|
||||||
"*This is an automated message.*"
|
"*This is an automated message.*"
|
||||||
|
|
||||||
m.save
|
m.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
|
@ -4,6 +4,12 @@ class ReadRibbon < ApplicationRecord
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :story
|
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
|
# don't add callbacks to this model; for performance the read tracking in
|
||||||
# StoriesController uses .bump and RepliesController uses update_all, etc.
|
# StoriesController uses .bump and RepliesController uses update_all, etc.
|
||||||
|
|
||||||
|
@ -28,7 +34,7 @@ class ReadRibbon < ApplicationRecord
|
||||||
# save without callbacks, validation, or transaction
|
# save without callbacks, validation, or transaction
|
||||||
def bump
|
def bump
|
||||||
if new_record?
|
if new_record?
|
||||||
save
|
save!
|
||||||
else
|
else
|
||||||
update_column(:updated_at, Time.now.utc)
|
update_column(:updated_at, Time.now.utc)
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,7 +13,7 @@ class ReplyingComment < ApplicationRecord
|
||||||
scope :unread_replies_for, ->(user_id) { for_user(user_id).where(is_unread: true) }
|
scope :unread_replies_for, ->(user_id) { for_user(user_id).where(is_unread: true) }
|
||||||
scope :comment_replies_for,
|
scope :comment_replies_for,
|
||||||
->(user_id) { for_user(user_id).where.not(parent_comment_id: nil) }
|
->(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
|
protected
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,7 @@ class Story < ApplicationRecord
|
||||||
user.nil? ? none : joins(:savings).merge(SavedStory.by(user))
|
user.nil? ? none : joins(:savings).merge(SavedStory.by(user))
|
||||||
}
|
}
|
||||||
scope :to_tweet, -> {
|
scope :to_tweet, -> {
|
||||||
hottest(nil, Tag.where(tag: "meta").pluck(:id))
|
hottest(nil, Tag.where(tag: "meta").ids)
|
||||||
.where(twitter_id: nil)
|
.where(twitter_id: nil)
|
||||||
.where("score >= 2")
|
.where("score >= 2")
|
||||||
.where("created_at >= ?", 2.days.ago)
|
.where("created_at >= ?", 2.days.ago)
|
||||||
|
@ -153,9 +153,9 @@ class Story < ApplicationRecord
|
||||||
attr_writer :fetched_response
|
attr_writer :fetched_response
|
||||||
|
|
||||||
before_validation :assign_short_id_and_score, on: :create
|
before_validation :assign_short_id_and_score, on: :create
|
||||||
before_create :assign_initial_hotness
|
|
||||||
before_save :log_moderation
|
before_save :log_moderation
|
||||||
before_save :fix_bogus_chars
|
before_save :fix_bogus_chars
|
||||||
|
before_create :assign_initial_hotness
|
||||||
after_create :mark_submitter, :record_initial_upvote
|
after_create :mark_submitter, :record_initial_upvote
|
||||||
after_save :update_cached_columns, :update_story_text
|
after_save :update_cached_columns, :update_story_text
|
||||||
|
|
||||||
|
@ -591,7 +591,7 @@ class Story < ApplicationRecord
|
||||||
}.join(", ")
|
}.join(", ")
|
||||||
|
|
||||||
m.reason = moderation_reason
|
m.reason = moderation_reason
|
||||||
m.save
|
m.save!
|
||||||
|
|
||||||
self.is_moderated = true
|
self.is_moderated = true
|
||||||
end
|
end
|
||||||
|
@ -614,7 +614,7 @@ class Story < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def merge_story_short_id=(sid)
|
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
|
end
|
||||||
|
|
||||||
def merge_story_short_id
|
def merge_story_short_id
|
||||||
|
@ -676,7 +676,7 @@ class Story < ApplicationRecord
|
||||||
|
|
||||||
st.each do |tagging|
|
st.each do |tagging|
|
||||||
if !new_tag_names_a.include?(tagging.tag.tag)
|
if !new_tag_names_a.include?(tagging.tag.tag)
|
||||||
tagging.destroy
|
tagging.destroy!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ class StoryRepository
|
||||||
end
|
end
|
||||||
|
|
||||||
def categories(cats)
|
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)
|
Story.base(@user).positive_ranked.where(id: tagged_story_ids).order(created_at: :desc)
|
||||||
end
|
end
|
||||||
|
@ -28,7 +28,7 @@ class StoryRepository
|
||||||
|
|
||||||
def active
|
def active
|
||||||
Story.base(@user)
|
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] || [])
|
.filter_tags(@params[:exclude_tags] || [])
|
||||||
.select('stories.*, (
|
.select('stories.*, (
|
||||||
select max(comments.id)
|
select max(comments.id)
|
||||||
|
|
|
@ -52,7 +52,7 @@ class User < ApplicationRecord
|
||||||
through: :votes,
|
through: :votes,
|
||||||
source: :story
|
source: :story
|
||||||
has_many :hats, dependent: :destroy
|
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",
|
class_name: "Hat",
|
||||||
inverse_of: :user
|
inverse_of: :user
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ class User < ApplicationRecord
|
||||||
h = super(only: attrs)
|
h = super(only: attrs)
|
||||||
|
|
||||||
h[:avatar_url] = avatar_url
|
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?
|
if github_username.present?
|
||||||
h[:github_username] = github_username
|
h[:github_username] = github_username
|
||||||
|
@ -264,7 +264,7 @@ class User < ApplicationRecord
|
||||||
self.banned_by_user_id = banner.id
|
self.banned_by_user_id = banner.id
|
||||||
self.banned_reason = reason
|
self.banned_reason = reason
|
||||||
|
|
||||||
BanNotification.notify(self, banner, reason) unless deleted_at?
|
BanNotificationMailer.notify(self, banner, reason) unless deleted_at?
|
||||||
delete!
|
delete!
|
||||||
|
|
||||||
m = Moderation.new
|
m = Moderation.new
|
||||||
|
@ -375,11 +375,11 @@ class User < ApplicationRecord
|
||||||
|
|
||||||
sent_messages.each do |m|
|
sent_messages.each do |m|
|
||||||
m.deleted_by_author = true
|
m.deleted_by_author = true
|
||||||
m.save
|
m.save!
|
||||||
end
|
end
|
||||||
received_messages.each do |m|
|
received_messages.each do |m|
|
||||||
m.deleted_by_recipient = true
|
m.deleted_by_recipient = true
|
||||||
m.save
|
m.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
invitations.destroy_all
|
invitations.destroy_all
|
||||||
|
@ -396,11 +396,11 @@ class User < ApplicationRecord
|
||||||
User.transaction do
|
User.transaction do
|
||||||
sent_messages.each do |m|
|
sent_messages.each do |m|
|
||||||
m.deleted_by_author = false
|
m.deleted_by_author = false
|
||||||
m.save
|
m.save!
|
||||||
end
|
end
|
||||||
received_messages.each do |m|
|
received_messages.each do |m|
|
||||||
m.deleted_by_recipient = false
|
m.deleted_by_recipient = false
|
||||||
m.save
|
m.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
self.deleted_at = nil
|
self.deleted_at = nil
|
||||||
|
@ -449,7 +449,7 @@ class User < ApplicationRecord
|
||||||
self.password_reset_token = "#{Time.current.to_i}-#{Utils.random_str(30)}"
|
self.password_reset_token = "#{Time.current.to_i}-#{Utils.random_str(30)}"
|
||||||
save!
|
save!
|
||||||
|
|
||||||
PasswordReset.password_reset_link(self, ip).deliver_now
|
PasswordResetMailer.password_reset_link(self, ip).deliver_now
|
||||||
end
|
end
|
||||||
|
|
||||||
def has_2fa?
|
def has_2fa?
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
show_story ||= @story.try(:id) != comment.story_id
|
show_story ||= @story.try(:id) != comment.story_id
|
||||||
# show merge icon only on story page when merged
|
# show merge icon only on story page when merged
|
||||||
was_merged = @story && (@story.id != comment.story_id)
|
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)%>
|
<%#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." %>
|
See the guidelines below for more." %>
|
||||||
</div>
|
</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>
|
<summary>Story submission guidelines</summary>
|
||||||
<ul>
|
<ul>
|
||||||
|
|
||||||
|
|
|
@ -78,12 +78,12 @@
|
||||||
|
|
||||||
<label class="required">Stories Submitted:</label>
|
<label class="required">Stories Submitted:</label>
|
||||||
<span class="d">
|
<span class="d">
|
||||||
<%= stories_submitted_content(@showing_user) %>
|
<%= stories_submitted_content(@user, @showing_user) %>
|
||||||
</span>
|
</span>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<label class="required">Comments Posted:</label>
|
<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>
|
<br>
|
||||||
|
|
||||||
<% if @showing_user.hats.any? %>
|
<% 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.
|
# 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.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
|
# Raise an exception when using mass assignment with unpermitted attributes
|
||||||
config.action_controller.action_on_unpermitted_parameters = :raise
|
config.action_controller.action_on_unpermitted_parameters = :raise
|
||||||
|
@ -56,8 +56,8 @@ module Lobsters
|
||||||
config.skip_yarn = true
|
config.skip_yarn = true
|
||||||
|
|
||||||
config.after_initialize do
|
config.after_initialize do
|
||||||
require "#{Rails.root}/lib/monkey.rb"
|
require Rails.root.join("lib/monkey.rb").to_s
|
||||||
require "#{Rails.root}/lib/time_series.rb"
|
require Rails.root.join("lib/time_series.rb").to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
config.generators do |g|
|
config.generators do |g|
|
||||||
|
|
|
@ -148,6 +148,29 @@
|
||||||
],
|
],
|
||||||
"note": "Rendered markdown"
|
"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_type": "SQL Injection",
|
||||||
"warning_code": 0,
|
"warning_code": 0,
|
||||||
|
@ -171,29 +194,6 @@
|
||||||
],
|
],
|
||||||
"note": "Search.flatten_title is a security control"
|
"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_type": "Cross-Site Scripting",
|
||||||
"warning_code": 2,
|
"warning_code": 2,
|
||||||
|
@ -297,6 +297,29 @@
|
||||||
],
|
],
|
||||||
"note": "calculated_hotness returns float; id is an integer"
|
"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_type": "SQL Injection",
|
||||||
"warning_code": 0,
|
"warning_code": 0,
|
||||||
|
@ -501,29 +524,6 @@
|
||||||
],
|
],
|
||||||
"note": "Search.strip_operators is a security control"
|
"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_type": "SQL Injection",
|
||||||
"warning_code": 0,
|
"warning_code": 0,
|
||||||
|
@ -571,6 +571,6 @@
|
||||||
"note": "IntervalHelper#time_interval is a security control"
|
"note": "IntervalHelper#time_interval is a security control"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"updated": "2023-12-17 20:12:30 -0600",
|
"updated": "2023-12-28 19:26:34 -0600",
|
||||||
"brakeman_version": "6.1.0"
|
"brakeman_version": "6.1.1"
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ Rails.application.configure do
|
||||||
|
|
||||||
# cache full pages for logged-out visitors without tag filters
|
# cache full pages for logged-out visitors without tag filters
|
||||||
config.action_controller.perform_caching = true
|
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?
|
# why help timing attacks?
|
||||||
config.middleware.delete(Rack::Runtime)
|
config.middleware.delete(Rack::Runtime)
|
||||||
|
|
|
@ -11,5 +11,5 @@ require Rails.root.join("lib/monkey.rb").to_s
|
||||||
|
|
||||||
%w[extras lib].each do |dir|
|
%w[extras lib].each do |dir|
|
||||||
Rails.autoloaders.main.push_dir(Rails.root.join(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
|
end
|
||||||
|
|
|
@ -6,7 +6,7 @@ check_hourly = 4.days.ago
|
||||||
check_daily = 2.weeks.ago
|
check_daily = 2.weeks.ago
|
||||||
top_score = Story.all.maximum("score")
|
top_score = Story.all.maximum("score")
|
||||||
|
|
||||||
SitemapGenerator::Sitemap.create do
|
SitemapGenerator::Sitemap.create! do
|
||||||
%w[/about /chat].each do |path|
|
%w[/about /chat].each do |path|
|
||||||
add path, changefreq: "monthly", lastmod: nil
|
add path, changefreq: "monthly", lastmod: nil
|
||||||
end
|
end
|
||||||
|
|
20
db/seeds.rb
20
db/seeds.rb
|
@ -1,12 +1,12 @@
|
||||||
pwd = SecureRandom.base58
|
pwd = SecureRandom.base58
|
||||||
User.create(
|
User.create!(
|
||||||
username: "inactive-user",
|
username: "inactive-user",
|
||||||
email: "inactive-user@example.com",
|
email: "inactive-user@example.com",
|
||||||
password: pwd,
|
password: pwd,
|
||||||
password_confirmation: pwd
|
password_confirmation: pwd
|
||||||
)
|
)
|
||||||
|
|
||||||
User.create(
|
User.create!(
|
||||||
username: "test",
|
username: "test",
|
||||||
email: "test@example.com",
|
email: "test@example.com",
|
||||||
password: "test",
|
password: "test",
|
||||||
|
@ -23,12 +23,12 @@ User.create(
|
||||||
)
|
)
|
||||||
|
|
||||||
c = Category.create!(category: "Category")
|
c = Category.create!(category: "Category")
|
||||||
Tag.create(category: c, tag: "test")
|
Tag.create!(category: c, tag: "test")
|
||||||
|
|
||||||
puts "created:"
|
Rails.logger.debug "created:"
|
||||||
puts " * an admin with username/password of test/test"
|
Rails.logger.debug " * an admin with username/password of test/test"
|
||||||
puts " * inactive-user for disowned comments by deleted users"
|
Rails.logger.debug " * inactive-user for disowned comments by deleted users"
|
||||||
puts " * a test tag"
|
Rails.logger.debug " * a test tag"
|
||||||
puts
|
Rails.logger.debug
|
||||||
puts "If this is a dev environment, you probably want to run `rails fake_data`"
|
Rails.logger.debug "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 "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
|
# typed: false
|
||||||
|
|
||||||
|
require "commonmarker"
|
||||||
|
|
||||||
class Markdowner
|
class Markdowner
|
||||||
# opts[:allow_images] allows <img> tags
|
# opts[:allow_images] allows <img> tags
|
||||||
|
|
||||||
|
|
|
@ -218,7 +218,7 @@ class FakeDataGenerator
|
||||||
story.editor = User.moderators.sample
|
story.editor = User.moderators.sample
|
||||||
story.moderation_reason = Faker::Lorem.sentence(word_count: 5)
|
story.moderation_reason = Faker::Lorem.sentence(word_count: 5)
|
||||||
end
|
end
|
||||||
story.update(is_deleted: true)
|
story.update!(is_deleted: true)
|
||||||
end
|
end
|
||||||
puts
|
puts
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@ class FakeDataGenerator
|
||||||
story.merged_story_id = second_story.id
|
story.merged_story_id = second_story.id
|
||||||
story.editing_from_suggestions = true
|
story.editing_from_suggestions = true
|
||||||
story.moderation_reason = Faker::Lorem.sentence(word_count: 5)
|
story.moderation_reason = Faker::Lorem.sentence(word_count: 5)
|
||||||
story.save
|
story.save!
|
||||||
end
|
end
|
||||||
puts
|
puts
|
||||||
|
|
||||||
|
@ -264,7 +264,7 @@ class FakeDataGenerator
|
||||||
story.title = Faker::Lorem.sentence(word_count: 4)
|
story.title = Faker::Lorem.sentence(word_count: 4)
|
||||||
story.editing_from_suggestions = true
|
story.editing_from_suggestions = true
|
||||||
story.moderation_reason = Faker::Lorem.sentence(word_count: 5)
|
story.moderation_reason = Faker::Lorem.sentence(word_count: 5)
|
||||||
story.save
|
story.save!
|
||||||
end
|
end
|
||||||
puts
|
puts
|
||||||
|
|
||||||
|
@ -275,7 +275,7 @@ class FakeDataGenerator
|
||||||
story.is_deleted = true
|
story.is_deleted = true
|
||||||
story.editing_from_suggestions = true
|
story.editing_from_suggestions = true
|
||||||
story.moderation_reason = Faker::Lorem.sentence(word_count: 5)
|
story.moderation_reason = Faker::Lorem.sentence(word_count: 5)
|
||||||
story.save
|
story.save!
|
||||||
end
|
end
|
||||||
puts
|
puts
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,17 +13,17 @@ class String
|
||||||
|
|
||||||
q_encode_word = ->(w) { "=?UTF-8?Q?#{w}?=" }
|
q_encode_word = ->(w) { "=?UTF-8?Q?#{w}?=" }
|
||||||
|
|
||||||
string \
|
string
|
||||||
# Undo linebreaks from #pack("M") because we'll be adding characters
|
# 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
|
# 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
|
# Spaces are insignificant in q-encoding so must be escaped
|
||||||
.gsub(/\s+/, " _") \
|
.gsub(/\s+/, " _")
|
||||||
# Take each space-separated word, then q-encode
|
# 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
|
# 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
|
# Compose final string, folding headers per rfc 2822 section 2.2.3
|
||||||
.lines.join("\t")
|
.lines.join("\t")
|
||||||
end
|
end
|
||||||
|
|
|
@ -70,7 +70,7 @@ end
|
||||||
if __FILE__ == $PROGRAM_NAME
|
if __FILE__ == $PROGRAM_NAME
|
||||||
last_story_id = (
|
last_story_id = (
|
||||||
Keystore.value_for(LAST_STORY_KEY) ||
|
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
|
).to_i
|
||||||
|
|
||||||
Story.where("id > ? AND is_deleted = ?", last_story_id, false).order(:id).each do |s|
|
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,
|
# ignore users that have previously been determined to have protected accounts,
|
||||||
# which cannot be added to a public list
|
# 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|
|
our_users.reject! do |k, _v|
|
||||||
k.downcase == ks.key.scan(/:(.+):/).first.first.downcase
|
k.downcase == ks.key.scan(/:(.+):/).first.first.downcase
|
||||||
end
|
end
|
||||||
|
|
|
@ -31,7 +31,7 @@ FactoryBot.define do
|
||||||
deleted_at { Time.current }
|
deleted_at { Time.current }
|
||||||
end
|
end
|
||||||
trait(:new) do
|
trait(:new) do
|
||||||
deleted_at { Time.current - 1.day }
|
deleted_at { 1.day.ago }
|
||||||
end
|
end
|
||||||
# users who were banned/deleted before a server move
|
# users who were banned/deleted before a server move
|
||||||
# you must also add banned/deleted trait with this
|
# you must also add banned/deleted trait with this
|
||||||
|
|
|
@ -97,7 +97,7 @@ RSpec.feature "Commenting" do
|
||||||
comment.reload
|
comment.reload
|
||||||
expect(comment.score).to eq(2)
|
expect(comment.score).to eq(2)
|
||||||
|
|
||||||
story.update(merged_stories: [hot_take])
|
story.update!(merged_stories: [hot_take])
|
||||||
visit "/s/#{story.short_id}"
|
visit "/s/#{story.short_id}"
|
||||||
expect(page.find(:css, ".comment.upvoted .score")).to have_content("2")
|
expect(page.find(:css, ".comment.upvoted .score")).to have_content("2")
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,8 +24,8 @@ RSpec.feature "Reading Homepage", type: :feature do
|
||||||
end
|
end
|
||||||
|
|
||||||
feature "browsing stories by tag" do
|
feature "browsing stories by tag" do
|
||||||
let(:tag_a) { Category.first.tags.create(tag: "A1").tag }
|
let(:tag_a) { Category.first.tags.create!(tag: "A1").tag }
|
||||||
let(:tag_b) { Category.first.tags.create(tag: "B2").tag }
|
let(:tag_b) { Category.first.tags.create!(tag: "B2").tag }
|
||||||
let!(:ab_story) { create(:story, tags_a: [tag_a, tag_b]) }
|
let!(:ab_story) { create(:story, tags_a: [tag_a, tag_b]) }
|
||||||
let!(:a_story) { create(:story, tags_a: [tag_a]) }
|
let!(:a_story) { create(:story, tags_a: [tag_a]) }
|
||||||
let!(:b_story) { create(:story, tags_a: [tag_b]) }
|
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
|
scenario "new user submitting a never-before-seen domain" do
|
||||||
inactive_user # TODO: remove reference after satisfying rubocop RSpec/LetSetup properly
|
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?)
|
refute(Domain.where(domain: "example.net").exists?)
|
||||||
expect {
|
expect {
|
||||||
visit "/stories/new"
|
visit "/stories/new"
|
||||||
|
@ -83,7 +83,7 @@ RSpec.feature "Submitting Stories", type: :feature do
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario "new user resubmitting a link" do
|
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)
|
s = create(:story, created_at: 1.year.ago)
|
||||||
expect {
|
expect {
|
||||||
visit "/stories/new"
|
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
|
inactive_user # TODO: remove reference after satisfying rubocop RSpec/LetSetup properly
|
||||||
drama = create(:tag, tag: "drama", permit_by_new_users: false)
|
drama = create(:tag, tag: "drama", permit_by_new_users: false)
|
||||||
earlier_story = create(:story)
|
earlier_story = create(:story)
|
||||||
user.update(created_at: 1.day.ago)
|
user.update!(created_at: 1.day.ago)
|
||||||
expect {
|
expect {
|
||||||
visit "/stories/new"
|
visit "/stories/new"
|
||||||
fill_in "URL", with: "https://#{earlier_story.domain.domain}/story"
|
fill_in "URL", with: "https://#{earlier_story.domain.domain}/story"
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
require "rails_helper"
|
require "rails_helper"
|
||||||
|
|
||||||
RSpec.describe EmailReply, type: :mailer do
|
RSpec.describe EmailReplyMailer, type: :mailer do
|
||||||
it "has a stable message-id" do
|
it "has a stable message-id" do
|
||||||
comment = create(:comment)
|
comment = create(:comment)
|
||||||
user = comment.user
|
user = comment.user
|
||||||
|
|
||||||
e1 = EmailReply.reply(comment, user)
|
e1 = EmailReplyMailer.reply(comment, user)
|
||||||
e2 = EmailReply.reply(comment, user)
|
e2 = EmailReplyMailer.reply(comment, user)
|
||||||
expect(e1["Message-ID"]).to_not be_nil
|
expect(e1["Message-ID"]).to_not be_nil
|
||||||
expect(e1["Message-ID"].to_s).to eq(e2["Message-ID"].to_s)
|
expect(e1["Message-ID"].to_s).to eq(e2["Message-ID"].to_s)
|
||||||
end
|
end
|
||||||
|
@ -18,7 +18,7 @@ RSpec.describe EmailReply, type: :mailer do
|
||||||
comment = create(:comment)
|
comment = create(:comment)
|
||||||
reply = create(:comment, parent_comment: 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["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["In-Reply-To"].to_s).to eq("<#{comment.mailing_list_message_id}>")
|
||||||
expect(email["References"].to_s).to include(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
|
user = comment.user
|
||||||
reply = create(:comment, parent_comment: comment)
|
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")
|
expect(email.body.encoded).to match("replied to you")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ RSpec.describe EmailReply, type: :mailer do
|
||||||
user = create(:story).user
|
user = create(:story).user
|
||||||
comment = create(:comment)
|
comment = create(:comment)
|
||||||
|
|
||||||
email = EmailReply.reply(comment, user)
|
email = EmailReplyMailer.reply(comment, user)
|
||||||
expect(email.body.encoded).to match("replied to your story")
|
expect(email.body.encoded).to match("replied to your story")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ RSpec.describe EmailReply, type: :mailer do
|
||||||
comment = create(:comment, user: create(:user, username: "alice"))
|
comment = create(:comment, user: create(:user, username: "alice"))
|
||||||
reply = create(:comment, parent_comment: comment)
|
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")
|
expect(email.body.encoded).to match("replied to alice")
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -5,7 +5,7 @@ require "rails_helper"
|
||||||
describe Category do
|
describe Category do
|
||||||
context "validations" do
|
context "validations" do
|
||||||
it "allows a valid category to be created" do
|
it "allows a valid category to be created" do
|
||||||
category = Category.create(
|
category = Category.create!(
|
||||||
category: Faker::Lorem.word
|
category: Faker::Lorem.word
|
||||||
)
|
)
|
||||||
expect(category).to be_valid
|
expect(category).to be_valid
|
||||||
|
|
|
@ -13,7 +13,7 @@ describe EmailParser do
|
||||||
@emailer = create(:user, mailing_list_mode: 1)
|
@emailer = create(:user, mailing_list_mode: 1)
|
||||||
|
|
||||||
@emails = {}
|
@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|
|
.each do |f|
|
||||||
@emails[File.basename(f).gsub(/\..*/, "")] = File.read(f)
|
@emails[File.basename(f).gsub(/\..*/, "")] = File.read(f)
|
||||||
.gsub("##SHORTNAME##", Rails.application.shortname)
|
.gsub("##SHORTNAME##", Rails.application.shortname)
|
||||||
|
|
|
@ -16,7 +16,7 @@ end
|
||||||
describe ReplyingComment do
|
describe ReplyingComment do
|
||||||
def followed_parent
|
def followed_parent
|
||||||
p = create(:comment)
|
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
|
p
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -384,7 +384,7 @@ describe Story do
|
||||||
create(:comment, story: story, score: -9, flags: 10)
|
create(:comment, story: story, score: -9, flags: 10)
|
||||||
# stories stop accepting comments after a while, but this calculation is
|
# 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
|
# 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
|
end
|
||||||
|
|
||||||
context "with positive base" do
|
context "with positive base" do
|
||||||
|
@ -396,7 +396,7 @@ describe Story do
|
||||||
context "with negative base" do
|
context "with negative base" do
|
||||||
before do
|
before do
|
||||||
tag = create(:tag, hotness_mod: -10)
|
tag = create(:tag, hotness_mod: -10)
|
||||||
story.update(tags: [tag])
|
story.update!(tags: [tag])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "return correct score" do
|
it "return correct score" do
|
||||||
|
|
|
@ -5,7 +5,7 @@ require "rails_helper"
|
||||||
describe Tag do
|
describe Tag do
|
||||||
context "validations" do
|
context "validations" do
|
||||||
it "allows a valid tag to be created" do
|
it "allows a valid tag to be created" do
|
||||||
tag = Tag.create(
|
tag = Tag.create!(
|
||||||
category: Category.first,
|
category: Category.first,
|
||||||
tag: "tag_name",
|
tag: "tag_name",
|
||||||
hotness_mod: 0.25,
|
hotness_mod: 0.25,
|
||||||
|
|
|
@ -160,7 +160,7 @@ describe "login", type: :request do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't reset if token expired" do
|
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 {
|
expect {
|
||||||
post "/login/set_new_password", params: {
|
post "/login/set_new_password", params: {
|
||||||
token: user.password_reset_token,
|
token: user.password_reset_token,
|
||||||
|
|
Loading…
Reference in New Issue