Auto Moderator

License Latest Stable Version

A Flarum extension.

Core Concept

The core idea is as follows:

When a user meets criteria X, do Y. When a user no longer meets criteria X, do Z.

Let's define some key terms:

  • Criteria Group: The set of all criteria that a user meets.
  • Criteria (singular Criterion): An arbitrary set of conditions. Criteria are paired with triggers and actions, and are composed of:
    • Metrics: A numerical condition. For example, post count or number of likes received. A criterion could require a range/minimum/maximum of metrics.
    • Requirement: An abstract boolean condition. For example, not being suspended, or having an email that matches a certain regex.
  • Action: Something that happens automatically when a criteria is met or lost. This could include anything from adding/removing a group to sending an email to suspending a user.
  • Triggers: A set of events that would cause a user's criteria groups to be reevaluated. These are associated with metrics and Requirements. LoggedIn is automatically a trigger for all criteria.

This makes for an extremely powerful extension. Furthermore, since extensions can add their own metrics, requirements, and actions, this extension can automate away a lot of moderation. Beyond the examples listed below, some things that could be possible are:

  • Automating assignment of achievements / badges
  • Sending emails/notifications to users when they reach thresholds (or just when they register)
  • Establishing a system of "trust levels" like Discourse
  • Onboard/offboard users to/from external systems when they receive/lose certain group membership
  • And a bunch more! The possibilities are endless.

Evaluation

When a trigger event occurs:

  • All metrics will be calculated for the relevant user (what is the numerical value of the metric?)
  • All requirements will be calculated for the relevant user (does the user satisfy each of the requirements?)
  • The user's new criteria group will be computed and diffed against the user's current criteria group. The two sets will be diffed. Only criteria triggered by the event will be adjusted.
  • Actions will be executed for any gained and lost criteria.

You can also use the php flarum criteria:recalculate console command to recalculate criteria for all users. Note that this will be quite slow, and shouldn't usually be done.

Examples

Example 1: Group Management

Criteria: Users that receive 50 or more likes and have started at least 10 discussions should placed in the "Active" group.

Here, the metrics are "received 50 or more likes" and "have started at least 10 discussions". Unsurprisingly, they come with the triggers (PostWasLiked, PostWasUnliked) and (Discussion\Started) respectively.

The actions are:

  • When the criteria is met, add the user to the "Active" group
  • When the criteria is lost, remove the user from the "Active" group

Example 2: Suspension

Criteria: If a user gets 15 warnings or more and is not an admin, suspend them.

Here, the metrics are "gets 15 warnings or more" and the requirements are "is not an admin". The triggers would be a new warning for the metric. The requirement has no triggers.

The actions are:

  • When the criteria is met, suspend them
  • When the criteria is lost, unsuspend them

Example 3: Auto Activation

Criteria: If a user's email matches a regex, activate their email.

The requirement is "a user's email matches a regex". The triggers are saving a user.

The actions are:

  • When the criteria is met, auto activate the user's email
  • When the criteria are not met, don't

Example 4: Default Group

Criteria: Add a user to a group

There are no metrics or requirements, so this will be applied to all users on login.

The actions are:

  • Add all users to a group on login

    Screenshots

Admin
Criterion Edit
Edit User

Metrics vs Requirements

It's clear to see that any metric could be represented as a Requirement.

  • A requirement must be specific. "More than 50 received likes" could be a requirement. However, metrics can allow for any range of values.
  • Metrics can be stored and used for other purposes. For example, a planned feature is combining all metrics to provide a "reputation" score.

Settings

Requirements and actions can require settings in the admin dashboard. For example:

  • The "add to group" action takes the group ID as a setting
  • The "suspend" action takes the number of days and whether the suspension is indefinite as settings
  • The "email matches regex" requirement takes the regex as a setting

Extensibility

This extension is extremely flexible. It can be considered a framework for automoderation actions.

Extensions can use the Askvortsov\AutoModerator\Extend\AutoModerator extender to add:

  • Action drivers
  • Metric drivers
  • Requirement drivers

You should look at the source code of the default drivers for examples. They're fairly exhaustive of what's offered.

If your extension adds action or requirement drivers that consume settings, you have 2 options:

  • Provide translation keys for the settings you need in the driver's availableSettings method. This is very easy, but also very restrictive. You can only use strings, and can't add any restrictions or UI.
  • You can declare a settings form component for your driver. See js/src/admin/components/SuspendSelector for an example. The component should take a settings stream as this.attrs.settings. The contents of the stream should be an object that maps setting keys to values. The component is responsible for updating the stream on input. You can register a form component by adding its class to app.autoModeratorForms[DRIVER CATEGORY][TYPE], where DRIVER CATEGORY is "action" or "requirement", and TYPE is the type string you registered your driver with in extend.php. See js/src/admin/index.js for the underlying data structure and examples.

TODO:

  • Add support for more metrics:
    • Posts read
    • Time spent on forum
    • Days visited
    • Days since account creation
    • Etc
  • Add support for dated metrics (discussions created in the past X days)
  • Introduce metric "weights", sum together to calculate a reputation. Make that reputation available as a metric.
  • Develop a data collection extension, which could cache things such as like counts, to improve performance on large forums
  • Investigate criterion "listeners": can we generalize stuff like removing links from posts of users without certain groups?

Contributions

Contributions and PRs are welcome! Any PRs adding new drivers should come with unit tests (like with all existing drivers).

Compatibility

Compatible starting with Flarum 1.0.

Installation

composer require askvortsov/flarum-auto-moderator:*

Updating

composer update askvortsov/flarum-auto-moderator

Links

    Wow, hats off to you 🎩! This looks fantastic, I really like that you've made it extensible so that the possibilities really are endless. What a nice treat for 1.0, I am very much looking forward to trying this gem. Thank you!

    v0.1.1

    Small update, and no one's using it yet, but why not.

    • Allow selecting icons for criteria.
    • Generate criteria color

    These changes make the automoderator page more colorful!

    • Fix duplicate managed groups
    • Make the criterion page a tiny bit prettier with some slight tweaks

    Love this. Really fantastic.

    What happens if a depending extension is no longer installed. Eg triggering suspension but suspend is uninstalled (and the db column is removed)?

      luceos What happens if a depending extension is no longer installed.

      All drivers (actions, metrics, and requirements) supply a list of extension dependencies. If those dependencies aren't met, you won't be able to create new criteria with those drivers. Existing criteria will be considered invalid, and gain/loss actions won't be executed while those criteria use drivers with missing dependencies. There will also be an error in the admin dashboard. Same goes if settings are missing / don't pass validation.

      The error messages aren't ideal (they don't say which extension / which driver exactly has validation issues), but using them and common sense, admins should be able to figure it out. Plus this is something that can be improved in the future.

      Why is it called Auto Moderator? It does not seems to moderate anything.

        rob006 well you can take actions normally done manually by a moderator or admin, I think some of the examples show that. Though I think it probably does even go far beyond that, more like a Beast Mode Moderator 😁

          ctml For me "moderation" is more about managing content (posts, discussions) instead of users (especially if we talk about assigning groups to users). On first look I thought it works more like https://discuss.flarum.org/d/5131-friendsofflarum-filter. Personally I think the name of extension is confusing and naming of https://discuss.flarum.org/d/25977-trust-levels-automatic-group-assignment was much more clear.

            rob006 For me "moderation" is more about managing content (posts, discussions) instead of users (especially if we talk about assigning groups to users).

            I think moderation of users is just as valid a concept as moderation of content. That being said,

            askvortsov Investigate criterion "listeners": can we generalize stuff like removing links from posts of users without certain groups?

            I am hoping to eventually build in some content moderation too. Just a matter of figuring out an elegant abstraction.

            I didn't like "trust levels" as a name, because this extension can do a lot more than that. Also, "levels" imply disjointedness and some form of order, which is not the case with this extension.

            This looks like a very valuable plugin
            I've been using sql scripts to partially provide this behavior

            I think moderation of users is just as valid a concept as moderation of content.

            Absolutely, for example, I recently made it so users in the "valid users" group can send private messages, upload files, etc. This after a user was sending private pm's to get other users off platform to scam them.
            This would make defining a "valid user" very easy 👍

            Very powerful concept and already great extension.

            askvortsov

            • Introduce metric "weights", sum together to calculate a reputation. Make that reputation available as a metric.

            I suggest including more calculations, such as differences, ratios, and even mathematical functions. This could be very helpful in putting things in perspective. 5 warnings within a few days and a handful of posts should be treated differently from the same number of warnings within years of active membership.

            I know that this could be handled within the current extension à la:

            • more than 2 warnings and less than 10 posts or
            • more than 3 warnings and less than 30 posts or
            • more than 4 warnings and less then 100 posts or
            • more than 5 warnings and less then 300 posts or
            • more than 6 warnings and less then 1000 posts

            ... but having a rule like $warnings > 2 * lg($posts) could make life much easier, especially when more then two metrics are to be combined.

              Pollux I suggest including more calculations, such as differences, ratios, and even mathematical functions. This could be very helpful in putting things in perspective.

              Hmm, I wonder if this could be implemented as a requirement? All that would be needed is for the metric values to be provided to requirements. Then, a requirement could take such a string like you provided ($warnings > 2 * lg($posts)) as a setting, parse it out (inventing mini programming languages is fun!), and validate against the provided metric values.

              Right now I need to focus on Flarum CLI, so this feature is going in the "eventual todo" list alongside content moderation.

              For content moderation, the most trivial solution would be to allow "listeners". So if the user satisfies criterion X, a function would run on some events. This would handle stuff like FoF filter, but the listeners would have to be quite bulky.

              What if metrics and requirements could be conceptually applied to various models? Then, we could create "rules" for members of criteria.

              For example, take creation of posts.

              If a user satisfies metrics M1 and requirements R1, and the post satisfies metrics M2 and requirements R2, do something to the post.

              The part I'm struggling to reconcile is actions vs that "something". Anyone who has done hardware development can recognize that actions happen "on the edge" of group membership qualification:

              (let one of those waveforms be qualification. When qualification state changes, on gain / on loss actions are executed)

              On the other hand, this "something" for content moderation happens while qualification is active (users currently qualifying for a criteria would be affected).

              Another way to consider this is that content created by users could be "mutated" on creation. This could be a generalization of the above "listener" idea that decouples the "when" (by having metrics and requirements for models beyond User) from the "what" (mutations applied to posts, discussions, messages, etc before they are created/edited).

              Then, there's the question of whether "mutations" and "actions" are isomorphic: does it matter that "actions" are triggered on state change, and "mutations" modify models as they are created / edited? I feel like yet again, the "what" should be decoupled from the "when", and these should be treated as isomorphic. But more thinking is needed here.

                askvortsov Hmm, I wonder if this could be implemented as a requirement? All that would be needed is for the metric values to be provided to requirements. Then, a requirement could take such a string like you provided ($warnings > 2 * lg($posts)) as a setting, parse it out (inventing mini programming languages is fun!), and validate against the provided metric values.

                This sounds good.

                Another way to consider this is that content created by users could be "mutated" on creation. This could be a generalization of the above "listener" idea that decouples the "when" (by having metrics and requirements for models beyond User) from the "what" (mutations applied to posts, discussions, messages, etc before they are created/edited).

                If we decouple the "when" from the "what," we might also consider acting retroactively.

                Example: We monitor new users who post external links (potential spammers). If a user posts more than 2 links within the last 4 posts or more than 3 links within the last 10 posts, we auto-flag their latest post. In this case, shouldn't we retroactively auto-flag all previous posts that contain a link?

                  Pollux In this case, shouldn't we retroactively auto-flag all previous posts that contain a link?

                  Hmm... If we lived in functional programming land, our "action" would be a pure function that takes a model (in this case a post) and returns a model instance with some modifications. While this would be clean and beautiful, PHP does not support something like this.

                  On the bright side, this means that an action could do anything. For example, instead of just mutating the post, it could do something to the post's author, or all posts of the post's author, or etc.

                  010101 gets 5 likes, they get a badge?

                  Yep, that's one possible application.

                  In theory, it's an abstraction of executing actions in response to events if certain criteria are met (or at least that's where I want to grow it in the future).

                  a month later

                  Great! It could be better to make it a flarum own feature so that other extensions have the opportunity to use it.

                    stimw extensions can built so they too can be extended and that's what the author has done, so it doesn't need to be a core feature 🙂 You'll notice the User Badges extension has added integration with AutoModerator for automatic badges.

                      ctml Oh, I see. Thank you 😄

                      But AutoModerator just doesn't seem to be a popular extension (at least in this discussion)...Maybe a core feature could help with it?