Reported content

What is Reported content?

Comments and resources created by users in Totara Engage can contain inappropriate content. The Reported content plugin allows users to flag content to the attention of Site Administrators, who can then remove the content using a single report. Moderation is a key component of any collaborative system.

Any new type of content added to Totara by users that is not approved in some manner should ideally be linked with the Reported content plugin, to allow users to flag anything inappropriate.

How Reported content works

When something needs reporting to a Site Administrator, a user can click the Report menu item. A GraphQL mutation to totara_reportedcontent_create_review will create a new instance of a "review". Calling the built-in GraphQL is not required, instead you may create your own instance of a review by calling the totara_reportedcontent\review::create static method.

If the standard GraphQL is used, a hook called get_review_content is fired. Each type of component that is reportable should observe this hook and return the context and content information.

Site Administrators can then view the Inappropriate Content embedded report. A list of items that have been reported show up by default, with action options available.

If the Site Administrator chooses the Approve option, then the status on the review is changed, and nothing further happens.

If the Site Administrator chooses the Remove option, then a hook remove_review_content is triggered, and a notification is sent to the offending user. The component in question should observe the hook and remove the content when triggered.

It's up to the component specifically to handle what removed content looks like. A message can be shown in place of the removed content, or the content can be completely removed.

Main API classes and methods

ClassPurpose
totara_reportedcontent\hook\remove_review_contentHook that's triggered when some reported content needs removing. Each component should observe this hook and react when the provided component is matched.
totara_reportedcontent\hook\get_review_context

Hook that's triggered when some reported content is initially reported. Only fired through the provided GraphQL. If your component instead calls totara_reportedcontent\review::create directly then this is not called or needed.

totara_reportedcontent\reviewMain instance of the reported content review. Main points are the target user (person being reported), complainer (person doing the reporting), reviewer (person managing the report) and content (what was reported).
totara_reportedcontent\task\remove_notify_taskAdhoc task that's fired when content is removed. It notifies the person reported that their content was removed.

How to add Reported content 

There are three parts to integrating with the Reported content plugin:

  • Removing content
  • Reporting content
  • The frontend

Removing content

You must create a new observer, and listen to the totara_reportedcontent\hook\remove_review_content hook.

In the db/hooks.php file:

$watchers = [
    [
        // Soft-delete the comment when the review has been marked as "removed"
        'hookname' => '\totara_reportedcontent\hook\remove_review_content',
        'callback' => '\new_component\watcher\reportedcontent_watcher::delete_component',
    ],
];

And now in the classes/watcher/new_component_watcher.php file:

namespace new_component\watcher;

use new_component\component_instance;
use totara_reportedcontent\hook\remove_review_content;

final class new_component_watcher {
    /**
     * @param remove_review_content $hook
     * @return void
     */
    public static function delete_component(remove_review_content $hook): void {
        // Only react to our own component
        if ('new_component' !== $hook->review->get_component()) {
            return;
        }

        $instance = component_instance::from_id($hook->review->get_item_id());
        $instance->delete(); // Can delete or soft delete

        $hook->success = true;
    }
}

When content is flagged for deletion by a Site Administrator, your hook will be called and you'll need to then delete the provided content.

Reporting content (custom code)

If you're creating your own method to report content, then all you need to do is make a call to the totara_reportedcontent\review::create static method.

// Do anything else around it
$component = my_component::from_id($id);
$review = review::create(
    $itemid, // The id of the item being reported
    $contextid, // Context of the item
    'new_component', // Component
    'comment', // Area or null, eg comment
    $url, // The URL where the content was reported on
    $component->get_content(), // Content of the component. Used to display the component in the report
    $component->get_format(), // Format matching the content above
    $component->get_timecreated(), // Timestamp when the content was made
    $component->get_userid(), // User who owns the content
    $USER->id // User making the complaint
);
// Now a review has been created, can proceed with anything else

Reporting content (provided GraphQL)

If you want to use the provided GraphQL in your frontend to report the content (totara_reportedcontent_create_review) then you'll need to create a hook observer to provide the content and context of the reported content.

use totara_reportedcontent\hook\get_review_context;

final class reportedcontent_watcher {
    /**
     * @param get_review_context $hook
     * @return void
     */
    public static function get_context(get_review_context $hook): void {
        if ('new_component' !== $hook->component) {
            return;
        }
        $component = new_component::from_id($hook->instance_id);

        // Note - if the content is large you can instead return some plain/html
        // of it trimmed down. Depends on the component specifically.
        $hook->content = $component->get_content();
        $hook->format = $component->get_format();
        $hook->context_id = $component->get_context()->id;
        $hook->content = $component->get_content();
        $hook->format = $component->get_format();
        $hook->time_created = $component->get_time_created();
        $hook->user_id = $component->get_user()->id;
        $hook->success = true;
    }
}

Add the hook to your watchers.

$watchers = [
    [
        'hookname' => '\totara_reportedcontent\hook\get_review_context',
        'callback' => '\new_component\watcher\reportedcontent_watcher::get_context',
    ],
];

Now you can call the GraphQL from your frontend component.

import createReview from 'totara_reportedcontent/graphql/create_review';

export default {
// ...
methods: {
   report() {
       return this.$apollo.mutate({
           mutation: createReview,
           variables: {
            component: this.component,
            area: this.area,
            item_id: this.item_id,
            instance_id: this.instance_id,
            url: window.location.href,
          }
       });
   }
},
// ...

Best practices

When providing content inside the hook, try to keep it limited. The entire content will be rendered, and if it's huge it can cause problems.