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

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

diff --git a/plugins/discourse-narrative-bot/config/locales/server.en.yml b/plugins/discourse-narrative-bot/config/locales/server.en.yml
index 6bd0bb2..5715ca4 100644
--- a/plugins/discourse-narrative-bot/config/locales/server.en.yml
+++ b/plugins/discourse-narrative-bot/config/locales/server.en.yml
@@ -201,12 +201,24 @@ en:
         like_not_found: |-
           Did you forget to like :heart: my [post?](%{url}) :crying_cat_face:
         not_found: |-
-          Looks like you didn’t upload an image so I’ve choosen a picture that I’m _sure_ you will enjoy.
+          Looks like you didn’t upload an image so I’ve chosen a picture that I’m _sure_ you will enjoy.
 
           `%{image_url}`
 
           Try uploading that one next, or pasting the link in on a line by itself!
 
+      likes:
+        instructions: |-
+          Here’s 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 wouldn’t!) 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:
         instructions: |-
           Can you make some words **bold** or _italic_ in your reply?
diff --git a/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/new_user_narrative.rb b/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/new_user_narrative.rb
index 8a9ed39..86ca941 100644
--- a/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/new_user_narrative.rb
+++ b/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/new_user_narrative.rb
@@ -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: {
+        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_instructions: Proc.new {
           I18n.t("#{I18N_KEY}.flag.instructions",
@@ -88,11 +103,12 @@ module DiscourseNarrativeBot
             about_url: url_helpers(:about_index_url),
             base_uri: Discourse.base_uri)
         },
-        reply: {
-          action: :reply_to_image
-        },
         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
 
-    def track_like
+    def track_images_like
       post_topic_id = @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_id: @data[:last_post_id],
         user_id: @user.id
@@ -362,6 +378,45 @@ module DiscourseNarrativeBot
       transition ? reply : false
     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
       post_topic_id = @post.topic_id
       return unless valid_topic?(post_topic_id)
diff --git a/plugins/discourse-narrative-bot/plugin.rb b/plugins/discourse-narrative-bot/plugin.rb
index 9efcd7a..b37e0a5 100644
--- a/plugins/discourse-narrative-bot/plugin.rb
+++ b/plugins/discourse-narrative-bot/plugin.rb
@@ -300,4 +300,17 @@ after_initialize do
     DiscourseNarrativeBot::BOT_USER_ID,
     "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
diff --git a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb
index 89d644c..f67f58c 100644
--- a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb
+++ b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb
@@ -542,6 +542,101 @@ describe DiscourseNarrativeBot::NewUserNarrative do
       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

[... diff too long, it was truncated ...]

GitHub sha: aa815e41

1 Like

This commit appears in #10497 which was merged by jbrw.

@jamiew I had another look at this and I don’t think discobot topics are created as the system_message subtytpe. I tested it locally and it came back as the user_to_user subtype. Maybe the right fix is for can_create_post? to always allow it if the user is in a pm with a non-human user and the topic’s subtype is not a system_message.

1 Like