FIX - make Discobot new user tutorial a little more robust (#10497)

* FIX - make Discobot new user tutorial a little more robust

Plugin allows reply, regardless of other SiteSettings

Skip image upload step if user can’t upload images, calls new ‘likes’ step instead

* Test that the images step is skipped

* Slight optimization
This commit is contained in:
jbrw 2020-08-21 13:13:13 -04:00 committed by GitHub
parent 0f63a61fa4
commit aa815e41e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 199 additions and 7 deletions

View File

@ -201,12 +201,24 @@ en:
like_not_found: |- like_not_found: |-
Did you forget to like :heart: my [post?](%{url}) :crying_cat_face: Did you forget to like :heart: my [post?](%{url}) :crying_cat_face:
not_found: |- not_found: |-
Looks like you didnt upload an image so Ive choosen a picture that Im _sure_ you will enjoy. Looks like you didnt upload an image so Ive chosen a picture that Im _sure_ you will enjoy.
`%{image_url}` `%{image_url}`
Try uploading that one next, or pasting the link in on a line by itself! Try uploading that one next, or pasting the link in on a line by itself!
likes:
instructions: |-
Heres a picture of a unicorn:
<img src="%{base_uri}/plugins/discourse-narrative-bot/images/unicorn.png" width="520" height="520">
If you like it (and who wouldnt!) go ahead and press the like :heart: button below this post to let me know.
reply: |-
Thanks for liking my post!
not_found: |-
Did you forget to like :heart: my [post?](%{url}) :crying_cat_face:
formatting: formatting:
instructions: |- instructions: |-
Can you make some words **bold** or _italic_ in your reply? Can you make some words **bold** or _italic_ in your reply?

View File

@ -80,7 +80,22 @@ module DiscourseNarrativeBot
} }
}, },
# Note: tutorial_images and tutorial_likes are mutually exclusive.
# The prerequisites should ensure only one of them is called.
tutorial_images: { tutorial_images: {
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_uri) },
reply: {
action: :reply_to_image
},
like: {
action: :track_images_like
}
},
tutorial_likes: {
prerequisite: Proc.new { !@user.has_trust_level?(SiteSetting.min_trust_to_post_embedded_media) },
next_state: :tutorial_flag, next_state: :tutorial_flag,
next_instructions: Proc.new { next_instructions: Proc.new {
I18n.t("#{I18N_KEY}.flag.instructions", I18n.t("#{I18N_KEY}.flag.instructions",
@ -88,11 +103,12 @@ module DiscourseNarrativeBot
about_url: url_helpers(:about_index_url), about_url: url_helpers(:about_index_url),
base_uri: Discourse.base_uri) base_uri: Discourse.base_uri)
}, },
reply: {
action: :reply_to_image
},
like: { like: {
action: :track_like action: :reply_to_likes
},
reply: {
next_state: :tutorial_likes,
action: :missing_likes_like
} }
}, },
@ -278,11 +294,11 @@ module DiscourseNarrativeBot
end end
end end
def track_like def track_images_like
post_topic_id = @post.topic_id post_topic_id = @post.topic_id
return unless valid_topic?(post_topic_id) return unless valid_topic?(post_topic_id)
post_liked = PostAction.find_by( post_liked = PostAction.exists?(
post_action_type_id: PostActionType.types[:like], post_action_type_id: PostActionType.types[:like],
post_id: @data[:last_post_id], post_id: @data[:last_post_id],
user_id: @user.id user_id: @user.id
@ -362,6 +378,45 @@ module DiscourseNarrativeBot
transition ? reply : false transition ? reply : false
end end
def missing_likes_like
return unless valid_topic?(@post.topic_id)
return if @post.user_id == self.discobot_user.id
fake_delay
enqueue_timeout_job(@user)
last_post = Post.find_by(id: @data[:last_post_id])
reply_to(@post, I18n.t("#{I18N_KEY}.likes.not_found", i18n_post_args(url: last_post.url)))
false
end
def reply_to_likes
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
)
if post_liked
raw = <<~RAW
#{I18n.t("#{I18N_KEY}.likes.reply", i18n_post_args)}
#{instance_eval(&@next_instructions)}
RAW
fake_delay
reply = reply_to(@post, raw)
enqueue_timeout_job(@user)
return reply
end
false
end
def reply_to_formatting def reply_to_formatting
post_topic_id = @post.topic_id post_topic_id = @post.topic_id
return unless valid_topic?(post_topic_id) return unless valid_topic?(post_topic_id)

View File

@ -300,4 +300,17 @@ after_initialize do
DiscourseNarrativeBot::BOT_USER_ID, DiscourseNarrativeBot::BOT_USER_ID,
"discobot@discourse.org" "discobot@discourse.org"
) )
PostGuardian.class_eval 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
existing_can_create_post?(parent)
end
end
end end

View File

@ -542,6 +542,101 @@ describe DiscourseNarrativeBot::NewUserNarrative do
end end
end end
describe 'likes tutorial' do
let(:post_2) { Fabricate(:post, topic: topic) }
before do
narrative.set_data(user,
state: :tutorial_likes,
topic_id: topic.id,
last_post_id: post_2.id,
track: described_class.to_s
)
end
describe 'when post is not in the right topic' do
it 'should not do anything' do
other_post
narrative.expects(:enqueue_timeout_job).with(user).never
expect { narrative.input(:reply, user, post: other_post) }.to_not change { Post.count }
expect(narrative.get_data(user)[:state].to_sym).to eq(:tutorial_likes)
end
end
describe 'when user replies to the topic' do
describe 'when reply contains the skip trigger' do
it 'should create the right reply' do
post.update!(raw: skip_trigger)
described_class.any_instance.expects(:enqueue_timeout_job).with(user)
DiscourseNarrativeBot::TrackSelector.new(:reply, user, post_id: post.id).select
new_post = Post.last
expect(new_post.raw).to eq(I18n.t(
'discourse_narrative_bot.new_user_narrative.flag.instructions',
guidelines_url: Discourse.base_url + '/guidelines',
about_url: Discourse.base_url + '/about',
base_uri: ''
))
expect(narrative.get_data(user)[:state].to_sym).to eq(:tutorial_flag)
end
describe 'when allow_flagging_staff is false' do
it 'should go to the right state' do
SiteSetting.allow_flagging_staff = false
post.update!(raw: skip_trigger)
DiscourseNarrativeBot::TrackSelector.new(
:reply,
user,
post_id: post.id
).select
expect(narrative.get_data(user)[:state].to_sym)
.to eq(:tutorial_search)
end
end
end
it 'should create the right reply' do
narrative.expects(:enqueue_timeout_job).with(user).once
narrative.input(:reply, user, post: post)
new_post = Post.last
expect(new_post.raw).to eq(I18n.t(
'discourse_narrative_bot.new_user_narrative.likes.not_found',
url: post_2.url, base_uri: ''
))
expect(narrative.get_data(user)[:state].to_sym).to eq(:tutorial_likes)
end
end
describe 'when the post is liked' do
it 'should create the right reply' do
PostActionCreator.like(user, post_2)
expected_raw = <<~RAW
#{I18n.t("discourse_narrative_bot.new_user_narrative.likes.reply")}
#{I18n.t(
'discourse_narrative_bot.new_user_narrative.flag.instructions',
guidelines_url: "#{Discourse.base_url}/guidelines",
about_url: "#{Discourse.base_url}/about",
base_uri: ''
)}
RAW
expect(Post.last.raw).to eq(expected_raw.chomp)
expect(narrative.get_data(user)[:state].to_sym).to eq(:tutorial_flag)
end
end
end
describe 'fomatting tutorial' do describe 'fomatting tutorial' do
before do before do
narrative.set_data(user, state: :tutorial_formatting, topic_id: topic.id) narrative.set_data(user, state: :tutorial_formatting, topic_id: topic.id)
@ -662,6 +757,23 @@ describe DiscourseNarrativeBot::NewUserNarrative do
end end
end end
describe 'when min_trust_to_post_embedded_media is too high' do
before do
SiteSetting.min_trust_to_post_embedded_media = 4
end
it 'should skip the images tutorial step' do
post.update!(
raw: "[quote=\"#{post.user}, post:#{post.post_number}, topic:#{topic.id}\"]\n:monkey: :fries:\n[/quote]"
)
narrative.expects(:enqueue_timeout_job).with(user)
narrative.input(:reply, user, post: post)
expect(narrative.get_data(user)[:state].to_sym).to eq(:tutorial_likes)
end
end
it 'should create the right reply' do it 'should create the right reply' do
post.update!( post.update!(
raw: "[quote=\"#{post.user}, post:#{post.post_number}, topic:#{topic.id}\"]\n:monkey: :fries:\n[/quote]" raw: "[quote=\"#{post.user}, post:#{post.post_number}, topic:#{topic.id}\"]\n:monkey: :fries:\n[/quote]"