diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index bbf2a5fbd..1e4cd1c9e 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -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 diff --git a/Guardfile b/Guardfile index 14dac7561..fbbeaf8e1 100644 --- a/Guardfile +++ b/Guardfile @@ -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 diff --git a/app/black_box/black_box.rb b/app/black_box/black_box.rb index 9256ce0ff..a2d56d483 100644 --- a/app/black_box/black_box.rb +++ b/app/black_box/black_box.rb @@ -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 diff --git a/app/controllers/additional_content_boxes_controller.rb b/app/controllers/additional_content_boxes_controller.rb index 7c45e8515..3ba418540 100644 --- a/app/controllers/additional_content_boxes_controller.rb +++ b/app/controllers/additional_content_boxes_controller.rb @@ -26,6 +26,7 @@ class AdditionalContentBoxesController < ApplicationController def randomize return true unless Rails.env.production? + rand(2) == 1 end end diff --git a/app/controllers/admin/application_controller.rb b/app/controllers/admin/application_controller.rb index 1d9b62bf7..5645b011b 100644 --- a/app/controllers/admin/application_controller.rb +++ b/app/controllers/admin/application_controller.rb @@ -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 diff --git a/app/controllers/api/v0/articles_controller.rb b/app/controllers/api/v0/articles_controller.rb index 25dd9069b..6a40bd7ee 100644 --- a/app/controllers/api/v0/articles_controller.rb +++ b/app/controllers/api/v0/articles_controller.rb @@ -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"] == "" diff --git a/app/controllers/api/v0/follows_controller.rb b/app/controllers/api/v0/follows_controller.rb index 3802f5a00..de4798b1c 100644 --- a/app/controllers/api/v0/follows_controller.rb +++ b/app/controllers/api/v0/follows_controller.rb @@ -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"]) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 122ac11a6..09cbf9712 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -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 diff --git a/app/controllers/articles_controller.rb b/app/controllers/articles_controller.rb index 8faa8445e..0baac6a60 100644 --- a/app/controllers/articles_controller.rb +++ b/app/controllers/articles_controller.rb @@ -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 diff --git a/app/controllers/async_info_controller.rb b/app/controllers/async_info_controller.rb index b749cea2a..a9f24c2f4 100644 --- a/app/controllers/async_info_controller.rb +++ b/app/controllers/async_info_controller.rb @@ -62,4 +62,4 @@ class AsyncInfoController < ApplicationController #{current_user&.articles_count}__ #{cookies[:remember_user_token]}" end -end \ No newline at end of file +end diff --git a/app/controllers/buffered_articles_controller.rb b/app/controllers/buffered_articles_controller.rb index 53f409846..7784719da 100644 --- a/app/controllers/buffered_articles_controller.rb +++ b/app/controllers/buffered_articles_controller.rb @@ -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 diff --git a/app/controllers/chat_channels_controller.rb b/app/controllers/chat_channels_controller.rb index 9f90608dd..60e05a457 100644 --- a/app/controllers/chat_channels_controller.rb +++ b/app/controllers/chat_channels_controller.rb @@ -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("/") diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index c1b20930d..fb5477cef 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -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) diff --git a/app/controllers/feedback_messages_controller.rb b/app/controllers/feedback_messages_controller.rb index 07b1c36cb..635ea3508 100644 --- a/app/controllers/feedback_messages_controller.rb +++ b/app/controllers/feedback_messages_controller.rb @@ -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} diff --git a/app/controllers/follows_controller.rb b/app/controllers/follows_controller.rb index c18df0503..35fe57844 100644 --- a/app/controllers/follows_controller.rb +++ b/app/controllers/follows_controller.rb @@ -45,7 +45,7 @@ class FollowsController < ApplicationController redirect_to "/dashboard/following" end end - + private def follow_params diff --git a/app/controllers/internal/feedback_messages_controller.rb b/app/controllers/internal/feedback_messages_controller.rb index 389e5903f..4aab0fe3d 100644 --- a/app/controllers/internal/feedback_messages_controller.rb +++ b/app/controllers/internal/feedback_messages_controller.rb @@ -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 diff --git a/app/controllers/internal/users_controller.rb b/app/controllers/internal/users_controller.rb index 7c5779479..ba402ea10 100644 --- a/app/controllers/internal/users_controller.rb +++ b/app/controllers/internal/users_controller.rb @@ -48,6 +48,7 @@ class Internal::UsersController < Internal::ApplicationController if @new_mentee.blank? && @new_mentor.blank? return end + make_matches end diff --git a/app/controllers/organizations_controller.rb b/app/controllers/organizations_controller.rb index 9df516786..7474b9385 100644 --- a/app/controllers/organizations_controller.rb +++ b/app/controllers/organizations_controller.rb @@ -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 diff --git a/app/controllers/pusher_controller.rb b/app/controllers/pusher_controller.rb index de9ffca07..9bfab6efc 100644 --- a/app/controllers/pusher_controller.rb +++ b/app/controllers/pusher_controller.rb @@ -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) diff --git a/app/controllers/stories_controller.rb b/app/controllers/stories_controller.rb index a26ccfcbc..50ee8e7cc 100644 --- a/app/controllers/stories_controller.rb +++ b/app/controllers/stories_controller.rb @@ -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 diff --git a/app/controllers/stripe_subscriptions_controller.rb b/app/controllers/stripe_subscriptions_controller.rb index 836c1724e..3b711fe62 100644 --- a/app/controllers/stripe_subscriptions_controller.rb +++ b/app/controllers/stripe_subscriptions_controller.rb @@ -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 diff --git a/app/controllers/tag_adjustments_controller.rb b/app/controllers/tag_adjustments_controller.rb index 6349edfab..52fd42e4d 100644 --- a/app/controllers/tag_adjustments_controller.rb +++ b/app/controllers/tag_adjustments_controller.rb @@ -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 diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index f980dd4ca..70fa3a944 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -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? diff --git a/app/dashboards/html_variant_dashboard.rb b/app/dashboards/html_variant_dashboard.rb index fcc37fa1c..104232ad0 100644 --- a/app/dashboards/html_variant_dashboard.rb +++ b/app/dashboards/html_variant_dashboard.rb @@ -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 diff --git a/app/decorators/article_decorator.rb b/app/decorators/article_decorator.rb index d033f3e44..4caa41c5d 100644 --- a/app/decorators/article_decorator.rb +++ b/app/decorators/article_decorator.rb @@ -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 diff --git a/app/decorators/user_decorator.rb b/app/decorators/user_decorator.rb index 39e488faa..96b538c35 100644 --- a/app/decorators/user_decorator.rb +++ b/app/decorators/user_decorator.rb @@ -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 diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index c3a9f2399..bfdc2368c 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -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, diff --git a/app/labor/article_analytics_fetcher.rb b/app/labor/article_analytics_fetcher.rb index 151c91a4f..6a7219619 100644 --- a/app/labor/article_analytics_fetcher.rb +++ b/app/labor/article_analytics_fetcher.rb @@ -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 diff --git a/app/labor/cache_buster.rb b/app/labor/cache_buster.rb index 90a088c4c..5c00798b2 100644 --- a/app/labor/cache_buster.rb +++ b/app/labor/cache_buster.rb @@ -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") diff --git a/app/labor/color_from_image.rb b/app/labor/color_from_image.rb index 3ed9d2fb2..a775fa5ce 100644 --- a/app/labor/color_from_image.rb +++ b/app/labor/color_from_image.rb @@ -5,6 +5,7 @@ class ColorFromImage def main return "#000000" unless Rails.env.production? + begin get_palette["colors"][0]["hex"] rescue StandardError diff --git a/app/labor/email_digest.rb b/app/labor/email_digest.rb index 37b85a108..583b3c4e0 100644 --- a/app/labor/email_digest.rb +++ b/app/labor/email_digest.rb @@ -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 diff --git a/app/labor/email_logic.rb b/app/labor/email_logic.rb index 9a453c790..91811c136 100644 --- a/app/labor/email_logic.rb +++ b/app/labor/email_logic.rb @@ -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 diff --git a/app/labor/flare_tag.rb b/app/labor/flare_tag.rb index e469093f5..4e260a744 100644 --- a/app/labor/flare_tag.rb +++ b/app/labor/flare_tag.rb @@ -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 } diff --git a/app/labor/generated_image.rb b/app/labor/generated_image.rb index 28c5a9cb6..012342865 100644 --- a/app/labor/generated_image.rb +++ b/app/labor/generated_image.rb @@ -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 diff --git a/app/labor/language_detector.rb b/app/labor/language_detector.rb index 6139d0c64..0803fd911 100644 --- a/app/labor/language_detector.rb +++ b/app/labor/language_detector.rb @@ -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 diff --git a/app/labor/mailchimp_bot.rb b/app/labor/mailchimp_bot.rb index a5ea6a159..8bc06148e 100644 --- a/app/labor/mailchimp_bot.rb +++ b/app/labor/mailchimp_bot.rb @@ -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 diff --git a/app/labor/markdown_parser.rb b/app/labor/markdown_parser.rb index c40c97960..d3b4716e2 100644 --- a/app/labor/markdown_parser.rb +++ b/app/labor/markdown_parser.rb @@ -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 diff --git a/app/labor/notification_counter.rb b/app/labor/notification_counter.rb index a080044a3..65ed1328c 100644 --- a/app/labor/notification_counter.rb +++ b/app/labor/notification_counter.rb @@ -5,6 +5,7 @@ class NotificationCounter def unread_notification_count return 0 if Rails.env.test? + @user.notifications.where(read: false).count end diff --git a/app/labor/rate_limit_checker.rb b/app/labor/rate_limit_checker.rb index c00bb5f3b..5b01c1211 100644 --- a/app/labor/rate_limit_checker.rb +++ b/app/labor/rate_limit_checker.rb @@ -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", diff --git a/app/labor/rss_reader.rb b/app/labor/rss_reader.rb index 09170e8e5..b0efab3f0 100644 --- a/app/labor/rss_reader.rb +++ b/app/labor/rss_reader.rb @@ -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 diff --git a/app/labor/sticky_article_collection.rb b/app/labor/sticky_article_collection.rb index 93139b147..aa2dc6cf5 100644 --- a/app/labor/sticky_article_collection.rb +++ b/app/labor/sticky_article_collection.rb @@ -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). diff --git a/app/labor/unread_notifications_emailer.rb b/app/labor/unread_notifications_emailer.rb index 0daa07d58..683521072 100644 --- a/app/labor/unread_notifications_emailer.rb +++ b/app/labor/unread_notifications_emailer.rb @@ -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 diff --git a/app/lib/acts_as_taggable_on/tag_parser.rb b/app/lib/acts_as_taggable_on/tag_parser.rb index fd76bba5d..5bee7d8e6 100644 --- a/app/lib/acts_as_taggable_on/tag_parser.rb +++ b/app/lib/acts_as_taggable_on/tag_parser.rb @@ -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 diff --git a/app/lib/constants.rb b/app/lib/constants.rb index 56abd1f2d..0a6625b36 100644 --- a/app/lib/constants.rb +++ b/app/lib/constants.rb @@ -52,6 +52,6 @@ module Constants "switter.at", "todon.nl", "toot.cafe", - "wikitetas.club" + "wikitetas.club", ].freeze end diff --git a/app/lib/redcarpet/render/html_rouge.rb b/app/lib/redcarpet/render/html_rouge.rb index 7685c2937..f46a6a7ee 100644 --- a/app/lib/redcarpet/render/html_rouge.rb +++ b/app/lib/redcarpet/render/html_rouge.rb @@ -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 //.match?(content) + link_attributes = "" @options[:link_attributes]&.each do |attribute, value| link_attributes += %( #{attribute}="#{value}") diff --git a/app/liquid_tags/github_tag/github_issue_tag.rb b/app/liquid_tags/github_tag/github_issue_tag.rb index b9ed8e473..bd4058eb7 100644 --- a/app/liquid_tags/github_tag/github_issue_tag.rb +++ b/app/liquid_tags/github_tag/github_issue_tag.rb @@ -74,6 +74,7 @@ class GithubTag number = content_json[:number] link = content_json[:html_url] return unless title + "

" \ "" \ "#{title} ##{number} " \ diff --git a/app/liquid_tags/glitch_tag.rb b/app/liquid_tags/glitch_tag.rb index 6c98d9142..300b614e8 100644 --- a/app/liquid_tags/glitch_tag.rb +++ b/app/liquid_tags/glitch_tag.rb @@ -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 diff --git a/app/liquid_tags/link_tag.rb b/app/liquid_tags/link_tag.rb index 14596ba49..3453ed5ba 100644 --- a/app/liquid_tags/link_tag.rb +++ b/app/liquid_tags/link_tag.rb @@ -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 diff --git a/app/liquid_tags/parler_tag.rb b/app/liquid_tags/parler_tag.rb index cebc8a009..0e6c90a06 100755 --- a/app/liquid_tags/parler_tag.rb +++ b/app/liquid_tags/parler_tag.rb @@ -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 diff --git a/app/liquid_tags/raw_tag.rb b/app/liquid_tags/raw_tag.rb index 6e4cceebe..54a327737 100644 --- a/app/liquid_tags/raw_tag.rb +++ b/app/liquid_tags/raw_tag.rb @@ -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) diff --git a/app/liquid_tags/youtube_tag.rb b/app/liquid_tags/youtube_tag.rb index fb6626adc..f1baa972c 100644 --- a/app/liquid_tags/youtube_tag.rb +++ b/app/liquid_tags/youtube_tag.rb @@ -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 diff --git a/app/mailers/notify_mailer.rb b/app/mailers/notify_mailer.rb index a5a4fea74..72bc59f30 100644 --- a/app/mailers/notify_mailer.rb +++ b/app/mailers/notify_mailer.rb @@ -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" diff --git a/app/models/article.rb b/app/models/article.rb index ba3801c4d..7d5743463 100644 --- a/app/models/article.rb +++ b/app/models/article.rb @@ -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 diff --git a/app/models/block.rb b/app/models/block.rb index 4e6ae06e9..a0b005cfc 100644 --- a/app/models/block.rb +++ b/app/models/block.rb @@ -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 diff --git a/app/models/buffer_update.rb b/app/models/buffer_update.rb index a6ee00b56..f910e4058 100644 --- a/app/models/buffer_update.rb +++ b/app/models/buffer_update.rb @@ -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, diff --git a/app/models/chat_channel.rb b/app/models/chat_channel.rb index 7bd3e9ddb..2e1491740 100644 --- a/app/models/chat_channel.rb +++ b/app/models/chat_channel.rb @@ -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 ") diff --git a/app/models/comment.rb b/app/models/comment.rb index 8e96a8397..6d4c9ecd0 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -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| "#{s}" } end diff --git a/app/models/follow.rb b/app/models/follow.rb index cfe8a0e76..ae3069ccd 100644 --- a/app/models/follow.rb +++ b/app/models/follow.rb @@ -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 diff --git a/app/models/github_repo.rb b/app/models/github_repo.rb index 9c78e34ac..4ee1732e9 100644 --- a/app/models/github_repo.rb +++ b/app/models/github_repo.rb @@ -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 diff --git a/app/models/html_variant.rb b/app/models/html_variant.rb index 61d85fa27..791252287 100644 --- a/app/models/html_variant.rb +++ b/app/models/html_variant.rb @@ -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 diff --git a/app/models/mentor_relationship.rb b/app/models/mentor_relationship.rb index d425c9df5..5b44e1ea0 100644 --- a/app/models/mentor_relationship.rb +++ b/app/models/mentor_relationship.rb @@ -41,7 +41,6 @@ class MentorRelationship < ApplicationRecord User.where(id: record_ids) end - private def mutual_follow diff --git a/app/models/message.rb b/app/models/message.rb index 236839070..8f8f1e455 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -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 diff --git a/app/models/notification.rb b/app/models/notification.rb index a7c8d462c..ab5f15729 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -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: { diff --git a/app/models/podcast_episode.rb b/app/models/podcast_episode.rb index 81c4d9bc1..73c1b8dee 100644 --- a/app/models/podcast_episode.rb +++ b/app/models/podcast_episode.rb @@ -161,6 +161,7 @@ class PodcastEpisode < ApplicationRecord def prefix_all_images return unless body.present? + self.processed_html = body.gsub("\r\n

 

\r\n", "").gsub("\r\n

 

\r\n", "").gsub("\r\n

 

\r\n", "").gsub("\r\n

 

\r\n", "") self.processed_html = "

#{processed_html}

" unless processed_html.include?("

") doc = Nokogiri::HTML(processed_html) diff --git a/app/models/tag.rb b/app/models/tag.rb index 53cc4e855..5e05db63b 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -1,5 +1,4 @@ class Tag < ActsAsTaggableOn::Tag - attr_accessor :points include AlgoliaSearch diff --git a/app/models/tag_adjustment.rb b/app/models/tag_adjustment.rb index d548fd401..8378f2f07 100644 --- a/app/models/tag_adjustment.rb +++ b/app/models/tag_adjustment.rb @@ -1,5 +1,4 @@ class TagAdjustment < ApplicationRecord - validates :user_id, presence: true validates :article_id, presence: true validates :tag_id, presence: true diff --git a/app/models/tweet.rb b/app/models/tweet.rb index 642cfd1b7..3b7ededc3 100644 --- a/app/models/tweet.rb +++ b/app/models/tweet.rb @@ -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 diff --git a/app/models/user.rb b/app/models/user.rb index 17aa3668d..65f92b716 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -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 diff --git a/app/observers/article_observer.rb b/app/observers/article_observer.rb index 4a83e7a94..17192106d 100644 --- a/app/observers/article_observer.rb +++ b/app/observers/article_observer.rb @@ -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", diff --git a/app/observers/comment_observer.rb b/app/observers/comment_observer.rb index c9bc3e08c..410a0029d 100644 --- a/app/observers/comment_observer.rb +++ b/app/observers/comment_observer.rb @@ -1,6 +1,7 @@ class CommentObserver < ApplicationObserver def after_save(comment) return if Rails.env.development? + warned_user_ping(comment) rescue StandardError puts "error" diff --git a/app/observers/organization_observer.rb b/app/observers/organization_observer.rb index d93752652..5fb91cd0e 100644 --- a/app/observers/organization_observer.rb +++ b/app/observers/organization_observer.rb @@ -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 diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb index d4f6f4f00..5d5797b1e 100644 --- a/app/policies/application_policy.rb +++ b/app/policies/application_policy.rb @@ -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 diff --git a/app/services/article_creation_service.rb b/app/services/article_creation_service.rb index 40cbf78ff..5a7d856ab 100644 --- a/app/services/article_creation_service.rb +++ b/app/services/article_creation_service.rb @@ -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 diff --git a/app/services/authorization_service.rb b/app/services/authorization_service.rb index 676e56b08..9f809473f 100644 --- a/app/services/authorization_service.rb +++ b/app/services/authorization_service.rb @@ -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 diff --git a/app/services/get_unseen_notifications_service.rb b/app/services/get_unseen_notifications_service.rb index b42ca554f..9be1946c1 100644 --- a/app/services/get_unseen_notifications_service.rb +++ b/app/services/get_unseen_notifications_service.rb @@ -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 diff --git a/app/services/membership_service.rb b/app/services/membership_service.rb index 54c272087..2fa2fd5f5 100644 --- a/app/services/membership_service.rb +++ b/app/services/membership_service.rb @@ -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 diff --git a/app/services/moderator/banisher.rb b/app/services/moderator/banisher.rb index b06d77552..e6863b980 100644 --- a/app/services/moderator/banisher.rb +++ b/app/services/moderator/banisher.rb @@ -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) diff --git a/app/views/api/v0/users/index.json.jbuilder b/app/views/api/v0/users/index.json.jbuilder index 29a2f49bb..b3a592765 100644 --- a/app/views/api/v0/users/index.json.jbuilder +++ b/app/views/api/v0/users/index.json.jbuilder @@ -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 diff --git a/config/initializers/honeycomb.rb b/config/initializers/honeycomb.rb index 2951e1276..0ac4787ae 100644 --- a/config/initializers/honeycomb.rb +++ b/config/initializers/honeycomb.rb @@ -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 diff --git a/lib/instrumentation.rb b/lib/instrumentation.rb index a566d50ee..b43c9d793 100644 --- a/lib/instrumentation.rb +++ b/lib/instrumentation.rb @@ -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" diff --git a/lib/tasks/fetch.rake b/lib/tasks/fetch.rake index 1f0708858..42c6ff1a9 100644 --- a/lib/tasks/fetch.rake +++ b/lib/tasks/fetch.rake @@ -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 diff --git a/spec/factories/podcasts.rb b/spec/factories/podcasts.rb index 9ede69abb..09e944d2a 100644 --- a/spec/factories/podcasts.rb +++ b/spec/factories/podcasts.rb @@ -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 diff --git a/spec/labor/user_similarity_spec.rb b/spec/labor/user_similarity_spec.rb index 4a04037aa..eb9de2409 100644 --- a/spec/labor/user_similarity_spec.rb +++ b/spec/labor/user_similarity_spec.rb @@ -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 diff --git a/spec/liquid_tags/youtube_tag_spec.rb b/spec/liquid_tags/youtube_tag_spec.rb index 7de0970b2..517073dfd 100644 --- a/spec/liquid_tags/youtube_tag_spec.rb +++ b/spec/liquid_tags/youtube_tag_spec.rb @@ -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, diff --git a/spec/models/buffer_update_spec.rb b/spec/models/buffer_update_spec.rb index 5f4065527..b7e8586e8 100644 --- a/spec/models/buffer_update_spec.rb +++ b/spec/models/buffer_update_spec.rb @@ -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) diff --git a/spec/models/comment_spec.rb b/spec/models/comment_spec.rb index 7b288edfa..b0d596a0f 100644 --- a/spec/models/comment_spec.rb +++ b/spec/models/comment_spec.rb @@ -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 diff --git a/spec/models/feedback_message_spec.rb b/spec/models/feedback_message_spec.rb index b98cbde96..9f97bdc7a 100644 --- a/spec/models/feedback_message_spec.rb +++ b/spec/models/feedback_message_spec.rb @@ -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 diff --git a/spec/models/html_variant_spec.rb b/spec/models/html_variant_spec.rb index 448cc5e43..8dfc7e615 100644 --- a/spec/models/html_variant_spec.rb +++ b/spec/models/html_variant_spec.rb @@ -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) diff --git a/spec/models/html_variant_success_spec.rb b/spec/models/html_variant_success_spec.rb index b7433582b..805ffb79f 100644 --- a/spec/models/html_variant_success_spec.rb +++ b/spec/models/html_variant_success_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" RSpec.describe HtmlVariantSuccess, type: :model do pending "add some examples to (or delete) #{__FILE__}" diff --git a/spec/models/html_variant_trial_spec.rb b/spec/models/html_variant_trial_spec.rb index 9b77d92a1..f0673cb34 100644 --- a/spec/models/html_variant_trial_spec.rb +++ b/spec/models/html_variant_trial_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" RSpec.describe HtmlVariantTrial, type: :model do pending "add some examples to (or delete) #{__FILE__}" diff --git a/spec/models/tag_adjustment_spec.rb b/spec/models/tag_adjustment_spec.rb index e3af1e3ef..290f19496 100644 --- a/spec/models/tag_adjustment_spec.rb +++ b/spec/models/tag_adjustment_spec.rb @@ -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) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 976f748d6..7cd936573 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -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 diff --git a/spec/policies/comment_policy_spec.rb b/spec/policies/comment_policy_spec.rb index 86d40043e..a955d7267 100644 --- a/spec/policies/comment_policy_spec.rb +++ b/spec/policies/comment_policy_spec.rb @@ -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 diff --git a/spec/policies/html_variant_policy_spec.rb b/spec/policies/html_variant_policy_spec.rb index 15be28800..d7a2c5eb7 100644 --- a/spec/policies/html_variant_policy_spec.rb +++ b/spec/policies/html_variant_policy_spec.rb @@ -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 diff --git a/spec/policies/organization_policy_spec.rb b/spec/policies/organization_policy_spec.rb index ef5e04b10..deb18b1e2 100644 --- a/spec/policies/organization_policy_spec.rb +++ b/spec/policies/organization_policy_spec.rb @@ -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 diff --git a/spec/requests/articles_api_spec.rb b/spec/requests/articles_api_spec.rb index e694193ca..bd1abe57e 100644 --- a/spec/requests/articles_api_spec.rb +++ b/spec/requests/articles_api_spec.rb @@ -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) diff --git a/spec/requests/dashboard_spec.rb b/spec/requests/dashboard_spec.rb index 8cc146bf7..f695d2570 100644 --- a/spec/requests/dashboard_spec.rb +++ b/spec/requests/dashboard_spec.rb @@ -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 diff --git a/spec/requests/html_variant_successes_spec.rb b/spec/requests/html_variant_successes_spec.rb index af3e61f32..ef7e4d568 100644 --- a/spec/requests/html_variant_successes_spec.rb +++ b/spec/requests/html_variant_successes_spec.rb @@ -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 diff --git a/spec/requests/html_variant_trials_spec.rb b/spec/requests/html_variant_trials_spec.rb index 6ba711c39..c2ce0f441 100644 --- a/spec/requests/html_variant_trials_spec.rb +++ b/spec/requests/html_variant_trials_spec.rb @@ -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 diff --git a/spec/requests/html_variants_spec.rb b/spec/requests/html_variants_spec.rb index bd09fb9bc..b37e728a2 100644 --- a/spec/requests/html_variants_spec.rb +++ b/spec/requests/html_variants_spec.rb @@ -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 diff --git a/spec/requests/internal_reactions_spec.rb b/spec/requests/internal_reactions_spec.rb index 45febd475..a2d99c88e 100644 --- a/spec/requests/internal_reactions_spec.rb +++ b/spec/requests/internal_reactions_spec.rb @@ -8,32 +8,39 @@ RSpec.describe "/internal/reactions", type: :request do describe "PUT /internal/reactions as admin" do before do user.add_role(:trusted) - @reaction = create(:reaction, category: "vomit", user_id: user.id, reactable_id: article.id) login_as admin end + + let(:reaction) { create(:reaction, category: "vomit", user_id: user.id, reactable_id: article.id) } + it "updates reaction to be confirmed" do - put "/internal/reactions/#{@reaction.id}", params: { + put "/internal/reactions/#{reaction.id}", params: { reaction: { status: "confirmed" } } - expect(@reaction.reload.status).to eq("confirmed") + expect(reaction.reload.status).to eq("confirmed") end + it "does not set invalid status" do - put "/internal/reactions/#{@reaction.id}", params: { + put "/internal/reactions/#{reaction.id}", params: { reaction: { status: "confirmedsssss" } } - expect(@reaction.reload.status).not_to eq("confirmedsssss") + expect(reaction.reload.status).not_to eq("confirmedsssss") end end + describe "PUT /internal/reactions as non-admin" do before do user.add_role(:trusted) - @reaction = create(:reaction, category: "vomit", user_id: user.id, reactable_id: article.id) login_as user end + + let(:reaction) { create(:reaction, category: "vomit", user_id: user.id, reactable_id: article.id) } + it "updates reaction to be confirmed" do - expect { put "/internal/reactions/#{@reaction.id}", params: { - reaction: { status: "confirmed" } - } }.to raise_error(Pundit::NotAuthorizedError) + expect { + put "/internal/reactions/#{reaction.id}", params: { + reaction: { status: "confirmed" } + } }.to raise_error(Pundit::NotAuthorizedError) end end end diff --git a/spec/requests/registration_spec.rb b/spec/requests/registration_spec.rb index f194c6462..be953565d 100644 --- a/spec/requests/registration_spec.rb +++ b/spec/requests/registration_spec.rb @@ -15,7 +15,7 @@ RSpec.describe "Registrations", type: :request do it "redirects to /dashboard" do login_as user get "/enter" - is_expected.to redirect_to("/dashboard?signed-in-already&t=#{Time.current.to_i}") + expect(response).to redirect_to("/dashboard?signed-in-already&t=#{Time.current.to_i}") end end end diff --git a/spec/requests/tag_adjustments_spec.rb b/spec/requests/tag_adjustments_spec.rb index ea46f2168..de9973abd 100644 --- a/spec/requests/tag_adjustments_spec.rb +++ b/spec/requests/tag_adjustments_spec.rb @@ -1,8 +1,8 @@ require "rails_helper" RSpec.describe "TagAdjustments", type: :request do - let(:user) { create(:user) } - let(:user2) { create(:user) } + let(:user) { create(:user) } + let(:user2) { create(:user) } let(:tag) { create(:tag) } # let(:article) { create(:article, ) } @@ -13,6 +13,7 @@ RSpec.describe "TagAdjustments", type: :request do user.add_role(:trusted) sign_in user end + it "removes the tag" do article = Article.create!(user_id: user2.id, title: "test TEST", body_markdown: "Yo ho h o#{rand(100)}", tag_list: "#{tag.name}, yoyo, bobo", published: true) post "/tag_adjustments", params: { @@ -20,7 +21,7 @@ RSpec.describe "TagAdjustments", type: :request do tag_name: tag.name, article_id: article.id, reason_for_adjustment: "Test #{rand(100)}" - }, + } } expect(article.reload.tag_list.include?(tag.name)).to eq(false) end @@ -43,7 +44,7 @@ RSpec.describe "TagAdjustments", type: :request do tag_name: tag.name, article_id: article.id, reason_for_adjustment: "Test #{rand(100)}" - }, + } } expect(article.reload.tag_list.include?(tag.name)).to eq(false) end @@ -54,7 +55,7 @@ RSpec.describe "TagAdjustments", type: :request do tag_name: tag.name, article_id: article.id, reason_for_adjustment: "Test #{rand(100)}" - }, + } } expect(article.reload.tag_list.include?("heyheyhey")).to eq(true) end diff --git a/spec/services/exporter/service_spec.rb b/spec/services/exporter/service_spec.rb index 587b6aec0..186b4cae3 100644 --- a/spec/services/exporter/service_spec.rb +++ b/spec/services/exporter/service_spec.rb @@ -23,6 +23,7 @@ RSpec.describe Exporter::Service do loop do entry = stream.get_next_entry break if entry.blank? + exports[entry.name] = stream.read end end diff --git a/spec/services/tag_adjustment_creation_service_spec.rb b/spec/services/tag_adjustment_creation_service_spec.rb index 7400bf234..026a5d169 100644 --- a/spec/services/tag_adjustment_creation_service_spec.rb +++ b/spec/services/tag_adjustment_creation_service_spec.rb @@ -5,25 +5,35 @@ RSpec.describe TagAdjustmentCreationService do let(:article) { create(:article) } let(:tag) { create(:tag) } + def create_tag_adjustment + described_class.new( + user, + { + adjustment_type: "removal", + status: "committed", + tag_name: tag.name, + article_id: article.id, + reason_for_adjustment: "Test" + } + ).create + end + before do user.add_role(:tag_moderator, tag) - @tag_adjustment = described_class.new(user, { - adjustment_type: "removal", - status: "committed", - tag_name: tag.name, - article_id: article.id, - reason_for_adjustment: "Test" - }).create end it "creates tag adjustment" do - expect(@tag_adjustment).to be_valid - expect(@tag_adjustment.tag_id).to eq(tag.id) - expect(@tag_adjustment.status).to eq("committed") + tag_adjustment = create_tag_adjustment + + expect(tag_adjustment).to be_valid + expect(tag_adjustment.tag_id).to eq(tag.id) + expect(tag_adjustment.status).to eq("committed") end it "creates notification" do + tag_adjustment = create_tag_adjustment + expect(Notification.last.user_id).to eq(article.user_id) - expect(Notification.last.json_data["adjustment_type"]).to eq(@tag_adjustment.adjustment_type) + expect(Notification.last.json_data["adjustment_type"]).to eq(tag_adjustment.adjustment_type) end end diff --git a/spec/services/tag_adjustment_update_service_spec.rb b/spec/services/tag_adjustment_update_service_spec.rb index a120a2730..799353f2f 100644 --- a/spec/services/tag_adjustment_update_service_spec.rb +++ b/spec/services/tag_adjustment_update_service_spec.rb @@ -5,25 +5,35 @@ RSpec.describe TagAdjustmentUpdateService do let(:article) { create(:article) } let(:tag) { create(:tag) } + def create_tag_adjustment + TagAdjustmentCreationService.new( + user, + { + adjustment_type: "removal", + status: "committed", + tag_name: tag.name, + article_id: article.id + } + ).create + end + before do user.add_role(:tag_moderator, tag) - @tag_adjustment = TagAdjustmentCreationService.new(user, { - adjustment_type: "removal", - status: "committed", - tag_name: tag.name, - article_id: article.id - }).create end xit "creates tag adjustment" do - described_class.new(@tag_adjustment, {status: "resolved"}).update - expect(@tag_adjustment).to be_valid - expect(@tag_adjustment.tag_id).to eq(tag.id) - expect(@tag_adjustment.status).to eq("resolved") + tag_adjustment = create_tag_adjustment + described_class.new(tag_adjustment, { status: "resolved" }).update + + expect(tag_adjustment).to be_valid + expect(tag_adjustment.tag_id).to eq(tag.id) + expect(tag_adjustment.status).to eq("resolved") end xit "updates notification" do - described_class.new(@tag_adjustment, {status: "resolved"}).update + tag_adjustment = create_tag_adjustment + described_class.new(tag_adjustment, { status: "resolved" }).update + expect(Notification.last.user_id).to eq(article.user_id) expect(Notification.last.json_data["status"]).to eq("resolved") end diff --git a/spec/support/initializers/database_cleaner.rb b/spec/support/initializers/database_cleaner.rb index 39cc8bef1..dc109b607 100644 --- a/spec/support/initializers/database_cleaner.rb +++ b/spec/support/initializers/database_cleaner.rb @@ -16,6 +16,7 @@ RSpec.configure do |config| uncommitted transaction data setup over the spec's database connection. MSG end + DatabaseCleaner.clean_with(:truncation) end diff --git a/spec/support/omniauth_macros.rb b/spec/support/omniauth_macros.rb index 3f2d57ccc..297b1e7ca 100644 --- a/spec/support/omniauth_macros.rb +++ b/spec/support/omniauth_macros.rb @@ -39,7 +39,7 @@ module OmniauthMacros info: INFO, extra: EXTRA_INFO, credentials: CREDENTIAL - } + }.freeze def mock_auth_hash mock_twitter