Rendering custom post field in Flagged Queue

Hi,

I am trying to render a custom field in a plugin outlet but cannot seem to get access to it. The outlet being used is flagged-post-below-controls plugin outlet in /app/assets/javascripts/admin/templates/components/flagged-post.hbs but the “flaggedPost” that gets passed to my template does not have the custom field.

The custom field is added to the Post serializer, and access to it from another custom template (not a plugin outlet) works just fine so I am missing something obvious about flaggedPost.

Added to serializer

add_to_serializer(:post, :my_custom_field) do
  post_custom_fields["my_custom_field"]
end

Using it a custom template for a custom queue

  <div>
    {{#if post.my_custom_field }}
        <span>Value: {{post.my_custom_field}}</span>
    {{~else~}}
	  <span>No custom field value</span>
    {{/if}}
  </div>

Trying to access it like this in assets/javascripts/discourse/templates/connectors/flagged-post-below-controls/my_outlet.hbs (i.e. flaggedPost.my_custom_field) does not work.

I know I am missing something obvious, but I have no experience with Ruby/Rails/Discourse so any help would be appreciated!

Thanks

1 Like

Looks like the flaggedPost object gets its origin here:

https://github.com/discourse/discourse/blob/8ff41045550ba872d02590d7c44394ede1a7c89f/lib/flag_query.rb#L31

That means it’s not using the PostSerializer to create flaggedPost. Which means you would likely have to either monkey-patch it (not recommended) or append the custom fields after the Ember app creates flaggedPost (not fun).

That said, it seems odd to me that the flags structure uses a FlaggedTopicSerializer but not a FlaggedPostSerializer.

3 Likes

Thanks for your response @joebuhlig , sorry I did not respond earlier.

I guess I was expecting that because the flagged post JS object was extending the default Post object (/app/assets/javascripts/admin/models/flagged-post.js.es6) then the custom fields would just be there. I really have no idea what I am doing with Rails or Ember though!

Would you be able to point me in the right direction in how to append the custom fields to flaggedPost? Is there a good tutorial or plugin example I can look at to show me how to do it?

EDIT: Does it involve using something like “FlaggedPost.reopen({code-to-make-my-custom-field-show-here})”

Okay, I am really struggling to understand what is going. I know I am missing something obvious but at this point it is like black magic.

I tried reopen() on FlaggedPost and I know my code is getting called because if I have an error then there is a javascript error until I fix it but I can’t get access to my code from the template.

Here is my /assets/javascripts/admin/models/flagged-post.js.es6. I ended up just throwing everything at the wall to try to get something to show, never mind trying to get my custom field to show. I have tried reopen() and reopenClass() to see if that makes a difference:

import flaggedPost from 'admin/models/flagged-post';
import computed from 'ember-addons/ember-computed-decorators';

console.log('loaded');

flaggedPost.reopenClass({

    @computed
    test_response_1() {
	    return true;
    },

    test_response_2() {
	    return true;
    },
    
    @computed
    test_response_3: true,

    test_response_4: true,

});

and my /assets/javascripts/discourse/templates/connectors/flagged-post-below-controls/test_template.hbs:

<div >
  Stuff will show here
  <div>
    blah
    post: {{flaggedPost}}
    log: {{log flaggedPost}}
    blah    
  </div>
  <div>
    test_response_1: {{flaggedPost.test_response_1}}
    log test_response_1: {{log flaggedPost.test_response_1}}
  </div>
  <div>
    {{#if flaggedPost.test_response_1}}
    True
    {{else}}
    False
    {{/if}}
  </div>
  <div>
    {{#if flaggedPost.test_response_2}}
    True
    {{else}}
    False
    {{/if}}
  </div>
  <div>
    {{#if flaggedPost.test_response_3}}
    True
    {{else}}
    False
    {{/if}}
  </div>
  <div>
    {{#if flaggedPost.test_response_4}}
    True
    {{else}}
    False
    {{/if}}
  </div>
</div>

but all that shows is:

Stuff will show here

blah post: &lt;(unknown mixin):ember1113&gt; log: blah

test_response_1: log test_response_1:

False

False

False

False

I need some help to point me in the right direction, as I am completely lost here.

Thanks!

Where are you performing your reopen? Is it in an initializer?

If it’s just in a regular JavaScript file it might not be evaluated.

4 Likes

To follow what @eviltrout mentioned, it really depends on when your code runs. But regardless, if you’re trying to add custom fields to those posts, you’ll have a rough time. They don’t exist in the Post objects that are being passed to the front end. So you would need to match them up via Ember or rewrite the SqlBuilder, which I don’t recommend.

Maybe share what the end goal is? There may be a better way than​ trying to force a custom field on the flagged queue.

3 Likes

Thanks guys. The reopen is being done exactly where it is shown there, that is the entirety of the file for my attempt at extending the FlaggedPost object. It is at <myplugin>/assets/javascripts/admin/models/flagged-post.js.es6 So I am not using an initializer or anything, and obviously missing the target :slight_smile:

The end goal is that I want to render information I am storing in the custom field in the flagged queue template. Elsewhere in the plugin I am storing some information on Posts in a custom field as JSON and I need to render that information in the flag queue.

I have had success rendering the information in my own custom queue no problem, but I understand now that is is because that is getting the regular Post object which gets the field serialized by the registration, but the FlaggedPost is not respecting that process and so does not have access to it (thanks for the explanation @joebuhlig)

Unfortunately I have a use case where I need to show the same information in the Flag queue as well. My intention now was extend the FlaggedPost by “querying” for my custom field and adding it (where “querying” is still undefined and unknown to me at this point :slight_smile: ). I have access to the post id, so I assumed that part was solvable, even if not efficient, but so far I can’t even extended the FlaggedPost just to show a static value

1 Like

Tell me to stop asking if it’s not worth it, but what fields and information are you trying to add? I can’t think of a scenario where adding information to that specific list is worth the time.

No worries, I really appreciate your time.

I am classifying the text of a post and storing the classification. In the queue the client wants to see the classification information to make determinations for moderation.

So as a simple example, say we classify a post as Bullying and Vulgar, with a level for each, and if the levels cross an acceptance threshold then it is automatically flagged. The client wants to see the classifications and levels in the queue so their moderators can see why it was flagged.

Does that make sense? I am not so good with the words :wink:

3 Likes

Yes you will want to use an initializer to reopen your class. You should start there, then your extended one should work. Here’s an example of modifying a class in an initializer using our plugin api.

As for adding the custom fields to the flagged post result, that might be a little trickier. The code to query flagged posts is here and uses our SqlBuilder for performance reasons.

You would have to modify that query to include the custom fields. That might require an extension point in core to do elegantly.

6 Likes

Thanks Robin.

My idea in reopening FlaggedPost was to query separately and “inject” my field into it. If I modify the query that builds the FlaggedPost then I wouldn’t need to do that right? But there is no way to override the query building, I would have to have an extension point as you point out but that is not presently in the code as far as I can tell right? It would be something akin to the plugin outlets in templates, but for query building?

Is there a reason doing the reopen and inject method would not work? Is there no way to query for my custom field from that side?

Yes if you modify the query that builds the FlaggedPost on the server side (that SQLBuilder I sent across) the properties would just be there. Adding an extension point there could be something like:

  # in flagged_posts_report, after posts.map!(&:marshal_dump)
  posts = FlagPostQuery.load_extra_data(posts)

Then you could add an identity method like:

def self.load_extra_data(posts)
  posts
end

Then in your plugin.rb you could do:

add_class_method(:flag_query, :load_extra_data) do |posts|
  # Shove the extra data in `posts` here
  posts
end

You can reopen the class in the front end, but when would you load the data? In general our application expects data to be loaded before a route is entered. There are exceptions, such as clicking on a button to load more data.

6 Likes

Thanks Robin. I really need a solution that does not patch the Discourse source. Is that something you were thinking of adding, the ability to “extend” SQL builders?

I am a little confused about how your load_extra_data can extend the query being used to create posts. It looks to me that the query has already been built and executed by that point and all one could do is inject extra data into the result objects. I have to admit that Ruby syntax does mess with my mind though, so maybe I missed something? Or are you saying that separately from the extend the query method, as in:

option 1: modify the query building the posts
OR
option 2: inject extra data into the results after the initial query.

Either one seems like I would need to modify the Discourse source to accomplish, and I would need a solution that can be done completely from the plugin.

In this case what I was recommending was you submit a PR to Discourse to add the extension point you need, once you figure out exactly how it would work.

You’re right in that what I suggested does not modify the SQL. That seems really complicated, so what I was thinking was you’d get back the list of posts, then you could use that to perform an additional query, then add those fields back to the marshaled version.

5 Likes