diff --git a/Gemfile b/Gemfile index cd32801f9c..4aec7a616f 100644 --- a/Gemfile +++ b/Gemfile @@ -99,7 +99,7 @@ gem "rails", "~> 5.2.3" gem "recaptcha", "~> 3.3", require: "recaptcha/rails" # Cache with Redis -gem 'redis', '~> 4.0.1' +gem 'redis', '~> 4.1.2' # Generate QR codes for TOTP 2fa gem "rqrcode", "~> 0.10" diff --git a/Gemfile.lock b/Gemfile.lock index 868846dede..6adc0bb890 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -76,22 +76,22 @@ GEM ast (2.4.0) attr_encrypted (3.1.0) encryptor (~> 3.0.0) - autoprefixer-rails (9.5.1) + autoprefixer-rails (9.5.1.1) execjs aws-eventstream (1.0.3) - aws-partitions (1.158.0) - aws-sdk-core (3.49.0) + aws-partitions (1.170.0) + aws-sdk-core (3.54.1) aws-eventstream (~> 1.0, >= 1.0.2) aws-partitions (~> 1.0) aws-sigv4 (~> 1.1) jmespath (~> 1.0) - aws-sdk-kms (1.18.0) - aws-sdk-core (~> 3, >= 3.48.2) + aws-sdk-kms (1.21.0) + aws-sdk-core (~> 3, >= 3.53.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.36.1) - aws-sdk-core (~> 3, >= 3.48.2) + aws-sdk-s3 (1.41.0) + aws-sdk-core (~> 3, >= 3.53.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.0) + aws-sigv4 (~> 1.1) aws-sigv4 (1.1.0) aws-eventstream (~> 1.0, >= 1.0.2) bcrypt (3.1.12) @@ -106,7 +106,7 @@ GEM autoprefixer-rails (>= 9.1.0) popper_js (>= 1.14.3, < 2) sassc-rails (>= 2.0.0) - brakeman (4.5.0) + brakeman (4.5.1) browser (2.5.3) builder (3.2.3) bundler-audit (0.6.1) @@ -162,7 +162,7 @@ GEM execjs (2.7.0) faraday (0.9.2) multipart-post (>= 1.2, < 3) - ffi (1.10.0) + ffi (1.11.1) font-awesome-rails (4.7.0.5) railties (>= 3.2, < 6.1) fugit (1.2.1) @@ -170,7 +170,7 @@ GEM raabro (~> 1.1) globalid (0.4.2) activesupport (>= 4.2.0) - hashdiff (0.3.9) + hashdiff (0.4.0) hashie (3.6.0) highline (2.0.2) htmlentities (4.3.4) @@ -196,11 +196,11 @@ GEM jmespath (1.4.0) json (2.2.0) jsonapi-renderer (0.2.0) - jwt (2.1.0) + jwt (2.2.1) listen (3.0.8) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) - lograge (0.11.0) + lograge (0.11.1) actionpack (>= 4) activesupport (>= 4) railties (>= 4) @@ -243,7 +243,7 @@ GEM msgpack (1.2.10) multi_json (1.13.1) multi_xml (0.6.0) - multipart-post (2.0.0) + multipart-post (2.1.1) mustermann (1.0.3) netrc (0.11.0) newrelic_rpm (3.18.1.330) @@ -357,7 +357,7 @@ GEM ffi (~> 1.0) recaptcha (3.4.0) json - redis (4.0.3) + redis (4.1.2) request_store (1.4.1) rack (>= 1.4) responders (2.4.1) @@ -383,9 +383,9 @@ GEM rubocop-rspec (~> 1.30.0) rubocop-rspec (1.30.0) rubocop (>= 0.58.0) - ruby-progressbar (1.10.0) + ruby-progressbar (1.10.1) ruby_http_client (3.3.0) - rubyzip (1.2.2) + rubyzip (1.2.3) rufus-scheduler (3.6.0) fugit (~> 1.1, >= 1.1.6) safe_yaml (1.0.5) @@ -409,7 +409,7 @@ GEM sprockets (> 3.0) sprockets-rails tilt - selenium-webdriver (3.142.0) + selenium-webdriver (3.142.3) childprocess (>= 0.5, < 2.0) rubyzip (~> 1.2, >= 1.2.2) sendgrid-ruby (5.3.0) @@ -470,8 +470,8 @@ GEM unf (0.1.4) unf_ext unf_ext (0.0.7.6) - unicode-display_width (1.5.0) - vcr (4.0.0) + unicode-display_width (1.6.0) + vcr (5.0.0) warden (1.2.8) rack (>= 2.0.6) web-console (3.7.0) @@ -483,7 +483,7 @@ GEM addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff - webpacker (4.0.2) + webpacker (4.0.6) activesupport (>= 4.2) rack-proxy (>= 0.6.1) railties (>= 4.2) @@ -555,7 +555,7 @@ DEPENDENCIES rails-controller-testing railties (~> 5.2.3) recaptcha (~> 3.3) - redis (~> 4.0.1) + redis (~> 4.1.2) rotp (~> 3.3) rqrcode (~> 0.10) rubocop-airbnb diff --git a/app/jobs/cache_browser_channels_json_job.rb b/app/jobs/cache_browser_channels_json_job.rb index 20ef760676..3c742102ed 100644 --- a/app/jobs/cache_browser_channels_json_job.rb +++ b/app/jobs/cache_browser_channels_json_job.rb @@ -1,9 +1,26 @@ class CacheBrowserChannelsJsonJob < ApplicationJob queue_as :heavy + MAX_RETRY = 10 + def perform channels_json = JsonBuilders::ChannelsJsonBuilder.new.build - result = Rails.cache.write('browser_channels_json', channels_json) - Rails.logger.info("CacheBrowserChannelsJsonJob updated the cached browser channels json. Result: #{result}") + retry_count = 0 + result = nil + + loop do + result = Rails.cache.write('browser_channels_json', channels_json) + break if result || retry_count > MAX_RETRY + + retry_count += 1 + Rails.logger.info("CacheBrowserChannelsJsonJob could not write to Redis result: #{result}. Retrying: #{retry_count}/#{MAX_RETRY}") + end + + if result + Rails.logger.info("CacheBrowserChannelsJsonJob updated the cached browser channels json.") + else + SlackMessenger.new(message: "🚨 CacheBrowserChannelsJsonJob could not update the channels JSON. @publishers-team 🚨") + Rails.logger.info("CacheBrowserChannelsJsonJob could not update the channels JSON.") + end end end diff --git a/app/models/channel.rb b/app/models/channel.rb index af7bfc75dd..4800fdc759 100644 --- a/app/models/channel.rb +++ b/app/models/channel.rb @@ -66,6 +66,8 @@ class Channel < ApplicationRecord validate :verified_duplicate_channels_must_be_contested, if: -> { verified? } after_save :register_channel_for_promo, if: :should_register_channel_for_promo + after_save :notify_slack, if: :saved_change_to_verified? + before_save :clear_verified_at_if_necessary before_destroy :preserve_contested_by_channels @@ -328,6 +330,29 @@ def register_channel_for_promo RegisterChannelForPromoJob.new.perform(channel: self) end + def notify_slack + return unless verified? + emoji = + case details_type + when "SiteChannelDetails" + "🌐" + when "TwitchChannelDetails" + "👾" + when "YoutubeChannelDetails" + "📺" + when "VimeoChannelDetails" + "🎥" + when "TwitterChannelDetails" + "🐦" + else + "" + end + + SlackMessenger.new( + message: "#{emoji} *#{details.publication_title}* verified by owner #{publisher.owner_identifier}; id=#{details.channel_identifier}; url=#{details.url}" + ).perform + end + def site_channel_details_brave_publisher_id_unique_for_publisher duplicate_unverified_channels = publisher.channels.visible_site_channels. where(site_channel_details: { brave_publisher_id: details.brave_publisher_id }). diff --git a/app/services/publisher_unverified_calculator.rb b/app/services/publisher_unverified_calculator.rb deleted file mode 100644 index 5ea994cb8c..0000000000 --- a/app/services/publisher_unverified_calculator.rb +++ /dev/null @@ -1,23 +0,0 @@ -# Returns publishers who have abandoned verification process and do not have another publisher account (win back publishers) -class PublisherUnverifiedCalculator < BaseService - WIN_BACK_THRESHOLD = 5.days - WIN_BACK_MAX_AGE = 30.days - - def perform - # Only include publishers who have filled contact information - unverified_channels = Channel. - where(verified: false). - where("created_at < ?", WIN_BACK_THRESHOLD.ago). - where("created_at > ?", WIN_BACK_MAX_AGE.ago) - - win_back_publishers = [] - - unverified_channels.find_each do |channel| - unless win_back_publishers.include?(channel.publisher) - win_back_publishers.push channel.publisher - end - end - - win_back_publishers - end -end diff --git a/app/services/site_channel_verifier.rb b/app/services/site_channel_verifier.rb index a9dd84ac52..dc5e7c848b 100644 --- a/app/services/site_channel_verifier.rb +++ b/app/services/site_channel_verifier.rb @@ -55,7 +55,6 @@ def contested_channel(brave_publisher_id) def verified_channel_post_verify MailerServices::VerificationDoneEmailer.new(verified_channel: channel).perform - SlackMessenger.new(message: "*#{channel.publication_title}* verified by owner #{channel.publisher.owner_identifier}; id=#{channel.details.channel_identifier}").perform end def verify_site_channel diff --git a/config/environments/production.rb b/config/environments/production.rb index eae2f92329..7e65fd378b 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -71,8 +71,8 @@ config.cache_store = :redis_cache_store, { url: Rails.application.secrets[:redis_url], connect_timeout: 30, # Defaults to 20 seconds - read_timeout: 10, # Defaults to 1 second - write_timeout: 60, # Defaults to 1 second + read_timeout: 5, # Defaults to 1 second + write_timeout: 10, # Defaults to 1 second error_handler: -> (method:, returning:, exception:) { # Report errors to Sentry as warnings diff --git a/config/environments/staging.rb b/config/environments/staging.rb index a7eab58d23..60f1ebb472 100644 --- a/config/environments/staging.rb +++ b/config/environments/staging.rb @@ -64,8 +64,8 @@ config.cache_store = :redis_cache_store, { url: Rails.application.secrets[:redis_url], connect_timeout: 30, # Defaults to 20 seconds - read_timeout: 10, # Defaults to 1 second - write_timeout: 60, # Defaults to 1 second + read_timeout: 5, # Defaults to 1 second + write_timeout: 10, # Defaults to 1 second error_handler: -> (method:, returning:, exception:) { # Report errors to Sentry as warnings diff --git a/lib/tasks/publisher_inventory.rake b/lib/tasks/publisher_inventory.rake deleted file mode 100644 index ba960758fc..0000000000 --- a/lib/tasks/publisher_inventory.rake +++ /dev/null @@ -1,15 +0,0 @@ -namespace :publisher_inventory do - task :print_win_back_publishers => :environment do - total_publishers = Publisher.count - total_verified_publishers = Publisher.where(verified: true).count - total_unverified_publishers = Publisher.where(verified: false).count - total_win_back_publishers = PublisherUnverifiedCalculator.new.perform.count - - puts "\n------Publisher Inventory------" - puts "Publishers: #{total_publishers}" - puts "Verified Publishers: #{total_verified_publishers}" - puts "Unverified Publishers: #{total_unverified_publishers}" - puts "Win Back Publishers: #{total_win_back_publishers}" - puts "-------------------------------\n" - end -end \ No newline at end of file diff --git a/test/services/publisher_unverified_calculator_test.rb b/test/services/publisher_unverified_calculator_test.rb deleted file mode 100644 index 5a0a9d8b04..0000000000 --- a/test/services/publisher_unverified_calculator_test.rb +++ /dev/null @@ -1,59 +0,0 @@ -require 'test_helper' -require "webmock/minitest" -class PublisherUnverifiedCalculatorTest < ActiveJob::TestCase - test "only returns publishers with an unverified channel within the window" do - - publisher_dave = Publisher.create!( - name: "Dave", - email: "dave@brave.com" - ) - - publisher_dave.channels.new( - verified: true - ).save!(validate: false) - - # Create a verified: false channel. This causes publisher_dave to - # be in the win back list - publisher_dave.channels.new( - verified: false - ).save!(validate: false) - - # Create a second verified: false. Despite this the publisher should - # only be in the final list once - publisher_dave.channels.new( - verified: false - ).save!(validate: false) - - publisher_alice = Publisher.create!( - name: "Alice", - email: "alice@brave.com", - phone: "15555555555", - phone_normalized: "+15555555555" - ) - - publisher_alice.channels.new( - verified: true - ).save!(validate: false) - - calculator = PublisherUnverifiedCalculator.new - - publishers = calculator.perform - assert_not_includes publishers, publisher_dave - assert_not_includes publishers, publisher_alice - assert_equal [], publishers - - travel PublisherUnverifiedCalculator::WIN_BACK_THRESHOLD + 1.second do - publishers = calculator.perform - assert_includes publishers, publisher_dave - assert_not_includes publishers, publisher_alice - assert_equal publishers.uniq, publishers - end - - travel PublisherUnverifiedCalculator::WIN_BACK_MAX_AGE + 1.second do - publishers = calculator.perform - assert_not_includes publishers, publisher_dave - assert_not_includes publishers, publisher_alice - assert_equal publishers.uniq, publishers - end - end -end