DEV: Make `discourse_narrative_bot` use Rails autoload (#26044)
Why this change? Instead of manually loading files, we should just structure the plugin so that it relies on Rails autoload strategy and avoid all the manual `require_relative`s. What does this change do? 1. Structure the plugin to use Rails autoloading convention 2. Remove onceff jobs that were added 5-6 years ago. There is no need to carry these jobs anymore after such a long time. 3. Move setting of `SiteSetting.discourse_narrative_bot_enabled` to `false` in the test environment from core into the plugin.
This commit is contained in:
parent
6b46b9ab78
commit
3491642f98
|
@ -95,11 +95,6 @@ Discourse::Application.configure do
|
|||
# Most existing tests were written assuming allow_uncategorized_topics
|
||||
# was enabled, so we should set it to true.
|
||||
s.set_regardless_of_locale(:allow_uncategorized_topics, true)
|
||||
|
||||
# disable plugins
|
||||
if ENV["LOAD_PLUGINS"] == "1"
|
||||
s.set_regardless_of_locale(:discourse_narrative_bot_enabled, false)
|
||||
end
|
||||
end
|
||||
|
||||
SiteSetting.refresh!
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module DiscourseNarrativeBot
|
||||
class CertificatesController < ::ApplicationController
|
||||
requires_plugin DiscourseNarrativeBot::PLUGIN_NAME
|
||||
layout false
|
||||
skip_before_action :check_xhr
|
||||
requires_login
|
||||
|
||||
def generate
|
||||
immutable_for(24.hours)
|
||||
|
||||
%i[date user_id].each do |key|
|
||||
unless params[key]&.present?
|
||||
raise Discourse::InvalidParameters.new("#{key} must be present")
|
||||
end
|
||||
end
|
||||
|
||||
if params[:user_id].to_i != current_user.id
|
||||
rate_limiter = RateLimiter.new(current_user, "svg_certificate", 3, 1.minute)
|
||||
else
|
||||
rate_limiter = RateLimiter.new(current_user, "svg_certificate_self", 30, 10.minutes)
|
||||
end
|
||||
rate_limiter.performed! unless current_user.staff?
|
||||
|
||||
user = User.find_by(id: params[:user_id])
|
||||
raise Discourse::NotFound if user.blank?
|
||||
|
||||
hijack do
|
||||
generator = CertificateGenerator.new(user, params[:date], avatar_url(user))
|
||||
|
||||
svg = params[:type] == "advanced" ? generator.advanced_user_track : generator.new_user_track
|
||||
|
||||
respond_to { |format| format.svg { render inline: svg } }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def avatar_url(user)
|
||||
UrlHelper.absolute(Discourse.base_path + user.avatar_template.gsub("{size}", "250"))
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,33 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jobs
|
||||
module DiscourseNarrativeBot
|
||||
class GrantBadges < ::Jobs::Onceoff
|
||||
def execute_onceoff(args)
|
||||
new_user_track_badge =
|
||||
Badge.find_by(name: ::DiscourseNarrativeBot::NewUserNarrative.badge_name)
|
||||
|
||||
advanced_user_track_badge =
|
||||
Badge.find_by(name: ::DiscourseNarrativeBot::AdvancedUserNarrative.badge_name)
|
||||
|
||||
PluginStoreRow
|
||||
.where(plugin_name: ::DiscourseNarrativeBot::PLUGIN_NAME, type_name: "JSON")
|
||||
.find_each do |row|
|
||||
value = JSON.parse(row.value)
|
||||
completed = value["completed"]
|
||||
user = User.find_by(id: row.key)
|
||||
|
||||
if user && completed
|
||||
if completed.include?(::DiscourseNarrativeBot::NewUserNarrative.to_s)
|
||||
BadgeGranter.grant(new_user_track_badge, user)
|
||||
end
|
||||
|
||||
if completed.include?(::DiscourseNarrativeBot::AdvancedUserNarrative.to_s)
|
||||
BadgeGranter.grant(advanced_user_track_badge, user)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,44 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jobs
|
||||
module DiscourseNarrativeBot
|
||||
class RemapOldBotImages < ::Jobs::Onceoff
|
||||
def execute_onceoff(args)
|
||||
paths = %w[
|
||||
/images/font-awesome-link.png
|
||||
/images/unicorn.png
|
||||
/images/font-awesome-ellipsis.png
|
||||
/images/font-awesome-bookmark.png
|
||||
/images/font-awesome-smile.png
|
||||
/images/font-awesome-flag.png
|
||||
/images/font-awesome-search.png
|
||||
/images/capybara-eating.gif
|
||||
/images/font-awesome-pencil.png
|
||||
/images/font-awesome-trash.png
|
||||
/images/font-awesome-rotate-left.png
|
||||
/images/font-awesome-gear.png
|
||||
]
|
||||
|
||||
Post
|
||||
.raw_match("/images/")
|
||||
.where(user_id: -2)
|
||||
.find_each do |post|
|
||||
if (
|
||||
matches =
|
||||
post.raw.scan(%r{(?<!/plugins/discourse-narrative-bot)(#{paths.join("|")})})
|
||||
).present?
|
||||
new_raw = post.raw
|
||||
|
||||
matches.each do |match|
|
||||
path = match.first
|
||||
new_raw = new_raw.gsub(path, "/plugins/discourse-narrative-bot#{path}")
|
||||
end
|
||||
|
||||
post.update_columns(raw: new_raw)
|
||||
post.rebake!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
DiscourseNarrativeBot::Engine.routes.draw do
|
||||
get "/certificate" => "certificates#generate", :format => :svg
|
||||
end
|
||||
|
||||
Discourse::Application.routes.draw { mount ::DiscourseNarrativeBot::Engine, at: "/discobot" }
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module DiscourseNarrativeBot
|
||||
class Engine < ::Rails::Engine
|
||||
engine_name PLUGIN_NAME
|
||||
isolate_namespace DiscourseNarrativeBot
|
||||
config.autoload_paths << File.join(config.root, "lib")
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_dependency "plugin_store"
|
||||
|
||||
module DiscourseNarrativeBot
|
||||
class Store
|
||||
def self.set(key, value)
|
||||
::PluginStore.set(PLUGIN_NAME, key, value)
|
||||
end
|
||||
|
||||
def self.get(key)
|
||||
::PluginStore.get(PLUGIN_NAME, key)
|
||||
end
|
||||
|
||||
def self.remove(key)
|
||||
::PluginStore.remove(PLUGIN_NAME, key)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -9,22 +9,26 @@
|
|||
enabled_site_setting :discourse_narrative_bot_enabled
|
||||
hide_plugin
|
||||
|
||||
if Rails.env == "development"
|
||||
# workaround, teach reloader to reload jobs
|
||||
# if we do not do this then
|
||||
#
|
||||
# 1. on reload rails goes and undefines Jobs::Base
|
||||
# 2. as a side effect this undefines Jobs::BotInput
|
||||
# 3. we have a post_edited hook that queues a job for bot input
|
||||
# 4. if you are not running sidekiq in dev every time you save a post it will trigger it
|
||||
# 5. but the constant can not be autoloaded
|
||||
Rails.configuration.autoload_paths << File.expand_path("../autoload/jobs", __FILE__)
|
||||
end
|
||||
|
||||
require_relative "lib/discourse_narrative_bot/welcome_post_type_site_setting"
|
||||
register_asset "stylesheets/discourse-narrative-bot.scss"
|
||||
|
||||
module ::DiscourseNarrativeBot
|
||||
PLUGIN_NAME = "discourse-narrative-bot".freeze
|
||||
BOT_USER_ID = -2
|
||||
end
|
||||
|
||||
require_relative "lib/discourse_narrative_bot/engine"
|
||||
|
||||
after_initialize do
|
||||
if Rails.env.test?
|
||||
::SiteSetting.defaults.tap do |s|
|
||||
# disable plugins
|
||||
if ENV["LOAD_PLUGINS"] == "1"
|
||||
s.set_regardless_of_locale(:discourse_narrative_bot_enabled, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
SeedFu.fixture_paths << Rails
|
||||
.root
|
||||
.join("plugins", "discourse-narrative-bot", "db", "fixtures")
|
||||
|
@ -32,24 +36,6 @@ after_initialize do
|
|||
|
||||
Mime::Type.register "image/svg+xml", :svg
|
||||
|
||||
require_relative "autoload/jobs/regular/bot_input"
|
||||
require_relative "autoload/jobs/regular/narrative_timeout"
|
||||
require_relative "autoload/jobs/regular/narrative_init"
|
||||
require_relative "autoload/jobs/regular/send_default_welcome_message"
|
||||
require_relative "autoload/jobs/onceoff/discourse_narrative_bot/grant_badges"
|
||||
require_relative "autoload/jobs/onceoff/discourse_narrative_bot/remap_old_bot_images"
|
||||
require_relative "lib/discourse_narrative_bot/actions"
|
||||
require_relative "lib/discourse_narrative_bot/base"
|
||||
require_relative "lib/discourse_narrative_bot/new_user_narrative"
|
||||
require_relative "lib/discourse_narrative_bot/advanced_user_narrative"
|
||||
require_relative "lib/discourse_narrative_bot/track_selector"
|
||||
require_relative "lib/discourse_narrative_bot/certificate_generator"
|
||||
require_relative "lib/discourse_narrative_bot/dice"
|
||||
require_relative "lib/discourse_narrative_bot/quote_generator"
|
||||
require_relative "lib/discourse_narrative_bot/magic_8_ball"
|
||||
require_relative "lib/discourse_narrative_bot/welcome_post_type_site_setting"
|
||||
require_relative "lib/discourse_narrative_bot/post_guardian_extension"
|
||||
|
||||
RailsMultisite::ConnectionManagement.safe_each_connection do
|
||||
if SiteSetting.discourse_narrative_bot_enabled
|
||||
# Disable welcome message because that is what the bot is supposed to replace.
|
||||
|
@ -63,79 +49,6 @@ after_initialize do
|
|||
end
|
||||
end
|
||||
|
||||
require_dependency "plugin_store"
|
||||
|
||||
module ::DiscourseNarrativeBot
|
||||
PLUGIN_NAME = "discourse-narrative-bot".freeze
|
||||
BOT_USER_ID = -2
|
||||
|
||||
class Engine < ::Rails::Engine
|
||||
engine_name PLUGIN_NAME
|
||||
isolate_namespace DiscourseNarrativeBot
|
||||
end
|
||||
|
||||
class Store
|
||||
def self.set(key, value)
|
||||
::PluginStore.set(PLUGIN_NAME, key, value)
|
||||
end
|
||||
|
||||
def self.get(key)
|
||||
::PluginStore.get(PLUGIN_NAME, key)
|
||||
end
|
||||
|
||||
def self.remove(key)
|
||||
::PluginStore.remove(PLUGIN_NAME, key)
|
||||
end
|
||||
end
|
||||
|
||||
class CertificatesController < ::ApplicationController
|
||||
layout false
|
||||
skip_before_action :check_xhr
|
||||
requires_login
|
||||
|
||||
def generate
|
||||
immutable_for(24.hours)
|
||||
|
||||
%i[date user_id].each do |key|
|
||||
unless params[key]&.present?
|
||||
raise Discourse::InvalidParameters.new("#{key} must be present")
|
||||
end
|
||||
end
|
||||
|
||||
if params[:user_id].to_i != current_user.id
|
||||
rate_limiter = RateLimiter.new(current_user, "svg_certificate", 3, 1.minute)
|
||||
else
|
||||
rate_limiter = RateLimiter.new(current_user, "svg_certificate_self", 30, 10.minutes)
|
||||
end
|
||||
rate_limiter.performed! unless current_user.staff?
|
||||
|
||||
user = User.find_by(id: params[:user_id])
|
||||
raise Discourse::NotFound if user.blank?
|
||||
|
||||
hijack do
|
||||
generator = CertificateGenerator.new(user, params[:date], avatar_url(user))
|
||||
|
||||
svg =
|
||||
params[:type] == "advanced" ? generator.advanced_user_track : generator.new_user_track
|
||||
|
||||
respond_to { |format| format.svg { render inline: svg } }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def avatar_url(user)
|
||||
UrlHelper.absolute(Discourse.base_path + user.avatar_template.gsub("{size}", "250"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
DiscourseNarrativeBot::Engine.routes.draw do
|
||||
get "/certificate" => "certificates#generate", :format => :svg
|
||||
end
|
||||
|
||||
Discourse::Application.routes.append { mount ::DiscourseNarrativeBot::Engine, at: "/discobot" }
|
||||
|
||||
self.add_model_callback(User, :after_destroy) { DiscourseNarrativeBot::Store.remove(self.id) }
|
||||
|
||||
self.on(:user_created) do |user|
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe Jobs::DiscourseNarrativeBot::GrantBadges do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:other_user) { Fabricate(:user) }
|
||||
|
||||
before do
|
||||
DiscourseNarrativeBot::Store.set(
|
||||
user.id,
|
||||
completed: [
|
||||
DiscourseNarrativeBot::NewUserNarrative.to_s,
|
||||
DiscourseNarrativeBot::AdvancedUserNarrative.to_s,
|
||||
],
|
||||
)
|
||||
end
|
||||
|
||||
it "should grant the right badges" do
|
||||
described_class.new.execute_onceoff({})
|
||||
|
||||
expect(user.badges.count).to eq(2)
|
||||
|
||||
expect(user.badges.map(&:name)).to contain_exactly(
|
||||
DiscourseNarrativeBot::NewUserNarrative.badge_name,
|
||||
DiscourseNarrativeBot::AdvancedUserNarrative.badge_name,
|
||||
)
|
||||
|
||||
expect(other_user.badges.count).to eq(0)
|
||||
end
|
||||
end
|
|
@ -1,43 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe Jobs::DiscourseNarrativeBot::RemapOldBotImages do
|
||||
context "when bot's post contains an old link" do
|
||||
let!(:post) do
|
||||
Fabricate(
|
||||
:post,
|
||||
user: ::DiscourseNarrativeBot::Base.new.discobot_user,
|
||||
raw:
|
||||
'If you’d like to learn more, select <img src="/images/font-awesome-gear.png" width="16" height="16"> <img src="/images/font-awesome-ellipsis.png" width="16" height="16"> below and <img src="/images/font-awesome-bookmark.png" width="16" height="16"> **bookmark this private message**. If you do, there may be a :gift: in your future!',
|
||||
)
|
||||
end
|
||||
|
||||
it "should remap the links correctly" do
|
||||
expected_raw =
|
||||
'If you’d like to learn more, select <img src="/plugins/discourse-narrative-bot/images/font-awesome-gear.png" width="16" height="16"> <img src="/plugins/discourse-narrative-bot/images/font-awesome-ellipsis.png" width="16" height="16"> below and <img src="/plugins/discourse-narrative-bot/images/font-awesome-bookmark.png" width="16" height="16"> **bookmark this private message**. If you do, there may be a :gift: in your future!'
|
||||
|
||||
2.times do
|
||||
described_class.new.execute_onceoff({})
|
||||
expect(post.reload.raw).to eq(expected_raw)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with subfolder" do
|
||||
let!(:post) do
|
||||
Fabricate(
|
||||
:post,
|
||||
user: ::DiscourseNarrativeBot::Base.new.discobot_user,
|
||||
raw:
|
||||
'If you’d like to learn more, select <img src="/community/images/font-awesome-ellipsis.png" width="16" height="16"> below and <img src="/community/images/font-awesome-bookmark.png" width="16" height="16"> **bookmark this private message**. If you do, there may be a :gift: in your future!',
|
||||
)
|
||||
end
|
||||
|
||||
it "should remap the links correctly" do
|
||||
described_class.new.execute_onceoff({})
|
||||
|
||||
expect(post.reload.raw).to eq(
|
||||
'If you’d like to learn more, select <img src="/community/plugins/discourse-narrative-bot/images/font-awesome-ellipsis.png" width="16" height="16"> below and <img src="/community/plugins/discourse-narrative-bot/images/font-awesome-bookmark.png" width="16" height="16"> **bookmark this private message**. If you do, there may be a :gift: in your future!',
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe "Plugin specs" do
|
||||
let(:narrative_bot) { ::DiscourseNarrativeBot::Base.new }
|
||||
let(:discobot_user) { narrative_bot.discobot_user }
|
||||
|
||||
before { SiteSetting.discourse_narrative_bot_enabled = true }
|
||||
it "should update bot's `UserProfile#bio_raw` when `default_locale` site setting is changed" do
|
||||
expect(discobot_user.user_profile.bio_raw).to eq(
|
||||
I18n.with_locale(:en) { I18n.t("discourse_narrative_bot.bio") },
|
||||
)
|
||||
|
||||
SiteSetting.default_locale = "zn_CN"
|
||||
|
||||
expect(discobot_user.user_profile.bio_raw).to eq(
|
||||
I18n.with_locale(:zh_CN) { I18n.t("discourse_narrative_bot.bio") },
|
||||
)
|
||||
end
|
||||
end
|
|
@ -2,9 +2,10 @@
|
|||
|
||||
RSpec.describe "Discobot Certificate" do
|
||||
let(:user) { Fabricate(:user, name: "Jeff Atwood") }
|
||||
|
||||
let(:params) { { date: Time.zone.now.strftime("%b %d %Y"), user_id: user.id } }
|
||||
|
||||
before { SiteSetting.discourse_narrative_bot_enabled = true }
|
||||
|
||||
describe "when viewing the certificate" do
|
||||
describe "when no logged in" do
|
||||
it "should return the right response" do
|
||||
|
|
Loading…
Reference in New Issue