# Creating a User - Tag relation plugin

**URL:** https://meta.discourse.org/t/creating-a-user-tag-relation-plugin/235208
**Category:** Development
**Created:** [August 5, 2022, 10:02am UTC](https://meta.discourse.org/t/creating-a-user-tag-relation-plugin/235208 "2022-08-05T10:02:14Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![attj](https://avatars.discourse-cdn.com/v4/letter/a/a698b9/32.png) [@attj](https://meta.discourse.org/u/attj)
#### Post date: [August 5, 2022, 10:02am UTC](https://meta.discourse.org/t/creating-a-user-tag-relation-plugin/235208/1 "2022-08-05T10:02:14Z")

</div>

Hello, I am currently working on a specific plugin but couldn’t figure where to start yet (I read the introductory material here and installed some simple plugins and played with their source a bit).

**The setup:** I have a csv file that contains several usernames from the system and some tags they are related to. For example, an entry “user1, tag#1” reads: “user1 knows about tag#1”. Many users can be related to one tag and one user can be related to many tags. Moreover, this csv will be updated time to time (once almost everyday). The file is in the same server that hosts the discourse instance.

**How would the plugin ideally work:** I will explain this using an example csv and a picture.

CSV:

userOP, tag#1  
userOP, tag#2  
user2, tag#1

Given this CSV, whenever there is a topic created with any of the tags included in the CSV (The topic author might not be on the list). The ideal output should be as follows:

 ![New Project-6](https://global.discourse-cdn.com/meta/original/4X/2/7/e/27edf2181b0fbcdefcee6ccc0ccec694d54e22ad.png)

Moreover a user can see their known tags as clickable links on their user panel with an additional tab called Known Tags:

 ![Screenshot 2022-08-05 at 16.44.01](https://global.discourse-cdn.com/meta/original/4X/8/b/d/8bd4688ee86fd104efc2f38f660ee8b90b33008b.png)

Ideally, this tab should be quickly accessible by the top left menu:

 ![Screenshot 2022-08-05 at 16.45.06](https://global.discourse-cdn.com/meta/original/4X/2/2/4/2246920fe12a8dabe3f8e336ac198e8d5b8ca9ec.png)

That is, based on the relation defined in the csv, there should be small text or a badge for any user (OP or others) that posts under the topic with a tag they are related.

I am open to suggestions about how to accomplish this.

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [August 5, 2022, 10:17am UTC](https://meta.discourse.org/t/creating-a-user-tag-relation-plugin/235208/2 "2022-08-05T10:17:22Z")

</div>

One thing you’ll need to do on the rails side is add those user/tag relations to the serializer so that those data are available to the front end. Look for some other plugins that call `add_to_serializer` or search for it in the discourse source, as it’s well documented there.

Then you’ll be able to use a plugin outlet in ember to add that to the page. The theme component documentation has examples of that.

I would probably add a route to manage the custom user fields rather than use a csv file, but if you want to go the csv way, you might want a job that reads it every hour or something, so find a plugin that has something in `jobs/scheduled`.

There is a Discourse repo called `all_the_plugins` that I sometimes grep to find examples of stuff. If you wade through `github.com/discourse` you should be able to find it.

---

<div class="post-metadata">

### Author: ![attj](https://avatars.discourse-cdn.com/v4/letter/a/a698b9/32.png) [@attj](https://meta.discourse.org/u/attj)
#### Post date: [August 5, 2022, 11:46am UTC](https://meta.discourse.org/t/creating-a-user-tag-relation-plugin/235208/3 "2022-08-05T11:46:27Z")

</div>

Thank you for the information. The mental model that I have right now is, I should add a custom field to tags (like tag\_description) called attached\_users. For the above example, tag#1 should have attached\_users: [“userOP”, “user1”].

Then, I should somehow add this to the serializer and figure how to display it in the post.

While thinking about this, I had another idea. If I use discourse assign ([Discourse Assign](https://meta.discourse.org/t/discourse-assign/58044)) to assign these users to topics based on tags. I can already retrieve this information from the topic and I guess displaying it would be easier. However, discourse assign doesn’t provide any way of programmatically adding users.

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [August 5, 2022, 12:06pm UTC](https://meta.discourse.org/t/creating-a-user-tag-relation-plugin/235208/4 "2022-08-05T12:06:55Z")

</div>

Using assign seems like a good idea. I’m pretty sure that you could add users with the API. See [How to reverse engineer the Discourse API](https://meta.discourse.org/t/how-to-reverse-engineer-the-discourse-api/20576)

---

<div class="post-metadata">

### Author: ![attj](https://avatars.discourse-cdn.com/v4/letter/a/a698b9/32.png) [@attj](https://meta.discourse.org/u/attj)
#### Post date: [August 5, 2022, 12:25pm UTC](https://meta.discourse.org/t/creating-a-user-tag-relation-plugin/235208/5 "2022-08-05T12:25:17Z")

</div>

I wonder if it would put too much weight on the server. Because there will be many assignments and in the previous idea, it is essentially just an assignment to tags and doesn’t have to be assigned to each topic seperately.

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [August 5, 2022, 2:15pm UTC](https://meta.discourse.org/t/creating-a-user-tag-relation-plugin/235208/6 "2022-08-05T14:15:41Z")

</div>

Using an existing plugin that is maintained will be much easier than developing and maintaining your own.

---

<div class="post-metadata">

### Author: ![angus](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/angus/32/341715_2.png) [@angus](https://meta.discourse.org/u/angus)
#### Post date: [August 8, 2022, 9:38am UTC](https://meta.discourse.org/t/creating-a-user-tag-relation-plugin/235208/7 "2022-08-08T09:38:51Z")

</div>

You can do this with a simple plugin.

### What you need to do

The plugin will need to do the following:

1. Add a user custom field called `known_tags`, a list of strings.

2. Add an interface in the user profile where the user can edit `known_tags`. I don’t think it’s necessary to add an entirely new profile tab for this, but you could if you wanted to. If you don’t want users editing it themselves, just make it only editable by admins and just go into users profiles and update it based on your CSV file.

3. Add an event hook which uses the `before_create_post` or `post_created` events in the `PostCreator` to add the content you want to the post based on the tags in the topic.

### How to do it

Parts 1 and 2 are very similar to the example plugins for other models in the topic linked below. See if you can figure it out by analogy. If you get really stuck ask me for a pointer there.

> [@How to add custom fields to models](https://meta.discourse.org/t/how-to-add-custom-fields-to-models/184485):
>
> This is a collection of education plugins that demonstrate how to add a custom field to different models in Discourse. They are intended as learning tools for those looking to learn how to build discourse plugins. [[GitHub-Mark] How to add a custom field to a topic](https://github.com/pavilionedu/discourse-topic-custom-fields)[[GitHub-Mark] How to add a custom field to a category](https://github.com/pavilionedu/discourse-category-custom-fields)Who they’re for These plugins are for people looking to learn more about creating Discourse plugins. Before you start working with these plugins, you should complete the [beginner…](https://meta.discourse.org/t/beginners-guide-to-creating-discourse-plugins/30515)

Part 3 will also go in your plugin.rb file. It’ll look something like this

```plaintext
on(:post_created) |post, opts, user|
  if post.is_first_post? && post.topic.tags.present?
     user_ids = UserCustomField.where(name: 'known_tags', value: post.topic.tags).pluck(:user_id)
     usernames = User.where(id: user_ids).pluck(:username)
     new_raw = post.raw + "something something #{usernames}"
     PostRevisor.new(post).revise!(
      user,
      {
        raw: new_raw,
        edit_reason: "some reason"
      },
      skip_validations: true,
      bypass_bump: true
    )
  end 
end

```

Give it a royal go yourself. If you get really stuck I’ll help. I’m always more inclined to help if there’s strong evidence you’re trying to figure it out yourself 🙂

---

<div class="post-metadata">

### Author: ![attj](https://avatars.discourse-cdn.com/v4/letter/a/a698b9/32.png) [@attj](https://meta.discourse.org/u/attj)
#### Post date: [August 8, 2022, 9:58am UTC](https://meta.discourse.org/t/creating-a-user-tag-relation-plugin/235208/8 "2022-08-08T09:58:16Z")

</div>

Thanks a lot for providing a very nice roadmap, I am on it! Small question:

> [@angus](#):
>
> go into users profiles and update it based on your CSV file.

Does this part have to be manual using this approach (by manual, I mean adding entries one by one via an interface)? Ideally, I would like to add this using my admin API key since the csv file is a bit loaded and will grow over time.

---

<div class="post-metadata">

### Author: ![angus](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/angus/32/341715_2.png) [@angus](https://meta.discourse.org/u/angus)
#### Post date: [August 8, 2022, 10:02am UTC](https://meta.discourse.org/t/creating-a-user-tag-relation-plugin/235208/9 "2022-08-08T10:02:19Z")

</div>

No it doesn’t need to be manual. There are quite a few different ways you could fill out the user custom fields based on the CSV. It really depends on how you want to handle the updates. I’d suggest doing the other parts first and just testing this out with a small dataset. Then if you’re happy with how it’s working add an automatic import for the CSV. Making that part efficient is a secondary step.
