DEV: Apply syntax_tree formatting to plugins/*

This commit is contained in:
David Taylor
2023-01-06 20:42:16 +00:00
parent 93e2dad656
commit 055310cea4
110 changed files with 3712 additions and 3158 deletions

View File

@@ -4,33 +4,29 @@ module Jobs
module DiscourseNarrativeBot
class GrantBadges < ::Jobs::Onceoff
def execute_onceoff(args)
new_user_track_badge = Badge.find_by(
name: ::DiscourseNarrativeBot::NewUserNarrative.badge_name
)
new_user_track_badge =
Badge.find_by(name: ::DiscourseNarrativeBot::NewUserNarrative.badge_name)
advanced_user_track_badge = Badge.find_by(
name: ::DiscourseNarrativeBot::AdvancedUserNarrative.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|
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)
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 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)
if completed.include?(::DiscourseNarrativeBot::AdvancedUserNarrative.to_s)
BadgeGranter.grant(advanced_user_track_badge, user)
end
end
end
end
end
end
end

View File

@@ -4,34 +4,40 @@ module Jobs
module DiscourseNarrativeBot
class RemapOldBotImages < ::Jobs::Onceoff
def execute_onceoff(args)
paths = [
"/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",
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(/(?<!\/plugins\/discourse-narrative-bot)(#{paths.join("|")})/)).present?
new_raw = post.raw
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}")
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
post.update_columns(raw: new_raw)
post.rebake!
end
end
end
end
end

View File

@@ -2,16 +2,17 @@
module Jobs
class BotInput < ::Jobs::Base
sidekiq_options queue: 'critical', retry: false
sidekiq_options queue: "critical", retry: false
def execute(args)
return unless user = User.find_by(id: args[:user_id])
I18n.with_locale(user.effective_locale) do
::DiscourseNarrativeBot::TrackSelector.new(args[:input].to_sym, user,
::DiscourseNarrativeBot::TrackSelector.new(
args[:input].to_sym,
user,
post_id: args[:post_id],
topic_id: args[:topic_id]
topic_id: args[:topic_id],
).select
end
end

View File

@@ -2,13 +2,11 @@
module Jobs
class NarrativeInit < ::Jobs::Base
sidekiq_options queue: 'critical'
sidekiq_options queue: "critical"
def execute(args)
if user = User.find_by(id: args[:user_id])
I18n.with_locale(user.effective_locale) do
args[:klass].constantize.new.input(:init, user)
end
I18n.with_locale(user.effective_locale) { args[:klass].constantize.new.input(:init, user) }
end
end
end

View File

@@ -4,23 +4,24 @@ module Jobs
class SendDefaultWelcomeMessage < ::Jobs::Base
def execute(args)
if user = User.find_by(id: args[:user_id])
type = user.invited_by ? 'welcome_invite' : 'welcome_user'
type = user.invited_by ? "welcome_invite" : "welcome_user"
params = SystemMessage.new(user).defaults
title = I18n.t("system_messages.#{type}.subject_template", params)
raw = I18n.t("system_messages.#{type}.text_body_template", params)
discobot_user = ::DiscourseNarrativeBot::Base.new.discobot_user
post = PostCreator.create!(
discobot_user,
title: title,
raw: raw,
archetype: Archetype.private_message,
target_usernames: user.username,
skip_validations: true
)
post =
PostCreator.create!(
discobot_user,
title: title,
raw: raw,
archetype: Archetype.private_message,
target_usernames: user.username,
skip_validations: true,
)
post.topic.update_status('closed', true, discobot_user)
post.topic.update_status("closed", true, discobot_user)
end
end
end

View File

@@ -1,6 +1,6 @@
# frozen_string_literal: true
discobot_username = 'discobot'
discobot_username = "discobot"
def seed_primary_email
UserEmail.seed do |ue|
@@ -42,15 +42,13 @@ bot.create_user_option! if !bot.user_option
bot.user_option.update!(
email_messages_level: UserOption.email_level_types[:never],
email_level: UserOption.email_level_types[:never]
email_level: UserOption.email_level_types[:never],
)
bot.create_user_profile! if !bot.user_profile
if !bot.user_profile.bio_raw
bot.user_profile.update!(
bio_raw: I18n.t('discourse_narrative_bot.bio')
)
bot.user_profile.update!(bio_raw: I18n.t("discourse_narrative_bot.bio"))
end
Group.user_trust_level_change!(DiscourseNarrativeBot::BOT_USER_ID, TrustLevel[4])

View File

@@ -1,41 +1,33 @@
# frozen_string_literal: true
Badge
.where(name: 'Complete New User Track')
.update_all(name: DiscourseNarrativeBot::NewUserNarrative::BADGE_NAME)
Badge.where(name: "Complete New User Track").update_all(
name: DiscourseNarrativeBot::NewUserNarrative::BADGE_NAME,
)
Badge
.where(name: 'Complete Discobot Advanced User Track')
.update_all(name: DiscourseNarrativeBot::AdvancedUserNarrative::BADGE_NAME)
Badge.where(name: "Complete Discobot Advanced User Track").update_all(
name: DiscourseNarrativeBot::AdvancedUserNarrative::BADGE_NAME,
)
new_user_narrative_badge = Badge.find_by(name: DiscourseNarrativeBot::NewUserNarrative::BADGE_NAME)
unless new_user_narrative_badge
new_user_narrative_badge = Badge.create!(
name: DiscourseNarrativeBot::NewUserNarrative::BADGE_NAME,
badge_type_id: 3
)
new_user_narrative_badge =
Badge.create!(name: DiscourseNarrativeBot::NewUserNarrative::BADGE_NAME, badge_type_id: 3)
end
advanced_user_narrative_badge = Badge.find_by(name: DiscourseNarrativeBot::AdvancedUserNarrative::BADGE_NAME)
advanced_user_narrative_badge =
Badge.find_by(name: DiscourseNarrativeBot::AdvancedUserNarrative::BADGE_NAME)
unless advanced_user_narrative_badge
advanced_user_narrative_badge = Badge.create!(
name: DiscourseNarrativeBot::AdvancedUserNarrative::BADGE_NAME,
badge_type_id: 2
)
advanced_user_narrative_badge =
Badge.create!(name: DiscourseNarrativeBot::AdvancedUserNarrative::BADGE_NAME, badge_type_id: 2)
end
badge_grouping = BadgeGrouping.find(1)
[
[new_user_narrative_badge, I18n.t('badges.certified.description')],
[advanced_user_narrative_badge, I18n.t('badges.licensed.description')]
[new_user_narrative_badge, I18n.t("badges.certified.description")],
[advanced_user_narrative_badge, I18n.t("badges.licensed.description")],
].each do |badge, description|
badge.update!(
badge_grouping: badge_grouping,
description: description,
system: true
)
badge.update!(badge_grouping: badge_grouping, description: description, system: true)
end

View File

@@ -23,18 +23,19 @@ module DiscourseNarrativeBot
topic_id: post.topic_id,
reply_to_post_number: post.post_number,
post_alert_options: defaut_post_alert_opts,
skip_validations: true
skip_validations: true,
}
new_post = PostCreator.create!(self.discobot_user, default_opts.merge(opts))
reset_rate_limits(post) if new_post
new_post
else
PostCreator.create!(self.discobot_user, {
post_alert_options: defaut_post_alert_opts,
raw: raw,
skip_validations: true
}.merge(opts))
PostCreator.create!(
self.discobot_user,
{ post_alert_options: defaut_post_alert_opts, raw: raw, skip_validations: true }.merge(
opts,
),
)
end
end
@@ -53,7 +54,8 @@ module DiscourseNarrativeBot
data = DiscourseNarrativeBot::Store.get(user.id.to_s)
return unless data
key = "#{DiscourseNarrativeBot::PLUGIN_NAME}:reset-rate-limit:#{post.topic_id}:#{data['state']}"
key =
"#{DiscourseNarrativeBot::PLUGIN_NAME}:reset-rate-limit:#{post.topic_id}:#{data["state"]}"
if !(count = Discourse.redis.get(key))
count = 0
@@ -76,12 +78,14 @@ module DiscourseNarrativeBot
valid = false
doc.css(".mention").each do |mention|
if User.normalize_username(mention.text) == "@#{self.discobot_username}"
valid = true
break
doc
.css(".mention")
.each do |mention|
if User.normalize_username(mention.text) == "@#{self.discobot_username}"
valid = true
break
end
end
end
valid
end
@@ -94,8 +98,7 @@ module DiscourseNarrativeBot
topic = post.topic
return false if !topic
topic.pm_with_non_human_user? &&
topic.topic_allowed_users.where(user_id: -2).exists?
topic.pm_with_non_human_user? && topic.topic_allowed_users.where(user_id: -2).exists?
end
def cancel_timeout_job(user)
@@ -107,9 +110,11 @@ module DiscourseNarrativeBot
cancel_timeout_job(user)
Jobs.enqueue_in(TIMEOUT_DURATION, :narrative_timeout,
Jobs.enqueue_in(
TIMEOUT_DURATION,
:narrative_timeout,
user_id: user.id,
klass: self.class.to_s
klass: self.class.to_s,
)
end
end

View File

@@ -3,99 +3,101 @@
module DiscourseNarrativeBot
class AdvancedUserNarrative < Base
I18N_KEY = "discourse_narrative_bot.advanced_user_narrative".freeze
BADGE_NAME = 'Licensed'.freeze
BADGE_NAME = "Licensed".freeze
TRANSITION_TABLE = {
begin: {
next_state: :tutorial_edit,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.edit.instructions", i18n_post_args) },
init: {
action: :start_advanced_track
}
action: :start_advanced_track,
},
},
tutorial_edit: {
next_state: :tutorial_delete,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.delete.instructions", i18n_post_args) },
edit: {
action: :reply_to_edit
action: :reply_to_edit,
},
reply: {
next_state: :tutorial_edit,
action: :missing_edit
}
action: :missing_edit,
},
},
tutorial_delete: {
next_state: :tutorial_recover,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.recover.instructions", i18n_post_args) },
delete: {
action: :reply_to_delete
action: :reply_to_delete,
},
reply: {
next_state: :tutorial_delete,
action: :missing_delete
}
action: :missing_delete,
},
},
tutorial_recover: {
next_state: :tutorial_category_hashtag,
next_instructions: Proc.new do
category = Category.secured(Guardian.new(@user)).last
slug = category.slug
next_instructions:
Proc.new do
category = Category.secured(Guardian.new(@user)).last
slug = category.slug
if parent_category = category.parent_category
slug = "#{parent_category.slug}#{CategoryHashtag::SEPARATOR}#{slug}"
end
if parent_category = category.parent_category
slug = "#{parent_category.slug}#{CategoryHashtag::SEPARATOR}#{slug}"
end
I18n.t("#{I18N_KEY}.category_hashtag.instructions",
i18n_post_args(category: "##{slug}")
)
end,
I18n.t(
"#{I18N_KEY}.category_hashtag.instructions",
i18n_post_args(category: "##{slug}"),
)
end,
recover: {
action: :reply_to_recover
action: :reply_to_recover,
},
reply: {
next_state: :tutorial_recover,
action: :missing_recover
}
action: :missing_recover,
},
},
tutorial_category_hashtag: {
next_state: :tutorial_change_topic_notification_level,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.change_topic_notification_level.instructions", i18n_post_args) },
next_instructions:
Proc.new do
I18n.t("#{I18N_KEY}.change_topic_notification_level.instructions", i18n_post_args)
end,
reply: {
action: :reply_to_category_hashtag
}
action: :reply_to_category_hashtag,
},
},
tutorial_change_topic_notification_level: {
next_state: :tutorial_poll,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.poll.instructions", i18n_post_args) },
topic_notification_level_changed: {
action: :reply_to_topic_notification_level_changed
action: :reply_to_topic_notification_level_changed,
},
reply: {
next_state: :tutorial_change_topic_notification_level,
action: :missing_topic_notification_level_change
}
action: :missing_topic_notification_level_change,
},
},
tutorial_poll: {
prerequisite: Proc.new { SiteSetting.poll_enabled && @user.has_trust_level?(SiteSetting.poll_minimum_trust_level_to_create) },
prerequisite:
Proc.new do
SiteSetting.poll_enabled &&
@user.has_trust_level?(SiteSetting.poll_minimum_trust_level_to_create)
end,
next_state: :tutorial_details,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.details.instructions", i18n_post_args) },
reply: {
action: :reply_to_poll
}
action: :reply_to_poll,
},
},
tutorial_details: {
next_state: :end,
reply: {
action: :reply_to_details
}
}
action: :reply_to_details,
},
},
}
def self.badge_name
@@ -103,7 +105,7 @@ module DiscourseNarrativeBot
end
def self.reset_trigger
I18n.t('discourse_narrative_bot.advanced_user_narrative.reset_trigger')
I18n.t("discourse_narrative_bot.advanced_user_narrative.reset_trigger")
end
def reset_bot(user, post)
@@ -123,13 +125,18 @@ module DiscourseNarrativeBot
fake_delay
post = PostCreator.create!(
@user,
raw: I18n.t("#{I18N_KEY}.edit.bot_created_post_raw", i18n_post_args(discobot_username: self.discobot_username)),
topic_id: data[:topic_id],
skip_bot: true,
skip_validations: true
)
post =
PostCreator.create!(
@user,
raw:
I18n.t(
"#{I18N_KEY}.edit.bot_created_post_raw",
i18n_post_args(discobot_username: self.discobot_username),
),
topic_id: data[:topic_id],
skip_bot: true,
skip_validations: true,
)
set_state_data(:post_id, post.id)
post
@@ -138,13 +145,18 @@ module DiscourseNarrativeBot
def init_tutorial_recover
data = get_data(@user)
post = PostCreator.create!(
@user,
raw: I18n.t("#{I18N_KEY}.recover.deleted_post_raw", i18n_post_args(discobot_username: self.discobot_username)),
topic_id: data[:topic_id],
skip_bot: true,
skip_validations: true
)
post =
PostCreator.create!(
@user,
raw:
I18n.t(
"#{I18N_KEY}.recover.deleted_post_raw",
i18n_post_args(discobot_username: self.discobot_username),
),
topic_id: data[:topic_id],
skip_bot: true,
skip_validations: true,
)
set_state_data(:post_id, post.id)
@@ -172,18 +184,15 @@ module DiscourseNarrativeBot
opts = {
title: I18n.t("#{I18N_KEY}.title"),
target_usernames: @user.username,
archetype: Archetype.private_message
archetype: Archetype.private_message,
}
if @post &&
@post.topic.private_message? &&
@post.topic.topic_allowed_users.pluck(:user_id).include?(@user.id)
if @post && @post.topic.private_message? &&
@post.topic.topic_allowed_users.pluck(:user_id).include?(@user.id)
end
if @data[:topic_id]
opts = opts
.merge(topic_id: @data[:topic_id])
.except(:title, :target_usernames, :archetype)
opts = opts.merge(topic_id: @data[:topic_id]).except(:title, :target_usernames, :archetype)
end
post = reply_to(@post, raw, opts)
@@ -213,9 +222,10 @@ module DiscourseNarrativeBot
fake_delay
unless @data[:attempted]
reply_to(@post, I18n.t("#{I18N_KEY}.edit.not_found",
i18n_post_args(url: Post.find_by(id: post_id).url)
))
reply_to(
@post,
I18n.t("#{I18N_KEY}.edit.not_found", i18n_post_args(url: Post.find_by(id: post_id).url)),
)
end
enqueue_timeout_job(@user)
@@ -233,16 +243,15 @@ module DiscourseNarrativeBot
#{instance_eval(&@next_instructions)}
MD
PostCreator.create!(self.discobot_user,
raw: raw,
topic_id: @topic_id
)
PostCreator.create!(self.discobot_user, raw: raw, topic_id: @topic_id)
end
def missing_delete
return unless valid_topic?(@post.topic_id)
fake_delay
reply_to(@post, I18n.t("#{I18N_KEY}.delete.not_found", i18n_post_args)) unless @data[:attempted]
unless @data[:attempted]
reply_to(@post, I18n.t("#{I18N_KEY}.delete.not_found", i18n_post_args))
end
enqueue_timeout_job(@user)
false
end
@@ -258,18 +267,19 @@ module DiscourseNarrativeBot
#{instance_eval(&@next_instructions)}
MD
PostCreator.create!(self.discobot_user,
raw: raw,
topic_id: @post.topic_id
)
PostCreator.create!(self.discobot_user, raw: raw, topic_id: @post.topic_id)
end
def missing_recover
return unless valid_topic?(@post.topic_id) &&
post_id = get_state_data(:post_id) && @post.id != post_id
unless valid_topic?(@post.topic_id) &&
post_id = get_state_data(:post_id) && @post.id != post_id
return
end
fake_delay
reply_to(@post, I18n.t("#{I18N_KEY}.recover.not_found", i18n_post_args)) unless @data[:attempted]
unless @data[:attempted]
reply_to(@post, I18n.t("#{I18N_KEY}.recover.not_found", i18n_post_args))
end
enqueue_timeout_job(@user)
false
end
@@ -278,7 +288,7 @@ module DiscourseNarrativeBot
topic_id = @post.topic_id
return unless valid_topic?(topic_id)
if Nokogiri::HTML5.fragment(@post.cooked).css('.hashtag').size > 0
if Nokogiri::HTML5.fragment(@post.cooked).css(".hashtag").size > 0
raw = <<~MD
#{I18n.t("#{I18N_KEY}.category_hashtag.reply", i18n_post_args)}
@@ -289,7 +299,9 @@ module DiscourseNarrativeBot
reply_to(@post, raw)
else
fake_delay
reply_to(@post, I18n.t("#{I18N_KEY}.category_hashtag.not_found", i18n_post_args)) unless @data[:attempted]
unless @data[:attempted]
reply_to(@post, I18n.t("#{I18N_KEY}.category_hashtag.not_found", i18n_post_args))
end
enqueue_timeout_job(@user)
false
end
@@ -299,7 +311,12 @@ module DiscourseNarrativeBot
return unless valid_topic?(@post.topic_id)
fake_delay
reply_to(@post, I18n.t("#{I18N_KEY}.change_topic_notification_level.not_found", i18n_post_args)) unless @data[:attempted]
unless @data[:attempted]
reply_to(
@post,
I18n.t("#{I18N_KEY}.change_topic_notification_level.not_found", i18n_post_args),
)
end
enqueue_timeout_job(@user)
false
end
@@ -316,10 +333,7 @@ module DiscourseNarrativeBot
fake_delay
post = PostCreator.create!(self.discobot_user,
raw: raw,
topic_id: @topic_id
)
post = PostCreator.create!(self.discobot_user, raw: raw, topic_id: @topic_id)
enqueue_timeout_job(@user)
post
@@ -340,7 +354,9 @@ module DiscourseNarrativeBot
reply_to(@post, raw)
else
fake_delay
reply_to(@post, I18n.t("#{I18N_KEY}.poll.not_found", i18n_post_args)) unless @data[:attempted]
unless @data[:attempted]
reply_to(@post, I18n.t("#{I18N_KEY}.poll.not_found", i18n_post_args))
end
enqueue_timeout_job(@user)
false
end
@@ -355,7 +371,9 @@ module DiscourseNarrativeBot
if Nokogiri::HTML5.fragment(@post.cooked).css("details").size > 0
reply_to(@post, I18n.t("#{I18N_KEY}.details.reply", i18n_post_args))
else
reply_to(@post, I18n.t("#{I18N_KEY}.details.not_found", i18n_post_args)) unless @data[:attempted]
unless @data[:attempted]
reply_to(@post, I18n.t("#{I18N_KEY}.details.not_found", i18n_post_args))
end
enqueue_timeout_job(@user)
false
end
@@ -370,7 +388,9 @@ module DiscourseNarrativeBot
if @post.wiki
reply_to(@post, I18n.t("#{I18N_KEY}.wiki.reply", i18n_post_args))
else
reply_to(@post, I18n.t("#{I18N_KEY}.wiki.not_found", i18n_post_args)) unless @data[:attempted]
unless @data[:attempted]
reply_to(@post, I18n.t("#{I18N_KEY}.wiki.not_found", i18n_post_args))
end
enqueue_timeout_job(@user)
false
end
@@ -379,9 +399,10 @@ module DiscourseNarrativeBot
def end_reply
fake_delay
reply_to(@post, I18n.t("#{I18N_KEY}.end.message",
i18n_post_args(certificate: certificate('advanced'))
))
reply_to(
@post,
I18n.t("#{I18N_KEY}.end.message", i18n_post_args(certificate: certificate("advanced"))),
)
end
def synchronize(user)

View File

@@ -4,7 +4,8 @@ module DiscourseNarrativeBot
class Base
include Actions
class InvalidTransitionError < StandardError; end
class InvalidTransitionError < StandardError
end
def input(input, user, post: nil, topic_id: nil, skip: false)
new_post = nil
@@ -30,16 +31,18 @@ module DiscourseNarrativeBot
next_opts = self.class::TRANSITION_TABLE.fetch(next_state)
prerequisite = next_opts[:prerequisite]
if (!prerequisite || instance_eval(&prerequisite)) && !(
SiteSetting.discourse_narrative_bot_skip_tutorials.present? &&
SiteSetting.discourse_narrative_bot_skip_tutorials.split("|").include?(next_state.to_s))
if (!prerequisite || instance_eval(&prerequisite)) &&
!(
SiteSetting.discourse_narrative_bot_skip_tutorials.present? &&
SiteSetting
.discourse_narrative_bot_skip_tutorials
.split("|")
.include?(next_state.to_s)
)
break
end
[:next_state, :next_instructions].each do |key|
opts[key] = next_opts[key]
end
%i[next_state next_instructions].each { |key| opts[key] = next_opts[key] }
end
rescue InvalidTransitionError
# For given input, no transition for current state
@@ -78,16 +81,9 @@ module DiscourseNarrativeBot
end_reply
cancel_timeout_job(user)
BadgeGranter.grant(
Badge.find_by(name: self.class.badge_name),
user
)
BadgeGranter.grant(Badge.find_by(name: self.class.badge_name), user)
set_data(@user,
topic_id: new_post.topic_id,
state: :end,
track: self.class.to_s
)
set_data(@user, topic_id: new_post.topic_id, state: :end, track: self.class.to_s)
end
end
rescue => e
@@ -116,25 +112,29 @@ module DiscourseNarrativeBot
@data = get_data(user) || {}
if post = Post.find_by(id: @data[:last_post_id])
reply_to(post, I18n.t("discourse_narrative_bot.timeout.message",
i18n_post_args(
username: user.username,
skip_trigger: TrackSelector.skip_trigger,
reset_trigger: "#{TrackSelector.reset_trigger} #{self.class.reset_trigger}"
)
), {}, skip_send_email: false)
reply_to(
post,
I18n.t(
"discourse_narrative_bot.timeout.message",
i18n_post_args(
username: user.username,
skip_trigger: TrackSelector.skip_trigger,
reset_trigger: "#{TrackSelector.reset_trigger} #{self.class.reset_trigger}",
),
),
{},
skip_send_email: false,
)
end
end
def certificate(type = nil)
options = {
user_id: @user.id,
date: Time.zone.now.strftime('%b %d %Y'),
format: :svg
}
options = { user_id: @user.id, date: Time.zone.now.strftime("%b %d %Y"), format: :svg }
options.merge!(type: type) if type
src = Discourse.base_url + DiscourseNarrativeBot::Engine.routes.url_helpers.certificate_path(options)
src =
Discourse.base_url +
DiscourseNarrativeBot::Engine.routes.url_helpers.certificate_path(options)
alt = CGI.escapeHTML(I18n.t("#{self.class::I18N_KEY}.certificate.alt"))
"<iframe class='discobot-certificate' src='#{src}' width='650' height='464' alt='#{alt}'></iframe>"
@@ -192,7 +192,7 @@ module DiscourseNarrativeBot
end
def not_implemented
raise 'Not implemented.'
raise "Not implemented."
end
private

View File

@@ -10,7 +10,7 @@ module DiscourseNarrativeBot
begin
Date.parse(date)
rescue ArgumentError => e
if e.message == 'invalid date'
if e.message == "invalid date"
Date.parse(Date.today.to_s)
else
raise e
@@ -25,14 +25,20 @@ module DiscourseNarrativeBot
svg_default_width = 538.583
logo_container = logo_group(55, svg_default_width, 280)
ApplicationController.render(inline: read_template('new_user'), assigns: assign_options(svg_default_width, logo_container))
ApplicationController.render(
inline: read_template("new_user"),
assigns: assign_options(svg_default_width, logo_container),
)
end
def advanced_user_track
svg_default_width = 722.8
logo_container = logo_group(40, svg_default_width, 350)
ApplicationController.render(inline: read_template('advanced_user'), assigns: assign_options(svg_default_width, logo_container))
ApplicationController.render(
inline: read_template("advanced_user"),
assigns: assign_options(svg_default_width, logo_container),
)
end
private
@@ -48,7 +54,7 @@ module DiscourseNarrativeBot
date: @date,
avatar_url: @avatar_url,
logo_group: logo_group,
name: name
name: name,
}
end

View File

@@ -7,25 +7,26 @@ module DiscourseNarrativeBot
def self.roll(num_of_dice, range_of_dice)
if num_of_dice == 0 || range_of_dice == 0
return I18n.t('discourse_narrative_bot.dice.invalid')
return I18n.t("discourse_narrative_bot.dice.invalid")
end
output = +''
output = +""
if num_of_dice > MAXIMUM_NUM_OF_DICE
output << I18n.t('discourse_narrative_bot.dice.not_enough_dice', count: MAXIMUM_NUM_OF_DICE)
output << I18n.t("discourse_narrative_bot.dice.not_enough_dice", count: MAXIMUM_NUM_OF_DICE)
output << "\n\n"
num_of_dice = MAXIMUM_NUM_OF_DICE
end
if range_of_dice > MAXIMUM_RANGE_OF_DICE
output << I18n.t('discourse_narrative_bot.dice.out_of_range')
output << I18n.t("discourse_narrative_bot.dice.out_of_range")
output << "\n\n"
range_of_dice = MAXIMUM_RANGE_OF_DICE
end
output << I18n.t('discourse_narrative_bot.dice.results',
results: num_of_dice.times.map { rand(1..range_of_dice) }.join(", ")
output << I18n.t(
"discourse_narrative_bot.dice.results",
results: num_of_dice.times.map { rand(1..range_of_dice) }.join(", "),
)
end
end

View File

@@ -3,9 +3,10 @@
module DiscourseNarrativeBot
class Magic8Ball
def self.generate_answer
I18n.t("discourse_narrative_bot.magic_8_ball.result", result: I18n.t(
"discourse_narrative_bot.magic_8_ball.answers.#{rand(1..20)}"
))
I18n.t(
"discourse_narrative_bot.magic_8_ball.result",
result: I18n.t("discourse_narrative_bot.magic_8_ball.answers.#{rand(1..20)}"),
)
end
end
end

View File

@@ -1,136 +1,136 @@
# frozen_string_literal: true
require 'distributed_mutex'
require "distributed_mutex"
module DiscourseNarrativeBot
class NewUserNarrative < Base
I18N_KEY = "discourse_narrative_bot.new_user_narrative".freeze
BADGE_NAME = 'Certified'.freeze
BADGE_NAME = "Certified".freeze
TRANSITION_TABLE = {
begin: {
init: {
next_state: :tutorial_bookmark,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.bookmark.instructions", base_uri: Discourse.base_path) },
action: :say_hello
}
next_instructions:
Proc.new { I18n.t("#{I18N_KEY}.bookmark.instructions", base_uri: Discourse.base_path) },
action: :say_hello,
},
},
tutorial_bookmark: {
next_state: :tutorial_onebox,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.onebox.instructions", base_uri: Discourse.base_path) },
next_instructions:
Proc.new { I18n.t("#{I18N_KEY}.onebox.instructions", base_uri: Discourse.base_path) },
bookmark: {
action: :reply_to_bookmark
action: :reply_to_bookmark,
},
reply: {
next_state: :tutorial_bookmark,
action: :missing_bookmark
}
action: :missing_bookmark,
},
},
tutorial_onebox: {
next_state: :tutorial_emoji,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.emoji.instructions", base_uri: Discourse.base_path) },
next_instructions:
Proc.new { I18n.t("#{I18N_KEY}.emoji.instructions", base_uri: Discourse.base_path) },
reply: {
action: :reply_to_onebox
}
action: :reply_to_onebox,
},
},
tutorial_emoji: {
prerequisite: Proc.new { SiteSetting.enable_emoji },
next_state: :tutorial_mention,
next_instructions: Proc.new {
I18n.t("#{I18N_KEY}.mention.instructions",
discobot_username: self.discobot_username,
base_uri: Discourse.base_path)
},
next_instructions:
Proc.new do
I18n.t(
"#{I18N_KEY}.mention.instructions",
discobot_username: self.discobot_username,
base_uri: Discourse.base_path,
)
end,
reply: {
action: :reply_to_emoji
}
action: :reply_to_emoji,
},
},
tutorial_mention: {
prerequisite: Proc.new { SiteSetting.enable_mentions },
next_state: :tutorial_formatting,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.formatting.instructions", base_uri: Discourse.base_path) },
next_instructions:
Proc.new { I18n.t("#{I18N_KEY}.formatting.instructions", base_uri: Discourse.base_path) },
reply: {
action: :reply_to_mention
}
action: :reply_to_mention,
},
},
tutorial_formatting: {
next_state: :tutorial_quote,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.quoting.instructions", base_uri: Discourse.base_path) },
next_instructions:
Proc.new { I18n.t("#{I18N_KEY}.quoting.instructions", base_uri: Discourse.base_path) },
reply: {
action: :reply_to_formatting
}
action: :reply_to_formatting,
},
},
tutorial_quote: {
next_state: :tutorial_images,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.images.instructions", base_uri: Discourse.base_path) },
next_instructions:
Proc.new { I18n.t("#{I18N_KEY}.images.instructions", base_uri: Discourse.base_path) },
reply: {
action: :reply_to_quote
}
action: :reply_to_quote,
},
},
# Note: tutorial_images and tutorial_likes are mutually exclusive.
# The prerequisites should ensure only one of them is called.
tutorial_images: {
prerequisite: Proc.new { @user.has_trust_level?(SiteSetting.min_trust_to_post_embedded_media) },
prerequisite:
Proc.new { @user.has_trust_level?(SiteSetting.min_trust_to_post_embedded_media) },
next_state: :tutorial_likes,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.likes.instructions", base_uri: Discourse.base_path) },
next_instructions:
Proc.new { I18n.t("#{I18N_KEY}.likes.instructions", base_uri: Discourse.base_path) },
reply: {
action: :reply_to_image
action: :reply_to_image,
},
like: {
action: :track_images_like
}
action: :track_images_like,
},
},
tutorial_likes: {
prerequisite: Proc.new { !@user.has_trust_level?(SiteSetting.min_trust_to_post_embedded_media) },
prerequisite:
Proc.new { !@user.has_trust_level?(SiteSetting.min_trust_to_post_embedded_media) },
next_state: :tutorial_flag,
next_instructions: Proc.new {
I18n.t("#{I18N_KEY}.flag.instructions",
guidelines_url: url_helpers(:guidelines_url),
about_url: url_helpers(:about_index_url),
base_uri: Discourse.base_path)
},
next_instructions:
Proc.new do
I18n.t(
"#{I18N_KEY}.flag.instructions",
guidelines_url: url_helpers(:guidelines_url),
about_url: url_helpers(:about_index_url),
base_uri: Discourse.base_path,
)
end,
like: {
action: :reply_to_likes
action: :reply_to_likes,
},
reply: {
next_state: :tutorial_likes,
action: :missing_likes_like
}
action: :missing_likes_like,
},
},
tutorial_flag: {
prerequisite: Proc.new { SiteSetting.allow_flagging_staff },
next_state: :tutorial_search,
next_instructions: Proc.new { I18n.t("#{I18N_KEY}.search.instructions", base_uri: Discourse.base_path) },
next_instructions:
Proc.new { I18n.t("#{I18N_KEY}.search.instructions", base_uri: Discourse.base_path) },
flag: {
action: :reply_to_flag
action: :reply_to_flag,
},
reply: {
next_state: :tutorial_flag,
action: :missing_flag
}
action: :missing_flag,
},
},
tutorial_search: {
next_state: :end,
reply: {
action: :reply_to_search
}
}
action: :reply_to_search,
},
},
}
def self.badge_name
@@ -138,7 +138,7 @@ module DiscourseNarrativeBot
end
def self.search_answer
':herb:'
":herb:"
end
def self.search_answer_emoji
@@ -146,7 +146,7 @@ module DiscourseNarrativeBot
end
def self.reset_trigger
I18n.t('discourse_narrative_bot.new_user_narrative.reset_trigger')
I18n.t("discourse_narrative_bot.new_user_narrative.reset_trigger")
end
def reset_bot(user, post)
@@ -173,7 +173,7 @@ module DiscourseNarrativeBot
topic = @post.topic
post = topic.first_post
MessageBus.publish('/new_user_narrative/tutorial_search', {}, user_ids: [@user.id])
MessageBus.publish("/new_user_narrative/tutorial_search", {}, user_ids: [@user.id])
raw = <<~MD
#{post.raw}
@@ -184,7 +184,8 @@ module DiscourseNarrativeBot
PostRevisor.new(post, topic).revise!(
self.discobot_user,
{ raw: raw },
skip_validations: true, force_new_version: true
skip_validations: true,
force_new_version: true,
)
set_state_data(:post_version, post.reload.version || 0)
@@ -198,13 +199,11 @@ module DiscourseNarrativeBot
end
def say_hello
raw = I18n.t(
"#{I18N_KEY}.hello.message",
i18n_post_args(
username: @user.username,
title: SiteSetting.title
raw =
I18n.t(
"#{I18N_KEY}.hello.message",
i18n_post_args(username: @user.username, title: SiteSetting.title),
)
)
raw = <<~MD
#{raw}
@@ -213,9 +212,7 @@ module DiscourseNarrativeBot
MD
title = I18n.t("#{I18N_KEY}.hello.title", title: SiteSetting.title)
if SiteSetting.max_emojis_in_title == 0
title = title.gsub(/:([\w\-+]+(?::t\d)?):/, '').strip
end
title = title.gsub(/:([\w\-+]+(?::t\d)?):/, "").strip if SiteSetting.max_emojis_in_title == 0
opts = {
title: title,
@@ -224,17 +221,13 @@ module DiscourseNarrativeBot
subtype: TopicSubtype.system_message,
}
if @post &&
@post.topic.private_message? &&
@post.topic.topic_allowed_users.pluck(:user_id).include?(@user.id)
if @post && @post.topic.private_message? &&
@post.topic.topic_allowed_users.pluck(:user_id).include?(@user.id)
opts = opts.merge(topic_id: @post.topic_id)
end
if @data[:topic_id]
opts = opts
.merge(topic_id: @data[:topic_id])
.except(:title, :target_usernames, :archetype)
opts = opts.merge(topic_id: @data[:topic_id]).except(:title, :target_usernames, :archetype)
end
post = reply_to(@post, raw, opts)
@@ -249,7 +242,9 @@ module DiscourseNarrativeBot
fake_delay
enqueue_timeout_job(@user)
reply_to(@post, I18n.t("#{I18N_KEY}.bookmark.not_found", i18n_post_args)) unless @data[:attempted]
unless @data[:attempted]
reply_to(@post, I18n.t("#{I18N_KEY}.bookmark.not_found", i18n_post_args))
end
false
end
@@ -292,7 +287,9 @@ module DiscourseNarrativeBot
reply
else
fake_delay
reply_to(@post, I18n.t("#{I18N_KEY}.onebox.not_found", i18n_post_args)) unless @data[:attempted]
unless @data[:attempted]
reply_to(@post, I18n.t("#{I18N_KEY}.onebox.not_found", i18n_post_args))
end
enqueue_timeout_job(@user)
false
end
@@ -302,11 +299,12 @@ module DiscourseNarrativeBot
post_topic_id = @post.topic_id
return unless valid_topic?(post_topic_id)
post_liked = PostAction.exists?(
post_action_type_id: PostActionType.types[:like],
post_id: @data[:last_post_id],
user_id: @user.id
)
post_liked =
PostAction.exists?(
post_action_type_id: PostActionType.types[:like],
post_id: @data[:last_post_id],
user_id: @user.id,
)
if post_liked
set_state_data(:liked, true)
@@ -358,18 +356,23 @@ module DiscourseNarrativeBot
like_post(@post)
else
raw = I18n.t(
"#{I18N_KEY}.images.like_not_found",
i18n_post_args(url: Post.find_by(id: @data[:last_post_id]).url)
)
raw =
I18n.t(
"#{I18N_KEY}.images.like_not_found",
i18n_post_args(url: Post.find_by(id: @data[:last_post_id]).url),
)
transition = false
end
else
raw = I18n.t(
"#{I18N_KEY}.images.not_found",
i18n_post_args(image_url: "#{Discourse.base_url}/plugins/discourse-narrative-bot/images/dog-walk.gif")
)
raw =
I18n.t(
"#{I18N_KEY}.images.not_found",
i18n_post_args(
image_url:
"#{Discourse.base_url}/plugins/discourse-narrative-bot/images/dog-walk.gif",
),
)
transition = false
end
@@ -398,11 +401,12 @@ module DiscourseNarrativeBot
post_topic_id = @post.topic_id
return unless valid_topic?(post_topic_id)
post_liked = PostAction.exists?(
post_action_type_id: PostActionType.types[:like],
post_id: @data[:last_post_id],
user_id: @user.id
)
post_liked =
PostAction.exists?(
post_action_type_id: PostActionType.types[:like],
post_id: @data[:last_post_id],
user_id: @user.id,
)
if post_liked
raw = <<~MD
@@ -425,7 +429,10 @@ module DiscourseNarrativeBot
post_topic_id = @post.topic_id
return unless valid_topic?(post_topic_id)
if Nokogiri::HTML5.fragment(@post.cooked).css("b", "strong", "em", "i", ".bbcode-i", ".bbcode-b").size > 0
if Nokogiri::HTML5
.fragment(@post.cooked)
.css("b", "strong", "em", "i", ".bbcode-i", ".bbcode-b")
.size > 0
raw = <<~MD
#{I18n.t("#{I18N_KEY}.formatting.reply", i18n_post_args)}
@@ -439,7 +446,9 @@ module DiscourseNarrativeBot
reply
else
fake_delay
reply_to(@post, I18n.t("#{I18N_KEY}.formatting.not_found", i18n_post_args)) unless @data[:attempted]
unless @data[:attempted]
reply_to(@post, I18n.t("#{I18N_KEY}.formatting.not_found", i18n_post_args))
end
enqueue_timeout_job(@user)
false
end
@@ -465,7 +474,9 @@ module DiscourseNarrativeBot
reply
else
fake_delay
reply_to(@post, I18n.t("#{I18N_KEY}.quoting.not_found", i18n_post_args)) unless @data[:attempted]
unless @data[:attempted]
reply_to(@post, I18n.t("#{I18N_KEY}.quoting.not_found", i18n_post_args))
end
enqueue_timeout_job(@user)
false
end
@@ -491,7 +502,9 @@ module DiscourseNarrativeBot
reply
else
fake_delay
reply_to(@post, I18n.t("#{I18N_KEY}.emoji.not_found", i18n_post_args)) unless @data[:attempted]
unless @data[:attempted]
reply_to(@post, I18n.t("#{I18N_KEY}.emoji.not_found", i18n_post_args))
end
enqueue_timeout_job(@user)
false
end
@@ -517,13 +530,13 @@ module DiscourseNarrativeBot
fake_delay
unless @data[:attempted]
reply_to(@post, I18n.t(
"#{I18N_KEY}.mention.not_found",
i18n_post_args(
username: @user.username,
discobot_username: self.discobot_username
)
))
reply_to(
@post,
I18n.t(
"#{I18N_KEY}.mention.not_found",
i18n_post_args(username: @user.username, discobot_username: self.discobot_username),
),
)
end
enqueue_timeout_job(@user)
@@ -536,9 +549,13 @@ module DiscourseNarrativeBot
# Remove any incorrect flags so that they can try again
if @post.user_id == -2
@post.post_actions
@post
.post_actions
.where(user_id: @user.id)
.where("post_action_type_id IN (?)", (PostActionType.flag_types.values - [PostActionType.types[:inappropriate]]))
.where(
"post_action_type_id IN (?)",
(PostActionType.flag_types.values - [PostActionType.types[:inappropriate]]),
)
.destroy_all
end
@@ -571,12 +588,18 @@ module DiscourseNarrativeBot
post_topic_id = @post.topic_id
return unless valid_topic?(post_topic_id)
if @post.raw.include?(NewUserNarrative.search_answer) || @post.raw.include?(NewUserNarrative.search_answer_emoji)
if @post.raw.include?(NewUserNarrative.search_answer) ||
@post.raw.include?(NewUserNarrative.search_answer_emoji)
fake_delay
reply_to(@post, I18n.t("#{I18N_KEY}.search.reply", i18n_post_args(search_url: url_helpers(:search_url))))
reply_to(
@post,
I18n.t("#{I18N_KEY}.search.reply", i18n_post_args(search_url: url_helpers(:search_url))),
)
else
fake_delay
reply_to(@post, I18n.t("#{I18N_KEY}.search.not_found", i18n_post_args)) unless @data[:attempted]
unless @data[:attempted]
reply_to(@post, I18n.t("#{I18N_KEY}.search.not_found", i18n_post_args))
end
enqueue_timeout_job(@user)
false
end
@@ -587,16 +610,17 @@ module DiscourseNarrativeBot
reply_to(
@post,
I18n.t("#{I18N_KEY}.end.message",
I18n.t(
"#{I18N_KEY}.end.message",
i18n_post_args(
username: @user.username,
base_url: Discourse.base_url,
certificate: certificate,
discobot_username: self.discobot_username,
advanced_trigger: AdvancedUserNarrative.reset_trigger
)
advanced_trigger: AdvancedUserNarrative.reset_trigger,
),
),
topic_id: @data[:topic_id]
topic_id: @data[:topic_id],
)
end
@@ -605,15 +629,12 @@ module DiscourseNarrativeBot
end
def welcome_topic
Topic.find_by(slug: 'welcome-to-discourse', archetype: Archetype.default) ||
Topic.find_by(slug: "welcome-to-discourse", archetype: Archetype.default) ||
Topic.recent(1).first
end
def url_helpers(url, opts = {})
Rails.application.routes.url_helpers.public_send(
url,
opts.merge(host: Discourse.base_url)
)
Rails.application.routes.url_helpers.public_send(url, opts.merge(host: Discourse.base_url))
end
end
end

View File

@@ -1,24 +1,21 @@
# frozen_string_literal: true
require 'excon'
require "excon"
module DiscourseNarrativeBot
class QuoteGenerator
API_ENDPOINT = 'http://api.forismatic.com/api/1.0/'.freeze
API_ENDPOINT = "http://api.forismatic.com/api/1.0/".freeze
def self.format_quote(quote, author)
I18n.t('discourse_narrative_bot.quote.results', quote: quote, author: author)
I18n.t("discourse_narrative_bot.quote.results", quote: quote, author: author)
end
def self.generate(user)
quote, author =
if !user.effective_locale.start_with?('en')
if !user.effective_locale.start_with?("en")
translation_key = "discourse_narrative_bot.quote.#{rand(1..10)}"
[
I18n.t("#{translation_key}.quote"),
I18n.t("#{translation_key}.author")
]
[I18n.t("#{translation_key}.quote"), I18n.t("#{translation_key}.author")]
else
connection = Excon.new("#{API_ENDPOINT}?lang=en&format=json&method=getQuote")
response = connection.request(expects: [200, 201], method: :Get)

View File

@@ -4,18 +4,12 @@ module DiscourseNarrativeBot
class TrackSelector
include Actions
GENERIC_REPLIES_COUNT_PREFIX = 'discourse-narrative-bot:track-selector-count:'.freeze
PUBLIC_DISPLAY_BOT_HELP_KEY = 'discourse-narrative-bot:track-selector:display-bot-help'.freeze
GENERIC_REPLIES_COUNT_PREFIX = "discourse-narrative-bot:track-selector-count:".freeze
PUBLIC_DISPLAY_BOT_HELP_KEY = "discourse-narrative-bot:track-selector:display-bot-help".freeze
TRACKS = [
AdvancedUserNarrative,
NewUserNarrative
]
TRACKS = [AdvancedUserNarrative, NewUserNarrative]
TOPIC_ACTIONS = [
:delete,
:topic_notification_level_changed
].each(&:freeze)
TOPIC_ACTIONS = %i[delete topic_notification_level_changed].each(&:freeze)
RESET_TRIGGER_EXACT_MATCH_LENGTH = 200
@@ -118,7 +112,7 @@ module DiscourseNarrativeBot
trigger = "#{self.class.reset_trigger} #{klass.reset_trigger}"
if @post.raw.length < RESET_TRIGGER_EXACT_MATCH_LENGTH && @is_pm_to_bot
@post.raw.match(Regexp.new("\\b\\W\?#{trigger}\\W\?\\b", 'i'))
@post.raw.match(Regexp.new("\\b\\W\?#{trigger}\\W\?\\b", "i"))
else
match_trigger?(trigger)
end
@@ -127,7 +121,7 @@ module DiscourseNarrativeBot
def bot_commands(hint = true)
raw =
if @user.manually_disabled_discobot?
I18n.t(self.class.i18n_key('random_mention.discobot_disabled'))
I18n.t(self.class.i18n_key("random_mention.discobot_disabled"))
elsif match_data = match_trigger?("#{self.class.dice_trigger} (\\d+)d(\\d+)")
DiscourseNarrativeBot::Dice.roll(match_data[1].to_i, match_data[2].to_i)
elsif match_trigger?(self.class.quote_trigger)
@@ -137,20 +131,23 @@ module DiscourseNarrativeBot
elsif match_trigger?(self.class.help_trigger)
help_message
elsif hint
message = I18n.t(self.class.i18n_key('random_mention.reply'),
discobot_username: self.discobot_username,
help_trigger: self.class.help_trigger
)
message =
I18n.t(
self.class.i18n_key("random_mention.reply"),
discobot_username: self.discobot_username,
help_trigger: self.class.help_trigger,
)
if public_reply?
key = "#{PUBLIC_DISPLAY_BOT_HELP_KEY}:#{@post.topic_id}"
last_bot_help_post_number = Discourse.redis.get(key)
if !last_bot_help_post_number ||
(last_bot_help_post_number &&
@post.post_number - 10 > last_bot_help_post_number.to_i &&
(1.day.to_i - Discourse.redis.ttl(key)) > 6.hours.to_i)
(
last_bot_help_post_number &&
@post.post_number - 10 > last_bot_help_post_number.to_i &&
(1.day.to_i - Discourse.redis.ttl(key)) > 6.hours.to_i
)
Discourse.redis.setex(key, 1.day.to_i, @post.post_number)
message
end
@@ -166,20 +163,24 @@ module DiscourseNarrativeBot
end
def help_message
message = I18n.t(
self.class.i18n_key('random_mention.tracks'),
discobot_username: self.discobot_username,
reset_trigger: self.class.reset_trigger,
tracks: [NewUserNarrative.reset_trigger, AdvancedUserNarrative.reset_trigger].join(', ')
)
message =
I18n.t(
self.class.i18n_key("random_mention.tracks"),
discobot_username: self.discobot_username,
reset_trigger: self.class.reset_trigger,
tracks: [NewUserNarrative.reset_trigger, AdvancedUserNarrative.reset_trigger].join(", "),
)
message << "\n\n#{I18n.t(self.class.i18n_key('random_mention.bot_actions'),
discobot_username: self.discobot_username,
dice_trigger: self.class.dice_trigger,
quote_trigger: self.class.quote_trigger,
quote_sample: DiscourseNarrativeBot::QuoteGenerator.generate(@user),
magic_8_ball_trigger: self.class.magic_8_ball_trigger
)}"
message << "\n\n#{
I18n.t(
self.class.i18n_key("random_mention.bot_actions"),
discobot_username: self.discobot_username,
dice_trigger: self.class.dice_trigger,
quote_trigger: self.class.quote_trigger,
quote_sample: DiscourseNarrativeBot::QuoteGenerator.generate(@user),
magic_8_ball_trigger: self.class.magic_8_ball_trigger,
)
}"
end
def generic_replies_key(user)
@@ -193,18 +194,23 @@ module DiscourseNarrativeBot
case count
when 0
raw = I18n.t(self.class.i18n_key('do_not_understand.first_response'))
raw = I18n.t(self.class.i18n_key("do_not_understand.first_response"))
if state && state.to_sym != :end
raw = "#{raw}\n\n#{I18n.t(self.class.i18n_key('do_not_understand.track_response'), reset_trigger: reset_trigger, skip_trigger: self.class.skip_trigger)}"
raw =
"#{raw}\n\n#{I18n.t(self.class.i18n_key("do_not_understand.track_response"), reset_trigger: reset_trigger, skip_trigger: self.class.skip_trigger)}"
end
reply_to(@post, raw)
when 1
reply_to(@post, I18n.t(self.class.i18n_key('do_not_understand.second_response'),
base_path: Discourse.base_path,
reset_trigger: self.class.reset_trigger
))
reply_to(
@post,
I18n.t(
self.class.i18n_key("do_not_understand.second_response"),
base_path: Discourse.base_path,
reset_trigger: self.class.reset_trigger,
),
)
else
# Stay out of the user's way
end
@@ -218,7 +224,9 @@ module DiscourseNarrativeBot
def skip_track?
if @is_pm_to_bot
@post.raw.match(/((^@#{self.discobot_username} #{self.class.skip_trigger})|(^#{self.class.skip_trigger}$))/i)
@post.raw.match(
/((^@#{self.discobot_username} #{self.class.skip_trigger})|(^#{self.class.skip_trigger}$))/i,
)
else
false
end
@@ -233,24 +241,23 @@ module DiscourseNarrativeBot
def match_trigger?(trigger)
# we remove the leading <p> to allow for trigger to be at the end of a paragraph
cooked_trigger = cook(trigger)[3..-1]
regexp = Regexp.new(cooked_trigger, 'i')
regexp = Regexp.new(cooked_trigger, "i")
match = @post.cooked.match(regexp)
if @is_pm_to_bot
match || @post.raw.strip.match(Regexp.new("^#{trigger}$", 'i'))
match || @post.raw.strip.match(Regexp.new("^#{trigger}$", "i"))
else
match
end
end
def like_user_post
if @post.raw.match(/thank/i)
PostActionCreator.like(self.discobot_user, @post)
end
PostActionCreator.like(self.discobot_user, @post) if @post.raw.match(/thank/i)
end
def bot_mentioned?
@bot_mentioned ||= PostAnalyzer.new(@post.raw, @post.topic_id).raw_mentions.include?(self.discobot_username)
@bot_mentioned ||=
PostAnalyzer.new(@post.raw, @post.topic_id).raw_mentions.include?(self.discobot_username)
end
def public_reply?

View File

@@ -8,8 +8,14 @@ module DiscourseNarrativeBot
def self.values
@values ||= [
{ name: 'discourse_narrative_bot.welcome_post_type.new_user_track', value: 'new_user_track' },
{ name: 'discourse_narrative_bot.welcome_post_type.welcome_message', value: 'welcome_message' }
{
name: "discourse_narrative_bot.welcome_post_type.new_user_track",
value: "new_user_track",
},
{
name: "discourse_narrative_bot.welcome_post_type.welcome_message",
value: "welcome_message",
},
]
end

View File

@@ -18,34 +18,37 @@ if Rails.env == "development"
# 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__)
Rails.configuration.autoload_paths << File.expand_path("../autoload/jobs", __FILE__)
end
require_relative 'lib/discourse_narrative_bot/welcome_post_type_site_setting.rb'
register_asset 'stylesheets/discourse-narrative-bot.scss'
require_relative "lib/discourse_narrative_bot/welcome_post_type_site_setting.rb"
register_asset "stylesheets/discourse-narrative-bot.scss"
after_initialize do
SeedFu.fixture_paths << Rails.root.join("plugins", "discourse-narrative-bot", "db", "fixtures").to_s
SeedFu.fixture_paths << Rails
.root
.join("plugins", "discourse-narrative-bot", "db", "fixtures")
.to_s
Mime::Type.register "image/svg+xml", :svg
[
'../autoload/jobs/regular/bot_input.rb',
'../autoload/jobs/regular/narrative_timeout.rb',
'../autoload/jobs/regular/narrative_init.rb',
'../autoload/jobs/regular/send_default_welcome_message.rb',
'../autoload/jobs/onceoff/discourse_narrative_bot/grant_badges.rb',
'../autoload/jobs/onceoff/discourse_narrative_bot/remap_old_bot_images.rb',
'../lib/discourse_narrative_bot/actions.rb',
'../lib/discourse_narrative_bot/base.rb',
'../lib/discourse_narrative_bot/new_user_narrative.rb',
'../lib/discourse_narrative_bot/advanced_user_narrative.rb',
'../lib/discourse_narrative_bot/track_selector.rb',
'../lib/discourse_narrative_bot/certificate_generator.rb',
'../lib/discourse_narrative_bot/dice.rb',
'../lib/discourse_narrative_bot/quote_generator.rb',
'../lib/discourse_narrative_bot/magic_8_ball.rb',
'../lib/discourse_narrative_bot/welcome_post_type_site_setting.rb'
%w[
../autoload/jobs/regular/bot_input.rb
../autoload/jobs/regular/narrative_timeout.rb
../autoload/jobs/regular/narrative_init.rb
../autoload/jobs/regular/send_default_welcome_message.rb
../autoload/jobs/onceoff/discourse_narrative_bot/grant_badges.rb
../autoload/jobs/onceoff/discourse_narrative_bot/remap_old_bot_images.rb
../lib/discourse_narrative_bot/actions.rb
../lib/discourse_narrative_bot/base.rb
../lib/discourse_narrative_bot/new_user_narrative.rb
../lib/discourse_narrative_bot/advanced_user_narrative.rb
../lib/discourse_narrative_bot/track_selector.rb
../lib/discourse_narrative_bot/certificate_generator.rb
../lib/discourse_narrative_bot/dice.rb
../lib/discourse_narrative_bot/quote_generator.rb
../lib/discourse_narrative_bot/magic_8_ball.rb
../lib/discourse_narrative_bot/welcome_post_type_site_setting.rb
].each { |path| load File.expand_path(path, __FILE__) }
RailsMultisite::ConnectionManagement.safe_each_connection do
@@ -55,12 +58,13 @@ after_initialize do
certificate_path = "#{Discourse.base_url}/discobot/certificate.svg"
if !SiteSetting.allowed_iframes.include?(certificate_path)
SiteSetting.allowed_iframes = SiteSetting.allowed_iframes.split('|').append(certificate_path).join('|')
SiteSetting.allowed_iframes =
SiteSetting.allowed_iframes.split("|").append(certificate_path).join("|")
end
end
end
require_dependency 'plugin_store'
require_dependency "plugin_store"
module ::DiscourseNarrativeBot
PLUGIN_NAME = "discourse-narrative-bot".freeze
@@ -94,13 +98,15 @@ after_initialize do
immutable_for(24.hours)
%i[date user_id].each do |key|
raise Discourse::InvalidParameters.new("#{key} must be present") unless params[key]&.present?
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)
rate_limiter = RateLimiter.new(current_user, "svg_certificate", 3, 1.minute)
else
rate_limiter = RateLimiter.new(current_user, 'svg_certificate_self', 30, 10.minutes)
rate_limiter = RateLimiter.new(current_user, "svg_certificate_self", 30, 10.minutes)
end
rate_limiter.performed! unless current_user.staff?
@@ -110,33 +116,28 @@ after_initialize do
hijack do
generator = CertificateGenerator.new(user, params[:date], avatar_url(user))
svg = params[:type] == 'advanced' ? generator.advanced_user_track : generator.new_user_track
svg =
params[:type] == "advanced" ? generator.advanced_user_track : generator.new_user_track
respond_to do |format|
format.svg { render inline: svg }
end
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'))
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
get "/certificate" => "certificates#generate", :format => :svg
end
Discourse::Application.routes.append do
mount ::DiscourseNarrativeBot::Engine, at: "/discobot"
end
Discourse::Application.routes.append { mount ::DiscourseNarrativeBot::Engine, at: "/discobot" }
self.add_model_callback(User, :after_destroy) do
DiscourseNarrativeBot::Store.remove(self.id)
end
self.add_model_callback(User, :after_destroy) { DiscourseNarrativeBot::Store.remove(self.id) }
self.on(:user_created) do |user|
if SiteSetting.discourse_narrative_bot_welcome_post_delay == 0 && !user.staged
@@ -145,19 +146,13 @@ after_initialize do
end
self.on(:user_first_logged_in) do |user|
if SiteSetting.discourse_narrative_bot_welcome_post_delay > 0
user.enqueue_bot_welcome_post
end
user.enqueue_bot_welcome_post if SiteSetting.discourse_narrative_bot_welcome_post_delay > 0
end
self.on(:user_unstaged) do |user|
user.enqueue_bot_welcome_post
end
self.on(:user_unstaged) { |user| user.enqueue_bot_welcome_post }
self.add_model_callback(UserOption, :after_save) do
if saved_change_to_skip_new_user_tips? && self.skip_new_user_tips
user.delete_bot_welcome_post
end
user.delete_bot_welcome_post if saved_change_to_skip_new_user_tips? && self.skip_new_user_tips
end
self.add_to_class(:user, :enqueue_bot_welcome_post) do
@@ -166,28 +161,29 @@ after_initialize do
delay = SiteSetting.discourse_narrative_bot_welcome_post_delay
case SiteSetting.discourse_narrative_bot_welcome_post_type
when 'new_user_track'
when "new_user_track"
if enqueue_narrative_bot_job? && !manually_disabled_discobot?
Jobs.enqueue_in(delay, :narrative_init,
Jobs.enqueue_in(
delay,
:narrative_init,
user_id: self.id,
klass: DiscourseNarrativeBot::NewUserNarrative.to_s
klass: DiscourseNarrativeBot::NewUserNarrative.to_s,
)
end
when 'welcome_message'
when "welcome_message"
Jobs.enqueue_in(delay, :send_default_welcome_message, user_id: self.id)
end
end
self.add_to_class(:user, :manually_disabled_discobot?) do
user_option&.skip_new_user_tips
end
self.add_to_class(:user, :manually_disabled_discobot?) { user_option&.skip_new_user_tips }
self.add_to_class(:user, :enqueue_narrative_bot_job?) do
SiteSetting.discourse_narrative_bot_enabled &&
self.human? &&
!self.anonymous? &&
SiteSetting.discourse_narrative_bot_enabled && self.human? && !self.anonymous? &&
!self.staged &&
!SiteSetting.discourse_narrative_bot_ignored_usernames.split('|'.freeze).include?(self.username)
!SiteSetting
.discourse_narrative_bot_ignored_usernames
.split("|".freeze)
.include?(self.username)
end
self.add_to_class(:user, :delete_bot_welcome_post) do
@@ -219,42 +215,31 @@ after_initialize do
user = post.user
if user&.enqueue_narrative_bot_job? && !options[:skip_bot]
Jobs.enqueue(:bot_input,
user_id: user.id,
post_id: post.id,
input: "reply"
)
Jobs.enqueue(:bot_input, user_id: user.id, post_id: post.id, input: "reply")
end
end
self.on(:post_edited) do |post|
if post.user&.enqueue_narrative_bot_job?
Jobs.enqueue(:bot_input,
user_id: post.user.id,
post_id: post.id,
input: "edit"
)
Jobs.enqueue(:bot_input, user_id: post.user.id, post_id: post.id, input: "edit")
end
end
self.on(:post_destroyed) do |post, options, user|
if user&.enqueue_narrative_bot_job? && !options[:skip_bot]
Jobs.enqueue(:bot_input,
Jobs.enqueue(
:bot_input,
user_id: user.id,
post_id: post.id,
topic_id: post.topic_id,
input: "delete"
input: "delete",
)
end
end
self.on(:post_recovered) do |post, _, user|
if user&.enqueue_narrative_bot_job?
Jobs.enqueue(:bot_input,
user_id: user.id,
post_id: post.id,
input: "recover"
)
Jobs.enqueue(:bot_input, user_id: user.id, post_id: post.id, input: "recover")
end
end
@@ -268,20 +253,19 @@ after_initialize do
"like"
end
if input
Jobs.enqueue(:bot_input,
user_id: self.user.id,
post_id: self.post.id,
input: input
)
end
Jobs.enqueue(:bot_input, user_id: self.user.id, post_id: self.post.id, input: input) if input
end
end
self.add_model_callback(Bookmark, :after_commit, on: :create) do
if self.user.enqueue_narrative_bot_job?
if self.bookmarkable_type == "Post"
Jobs.enqueue(:bot_input, user_id: self.user_id, post_id: self.bookmarkable_id, input: "bookmark")
Jobs.enqueue(
:bot_input,
user_id: self.user_id,
post_id: self.bookmarkable_id,
input: "bookmark",
)
end
end
end
@@ -290,31 +274,36 @@ after_initialize do
user = User.find_by(id: user_id)
if user && user.enqueue_narrative_bot_job?
Jobs.enqueue(:bot_input,
Jobs.enqueue(
:bot_input,
user_id: user_id,
topic_id: topic_id,
input: "topic_notification_level_changed"
input: "topic_notification_level_changed",
)
end
end
UserAvatar.register_custom_user_gravatar_email_hash(
DiscourseNarrativeBot::BOT_USER_ID,
"discobot@discourse.org"
"discobot@discourse.org",
)
self.on(:system_message_sent) do |args|
next if !SiteSetting.discourse_narrative_bot_enabled
next if args[:message_type] != 'tl2_promotion_message'
next if args[:message_type] != "tl2_promotion_message"
recipient = args[:post].topic.topic_users.where.not(user_id: args[:post].user_id).last&.user
recipient ||= Discourse.site_contact_user if args[:post].user == Discourse.site_contact_user
next if recipient.nil?
I18n.with_locale(recipient.effective_locale) do
raw = I18n.t("discourse_narrative_bot.tl2_promotion_message.text_body_template",
discobot_username: ::DiscourseNarrativeBot::Base.new.discobot_username,
reset_trigger: "#{::DiscourseNarrativeBot::TrackSelector.reset_trigger} #{::DiscourseNarrativeBot::AdvancedUserNarrative.reset_trigger}")
raw =
I18n.t(
"discourse_narrative_bot.tl2_promotion_message.text_body_template",
discobot_username: ::DiscourseNarrativeBot::Base.new.discobot_username,
reset_trigger:
"#{::DiscourseNarrativeBot::TrackSelector.reset_trigger} #{::DiscourseNarrativeBot::AdvancedUserNarrative.reset_trigger}",
)
PostCreator.create!(
::DiscourseNarrativeBot::Base.new.discobot_user,
@@ -322,7 +311,7 @@ after_initialize do
raw: raw,
skip_validations: true,
archetype: Archetype.private_message,
target_usernames: recipient.username
target_usernames: recipient.username,
)
end
end
@@ -331,12 +320,12 @@ after_initialize do
alias_method :existing_can_create_post?, :can_create_post?
def can_create_post?(parent)
return true if SiteSetting.discourse_narrative_bot_enabled &&
parent.try(:subtype) == "system_message" &&
parent.try(:user) == ::DiscourseNarrativeBot::Base.new.discobot_user
if SiteSetting.discourse_narrative_bot_enabled && parent.try(:subtype) == "system_message" &&
parent.try(:user) == ::DiscourseNarrativeBot::Base.new.discobot_user
return true
end
existing_can_create_post?(parent)
end
end
end

View File

@@ -1,28 +1,28 @@
# frozen_string_literal: true
RSpec.describe DiscourseNarrativeBot::Store do
describe '.set' do
it 'should set the right value in the plugin store' do
key = 'somekey'
described_class.set(key, 'yay')
describe ".set" do
it "should set the right value in the plugin store" do
key = "somekey"
described_class.set(key, "yay")
plugin_store_row = PluginStoreRow.last
expect(plugin_store_row.value).to eq('yay')
expect(plugin_store_row.value).to eq("yay")
expect(plugin_store_row.plugin_name).to eq(DiscourseNarrativeBot::PLUGIN_NAME)
expect(plugin_store_row.key).to eq(key)
end
end
describe '.get' do
it 'should get the right value from the plugin store' do
describe ".get" do
it "should get the right value from the plugin store" do
PluginStoreRow.create!(
plugin_name: DiscourseNarrativeBot::PLUGIN_NAME,
key: 'somekey',
value: 'yay',
type_name: 'string'
key: "somekey",
value: "yay",
type_name: "string",
)
expect(described_class.get('somekey')).to eq('yay')
expect(described_class.get("somekey")).to eq("yay")
end
end
end

View File

@@ -5,13 +5,16 @@ RSpec.describe Jobs::DiscourseNarrativeBot::GrantBadges do
let(:other_user) { Fabricate(:user) }
before do
DiscourseNarrativeBot::Store.set(user.id, completed: [
DiscourseNarrativeBot::NewUserNarrative.to_s,
DiscourseNarrativeBot::AdvancedUserNarrative.to_s
])
DiscourseNarrativeBot::Store.set(
user.id,
completed: [
DiscourseNarrativeBot::NewUserNarrative.to_s,
DiscourseNarrativeBot::AdvancedUserNarrative.to_s,
],
)
end
it 'should grant the right badges' do
it "should grant the right badges" do
described_class.new.execute_onceoff({})
expect(user.badges.count).to eq(2)

View File

@@ -3,14 +3,17 @@
RSpec.describe Jobs::DiscourseNarrativeBot::RemapOldBotImages do
context "when bot's post contains an old link" do
let!(:post) do
Fabricate(:post,
Fabricate(
:post,
user: ::DiscourseNarrativeBot::Base.new.discobot_user,
raw: 'If youd 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!'
raw:
'If youd 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 youd 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!'
it "should remap the links correctly" do
expected_raw =
'If youd 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({})
@@ -19,19 +22,21 @@ RSpec.describe Jobs::DiscourseNarrativeBot::RemapOldBotImages do
end
end
context 'with subfolder' do
context "with subfolder" do
let!(:post) do
Fabricate(:post,
Fabricate(
:post,
user: ::DiscourseNarrativeBot::Base.new.discobot_user,
raw: 'If youd 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!'
raw:
'If youd 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
it "should remap the links correctly" do
described_class.new.execute_onceoff({})
expect(post.reload.raw).to eq(
'If youd 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!'
'If youd 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

View File

@@ -3,42 +3,51 @@
RSpec.describe Jobs::SendDefaultWelcomeMessage do
let(:user) { Fabricate(:user) }
it 'should send the right welcome message' do
it "should send the right welcome message" do
described_class.new.execute(user_id: user.id)
topic = Topic.last
expect(topic.title).to eq(I18n.t(
"system_messages.welcome_user.subject_template",
site_name: SiteSetting.title
))
expect(topic.title).to eq(
I18n.t("system_messages.welcome_user.subject_template", site_name: SiteSetting.title),
)
expect(topic.first_post.raw).to eq(I18n.t(
"system_messages.welcome_user.text_body_template",
SystemMessage.new(user).defaults
).chomp)
expect(topic.first_post.raw).to eq(
I18n.t(
"system_messages.welcome_user.text_body_template",
SystemMessage.new(user).defaults,
).chomp,
)
expect(topic.closed).to eq(true)
end
describe 'for an invited user' do
let(:invite) { Fabricate(:invite, email: 'foo@bar.com') }
let(:invited_user) { Fabricate(:invited_user, invite: invite, user: Fabricate(:user, email: 'foo@bar.com'), redeemed_at: Time.zone.now) }
describe "for an invited user" do
let(:invite) { Fabricate(:invite, email: "foo@bar.com") }
let(:invited_user) do
Fabricate(
:invited_user,
invite: invite,
user: Fabricate(:user, email: "foo@bar.com"),
redeemed_at: Time.zone.now,
)
end
it 'should send the right welcome message' do
it "should send the right welcome message" do
described_class.new.execute(user_id: invited_user.user_id)
topic = Topic.last
expect(topic.title).to eq(I18n.t(
"system_messages.welcome_invite.subject_template",
site_name: SiteSetting.title
))
expect(topic.title).to eq(
I18n.t("system_messages.welcome_invite.subject_template", site_name: SiteSetting.title),
)
expect(topic.first_post.raw).to eq(I18n.t(
"system_messages.welcome_invite.text_body_template",
SystemMessage.new(invited_user.user).defaults
).chomp)
expect(topic.first_post.raw).to eq(
I18n.t(
"system_messages.welcome_invite.text_body_template",
SystemMessage.new(invited_user.user).defaults,
).chomp,
)
expect(topic.closed).to eq(true)
end

View File

@@ -2,24 +2,21 @@
RSpec.describe DiscourseNarrativeBot::CertificateGenerator do
let(:user) { Fabricate(:user) }
let(:avatar_url) { 'http://test.localhost/cdn/avatar.png' }
let(:avatar_url) { "http://test.localhost/cdn/avatar.png" }
let(:date) { "2017-00-10" }
describe 'when an invalid date is given' do
it 'should default to the current date' do
describe "when an invalid date is given" do
it "should default to the current date" do
expect { described_class.new(user, date, avatar_url) }.to_not raise_error
end
end
describe '#logo_group' do
describe 'when SiteSetting.site_logo_small_url is blank' do
before do
SiteSetting.logo_small = ''
end
describe "#logo_group" do
describe "when SiteSetting.site_logo_small_url is blank" do
before { SiteSetting.logo_small = "" }
it 'should not try to fetch a image' do
expect(described_class.new(user, date, avatar_url).send(:logo_group, 1, 1, 1))
.to eq(nil)
it "should not try to fetch a image" do
expect(described_class.new(user, date, avatar_url).send(:logo_group, 1, 1, 1)).to eq(nil)
end
end
end

View File

@@ -1,48 +1,43 @@
# frozen_string_literal: true
RSpec.describe "Discobot Certificate" do
let(:user) { Fabricate(:user, name: 'Jeff Atwood') }
let(:user) { Fabricate(:user, name: "Jeff Atwood") }
let(:params) {
{
date: Time.zone.now.strftime("%b %d %Y"),
user_id: user.id
}
}
let(:params) { { date: Time.zone.now.strftime("%b %d %Y"), user_id: user.id } }
describe 'when viewing the certificate' do
describe 'when no logged in' do
it 'should return the right response' do
get '/discobot/certificate.svg', params: params
describe "when viewing the certificate" do
describe "when no logged in" do
it "should return the right response" do
get "/discobot/certificate.svg", params: params
expect(response.status).to eq(404)
end
end
describe 'when logged in' do
before do
sign_in(user)
end
describe "when logged in" do
before { sign_in(user) }
it 'should return the right text' do
stub_request(:get, /letter_avatar_proxy/).to_return(status: 200, body: 'http://test.localhost/cdn/avatar.png')
it "should return the right text" do
stub_request(:get, /letter_avatar_proxy/).to_return(
status: 200,
body: "http://test.localhost/cdn/avatar.png",
)
stub_request(:get, /avatar.png/).to_return(status: 200)
stub_request(:get, SiteSetting.site_logo_small_url)
.to_return(status: 200)
stub_request(:get, SiteSetting.site_logo_small_url).to_return(status: 200)
get '/discobot/certificate.svg', params: params
get "/discobot/certificate.svg", params: params
expect(response.status).to eq(200)
expect(response.body).to include('<svg')
expect(response.body).to include(user.avatar_template.gsub('{size}', '250'))
expect(response.body).to include("<svg")
expect(response.body).to include(user.avatar_template.gsub("{size}", "250"))
expect(response.body).to include(SiteSetting.site_logo_small_url)
end
describe 'when params are missing' do
describe "when params are missing" do
it "should raise the right errors" do
params.each do |key, _|
get '/discobot/certificate.svg', params: params.except(key)
get "/discobot/certificate.svg", params: params.except(key)
expect(response.status).to eq(400)
end
end

View File

@@ -3,40 +3,39 @@
RSpec.describe "Discobot welcome post" do
let(:user) { Fabricate(:user) }
before do
SiteSetting.discourse_narrative_bot_enabled = true
end
before { SiteSetting.discourse_narrative_bot_enabled = true }
context 'when discourse_narrative_bot_welcome_post_delay is 0' do
it 'should not delay the welcome post' do
context "when discourse_narrative_bot_welcome_post_delay is 0" do
it "should not delay the welcome post" do
user
expect { sign_in(user) }.to_not change { Jobs::NarrativeInit.jobs.count }
end
end
context 'when discourse_narrative_bot_welcome_post_delay is greater than 0' do
before do
SiteSetting.discourse_narrative_bot_welcome_post_delay = 5
end
context "when discourse_narrative_bot_welcome_post_delay is greater than 0" do
before { SiteSetting.discourse_narrative_bot_welcome_post_delay = 5 }
context 'when user logs in normally' do
it 'should delay the welcome post until user logs in' do
context "when user logs in normally" do
it "should delay the welcome post until user logs in" do
expect { sign_in(user) }.to change { Jobs::NarrativeInit.jobs.count }.by(1)
expect(Jobs::NarrativeInit.jobs.first["args"].first["user_id"]).to eq(user.id)
end
end
context 'when user redeems an invite' do
let!(:invite) { Fabricate(:invite, invited_by: Fabricate(:admin), email: 'testing@gmail.com') }
context "when user redeems an invite" do
let!(:invite) do
Fabricate(:invite, invited_by: Fabricate(:admin), email: "testing@gmail.com")
end
it 'should delay the welcome post until the user logs in' do
it "should delay the welcome post until the user logs in" do
expect do
put "/invites/show/#{invite.invite_key}.json", params: {
username: 'somename',
name: 'testing',
password: 'verystrongpassword',
email_token: invite.email_token
}
put "/invites/show/#{invite.invite_key}.json",
params: {
username: "somename",
name: "testing",
password: "verystrongpassword",
email_token: invite.email_token,
}
end.to change { User.count }.by(1)
expect(Jobs::NarrativeInit.jobs.first["args"].first["user_id"]).to eq(User.last.id)
@@ -44,14 +43,12 @@ RSpec.describe "Discobot welcome post" do
end
end
context 'when user is staged' do
context "when user is staged" do
let(:staged_user) { Fabricate(:user, staged: true) }
before do
SiteSetting.discourse_narrative_bot_welcome_post_type = 'welcome_message'
end
before { SiteSetting.discourse_narrative_bot_welcome_post_type = "welcome_message" }
it 'should not send welcome message' do
it "should not send welcome message" do
expect { staged_user }.to_not change { Jobs::SendDefaultWelcomeMessage.jobs.count }
end
end

View File

@@ -18,79 +18,76 @@ RSpec.describe User do
SiteSetting.discourse_narrative_bot_enabled = true
end
describe 'when a user is created' do
it 'should initiate the bot' do
describe "when a user is created" do
it "should initiate the bot" do
NotificationEmailer.expects(:process_notification).never
user
expected_raw = i18n_t('discourse_narrative_bot.new_user_narrative.hello.message',
username: user.username, title: SiteSetting.title
)
expected_raw =
i18n_t(
"discourse_narrative_bot.new_user_narrative.hello.message",
username: user.username,
title: SiteSetting.title,
)
expect(Post.last.raw).to include(expected_raw.chomp)
end
describe 'welcome post' do
context 'when disabled' do
before do
SiteSetting.disable_discourse_narrative_bot_welcome_post = true
end
describe "welcome post" do
context "when disabled" do
before { SiteSetting.disable_discourse_narrative_bot_welcome_post = true }
it 'should not initiate the bot' do
it "should not initiate the bot" do
expect { user }.to_not change { Post.count }
end
end
context 'with title emoji disabled' do
context "with title emoji disabled" do
before do
SiteSetting.disable_discourse_narrative_bot_welcome_post = false
SiteSetting.max_emojis_in_title = 0
end
it 'initiates the bot' do
it "initiates the bot" do
expect { user }.to change { Topic.count }.by(1)
expect(Topic.last.title).to eq(i18n_t(
'discourse_narrative_bot.new_user_narrative.hello.title'
).gsub(/:robot:/, '').strip)
expect(Topic.last.title).to eq(
i18n_t("discourse_narrative_bot.new_user_narrative.hello.title").gsub(
/:robot:/,
"",
).strip,
)
end
end
context 'when enabled' do
before do
SiteSetting.disable_discourse_narrative_bot_welcome_post = false
end
context "when enabled" do
before { SiteSetting.disable_discourse_narrative_bot_welcome_post = false }
it 'initiate the bot' do
it "initiate the bot" do
expect { user }.to change { Topic.count }.by(1)
expect(Topic.last.title).to eq(i18n_t(
'discourse_narrative_bot.new_user_narrative.hello.title'
))
expect(Topic.last.title).to eq(
i18n_t("discourse_narrative_bot.new_user_narrative.hello.title"),
)
end
describe "when send welcome message is selected" do
before do
SiteSetting.discourse_narrative_bot_welcome_post_type = 'welcome_message'
end
before { SiteSetting.discourse_narrative_bot_welcome_post_type = "welcome_message" }
it 'should send the right welcome message' do
it "should send the right welcome message" do
expect { user }.to change { Topic.count }.by(1)
expect(Topic.last.title).to eq(i18n_t(
"system_messages.welcome_user.subject_template",
site_name: SiteSetting.title
))
expect(Topic.last.title).to eq(
i18n_t("system_messages.welcome_user.subject_template", site_name: SiteSetting.title),
)
end
end
describe 'when welcome message is configured to be delayed' do
before do
SiteSetting.discourse_narrative_bot_welcome_post_delay = 100
end
describe "when welcome message is configured to be delayed" do
before { SiteSetting.discourse_narrative_bot_welcome_post_delay = 100 }
it 'should delay the welcome post until user logs in' do
it "should delay the welcome post until user logs in" do
user
expect(Jobs::NarrativeInit.jobs.count).to eq(0)
@@ -99,41 +96,37 @@ RSpec.describe User do
end
end
context 'when user is staged' do
context "when user is staged" do
let(:user) { Fabricate(:user, staged: true) }
it 'should not initiate the bot' do
it "should not initiate the bot" do
expect { user }.to_not change { Post.count }
end
end
context 'when user skipped the new user tips' do
context "when user skipped the new user tips" do
let(:user) { Fabricate(:user) }
it 'should not initiate the bot' do
it "should not initiate the bot" do
SiteSetting.default_other_skip_new_user_tips = true
expect { user }.to_not change { Post.count }
end
it 'should delete the existing PM' do
it "should delete the existing PM" do
user.user_option.skip_new_user_tips = true
expect {
user.user_option.save!
}.to change { Topic.count }.by(-1)
.and not_change { UserHistory.count }
.and change { user.unread_high_priority_notifications }.by(-1)
.and change { user.notifications.count }.by(-1)
expect { user.user_option.save! }.to change { Topic.count }.by(-1).and not_change {
UserHistory.count
}.and change { user.unread_high_priority_notifications }.by(-1).and change {
user.notifications.count
}.by(-1)
end
end
context 'when user is anonymous?' do
before do
SiteSetting.allow_anonymous_posting = true
end
it 'should initiate bot for real user only' do
context "when user is anonymous?" do
before { SiteSetting.allow_anonymous_posting = true }
it "should initiate bot for real user only" do
user = Fabricate(:user, trust_level: 1)
shadow = AnonymousShadowCreator.get(user)
@@ -145,21 +138,19 @@ RSpec.describe User do
context "when user's username should be ignored" do
let(:user) { Fabricate.build(:user) }
before do
SiteSetting.discourse_narrative_bot_ignored_usernames = 'discourse|test'
end
before { SiteSetting.discourse_narrative_bot_ignored_usernames = "discourse|test" }
['discourse', 'test'].each do |username|
it 'should not initiate the bot' do
%w[discourse test].each do |username|
it "should not initiate the bot" do
expect { user.update!(username: username) }.to_not change { Post.count }
end
end
end
end
describe 'when a user has been destroyed' do
describe "when a user has been destroyed" do
it "should clean up plugin's store" do
DiscourseNarrativeBot::Store.set(user.id, 'test')
DiscourseNarrativeBot::Store.set(user.id, "test")
user.destroy!
@@ -167,8 +158,8 @@ RSpec.describe User do
end
end
describe '#manually_disabled_discobot?' do
it 'returns true if the user manually disabled new user tips' do
describe "#manually_disabled_discobot?" do
it "returns true if the user manually disabled new user tips" do
user.user_option.skip_new_user_tips = true
expect(user.manually_disabled_discobot?).to eq(true)