Imported private discussion doesn't appear in the author inbox

Hi, I’m trying to import private messages from a vBulletin5 database.

It works, but in the author profile the discussion only appears in “sent”, not in “inbox”.

On the other participant profile, the discussion correctly appears in “inbox” as well as in “sent”.

Author profile:
Appears in “sent”

But not in “inbox”

Other participant profile:
Appears in both:

How can I make the discussion appears in the inbox of the author?

My current messy code if necessary

  def import_pm
    puts "", "importing topics PMs..."

    pms_count = mysql_query("SELECT COUNT(nodeid) cnt, starter
        FROM #{DB_PREFIX}node
        WHERE (unpublishdate = 0 OR unpublishdate IS NULL)
        AND (approved = 1 AND showapproved = 1)    
          AND starter = 2676436
        AND contenttypeid=#{@pm};"
    ).first["cnt"]

    batches(BATCH_SIZE) do |offset|
      pms = mysql_query <<-SQL
        SELECT pm.nodeid AS pmid, pm.starter, pm.title, pm.parentid AS parentid,pm.open,pm.userid AS postuserid,pm.publishdate AS dateline,
            nv.count views, 1 AS visible, pm.sticky,
            CONVERT(CAST(rawtext AS BINARY)USING utf8) AS raw
        FROM #{DB_PREFIX}node pm
        LEFT JOIN #{DB_PREFIX}nodeview nv ON nv.nodeid=pm.nodeid
        LEFT JOIN #{DB_PREFIX}text txt ON txt.nodeid=pm.nodeid
        WHERE
          pm.contenttypeid = #{@pm}
          AND (pm.unpublishdate = 0 OR pm.unpublishdate IS NULL)
          AND pm.approved = 1 AND pm.showapproved = 1
          AND pm.starter = 2676436
        ORDER BY pm.nodeid
          LIMIT #{BATCH_SIZE}
          OFFSET #{offset}
      SQL

      break if pms.size < 1

      create_posts(pms, total: pms_count, offset: 0) do |pm|
        p = {}

        p[:id] = "pm-#{pm['pmid']}"
        p[:user_id] = user_id_from_imported_user_id(pm['postuserid']) || Discourse::SYSTEM_USER_ID
        p[:raw] = preprocess_post_raw(pm['raw']) rescue nil
        p[:created_at] = parse_timestamp(pm["dateline"]),

        topic_id = nil

        next if p[:raw].blank?

        # if first post
        if pm['parentid'] == 8 
          #next unless post = topic_lookup_from_imported_post_id("pm-#{pm["pmid"]}")

          target_usernames = []
          target_userids = []
          # get user list
          userlist = mysql_query("select distinct userid from sentto where nodeid = #{pm["starter"]}")
          userlist.each do |user|
            userid = user_id_from_imported_user_id(user["userid"]) || Discourse::SYSTEM_USER_ID;
            target_userids << userid || Discourse::SYSTEM_USER_ID
            target_usernames << User.find_by(id: userid).try(:username) || "system"
          end

          participants = target_userids
          begin
            participants.sort!
          rescue
            puts "one of the participant's id is nil -- #{participants.inspect}"
          end

          p[:title] = @htmlentities.decode(pm['title']).strip[0...255]
          p[:archetype] = Archetype.private_message
          p[:target_usernames] = target_usernames.join(',')

          if p[:target_usernames].size < 1 # pm with yourself?
            # skip = true
            p[:target_usernames] = "system"
            puts "pm-#{pm['nodeid']} has no target"
          end
        # if not first post
        else
          next unless topic = topic_lookup_from_imported_post_id("pm-#{pm["starter"]}")
          p[:topic_id] = topic[:topic_id]

        end
        puts "post : #{p}\n"
        p
      end
    end
    exit
  end

From data explorer, I noticed that the participant_count value is wrong:

It’s written 1, but there are two people in the conversation.
If I update the topic’s field participant_count to 2 like this:

Topic.find_by(id: 218613).update(participant_count: 2)

the topic now appears in the author’s inbox:

I didn’t notice this behavior by updating other fields like reply_count for example, so it seems specific to participant_count and maybe other fields.

In my import script, I tried adding this:

p[:participant_count] = target_usernames.count

But it didn’t work, I guess we can’t set this field in the importers’ methods.

So I’m a bit stuck here. I’d like my users to have all their PMs with replies in their inbox, not only those that they didn’t start themselves.

Any idea?

1 Like

Any thoughts on this @kris.kotlarek?

1 Like

Thank you for mentioning that bug. I checked it myself and you are right - when participant_count is incorrect, then message is not visible in message’s author inbox.

Also, you are right that even if you explicitly add that param to create_posts - it is not set correctly.

This is because TopicCreate has explicit list of allowed params:
https://github.com/discourse/discourse/blob/master/lib/topic_creator.rb#L91:L131

Today I will create a PR to Discourse to accept that attribute in import mode.

In the meantime, to not wait for latest version of Discourse, you can run at the very end of your script

Topic.private_messages.map(&:update_statistics) - this should correct all numbers

5 Likes

PR is ready - https://github.com/discourse/discourse/pull/10632

Once merged and deployed you will be able to use it like:

create_posts(pms, total: pms_count, offset: 0) do |pm|
...
  p[:topic_opts][:participant_count] = target_usernames.count 
...
end

It has to be under [:topic_opts] because create_posts method is evaluating post_creator which triggers topic_creator

https://github.com/discourse/discourse/blob/master/lib/post_creator.rb#L56

3 Likes