Rubocop cleanups (#1415)

* Update rubocop-todo.yml with new violations

* Fix Layout/EmptyLine* rules

* Fix Layout/Indentation* rules

* Fix remaining Layout/* rules

* Fix Lint/DuplicateMethods by removing unused accessor

* Fix Lint/IneffectiveAccessModifier

* Fix Lint/MissingCopEnableDirective

* Re-run rubocop auto gen config

* Fix Layout/RescueEnsureAlignment

* Fix Naming/* rules

* Fix some RSpec/* rules

* Fix typos

* Fix RSpec/LetBeforeExamples

* Series should only be an attr_writer, not an attr_accessor

* Fix RSpec/InstanceVariable

* Fix RSpec/InstanceVariable

* Fix RSpec/RepeatedDescription and RSpec/RepeatedExample

* Fix Style/ClassAndModuleChildren

* Fix Style/ConditionalAssignment

* Fix some Style/* rules

* Trigger Travis CI build because failing tests are not failing locally

* Revert "Fix Style/ClassAndModuleChildren"

This reverts commit 1686801d8a1516ba1894f79e24401a20dea65f99.
This commit is contained in:
rhymes 2019-01-02 17:20:02 +01:00 committed by Ben Halpern
parent cfcc204a20
commit 6553f08d94
108 changed files with 443 additions and 680 deletions

View file

@ -1,207 +1,12 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2018-12-06 12:31:40 +0300 using RuboCop version 0.59.2.
# on 2018-12-29 20:55:12 +0100 using RuboCop version 0.59.2.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# Offense count: 110
# Cop supports --auto-correct.
Layout/EmptyLineAfterGuardClause:
Enabled: false
# Offense count: 4
# Cop supports --auto-correct.
Layout/EmptyLines:
Exclude:
- 'app/models/buffer_update.rb'
- 'app/models/mentor_relationship.rb'
- 'app/models/notification.rb'
- 'spec/requests/html_variants_spec.rb'
# Offense count: 3
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: empty_lines, no_empty_lines
Layout/EmptyLinesAroundBlockBody:
Exclude:
- 'spec/factories/podcasts.rb'
- 'spec/models/comment_spec.rb'
- 'spec/requests/html_variants_spec.rb'
# Offense count: 3
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines, beginning_only, ending_only
Layout/EmptyLinesAroundClassBody:
Exclude:
- 'app/models/buffer_update.rb'
- 'app/models/tag.rb'
- 'app/models/tag_adjustment.rb'
# Offense count: 5
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
Layout/ExtraSpacing:
Exclude:
- 'spec/factories/podcasts.rb'
- 'spec/models/tag_adjustment_spec.rb'
- 'spec/requests/tag_adjustments_spec.rb'
# Offense count: 6
# Cop supports --auto-correct.
# Configuration parameters: IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_braces
Layout/IndentHash:
EnforcedStyle: consistent
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: normal, rails
Layout/IndentationConsistency:
Exclude:
- 'app/observers/organization_observer.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: Width, IgnoredPatterns.
Layout/IndentationWidth:
Exclude:
- 'lib/tasks/fetch.rake'
# Offense count: 2
# Cop supports --auto-correct.
Layout/LeadingCommentSpace:
Exclude:
- 'app/controllers/stories_controller.rb'
- 'app/helpers/application_helper.rb'
# Offense count: 1
# Cop supports --auto-correct.
Layout/MultilineBlockLayout:
Exclude:
- 'spec/requests/internal_reactions_spec.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: symmetrical, new_line, same_line
Layout/MultilineHashBraceLayout:
Exclude:
- 'spec/requests/articles_api_spec.rb'
# Offense count: 3
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, IndentationWidth.
# SupportedStyles: aligned, indented, indented_relative_to_receiver
Layout/MultilineMethodCallIndentation:
Exclude:
- 'app/models/follow.rb'
- 'app/models/message.rb'
# Offense count: 14
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, IndentationWidth.
# SupportedStyles: aligned, indented
Layout/MultilineOperationIndentation:
Exclude:
- 'app/models/message.rb'
- 'app/models/user.rb'
- 'app/services/membership_service.rb'
# Offense count: 1
# Cop supports --auto-correct.
Layout/RescueEnsureAlignment:
Exclude:
- 'app/services/user_role_service.rb'
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: space, no_space
Layout/SpaceAroundEqualsInParameterDefault:
Exclude:
- 'app/models/buffer_update.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces.
# SupportedStyles: space, no_space
# SupportedStylesForEmptyBraces: space, no_space
Layout/SpaceBeforeBlockBraces:
Exclude:
- 'app/decorators/user_decorator.rb'
# Offense count: 1
# Cop supports --auto-correct.
Layout/SpaceBeforeComma:
Exclude:
- 'app/views/api/v0/users/index.json.jbuilder'
# Offense count: 8
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
# SupportedStyles: space, no_space
# SupportedStylesForEmptyBraces: space, no_space
Layout/SpaceInsideBlockBraces:
Exclude:
- 'app/decorators/user_decorator.rb'
- 'spec/models/tag_adjustment_spec.rb'
- 'spec/requests/html_variants_spec.rb'
# Offense count: 6
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces.
# SupportedStyles: space, no_space, compact
# SupportedStylesForEmptyBraces: space, no_space
Layout/SpaceInsideHashLiteralBraces:
Exclude:
- 'app/models/notification.rb'
- 'spec/services/tag_adjustment_update_service_spec.rb'
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: final_newline, final_blank_line
Layout/TrailingBlankLines:
Exclude:
- 'app/controllers/async_info_controller.rb'
- 'config/routes.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: AllowInHeredoc.
Layout/TrailingWhitespace:
Exclude:
- 'app/controllers/follows_controller.rb'
# Offense count: 1
Lint/DuplicateMethods:
Exclude:
- 'app/models/article.rb'
# Offense count: 4
Lint/IneffectiveAccessModifier:
Exclude:
- 'app/black_box/black_box.rb'
- 'app/models/tweet.rb'
# Offense count: 1
# Configuration parameters: MaximumRangeSize.
Lint/MissingCopEnableDirective:
Exclude:
- 'spec/requests/articles_api_spec.rb'
# Offense count: 2
# Configuration parameters: ContextCreatingMethods, MethodCreatingMethods.
Lint/UselessAccessModifier:
Exclude:
- 'app/black_box/black_box.rb'
- 'app/models/tweet.rb'
# Offense count: 9
# Configuration parameters: CountComments, ExcludedMethods.
# ExcludedMethods: refine
Metrics/BlockLength:
@ -211,123 +16,24 @@ Metrics/BlockLength:
Metrics/PerceivedComplexity:
Max: 15
# Offense count: 1
Naming/ConstantName:
Exclude:
- 'app/liquid_tags/raw_tag.rb'
# Offense count: 1
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
# AllowedNames: io, id, to, by, on, in, at, ip, db
Naming/UncommunicativeMethodParamName:
Exclude:
- 'app/models/message.rb'
# Offense count: 1
# Cop supports --auto-correct.
RSpec/EmptyLineAfterExampleGroup:
Exclude:
- 'spec/requests/internal_reactions_spec.rb'
# Offense count: 2
# Cop supports --auto-correct.
RSpec/EmptyLineAfterFinalLet:
Exclude:
- 'spec/models/user_spec.rb'
- 'spec/policies/html_variant_policy_spec.rb'
# Offense count: 5
# Cop supports --auto-correct.
RSpec/EmptyLineAfterHook:
Exclude:
- 'spec/requests/articles_api_spec.rb'
- 'spec/requests/internal_reactions_spec.rb'
- 'spec/requests/tag_adjustments_spec.rb'
# Offense count: 17
# Configuration parameters: Max.
RSpec/ExampleLength:
Exclude:
- 'spec/models/buffer_update_spec.rb'
- 'spec/models/html_variant_spec.rb'
- 'spec/models/mentor_relationship_spec.rb'
- 'spec/models/message_spec.rb'
- 'spec/models/notification_spec.rb'
- 'spec/requests/dashboard_spec.rb'
- 'spec/requests/html_variants_spec.rb'
- 'spec/requests/internal_buffer_updates_spec.rb'
- 'spec/requests/tag_adjustments_spec.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: CustomTransform, IgnoredWords.
RSpec/ExampleWording:
Exclude:
- 'spec/labor/user_similarity_spec.rb'
# Offense count: 1
# Configuration parameters: CustomTransform, IgnoreMethods.
RSpec/FilePath:
Exclude:
- 'spec/liquid_tags/raw_tag_spec.rb'
# Offense count: 1
# Cop supports --auto-correct.
RSpec/HooksBeforeExamples:
Exclude:
- 'spec/models/tag_adjustment_spec.rb'
# Offense count: 12
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: single_line_only, disallow
RSpec/ImplicitSubject:
Exclude:
- 'spec/models/feedback_message_spec.rb'
- 'spec/policies/comment_policy_spec.rb'
- 'spec/policies/organization_policy_spec.rb'
- 'spec/requests/dashboard_spec.rb'
- 'spec/requests/registration_spec.rb'
# Offense count: 19
# Configuration parameters: AssignmentOnly.
RSpec/InstanceVariable:
Exclude:
- 'spec/requests/articles_api_spec.rb'
- 'spec/requests/internal_reactions_spec.rb'
- 'spec/services/tag_adjustment_creation_service_spec.rb'
- 'spec/services/tag_adjustment_update_service_spec.rb'
# Offense count: 6
# Cop supports --auto-correct.
RSpec/LetBeforeExamples:
Exclude:
- 'spec/models/html_variant_spec.rb'
- 'spec/models/tag_adjustment_spec.rb'
# Offense count: 16
# Offense count: 15
# Configuration parameters: AggregateFailuresByDefault.
RSpec/MultipleExpectations:
Max: 6
# Offense count: 6
RSpec/RepeatedDescription:
Exclude:
- 'spec/models/buffer_update_spec.rb'
- 'spec/requests/articles_api_spec.rb'
# Offense count: 2
RSpec/RepeatedExample:
Exclude:
- 'spec/requests/articles_api_spec.rb'
# Offense count: 3
Security/Open:
Exclude:
- 'app/labor/podcast_feed.rb'
- 'app/labor/rss_reader.rb'
# Offense count: 1
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, IgnoredMethods.
# SupportedStyles: line_count_based, semantic, braces_for_chaining
@ -336,6 +42,7 @@ Security/Open:
# IgnoredMethods: lambda, proc, it
Style/BlockDelimiters:
Exclude:
- 'spec/requests/articles_api_spec.rb'
- 'spec/requests/internal_reactions_spec.rb'
# Offense count: 5
@ -370,15 +77,6 @@ Style/ClassAndModuleChildren:
- 'app/controllers/notifications/counts_controller.rb'
- 'app/controllers/notifications/reads_controller.rb'
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SingleLineConditionsOnly, IncludeTernaryExpressions.
# SupportedStyles: assign_to_condition, assign_inside_condition
Style/ConditionalAssignment:
Exclude:
- 'app/controllers/api/v0/articles_controller.rb'
- 'config/initializers/honeycomb.rb'
# Offense count: 1
Style/EvalWithLocation:
Exclude:
@ -389,81 +87,8 @@ Style/MixinUsage:
Exclude:
- 'app/models/podcast_episode.rb'
# Offense count: 1
# Cop supports --auto-correct.
Style/MutableConstant:
Exclude:
- 'spec/support/omniauth_macros.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, EnforcedStyle, IgnoredMethods.
# SupportedStyles: predicate, comparison
Style/NumericPredicate:
Exclude:
- 'spec/**/*'
- 'app/controllers/stories_controller.rb'
# Offense count: 1
# Cop supports --auto-correct.
Style/RedundantSelf:
Exclude:
- 'app/models/buffer_update.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: ConvertCodeThatCanStartToReturnNil, Whitelist.
# Whitelist: present?, blank?, presence, try, try!
Style/SafeNavigation:
Exclude:
- 'app/models/follow.rb'
# Offense count: 10
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
# SupportedStyles: single_quotes, double_quotes
Style/StringLiterals:
Exclude:
- 'app/controllers/api/v0/articles_controller.rb'
- 'config/initializers/honeycomb.rb'
- 'spec/models/buffer_update_spec.rb'
- 'spec/models/html_variant_spec.rb'
- 'spec/models/html_variant_success_spec.rb'
- 'spec/models/html_variant_trial_spec.rb'
- 'spec/models/tag_adjustment_spec.rb'
- 'tmp/user_visits_articles_by_tag_spec.rb'
# Offense count: 3
# Cop supports --auto-correct.
# Configuration parameters: .
# SupportedStyles: percent, brackets
Style/SymbolArray:
EnforcedStyle: percent
MinSize: 14
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyleForMultiline.
# SupportedStylesForMultiline: comma, consistent_comma, no_comma
Style/TrailingCommaInArrayLiteral:
Exclude:
- 'Guardfile'
- 'app/lib/constants.rb'
# Offense count: 7
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyleForMultiline.
# SupportedStylesForMultiline: comma, consistent_comma, no_comma
Style/TrailingCommaInHashLiteral:
Exclude:
- 'app/dashboards/html_variant_dashboard.rb'
- 'spec/requests/articles_api_spec.rb'
- 'spec/requests/html_variant_successes_spec.rb'
- 'spec/requests/html_variant_trials_spec.rb'
- 'spec/requests/tag_adjustments_spec.rb'
# Offense count: 1175
# Offense count: 1179
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
Metrics/LineLength:
Max: 274
Max: 279

View file

@ -65,7 +65,7 @@ guard :rspec, rspec_options do
[
rspec.spec.call("routing/#{m[1]}_routing"),
rspec.spec.call("controllers/#{m[1]}_controller"),
rspec.spec.call("acceptance/#{m[1]}")
rspec.spec.call("acceptance/#{m[1]}"),
]
end

View file

@ -1,38 +1,42 @@
class BlackBox
def self.article_hotness_score(article)
return (article.featured_number || 10000) / 10000 unless Rails.env.production?
reaction_points = article.score
super_super_recent_bonus = article.published_at > 1.hours.ago ? 18 : 0
super_recent_bonus = article.published_at > 3.hours.ago ? 11 : 0
recency_bonus = article.published_at > 11.hours.ago ? 70 : 0
today_bonus = article.published_at > 26.hours.ago ? 285 : 0
two_day_bonus = article.published_at > 48.hours.ago ? 120 : 0
FunctionCaller.new("blackbox-production-articleHotness",
{ article: article, user: article.user }.to_json).call +
reaction_points + recency_bonus + super_recent_bonus + super_super_recent_bonus + today_bonus + two_day_bonus
end
class << self
def article_hotness_score(article)
return (article.featured_number || 10000) / 10000 unless Rails.env.production?
def self.comment_quality_score(comment)
descendants_points = (comment.descendants.size / 2)
rep_points = comment.reactions.sum(:points)
bonus_points = calculate_bonus_score(comment.body_markdown)
spaminess_rating = calculate_spaminess(comment)
(rep_points + descendants_points + bonus_points - spaminess_rating).to_i
end
reaction_points = article.score
super_super_recent_bonus = article.published_at > 1.hours.ago ? 18 : 0
super_recent_bonus = article.published_at > 3.hours.ago ? 11 : 0
recency_bonus = article.published_at > 11.hours.ago ? 70 : 0
today_bonus = article.published_at > 26.hours.ago ? 285 : 0
two_day_bonus = article.published_at > 48.hours.ago ? 120 : 0
FunctionCaller.new("blackbox-production-articleHotness",
{ article: article, user: article.user }.to_json).call +
reaction_points + recency_bonus + super_recent_bonus + super_super_recent_bonus + today_bonus + two_day_bonus
end
def self.calculate_spaminess(story)
# accepts comment or article as story
return 0 unless Rails.env.production?
return 100 unless story.user
FunctionCaller.new("blackbox-production-spamScore",
{ story: story, user: story.user }.to_json).call
end
def comment_quality_score(comment)
descendants_points = (comment.descendants.size / 2)
rep_points = comment.reactions.sum(:points)
bonus_points = calculate_bonus_score(comment.body_markdown)
spaminess_rating = calculate_spaminess(comment)
(rep_points + descendants_points + bonus_points - spaminess_rating).to_i
end
private
def calculate_spaminess(story)
# accepts comment or article as story
return 0 unless Rails.env.production?
return 100 unless story.user
def self.calculate_bonus_score(body_markdown)
size_bonus = body_markdown.size > 200 ? 2 : 0
code_bonus = body_markdown.include?("`") ? 1 : 0
size_bonus + code_bonus
FunctionCaller.new("blackbox-production-spamScore",
{ story: story, user: story.user }.to_json).call
end
private
def calculate_bonus_score(body_markdown)
size_bonus = body_markdown.size > 200 ? 2 : 0
code_bonus = body_markdown.include?("`") ? 1 : 0
size_bonus + code_bonus
end
end
end

View file

@ -26,6 +26,7 @@ class AdditionalContentBoxesController < ApplicationController
def randomize
return true unless Rails.env.production?
rand(2) == 1
end
end

View file

@ -17,6 +17,7 @@ module Admin
# Temp monkey patch. Since we use https at the edge via fastly I think our protocol expectations
# are out of wack.
raise InvalidAuthenticityToken, NULL_ORIGIN_MESSAGE if request.origin == "null"
request.origin.nil? || request.origin.gsub("https", "http") == request.base_url.gsub("https", "http")
end

View file

@ -21,7 +21,7 @@ module Api
params[:signature],
params[:state],
]
set_surrogate_key_header key_headers.join('_')
set_surrogate_key_header key_headers.join("_")
end
def show
@ -79,11 +79,9 @@ module Api
def article_params
params["article"].transform_keys!(&:underscore)
if params["article"]["post_under_org"]
params["article"]["organization_id"] = @user.organization_id
else
params["article"]["organization_id"] = nil
end
params["article"]["organization_id"] = if params["article"]["post_under_org"]
@user.organization_id
end
if params["article"]["series"].present?
params["article"]["collection_id"] = Collection.find_series(params["article"]["series"], @user)&.id
elsif params["article"]["series"] == ""

View file

@ -3,6 +3,7 @@ module Api
class FollowsController < ApplicationController
def create
return unless user_signed_in?
users = JSON.parse(params[:users])
users.each do |user_hash|
followable = User.find(user_hash["id"])

View file

@ -53,11 +53,13 @@ class ApplicationController < ActionController::Base
# Not sure why, but once we work it out, we can delete this method.
# We are at least secure for now.
return if Rails.env.test?
if request.referer.present?
request.referer.start_with?(ApplicationConfig["APP_PROTOCOL"].to_s + ApplicationConfig["APP_DOMAIN"].to_s)
else
logger.info "**REQUEST ORIGIN CHECK** #{request.origin}"
raise InvalidAuthenticityToken, NULL_ORIGIN_MESSAGE if request.origin == "null"
request.origin.nil? || request.origin.gsub("https", "http") == request.base_url.gsub("https", "http")
end
end

View file

@ -187,6 +187,7 @@ class ArticlesController < ApplicationController
def job_opportunity_params
return nil unless params[:article][:job_opportunity].present?
params[:article].require(:job_opportunity).permit(
:remoteness, :location_given, :location_city, :location_postal_code,
:location_country_code, :location_lat, :location_long

View file

@ -62,4 +62,4 @@ class AsyncInfoController < ApplicationController
#{current_user&.articles_count}__
#{cookies[:remember_user_token]}"
end
end
end

View file

@ -11,9 +11,9 @@ class BufferedArticlesController < ApplicationController
if Rails.env.production?
Article.
where("last_buffered > ? OR published_at > ?", 24.hours.ago, 20.minutes.ago).
map { |a| "https://#{ApplicationConfig["APP_DOMAIN"]}#{a.path}" }
map { |a| "https://#{ApplicationConfig['APP_DOMAIN']}#{a.path}" }
else
Article.all.map { |a| "https://#{ApplicationConfig["APP_DOMAIN"]}#{a.path}" }
Article.all.map { |a| "https://#{ApplicationConfig['APP_DOMAIN']}#{a.path}" }
end
end
end

View file

@ -127,6 +127,7 @@ class ChatChannelsController < ApplicationController
def render_channels_html
return unless current_user
if params[:slug]
slug = if params[:slug]&.start_with?("@")
[current_user.username, params[:slug].gsub("@", "")].sort.join("/")

View file

@ -56,6 +56,7 @@ class CommentsController < ApplicationController
def create
authorize Comment
raise if RateLimitChecker.new(current_user).limit_by_situation("comment_creation")
@comment = Comment.new(permitted_attributes(Comment))
add_context(commentable_id: @comment.commentable_id,
commentable_type: @comment.commentable_type)

View file

@ -49,6 +49,7 @@ class FeedbackMessagesController < ApplicationController
def generate_user_detail
return "*Anonymous report:*" unless current_user
<<~HEREDOC
*Logged in user:*
reporter: #{current_user.username} - https://dev.to/#{current_user.username}

View file

@ -45,7 +45,7 @@ class FollowsController < ApplicationController
redirect_to "/dashboard/following"
end
end
private
def follow_params

View file

@ -83,7 +83,7 @@ class Internal::FeedbackMessagesController < Internal::ApplicationController
<<~HEREDOC
*New note from #{params['author_name']}:*
*Report status: #{params['feedback_message_status']}*
Report page: https://#{ApplicationConfig["APP_DOMAIN"]}/internal/reports/#{params['noteable_id']}
Report page: https://#{ApplicationConfig['APP_DOMAIN']}/internal/reports/#{params['noteable_id']}
--------
Message: #{params['content']}
HEREDOC

View file

@ -48,6 +48,7 @@ class Internal::UsersController < Internal::ApplicationController
if @new_mentee.blank? && @new_mentor.blank?
return
end
make_matches
end

View file

@ -35,6 +35,7 @@ class OrganizationsController < ApplicationController
def generate_new_secret
raise unless current_user.org_admin
@organization = current_user.organization
authorize @organization
@organization.secret = @organization.generated_random_secret

View file

@ -19,6 +19,7 @@ class PusherController < ApplicationController
def valid_presence_channel
return false unless params[:channel_name].include?("presence-channel-")
id = params[:channel_name].split("presence-channel-")[1].split("-")[0]
channel = ChatChannel.find(id)
channel.has_member?(current_user)

View file

@ -6,6 +6,7 @@ class StoriesController < ApplicationController
add_param_context(:username, :tag)
return handle_user_or_organization_or_podcast_index if params[:username]
return handle_tag_index if params[:tag]
handle_base_index
end
@ -125,7 +126,7 @@ class StoriesController < ApplicationController
where("reactions_count > ? OR featured = ?", 10, true).
order("hotness_score DESC")
if user_signed_in?
offset = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 5, 6, 7].sample #random offset, weighted more towards zero
offset = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 5, 6, 7].sample # random offset, weighted more towards zero
@stories = @stories.offset(offset)
end
@featured_story = @stories.where.not(main_image: nil).first&.decorate || Article.new
@ -188,6 +189,7 @@ class StoriesController < ApplicationController
@list_of = "articles"
redirect_if_view_param
return if performed?
set_surrogate_key_header "articles-user-#{@user.id}", @stories.map(&:record_key)
render template: "users/show"
end
@ -226,6 +228,7 @@ class StoriesController < ApplicationController
set_surrogate_key_header @article.record_key
redirect_if_show_view_param
return if performed?
render template: "articles/show"
end
@ -249,7 +252,7 @@ class StoriesController < ApplicationController
def assign_user_comments
comment_count = params[:view] == "comments" ? 250 : 8
@comments = if @user.comments_count > 0
@comments = if @user.comments_count.positive?
@user.comments.where(deleted: false).
order("created_at DESC").includes(:commentable).limit(comment_count)
else

View file

@ -73,6 +73,7 @@ class StripeSubscriptionsController < ApplicationController
def stripe_params
params[:amount] = convert_amount_to_cent
raise custom_error if invalid_amount?
accessible = %i[amount existing_card_id stripe_token]
params.permit(accessible)
end

View file

@ -1,13 +1,16 @@
class TagAdjustmentsController < ApplicationController
def create
authorize(User, :moderation_routes?)
TagAdjustmentCreationService.new(current_user, {
adjustment_type: "removal",
status: "committed",
tag_name: params[:tag_adjustment][:tag_name],
article_id: params[:tag_adjustment][:article_id],
reason_for_adjustment: params[:tag_adjustment][:reason_for_adjustment]
}).create
TagAdjustmentCreationService.new(
current_user,
{
adjustment_type: "removal",
status: "committed",
tag_name: params[:tag_adjustment][:tag_name],
article_id: params[:tag_adjustment][:article_id],
reason_for_adjustment: params[:tag_adjustment][:reason_for_adjustment]
}
).create
@article = Article.find(params[:tag_adjustment][:article_id])
redirect_to "#{@article.path}/mod"
end

View file

@ -137,11 +137,13 @@ class UsersController < ApplicationController
def follow_hiring_tag(user)
return unless user.looking_for_work?
user.delay.follow(Tag.find_by(name: "hiring"))
end
def handle_settings_tab
return @tab = "profile" if @tab.blank?
case @tab
when "organization"
@organization = @user.organization || Organization.new
@ -155,6 +157,7 @@ class UsersController < ApplicationController
when "billing"
stripe_code = current_user.stripe_id_code
return if stripe_code == "special"
@customer = Stripe::Customer.retrieve(stripe_code) if !stripe_code.blank?
when "membership"
if current_user.monthly_dues.zero?

View file

@ -20,7 +20,7 @@ class HtmlVariantDashboard < Administrate::BaseDashboard
published: Field::Boolean,
approved: Field::Boolean,
created_at: Field::DateTime,
updated_at: Field::DateTime,
updated_at: Field::DateTime
}.freeze
# COLLECTION_ATTRIBUTES
@ -28,45 +28,45 @@ class HtmlVariantDashboard < Administrate::BaseDashboard
#
# By default, it's limited to four items to reduce clutter on index pages.
# Feel free to add, remove, or rearrange items.
COLLECTION_ATTRIBUTES = [
:user,
:html_variant_trials,
:html_variant_successes,
:id,
COLLECTION_ATTRIBUTES = %i[
user
html_variant_trials
html_variant_successes
id
].freeze
# SHOW_PAGE_ATTRIBUTES
# an array of attributes that will be displayed on the model's show page.
SHOW_PAGE_ATTRIBUTES = [
:user,
:html_variant_trials,
:html_variant_successes,
:id,
:group,
:name,
:html,
:target_tag,
:success_rate,
:published,
:approved,
:created_at,
:updated_at,
SHOW_PAGE_ATTRIBUTES = %i[
user
html_variant_trials
html_variant_successes
id
group
name
html
target_tag
success_rate
published
approved
created_at
updated_at
].freeze
# FORM_ATTRIBUTES
# an array of attributes that will be displayed
# on the model's form (`new` and `edit`) pages.
FORM_ATTRIBUTES = [
:user,
:html_variant_trials,
:html_variant_successes,
:group,
:name,
:html,
:target_tag,
:success_rate,
:published,
:approved,
FORM_ATTRIBUTES = %i[
user
html_variant_trials
html_variant_successes
group
name
html
target_tag
success_rate
published
approved
].freeze
# Overwrite this method to customize how html variants are displayed

View file

@ -22,7 +22,7 @@ class ArticleDecorator < ApplicationDecorator
end
def url
"https://#{ApplicationConfig["APP_DOMAIN"]}#{path}"
"https://#{ApplicationConfig['APP_DOMAIN']}#{path}"
end
def liquid_tags_used

View file

@ -6,7 +6,7 @@ class UserDecorator < ApplicationDecorator
follows_query = Follow.where(follower_id: id, followable_type: "ActsAsTaggableOn::Tag").pluck(:followable_id, :points)
tags = Tag.where(id: follows_query.map { |f| f[0] }).order("hotness_score DESC")
tags.each do |t|
follow_query_item = follows_query.detect{|f| f[0] == t.id}
follow_query_item = follows_query.detect { |f| f[0] == t.id }
t.points = follow_query_item[1]
end
tags

View file

@ -124,6 +124,7 @@ module ApplicationHelper
Rails.cache.fetch(cache_key, expires_in: 1.hour) do
src = GeneratedImage.new(article).social_image
return src if src.start_with? "https://res.cloudinary.com/"
cl_image_path(src,
type: "fetch",
width: "1000",
@ -171,7 +172,7 @@ module ApplicationHelper
end
def follow_button(followable, style = "full")
tag :button, #Yikes
tag :button, # Yikes
class: "cta follow-action-button",
data: {
info: { id: followable.id, className: followable.class.name, style: style }.to_json,

View file

@ -7,6 +7,7 @@ class ArticleAnalyticsFetcher
articles_to_check = Article.where(user_id: user_id, published: true)
qualified_articles = get_articles_that_qualify(articles_to_check)
return if qualified_articles.none?
fetch_and_update_page_views_and_reaction_counts(qualified_articles, user_id)
end
@ -17,6 +18,7 @@ class ArticleAnalyticsFetcher
chunk.each do |article|
article.update_columns(previous_positive_reactions_count: article.positive_reactions_count)
next if article.page_views_count > page_views_obj[article.id].to_i
article.update_columns(page_views_count: page_views_obj[article.id].to_i)
end
end
@ -34,6 +36,7 @@ class ArticleAnalyticsFetcher
def should_fetch(article)
return true if @context == "force"
article.positive_reactions_count > article.previous_positive_reactions_count
end
end

View file

@ -5,6 +5,7 @@ class CacheBuster
def bust(path)
return unless Rails.env.production?
HTTParty.post("https://api.fastly.com/purge/https://dev.to#{path}",
headers: { "Fastly-Key" => ApplicationConfig["FASTLY_API_KEY"] })
HTTParty.post("https://api.fastly.com/purge/https://dev.to#{path}?i=i",
@ -79,6 +80,7 @@ class CacheBuster
def bust_tag_pages(article)
return unless article.published
article.tag_list.each do |tag|
if article.published_at.to_i > 3.minutes.ago.to_i
bust("/t/#{tag}/latest")

View file

@ -5,6 +5,7 @@ class ColorFromImage
def main
return "#000000" unless Rails.env.production?
begin
get_palette["colors"][0]["hex"]
rescue StandardError

View file

@ -16,6 +16,7 @@ class EmailDigest
@users.find_each do |user|
user_email_heuristic = EmailLogic.new(user).analyze
next unless user_email_heuristic.should_receive_email?
articles = user_email_heuristic.articles_to_send
begin
DigestMailer.digest_email(user, articles).deliver

View file

@ -75,6 +75,7 @@ class EmailLogic
def get_user_readiness
return true unless @last_email_sent_at
# Has it been at least x days since @user received an email?
Time.current - @last_email_sent_at >= @days_until_next_email.days.to_i
end
@ -86,6 +87,7 @@ class EmailLogic
def get_fresh_date
a_few_days_ago = 4.days.ago.utc
return a_few_days_ago unless @last_email_sent_at
a_few_days_ago > @last_email_sent_at ? a_few_days_ago : @last_email_sent_at
end

View file

@ -27,6 +27,7 @@ class FlareTag
def tag_hash
return unless tag
{ name: tag.name,
bg_color_hex: tag.bg_color_hex,
text_color_hex: tag.text_color_hex }

View file

@ -22,6 +22,7 @@ class GeneratedImage
return resource.social_image if resource.social_image.present?
return resource.main_image if resource.main_image.present?
return resource.video_thumbnail_url if resource.video_thumbnail_url.present?
cloudinary_generated_url "/article/#{resource.id}?bust=#{resource.comments_count}-#{resource.title}-#{resource.published}"
end

View file

@ -12,6 +12,7 @@ class LanguageDetector
def get_language
return { "result" => "en", "confidence" => 0.9 } unless Rails.env.production?
client = Algorithmia.client(ApplicationConfig["ALGORITHMIA_KEY"])
algo = client.algo("miguelher/LanguageDetector/0.1.0")
algo.pipe(text).result

View file

@ -9,6 +9,7 @@ class MailchimpBot
def upsert
return true unless Rails.env.production? || Rails.env.test?
upsert_to_membership_newsletter
upsert_to_newsletter
end
@ -46,6 +47,7 @@ class MailchimpBot
def upsert_to_membership_newsletter
return false unless a_sustaining_member?
success = false
# !!! user.monthly_due = 0 ? unsubscibe
tiers = %i[ triple_unicorn_member

View file

@ -34,6 +34,7 @@ class MarkdownParser
def evaluate_markdown
return if @content.blank?
renderer = Redcarpet::Render::HTMLRouge.new(hard_wrap: true, filter_html: false)
markdown = Redcarpet::Markdown.new(renderer, REDCARPET_CONFIG)
allowed_tags = %w(strong abbr aside em p h1 h2 h3 h4 h5 h6 i u b code pre
@ -46,6 +47,7 @@ class MarkdownParser
def evaluate_limited_markdown
return if @content.blank?
renderer = Redcarpet::Render::HTMLRouge.new(hard_wrap: true, filter_html: false)
markdown = Redcarpet::Markdown.new(renderer, REDCARPET_CONFIG)
allowed_tags = %w(strong i u b em p br code)
@ -57,6 +59,7 @@ class MarkdownParser
def evaluate_inline_markdown
return if @content.blank?
renderer_options = {
hard_wrap: true,
filter_html: false,
@ -70,6 +73,7 @@ class MarkdownParser
def tags_used
return [] unless @content.present?
cleaned_parsed = escape_liquid_tags_in_codeblock(@content)
tags = []
Liquid::Template.parse(cleaned_parsed).root.nodelist.each do |node|
@ -88,6 +92,7 @@ class MarkdownParser
next unless src
# allow image to render as-is
next if allowed_image_host?(src)
img["src"] = if giphy_img?(src)
src.gsub("https://media.", "https://i.")
else

View file

@ -5,6 +5,7 @@ class NotificationCounter
def unread_notification_count
return 0 if Rails.env.test?
@user.notifications.where(read: false).count
end

View file

@ -27,6 +27,7 @@ class RateLimitChecker
def ping_admins
return unless user && Rails.env.production?
SlackBot.ping(
"Rate limit exceeded. https://dev.to#{user.path}",
channel: "abuse-reports",

View file

@ -17,6 +17,7 @@ class RssReader
User.where.not(feed_url: nil).each do |u|
feed_url = u.feed_url.strip
next if feed_url == ""
create_articles_for_user(u)
end
end
@ -82,6 +83,7 @@ class RssReader
item_title: item.title,
item_summary_size: item.summary&.size) do |metadata|
return if medium_reply?(item) || article_exist?(user, item)
article_params = {
feed_source_url: feed_source_url = item.url.strip.split("?source=")[0],
user_id: user.id,
@ -95,6 +97,7 @@ class RssReader
Article.create!(article_params)
end
return unless Rails.env.production?
SlackBot.delay.ping(
"New Article Retrieved via RSS: #{article.title}\nhttps://dev.to#{article.path}",
channel: "activity",
@ -155,6 +158,7 @@ class RssReader
html_doc.css("iframe").each do |iframe|
a_tag = iframe.css("a")
next if a_tag.empty?
possible_link = a_tag[0].inner_html
if /medium\.com\/media\/.+\/href/.match?(possible_link)
real_link = ""
@ -162,6 +166,7 @@ class RssReader
real_link = h.base_uri.to_s
end
return unless real_link.include?("gist.github.com")
iframe.name = "p"
iframe.keys.each { |attr| iframe.remove_attribute(attr) }
iframe.inner_html = "{% gist #{real_link} %}"
@ -176,6 +181,7 @@ class RssReader
html_doc.css("blockquote").each do |bq|
bq_with_p = bq.css("p")
next if bq_with_p.empty?
second_content = bq_with_p.css("p")[1].css("a")[0].attributes["href"].value
if bq_with_p.length == 2 && second_content.include?("twitter.com")
bq.name = "p"
@ -207,6 +213,7 @@ class RssReader
html_doc.css("a").each do |a_tag|
link = a_tag.attributes["href"]&.value
next unless link
found_article = Article.find_by(feed_source_url: link)&.decorate
if found_article
a_tag.attributes["href"].value = found_article.url

View file

@ -35,6 +35,7 @@ class StickyArticleCollection
def more_articles
return [] if tag_articles.size > 6
Article.tagged_with(["career", "productivity", "discuss", "explainlikeimfive"], any: true).
includes(:user).
where("comments_count > ?", comment_count_num).

View file

@ -28,6 +28,7 @@ class UnreadNotificationsEmailer
def should_send_email?
return false if !user.email_unread_notifications
return false if last_email_sent_after(24.hours.ago)
emailable_notifications_count = user.notifications.where(read: false).where.not(notifiable_type: "Reaction").count
emailable_notifications_count > rand(1..6)
end

View file

@ -11,6 +11,7 @@ module ActsAsTaggableOn
def clean(string)
string = string.to_s
return [] if string.blank?
string.downcase.split(",").map do |t|
t.strip.gsub(" ", "").gsub(/[^0-9a-z]/i, "")
end

View file

@ -52,6 +52,6 @@ module Constants
"switter.at",
"todon.nl",
"toot.cafe",
"wikitetas.club"
"wikitetas.club",
].freeze
end

View file

@ -9,6 +9,7 @@ module Redcarpet
# Probably not the best fix but it does it's job of preventing
# a nested links.
return nil if /<a\s.+\/a>/.match?(content)
link_attributes = ""
@options[:link_attributes]&.each do |attribute, value|
link_attributes += %( #{attribute}="#{value}")

View file

@ -74,6 +74,7 @@ class GithubTag
number = content_json[:number]
link = content_json[:html_url]
return unless title
"<h1> " \
"<a href=\"#{link}\">" \
"<img class=\"github-logo\" src=\"#{ActionController::Base.helpers.asset_path('github-logo.svg')}\" /><span class=\"issue-title\">#{title}</span> <span class=\"issue-number\">##{number}</span> " \

View file

@ -30,6 +30,7 @@ class GlitchTag < LiquidTagBase
def parse_id(input)
id = input.split(" ").first
raise StandardError, "Invalid Glitch ID" unless valid_id?(id)
id
end

View file

@ -52,12 +52,14 @@ class LinkTag < LiquidTagBase
def find_article_by_user(hash)
user = User.find_by_username(hash[:username])
return unless user
user.articles.where(slug: hash[:slug])&.first
end
def find_article_by_org(hash)
org = Organization.find_by_slug(hash[:username])
return unless org
org.articles.where(slug: hash[:slug])&.first
end

View file

@ -23,6 +23,7 @@ class ParlerTag < LiquidTagBase
input_no_space = input.delete(" ")
input_no_space = input_no_space.scan(/\bhttps?:\/\/[a-z.\/0-9-]+\b/).first
raise StandardError, "Invalid Parler URL" unless valid_id?(input_no_space)
input_no_space
end

View file

@ -1,7 +1,7 @@
module Liquid
class Raw < Block
remove_const(:FullTokenPossiblyInvalid) if defined?(FullTokenPossiblyInvalid)
FullTokenPossiblyInvalid = /\A(.*)#{TagStart}\s*(\w+)\s*#{TagEnd}\z/om
FullTokenPossiblyInvalid = /\A(.*)#{TagStart}\s*(\w+)\s*#{TagEnd}\z/om # rubocop:disable Naming/ConstantName
end
Template.register_tag("raw", Raw)

View file

@ -24,6 +24,7 @@ class YoutubeTag < LiquidTagBase
input_no_space = input.delete(" ")
raise StandardError, "Invalid YouTube ID" unless valid_id?(input_no_space)
return translate_start_time(input_no_space) if input_no_space.include?("?t=")
input_no_space
end

View file

@ -2,6 +2,7 @@ class NotifyMailer < ApplicationMailer
def new_reply_email(comment)
@user = comment.parent_user
return if RateLimitChecker.new.limit_by_email_recipient_address(@user.email)
@unsubscribe = generate_unsubscribe_token(@user.id, :email_comment_notifications)
@comment = comment
mail(to: @user.email, subject: "#{@comment.user.name} replied to your #{@comment.parent_type}")
@ -10,6 +11,7 @@ class NotifyMailer < ApplicationMailer
def new_follower_email(follow)
@user = follow.followable
return if RateLimitChecker.new.limit_by_email_recipient_address(@user.email)
@follower = follow.follower
@unsubscribe = generate_unsubscribe_token(@user.id, :email_follower_notifications)
@ -19,6 +21,7 @@ class NotifyMailer < ApplicationMailer
def new_mention_email(mention)
@user = User.find(mention.user_id)
return if RateLimitChecker.new.limit_by_email_recipient_address(@user.email)
@mentioner = User.find(mention.mentionable.user_id)
@mentionable = mention.mentionable
@mention = mention
@ -30,6 +33,7 @@ class NotifyMailer < ApplicationMailer
def unread_notifications_email(user)
@user = user
return if RateLimitChecker.new.limit_by_email_recipient_address(@user.email)
@unread_notifications_count = NotificationCounter.new(@user).unread_notification_count
@unsubscribe = generate_unsubscribe_token(@user.id, :email_unread_notifications)
subject = "🔥 You have #{@unread_notifications_count} unread notifications on dev.to"

View file

@ -6,7 +6,8 @@ class Article < ApplicationRecord
acts_as_taggable_on :tags
attr_accessor :publish_under_org, :series
attr_accessor :publish_under_org
attr_writer :series
belongs_to :user
belongs_to :job_opportunity, optional: true
@ -261,6 +262,7 @@ class Article < ApplicationRecord
def username
return organization.slug if organization
user.username
end
@ -291,6 +293,7 @@ class Article < ApplicationRecord
def set_caches
return unless user
self.cached_user_name = user_name
self.cached_user_username = user_username
self.path = calculated_path
@ -323,12 +326,14 @@ class Article < ApplicationRecord
def update_main_image_background_hex
return if main_image.blank? || main_image_background_hex_color != "#dddddd"
update_column(:main_image_background_hex_color, ColorFromImage.new(main_image).main)
end
handle_asynchronously :update_main_image_background_hex
def detect_human_language
return if language.present?
update_column(:language, LanguageDetector.new(self).detect)
end
handle_asynchronously :detect_human_language
@ -423,8 +428,10 @@ class Article < ApplicationRecord
def parsed_date(date)
now = Time.current
return published_at || now unless date
error_msg = "must be entered in DD/MM/YYYY format with current or past date"
return errors.add(:date_time, error_msg) if date > now
date
end
@ -435,6 +442,7 @@ class Article < ApplicationRecord
self.tag_list = tag_list
end
return errors.add(:tag_list, "exceed the maximum of 4 tags") if tag_list.length > 4
tag_list.each do |tag|
if tag.length > 20
errors.add(:tag, "\"#{tag}\" is too long (maximum is 20 characters)")
@ -472,6 +480,7 @@ class Article < ApplicationRecord
def create_password
return unless password.blank?
self.password = SecureRandom.hex(60)
end

View file

@ -35,6 +35,7 @@ class Block < ApplicationRecord
def permissions
return if user&.has_role?(:super_admin)
errors.add(:commentable_id, "is not valid.")
end
end

View file

@ -1,13 +1,11 @@
class BufferUpdate < ApplicationRecord
belongs_to :article
validate :validate_body_text_recent_uniqueness
def self.buff!(article_id, text, buffer_profile_id_code, social_service_name="twitter", tag_id=nil)
def self.buff!(article_id, text, buffer_profile_id_code, social_service_name = "twitter", tag_id = nil)
buffer_response = send_to_buffer(text, buffer_profile_id_code)
self.create(
create(
article_id: article_id,
tag_id: tag_id,
body_text: text,

View file

@ -62,6 +62,7 @@ class ChatChannel < ApplicationRecord
def self.create_with_users(users, channel_type = "direct", contrived_name = "New Channel")
raise "Invalid direct channel" if users.size != 2 && channel_type == "direct"
if channel_type == "direct"
usernames = users.map(&:username).sort
contrived_name = "Direct chat between " + usernames.join(" and ")

View file

@ -211,6 +211,7 @@ class Comment < ApplicationRecord
def send_to_moderator
return if user && user.comments_count > 10
Notification.send_moderation_notification(self)
end
@ -230,6 +231,7 @@ class Comment < ApplicationRecord
def wrap_timestamps_if_video_present!
return unless commentable_type != "PodcastEpisode" && commentable.video.present?
self.processed_html = processed_html.gsub(/(([0-9]:)?)(([0-5][0-9]|[0-9])?):[0-5][0-9]/) { |s| "<a href='#{commentable.path}?t=#{s}'>#{s}</a>" }
end

View file

@ -50,8 +50,9 @@ class Follow < ApplicationRecord
def send_email_notification
if followable.class.name == "User" && followable.email.present? && followable.email_follower_notifications
return if EmailMessage.where(user_id: followable.id).
where("sent_at > ?", rand(15..35).hours.ago).
where("subject LIKE ?", "%followed you on dev.to%").any?
where("sent_at > ?", rand(15..35).hours.ago).
where("subject LIKE ?", "%followed you on dev.to%").any?
NotifyMailer.new_follower_email(self).deliver
end
end
@ -62,7 +63,7 @@ class Follow < ApplicationRecord
channel = follower.chat_channels.
where("slug LIKE ? OR slug like ?", "%/#{followable.username}%", "%#{followable.username}/%").
first
channel.update(status: "inactive") if channel
channel&.update(status: "inactive")
end
end
end

View file

@ -44,6 +44,7 @@ class GithubRepo < ApplicationRecord
def clear_caches
return if user.blank?
user.touch
cache_buster = CacheBuster.new
cache_buster.bust user.path

View file

@ -46,6 +46,7 @@ class HtmlVariant < ApplicationRecord
src = img.attr("src")
next unless src
next if allowed_image_host?(src)
img["src"] = if giphy_img?(src)
src.gsub("https://media.", "https://i.")
else

View file

@ -41,7 +41,6 @@ class MentorRelationship < ApplicationRecord
User.where(id: record_ids)
end
private
def mutual_follow

View file

@ -26,6 +26,7 @@ class Message < ApplicationRecord
where.not(user_id: user.id).pluck(:user_id)
PushNotificationSubscription.where(user_id: reciever_ids).each do |sub|
return if no_push_necessary?(sub)
Webpush.payload_send(
endpoint: sub.endpoint,
message: ActionView::Base.full_sanitizer.sanitize(message_html),
@ -43,6 +44,7 @@ class Message < ApplicationRecord
def direct_receiver
return if chat_channel.channel_type != "direct"
chat_channel.users.where.not(id: user.id).first
end
@ -101,20 +103,20 @@ class Message < ApplicationRecord
membership.last_opened_at > 40.seconds.ago
end
def rich_link_article(a)
if a["href"].include?("//#{ApplicationConfig['APP_DOMAIN']}/") && a["href"].split("/")[4]
Article.find_by_slug(a["href"].split("/")[4].split("?")[0])
def rich_link_article(link)
if link["href"].include?("//#{ApplicationConfig['APP_DOMAIN']}/") && link["href"].split("/")[4]
Article.find_by_slug(link["href"].split("/")[4].split("?")[0])
end
end
def send_email_if_appropriate
recipient = direct_receiver
return if !chat_channel.direct? ||
recipient.updated_at > 2.hours.ago ||
recipient.chat_channel_memberships.order("last_opened_at DESC").
first.last_opened_at > 18.hours.ago ||
chat_channel.last_message_at > 45.minutes.ago ||
recipient.email_connect_messages == false
recipient.updated_at > 2.hours.ago ||
recipient.chat_channel_memberships.order("last_opened_at DESC").
first.last_opened_at > 18.hours.ago ||
chat_channel.last_message_at > 45.minutes.ago ||
recipient.email_connect_messages == false
NotifyMailer.new_message_email(self).deliver
end

View file

@ -93,6 +93,7 @@ class Notification < ApplicationRecord
def send_reaction_notification(notifiable)
return if notifiable.user_id == notifiable.reactable.user_id
return if notifiable.points.negative?
aggregated_reaction_siblings = notifiable.reactable.reactions.
reject { |r| r.user_id == notifiable.reactable.user_id }.
map { |r| { category: r.category, created_at: r.created_at, user: user_data(r.user) } }
@ -150,6 +151,7 @@ class Notification < ApplicationRecord
def send_welcome_notification(receiver_id)
welcome_broadcast = Broadcast.find_by(title: "Welcome Notification")
return if welcome_broadcast == nil
dev_account = User.find_by_id(ENV["DEVTO_USER_ID"])
json_data = {
user: user_data(dev_account),
@ -170,6 +172,7 @@ class Notification < ApplicationRecord
def send_moderation_notification(notifiable)
available_moderators = User.with_role(:trusted).where("last_moderation_notification < ?", 28.hours.ago)
return if available_moderators.empty?
moderator = available_moderators.sample
dev_account = User.find_by_id(ENV["DEVTO_USER_ID"])
json_data = {
@ -190,7 +193,7 @@ class Notification < ApplicationRecord
def send_tag_adjustment_notification(notifiable)
article = notifiable.article
json_data = {
article: {title: article.title, path: article.path},
article: { title: article.title, path: article.path },
adjustment_type: notifiable.adjustment_type,
status: notifiable.status,
reason_for_adjustment: notifiable.reason_for_adjustment,
@ -206,7 +209,6 @@ class Notification < ApplicationRecord
end
handle_asynchronously :send_tag_adjustment_notification
def remove_all(notifiable_hash)
Notification.where(
notifiable_id: notifiable_hash[:id],
@ -235,6 +237,7 @@ class Notification < ApplicationRecord
action: action,
)
return if notifications.blank?
new_json_data = notifications.first.json_data
new_json_data[notifiable.class.name.downcase] = send("#{notifiable.class.name.downcase}_data", notifiable)
notifications.update_all(json_data: new_json_data)
@ -287,6 +290,7 @@ class Notification < ApplicationRecord
def send_push_notifications(user_id, title, body, path)
return unless ApplicationConfig["PUSHER_BEAMS_KEY"] && ApplicationConfig["PUSHER_BEAMS_KEY"].size == 64
payload = {
apns: {
aps: {

View file

@ -161,6 +161,7 @@ class PodcastEpisode < ApplicationRecord
def prefix_all_images
return unless body.present?
self.processed_html = body.gsub("\r\n<p>&nbsp;</p>\r\n", "").gsub("\r\n<p>&nbsp;</p>\r\n", "").gsub("\r\n<h3>&nbsp;</h3>\r\n", "").gsub("\r\n<h3>&nbsp;</h3>\r\n", "")
self.processed_html = "<p>#{processed_html}</p>" unless processed_html.include?("<p>")
doc = Nokogiri::HTML(processed_html)

View file

@ -1,5 +1,4 @@
class Tag < ActsAsTaggableOn::Tag
attr_accessor :points
include AlgoliaSearch

View file

@ -1,5 +1,4 @@
class TagAdjustment < ApplicationRecord
validates :user_id, presence: true
validates :article_id, presence: true
validates :tag_id, presence: true

View file

@ -56,57 +56,59 @@ class Tweet < ApplicationRecord
text
end
private
class << self
private
def self.try_to_get_tweet(twitter_id_code)
c = TwitterBot.new(random_identity).client
t = c.status(twitter_id_code, tweet_mode: "extended")
make_tweet_from_api_object(t)
end
def try_to_get_tweet(twitter_id_code)
c = TwitterBot.new(random_identity).client
t = c.status(twitter_id_code, tweet_mode: "extended")
make_tweet_from_api_object(t)
end
def self.make_tweet_from_api_object(tweeted)
twitter_bot = TwitterBot.new(random_identity)
tweeted = if tweeted.attrs[:retweeted_status]
twitter_bot.client.status(tweeted.attrs[:retweeted_status][:id_str])
else
tweeted
end
tweet = Tweet.where(twitter_id_code: tweeted.attrs[:id_str]).first_or_initialize
tweet.twitter_uid = tweeted.user.id.to_s
tweet.twitter_username = tweeted.user.screen_name.downcase
tweet.user_id = User.find_by_twitter_username(tweeted.user.screen_name).try(:id)
tweet.favorite_count = tweeted.favorite_count
tweet.retweet_count = tweeted.retweet_count
tweet.in_reply_to_user_id_code = tweeted.attrs[:in_reply_to_user_id_str]
tweet.in_reply_to_user_id_code = tweeted.attrs[:in_reply_to_status_id_str]
tweet.twitter_user_following_count = tweeted.user.friends_count
tweet.twitter_user_followers_count = tweeted.user.followers_count
tweet.twitter_id_code = tweeted.attrs[:id_str]
tweet.quoted_tweet_id_code = tweeted.attrs[:quoted_status_id_str]
tweet.in_reply_to_username = tweeted.in_reply_to_screen_name
tweet.source = tweeted.source
tweet.text = tweeted.attrs[:full_text]
tweet.twitter_name = tweeted.user.name
tweet.mentioned_usernames_serialized = tweeted.user_mentions.as_json
tweet.hashtags_serialized = tweeted.attrs[:entities][:hashtags]
tweet.remote_profile_image_url = tweeted.user.profile_image_url
tweet.urls_serialized = tweeted.attrs[:entities][:urls]
tweet.media_serialized = tweeted.attrs[:media]
tweet.extended_entities_serialized = tweeted.attrs[:extended_entities]
tweet.full_fetched_object_serialized = tweeted.attrs
tweet.tweeted_at = tweeted.attrs[:created_at]
tweet.last_fetched_at = Time.current
tweet.user_is_verified = tweeted.user.verified?
tweet.is_quote_status = tweeted.attrs[:is_quote_status]
tweet.save!
tweet
end
def make_tweet_from_api_object(tweeted)
twitter_bot = TwitterBot.new(random_identity)
tweeted = if tweeted.attrs[:retweeted_status]
twitter_bot.client.status(tweeted.attrs[:retweeted_status][:id_str])
else
tweeted
end
tweet = Tweet.where(twitter_id_code: tweeted.attrs[:id_str]).first_or_initialize
tweet.twitter_uid = tweeted.user.id.to_s
tweet.twitter_username = tweeted.user.screen_name.downcase
tweet.user_id = User.find_by_twitter_username(tweeted.user.screen_name).try(:id)
tweet.favorite_count = tweeted.favorite_count
tweet.retweet_count = tweeted.retweet_count
tweet.in_reply_to_user_id_code = tweeted.attrs[:in_reply_to_user_id_str]
tweet.in_reply_to_user_id_code = tweeted.attrs[:in_reply_to_status_id_str]
tweet.twitter_user_following_count = tweeted.user.friends_count
tweet.twitter_user_followers_count = tweeted.user.followers_count
tweet.twitter_id_code = tweeted.attrs[:id_str]
tweet.quoted_tweet_id_code = tweeted.attrs[:quoted_status_id_str]
tweet.in_reply_to_username = tweeted.in_reply_to_screen_name
tweet.source = tweeted.source
tweet.text = tweeted.attrs[:full_text]
tweet.twitter_name = tweeted.user.name
tweet.mentioned_usernames_serialized = tweeted.user_mentions.as_json
tweet.hashtags_serialized = tweeted.attrs[:entities][:hashtags]
tweet.remote_profile_image_url = tweeted.user.profile_image_url
tweet.urls_serialized = tweeted.attrs[:entities][:urls]
tweet.media_serialized = tweeted.attrs[:media]
tweet.extended_entities_serialized = tweeted.attrs[:extended_entities]
tweet.full_fetched_object_serialized = tweeted.attrs
tweet.tweeted_at = tweeted.attrs[:created_at]
tweet.last_fetched_at = Time.current
tweet.user_is_verified = tweeted.user.verified?
tweet.is_quote_status = tweeted.attrs[:is_quote_status]
tweet.save!
tweet
end
def self.random_identity
iden = Identity.where(provider: "twitter").last(250).sample
{
token: iden&.token || ApplicationConfig["TWITTER_KEY"],
secret: iden&.secret || ApplicationConfig["TWITTER_SECRET"]
}
def random_identity
iden = Identity.where(provider: "twitter").last(250).sample
{
token: iden&.token || ApplicationConfig["TWITTER_KEY"],
secret: iden&.secret || ApplicationConfig["TWITTER_SECRET"]
}
end
end
end

View file

@ -297,11 +297,13 @@ class User < ApplicationRecord
def reason_for_ban
return if notes.where(reason: "banned").blank?
Note.find_by(noteable_id: id, noteable_type: "User", reason: "banned").content
end
def reason_for_warning
return if notes.where(reason: "warned").blank?
Note.find_by(noteable_id: id, noteable_type: "User", reason: "warned").content
end
@ -461,6 +463,7 @@ class User < ApplicationRecord
def conditionally_validate_summary
# Grandfather people who had a too long summary before.
return if summary_was && summary_was.size > 200
if summary.present? && summary.size > 200
errors.add(:summary, "is too long.")
end
@ -468,13 +471,16 @@ class User < ApplicationRecord
def validate_feed_url
return unless feed_url.present?
errors.add(:feed_url, "is not a valid rss feed") unless RssReader.new.valid_feed_url?(feed_url)
end
def validate_mastodon_url
return unless mastodon_url.present?
uri = URI.parse(mastodon_url)
return if uri.host&.in?(Constants::ALLOWED_MASTODON_INSTANCES)
errors.add(:mastodon_url, "is not an allowed Mastodon instance")
end
@ -555,7 +561,8 @@ class User < ApplicationRecord
def destroy_empty_dm_channels
return if chat_channels.empty? ||
chat_channels.where(channel_type: "direct").empty?
chat_channels.where(channel_type: "direct").empty?
empty_dm_channels = chat_channels.where(channel_type: "direct").
select { |chat_channel| chat_channel.messages.empty? }
empty_dm_channels.destroy_all

View file

@ -1,6 +1,7 @@
class ArticleObserver < ApplicationObserver
def after_save(article)
return if Rails.env.development?
if article.published && article.published_at > 30.seconds.ago
SlackBot.delay.ping "New Article Published: #{article.title}\nhttps://dev.to#{article.path}",
channel: "activity",

View file

@ -1,6 +1,7 @@
class CommentObserver < ApplicationObserver
def after_save(comment)
return if Rails.env.development?
warned_user_ping(comment)
rescue StandardError
puts "error"

View file

@ -1,10 +1,13 @@
class OrganizationObserver < ActiveRecord::Observer
def after_create(organization)
return if Rails.env.development?
SlackBot.delay.ping "New Org Created: #{organization.name}\nhttps://dev.to/#{organization.username}",
channel: "orgactivity",
username: "org_bot",
icon_emoji: ":office:"
SlackBot.delay.ping(
"New Org Created: #{organization.name}\nhttps://dev.to/#{organization.username}",
channel: "orgactivity",
username: "org_bot",
icon_emoji: ":office:",
)
rescue StandardError
puts "error"
end

View file

@ -3,6 +3,7 @@ class ApplicationPolicy
def initialize(user, record)
raise Pundit::NotAuthorizedError, "You must be logged in" unless user
@user = user
@record = record
end
@ -44,6 +45,7 @@ class ApplicationPolicy
def initialize(user, scope)
raise Pundit::NotAuthorizedError, "must be logged in" unless user
@user = user
@scope = scope
end

View file

@ -9,6 +9,7 @@ class ArticleCreationService
def create!
raise if RateLimitChecker.new(user).limit_by_situation("published_article_creation")
article = Article.new(article_params)
article.user_id = user.id
article.show_comments = true

View file

@ -10,6 +10,7 @@ class AuthorizationService
def get_user
identity = build_identity
return signed_in_resource if user_identity_exists(identity)
user = proper_user(identity)
user = if user.nil?
build_user(identity)
@ -24,6 +25,7 @@ class AuthorizationService
def add_social_identity_data(user)
return unless auth&.provider && auth&.extra && auth.extra.raw_info
if auth.provider == "twitter"
user.twitter_created_at = auth.extra.raw_info.created_at
user.twitter_followers_count = auth.extra.raw_info.followers_count.to_i

View file

@ -6,6 +6,7 @@ class GetUnseenNotificationsService
def get
return 1 if Rails.env.test?
return 1 unless @user
NotificationCounter.new(@user).unread_notification_count
end
end

View file

@ -11,26 +11,26 @@ class MembershipService
def subscribe_customer
true if create_subscription &&
assign_membership_role &&
user.update(monthly_dues: monthly_dues,
membership_started_at: Time.current,
email_membership_newsletter: true,
stripe_id_code: customer.id) &&
send_welcome_email
assign_membership_role &&
user.update(monthly_dues: monthly_dues,
membership_started_at: Time.current,
email_membership_newsletter: true,
stripe_id_code: customer.id) &&
send_welcome_email
end
def update_subscription
true if update_stripe_plan_for_subscription &&
assign_membership_role &&
user.update(monthly_dues: monthly_dues) &&
send_update_email
assign_membership_role &&
user.update(monthly_dues: monthly_dues) &&
send_update_email
end
def unsubscribe_customer
true if cancel_subscription &&
remove_all_membership_roles &&
user.update(monthly_dues: 0, email_membership_newsletter: false) &&
send_cancellation_email
remove_all_membership_roles &&
user.update(monthly_dues: 0, email_membership_newsletter: false) &&
send_cancellation_email
end
def find_subscription

View file

@ -13,6 +13,7 @@ module Moderator
def banish
return unless user.comments.where("created_at < ?", 150.days.ago).empty?
new_name = "spam_#{rand(10000)}"
new_username = "spam_#{rand(10000)}"
if User.find_by(name: new_name) || User.find_by(username: new_username)

View file

@ -2,7 +2,7 @@ json.array! @users.each do |user|
json.id user.id
json.name user.name
json.username user.username
json.summary truncate(user.summary.present? ? user.summary : "Active DEV author" , length: 100)
json.summary truncate(user.summary.present? ? user.summary : "Active DEV author", length: 100)
json.profile_image_url ProfileImage.new(user).get(90)
json.following false
end

View file

@ -1,17 +1,17 @@
require 'libhoney'
require "libhoney"
key = ApplicationConfig["HONEYCOMB_API_KEY"]
dataset = "dev.to-#{Rails.env}"
if Rails.env.development? || Rails.env.test?
$libhoney = Libhoney::NullClient.new
else
$libhoney = Libhoney::Client.new(
writekey: key,
dataset: dataset,
user_agent_addition: HoneycombRails::USER_AGENT_SUFFIX,
)
end
$libhoney = if Rails.env.development? || Rails.env.test?
Libhoney::NullClient.new
else
Libhoney::Client.new(
writekey: key,
dataset: dataset,
user_agent_addition: HoneycombRails::USER_AGENT_SUFFIX,
)
end
HoneycombRails.configure do |conf|
conf.writekey = key

View file

@ -13,6 +13,7 @@ module Instrumentation
def append_to_honeycomb(request, controller_name)
return if honeycomb_metadata.nil?
honeycomb_metadata["trace.trace_id"] = request.request_id
honeycomb_metadata["trace.span_id"] = request.request_id
honeycomb_metadata[:service_name] = "rails"

View file

@ -68,6 +68,7 @@ end
task send_email_digest: :environment do
return if Time.current.wday < 3
EmailDigest.send_periodic_digest_email
end
@ -110,7 +111,7 @@ task remove_old_html_variant_data: :environment do
HtmlVariantSuccess.where("created_at < ?", 1.week.ago).destroy_all
HtmlVariant.find_each do |html_variant|
if html_variant.html_variant_successes.size > 3
html_variant.calculate_success_rate!
html_variant.calculate_success_rate!
end
end
end

View file

@ -9,7 +9,6 @@ FactoryBot.define do
description { Faker::Hipster.paragraph(1) }
slug { "slug-#{rand(10_000)}" }
feed_url { Faker::Internet.url }
after(:build) { |pod| pod.define_singleton_method(:pull_all_episodes) {} }
after(:build) { |pod| pod.define_singleton_method(:pull_all_episodes) {} }
end
end

View file

@ -5,25 +5,25 @@ RSpec.describe UserSimilarity, vcr: {} do
let(:similar_user) { create(:user, summary: "I like JavaScript and Go") }
let(:dissimilar_user) { create(:user, summary: "I like Haskell and functional programming") }
it "It returns similar user" do
simialar_score = UserSimilarity.new(user, similar_user).score
dissimialar_score = UserSimilarity.new(user, dissimilar_user).score
expect(simialar_score).to be > dissimialar_score
it "returns similar user" do
similar_score = UserSimilarity.new(user, similar_user).score
dissimilar_score = UserSimilarity.new(user, dissimilar_user).score
expect(similar_score).to be > dissimilar_score
end
it "Is not affected by stop words" do
user.summary = user.summary + " throughout yourself can indeed otherwise thru yourselves through yours by inc others"
dissimilar_user.summary = dissimilar_user.summary + " throughout yourself can indeed otherwise thru yourselves through yours by inc others"
simialar_score = UserSimilarity.new(user, similar_user).score
dissimialar_score = UserSimilarity.new(user, dissimilar_user).score
expect(simialar_score).to be > dissimialar_score
similar_score = UserSimilarity.new(user, similar_user).score
dissimilar_score = UserSimilarity.new(user, dissimilar_user).score
expect(similar_score).to be > dissimilar_score
end
it "Is affected by non-stop words" do
user.mentee_description = "Hot dogs languages punk rock hello"
dissimilar_user.mentor_description = "Hot dogs languages punk rock hello "
simialar_score = UserSimilarity.new(user, similar_user).score
dissimialar_score = UserSimilarity.new(user, dissimilar_user).score
expect(simialar_score).to be < dissimialar_score
similar_score = UserSimilarity.new(user, similar_user).score
dissimilar_score = UserSimilarity.new(user, dissimilar_user).score
expect(similar_score).to be < dissimilar_score
end
end

View file

@ -20,6 +20,7 @@ RSpec.describe YoutubeTag, type: :liquid_template do
def parsed_id(id)
return id unless id.include?("?t=")
id_array = id.split("?t=")
time_hash = {
h: id_array[1].scan(/\d+h/)[0]&.delete("h").to_i,

View file

@ -1,4 +1,4 @@
require 'rails_helper'
require "rails_helper"
RSpec.describe BufferUpdate, type: :model do
let(:user) { create(:user) }
@ -38,7 +38,7 @@ RSpec.describe BufferUpdate, type: :model do
expect(BufferUpdate.all.size).to eq(2)
end
it "allows same text across different tags" do
it "allows same text across different articles with the same tag" do
BufferUpdate.buff!(article.id, "twitter_buffer_text", "CODE", "twitter", 1)
BufferUpdate.buff!(create(:article).id, "twitter_buffer_text", "CODE", "twitter", 1)
expect(BufferUpdate.all.size).to eq(2)

View file

@ -205,6 +205,5 @@ RSpec.describe Comment, type: :model do
expect(ShareMeowClient).to have_received(:image_url)
end
end
end
# rubocop:enable RSpec/ExampleLength, RSpec/MultipleExpectations

View file

@ -5,7 +5,7 @@ RSpec.describe FeedbackMessage, type: :model do
let(:abuse_report) { create(:feedback_message, :abuse_report) }
describe "validations for an abuse report" do
subject do
subject(:feedback_message) do
FeedbackMessage.new(
feedback_type: "abuse-reports",
reported_url: "https://dev.to",
@ -19,13 +19,13 @@ RSpec.describe FeedbackMessage, type: :model do
it { is_expected.to validate_presence_of(:message) }
it do
is_expected.to validate_inclusion_of(:category).
expect(feedback_message).to validate_inclusion_of(:category).
in_array(["spam", "other", "rude or vulgar", "harassment", "bug"])
end
end
describe "validations for a bug report" do
subject do
subject(:feedback_message) do
FeedbackMessage.new(
feedback_type: "bug-reports",
category: "bug",
@ -38,7 +38,7 @@ RSpec.describe FeedbackMessage, type: :model do
it { is_expected.not_to validate_presence_of(:reported_url) }
it do
is_expected.to validate_inclusion_of(:category).
expect(feedback_message).to validate_inclusion_of(:category).
in_array(["spam", "other", "rude or vulgar", "harassment", "bug"])
end
end

View file

@ -1,12 +1,12 @@
require 'rails_helper'
require "rails_helper"
RSpec.describe HtmlVariant, type: :model do
let(:html_variant) { create(:html_variant, approved: true, published: true) }
it { is_expected.to validate_uniqueness_of(:name) }
it { is_expected.to validate_presence_of(:html) }
it { is_expected.to belong_to(:user) }
let(:html_variant) { create(:html_variant, approved: true, published: true) }
it "calculates success rate" do
HtmlVariantTrial.create!(html_variant_id: html_variant.id)
HtmlVariantTrial.create!(html_variant_id: html_variant.id)

View file

@ -1,4 +1,4 @@
require 'rails_helper'
require "rails_helper"
RSpec.describe HtmlVariantSuccess, type: :model do
pending "add some examples to (or delete) #{__FILE__}"

View file

@ -1,4 +1,4 @@
require 'rails_helper'
require "rails_helper"
RSpec.describe HtmlVariantTrial, type: :model do
pending "add some examples to (or delete) #{__FILE__}"

View file

@ -1,6 +1,17 @@
require 'rails_helper'
require "rails_helper"
RSpec.describe TagAdjustment, type: :model do
before do
mod_user.add_role(:tag_moderator, tag)
admin_user.add_role(:admin)
end
let(:article) { create(:article) }
let(:tag) { create(:tag) }
let(:admin_user) { create(:user) }
let(:mod_user) { create(:user) }
let(:regular_user) { create(:user) }
it { is_expected.to validate_presence_of(:user_id) }
it { is_expected.to validate_presence_of(:article_id) }
it { is_expected.to validate_presence_of(:tag_id) }
@ -8,17 +19,6 @@ RSpec.describe TagAdjustment, type: :model do
it { is_expected.to validate_presence_of(:adjustment_type) }
it { is_expected.to validate_presence_of(:status) }
let(:regular_user) { create(:user)}
let(:mod_user) { create(:user)}
let(:admin_user) { create(:user)}
let(:tag) { create(:tag)}
let(:article) { create(:article)}
before do
mod_user.add_role(:tag_moderator, tag)
admin_user.add_role(:admin)
end
describe "privileges" do
it "allows tag mods to create for their tags" do
tag_adjustment = build(:tag_adjustment, user_id: mod_user.id, article_id: article.id, tag_id: tag.id)

View file

@ -371,6 +371,7 @@ RSpec.describe User, type: :model do
let(:tag2) { create(:tag) }
let(:tag3) { create(:tag) }
let(:tag4) { create(:tag) }
it "returns empty if no tags followed" do
expect(user.decorate.cached_followed_tags.size).to eq(0)
end

View file

@ -1,7 +1,7 @@
require "rails_helper"
RSpec.describe CommentPolicy do
subject { described_class.new(user, comment) }
subject(:comment_policy) { described_class.new(user, comment) }
let(:comment) { build(:comment) }
@ -26,7 +26,7 @@ RSpec.describe CommentPolicy do
it { is_expected.to forbid_actions(%i[edit update destroy delete_confirm]) }
it do
is_expected.to permit_mass_assignment_of(valid_attributes_for_create).for_action(:create)
expect(comment_policy).to permit_mass_assignment_of(valid_attributes_for_create).for_action(:create)
end
context "with banned status" do
@ -57,7 +57,7 @@ RSpec.describe CommentPolicy do
it { is_expected.to forbid_actions(%i[create]) }
it do
is_expected.to permit_mass_assignment_of(valid_attributes_for_update).for_action(:update)
expect(comment_policy).to permit_mass_assignment_of(valid_attributes_for_update).for_action(:update)
end
end
@ -68,7 +68,7 @@ RSpec.describe CommentPolicy do
it { is_expected.to forbid_actions(%i[create]) }
it do
is_expected.to permit_mass_assignment_of(valid_attributes_for_update).for_action(:update)
expect(comment_policy).to permit_mass_assignment_of(valid_attributes_for_update).for_action(:update)
end
end
end

View file

@ -13,6 +13,7 @@ RSpec.describe HtmlVariantPolicy do
context "when user is an admin" do
let(:user) { build(:user, :super_admin) }
let(:html_variant) { build(:html_variant) }
it { is_expected.to permit_actions(%i[index show edit update create]) }
end
end

View file

@ -1,7 +1,7 @@
require "rails_helper"
RSpec.describe OrganizationPolicy do
subject { described_class.new(user, organization) }
subject(:organization_policy) { described_class.new(user, organization) }
let(:organization) { build(:organization) }
@ -30,7 +30,7 @@ RSpec.describe OrganizationPolicy do
before { user.update(organization: organization, org_admin: true) }
it "allows the user to update their own org" do
is_expected.to permit_action(:update)
expect(organization_policy).to permit_action(:update)
end
end
@ -41,7 +41,7 @@ RSpec.describe OrganizationPolicy do
before { user.update(organization: new_org, org_admin: true) }
it "does not allow the user to update another org" do
is_expected.to forbid_action(:update)
expect(organization_policy).to forbid_action(:update)
end
end
end

View file

@ -72,6 +72,7 @@ RSpec.describe "ArticlesApi", type: :request do
before do
sign_in user1
end
it "creates ordinary article with proper params" do
new_title = "NEW TITLE #{rand(100)}"
post "/api/articles", params: {
@ -79,7 +80,7 @@ RSpec.describe "ArticlesApi", type: :request do
}
expect(Article.last.user_id).to eq(user1.id)
end
# rubocop:disable RSpec/ExampleLength
it "creates article with front matter params" do
post "/api/articles", params: {
article: {
@ -89,19 +90,20 @@ RSpec.describe "ArticlesApi", type: :request do
}
expect(Article.last.title).to eq("hey hey hahuu")
end
it "creates article w/ series param" do
new_title = "NEW TITLE #{rand(100)}"
post "/api/articles", params: {
article: { title: new_title,
body_markdown: "Yo ho ho#{rand(100)}",
tag_list: "yo",
series: "helloyo",
}
series: "helloyo" }
}
expect(Article.last.collection).to eq(Collection.find_by_slug("helloyo"))
expect(Article.last.collection.user_id).to eq(Article.last.user_id)
end
it "creates article with front matter params" do
it "creates article within series with front matter params" do
post "/api/articles", params: {
article: {
body_markdown: "---\ntitle: hey hey hahuu\npublished: false\nseries: helloyo\n---\nYo ho ho#{rand(100)}",
@ -116,52 +118,51 @@ RSpec.describe "ArticlesApi", type: :request do
describe "PUT /api/articles/:id w/ current_user" do
before do
sign_in user1
@article = create(:article, user: user1)
end
let(:article) { create(:article, user: user1) }
it "updates ordinary article with proper params" do
new_title = "NEW TITLE #{rand(100)}"
put "/api/articles/#{@article.id}", params: {
article: { title: new_title, body_markdown: "Yo ho ho#{rand(100)}", tag_list: "yo" }
}
expect(Article.last.title).to eq(new_title)
end
it "updates ordinary article with proper params" do
new_title = "NEW TITLE #{rand(100)}"
put "/api/articles/#{@article.id}", params: {
put "/api/articles/#{article.id}", params: {
article: { title: new_title, body_markdown: "Yo ho ho#{rand(100)}", tag_list: "yo" }
}
expect(Article.last.title).to eq(new_title)
end
it "does not allow user to update a different article" do
new_title = "NEW TITLE #{rand(100)}"
@article.update_column(:user_id, user2.id)
article.update_column(:user_id, user2.id)
expect {
put "/api/articles/#{@article.id}",
params: { article: { title: new_title, body_markdown: "Yo ho ho#{rand(100)}", tag_list: "yo" }
}}.to raise_error(ActionController::RoutingError)
put "/api/articles/#{article.id}",
params: { article: { title: new_title, body_markdown: "Yo ho ho#{rand(100)}", tag_list: "yo" } }
} .to raise_error(ActionController::RoutingError)
end
it "does allow super user to update a different article" do
new_title = "NEW TITLE #{rand(100)}"
@article.update_column(:user_id, user2.id)
article.update_column(:user_id, user2.id)
user1.add_role(:super_admin)
put "/api/articles/#{@article.id}", params: {
put "/api/articles/#{article.id}", params: {
article: { title: new_title, body_markdown: "Yo ho ho#{rand(100)}", tag_list: "yo" }
}
expect(Article.last.title).to eq(new_title)
end
it "allows collection to be assigned via api" do
new_title = "NEW TITLE #{rand(100)}"
collection = Collection.create(user_id: @article.user_id, slug: "yoyoyo")
put "/api/articles/#{@article.id}", params: {
collection = Collection.create(user_id: article.user_id, slug: "yoyoyo")
put "/api/articles/#{article.id}", params: {
article: { title: new_title, body_markdown: "Yo ho ho#{rand(100)}", tag_list: "yo", collection_id: collection.id }
}
expect(Article.last.collection_id).to eq(collection.id)
end
it "does not allow collection which is not of user" do
new_title = "NEW TITLE #{rand(100)}"
collection = Collection.create(user_id: 3333, slug: "yoyoyo")
put "/api/articles/#{@article.id}", params: {
put "/api/articles/#{article.id}", params: {
article: { title: new_title, body_markdown: "Yo ho ho#{rand(100)}", tag_list: "yo", collection_id: collection.id }
}
expect(Article.last.collection_id).not_to eq(collection.id)

View file

@ -10,7 +10,7 @@ RSpec.describe "Dashboards", type: :request do
context "when not logged in" do
it "redirects to /enter" do
get "/dashboard"
is_expected.to redirect_to("/enter")
expect(response).to redirect_to("/enter")
end
end
@ -40,7 +40,7 @@ RSpec.describe "Dashboards", type: :request do
context "when not logged in" do
it "redirects to /enter" do
get "/dashboard/organization"
is_expected.to redirect_to("/enter")
expect(response).to redirect_to("/enter")
end
end
@ -59,7 +59,7 @@ RSpec.describe "Dashboards", type: :request do
context "when not logged in" do
it "redirects to /enter" do
get "/dashboard/following_users"
is_expected.to redirect_to("/enter")
expect(response).to redirect_to("/enter")
end
end
@ -85,7 +85,7 @@ RSpec.describe "Dashboards", type: :request do
context "when not logged in" do
it "redirects to /enter" do
get "/dashboard/user_followers"
is_expected.to redirect_to("/enter")
expect(response).to redirect_to("/enter")
end
end

View file

@ -17,7 +17,7 @@ RSpec.describe "HtmlVariantSuccesses", type: :request do
it "rejects non-permissioned user" do
post "/html_variant_successes", params: {
article_id: article.id,
html_variant_id: html_variant.id,
html_variant_id: html_variant.id
}
expect(HtmlVariantSuccess.all.size).to eq(1)
end

View file

@ -17,7 +17,7 @@ RSpec.describe "HtmlVariantTrials", type: :request do
it "rejects non-permissioned user" do
post "/html_variant_trials", params: {
article_id: article.id,
html_variant_id: html_variant.id,
html_variant_id: html_variant.id
}
expect(HtmlVariantTrial.all.size).to eq(1)
end

View file

@ -1,7 +1,7 @@
require "rails_helper"
RSpec.describe "HtmlVariants", type: :request do
let(:user) { create(:user)}
let(:user) { create(:user) }
let(:article) { create(:article, user_id: user.id, approved: true) }
before do
@ -105,6 +105,4 @@ RSpec.describe "HtmlVariants", type: :request do
expect(html_variant.reload.html).not_to eq(new_html)
end
end
end

Some files were not shown because too many files have changed in this diff Show more