Display Group Badge On Topic List?

Plugin Development
  • @baris Thank you for this. I can now see the groups variable for users listed on the topics page. I do have a follow up question. Is there a way for us to access all posts (including users) in a topic from the topics page? Our goal is to dynamically place a badge under the topic title to indicate that a dev had posted/replied in the topic.

  • @Teemberland For this you can use the sorted set tid:<tid>:posters it contains all uids who have posted in the topic (including the OP) and the score is the number of posts they have in that topic. So you need to grab the uids from this sorted set and check if any of the uids are in a dev group.

  • @baris great! I'll give this one a shot!

  • @baris thank you for your suggestion. I can get the posters now, but I'm not able to get their groups. Here's my code. Can you tell me what I'm missing here?

    var db = require.main.require('./src/database');
    
    theme.filterTopicsGetDevActivity = async function(hookData) {
      hookData.topics.forEach((t, i) => {
        db.getSortedSetRange('tid:' + t.tid + ':posters', 0, -1, function (err, uids) {
          t.foobar = uids;
        });
      });
      return hookData;
    }
    

    Here's my hook:

    {
      "hook": "filter:topics.get",
      "method": "filterTopicsGetDevActivity"
     }
    

    My template:

    <!-- IF topics.foobar.length -->
      <!-- BEGIN topics.foobar -->
        {topics.foobar}
      <!-- END topics.foobar -->
    <!-- ENDIF topics.foobar.length -->
    

    I tried using {topics.foobar.groups.slug} to display the group name, but the object becomes empty.

    0C69C8F1-2645-4727-9FAF-1FB311D185AF.png

  • Your code is only getting the uids who have posted in the topic it is not loading any group data. It is also loading the uids in a foreach which won't work as you expect it. You need to use promises and assign the data once the call is complete.

    You want something like below, adjust as necessary.

    myPlugin.filterTopicsGet = async function (hookData) {
      const groupData = hookData.topics.map(async (t) => {
           const uids = await db.getSortedSetMembers('tid:' + t.tid + ':posters'));
           const userGroups = await Groups.getUserGroupMembership('groups:createtime', uids);       
           return userGroups.flat().includes('My developer group');
      });
    
      hookData.topics.forEach((t, i) => {
          t.postedInByDeveloper = groupData[i];
      });
      return hookData;
    };
    
  • @baris thank you! I think we're very close. When I call postedInByDeveloper in my template {topics.postedInByDeveloper} I get an [object Promise] in view.

    I also tried making an api call in the console to check the object and found that postedInByDeveloper is empty. See screenshot below.

    Screen Shot 2020-07-07 at 14.27.20 PM.png

  • I was writing the code of the top of my head so it had errors, this should work I think.

    myPlugin.filterTopicsGet = async function (hookData) {
      const groupData = await Promise.all(hookData.topics.map(async (t) => {
           const uids = await db.getSortedSetMembers('tid:' + t.tid + ':posters');
           const userGroups = await Groups.getUserGroupMembership('groups:createtime', uids);       
           return userGroups.flat().includes('My developer group');
      }));
    
      hookData.topics.forEach((t, i) => {
          t.postedInByDeveloper = groupData[i];
      });
      return hookData;
    };
    
  • @baris I had to update to 1.14.x to get access to getSortedSetMember. I didn't know that this method was new. Also, I had to use a different method for flat() since I'm on the older version of node locally.

    Thank you once again for all your help!

  • patsanchP patsanch referenced this topic on
  • @Teemberland @patsanch I've rewritten the above filter to use less database calls. You can give it a try as well if you don't want to add new hooks from the referenced topic.

    myPlugin.filterTopicsGet = async function (hookData) {
    	const tids = hookData.topics.map(t => t && t.tid);
    	const posterUids = await db.getSortedSetsMembers(tids.map(tid => `tid:${tid}:posters`));
    	const uids = _.uniq(_.flatten(posterUids));
    	const isMembers = await Groups.isMembers(uids, 'My developer group');
    	const membershipMap = _.zipObject(uids, isMembers);
    	hookData.topics.forEach((t, i) => {
    		t.postedInByDeveloper = posterUids[i].some(uid => membershipMap[uid]);
    	});
    	return hookData;
    };
    

    This runs a lot faster since it's only making 2 database calls.

    before 
    took 975.6332 milliseconds
    took 922.0847 milliseconds
    took 819.809 milliseconds
    
    after
    took 3.9381 milliseconds
    took 3.8666 milliseconds
    took 3.1888 milliseconds
    
  • Thanks baris! We'll keep this for reference πŸ™‚


Suggested Topics