A simple Content Moderation System for Laravel 5.* that allows you to Approve or Reject resources like posts, comments, users, etc.

Overview

Laravel Moderation Build Status Version Total Downloads Software License

A simple Moderation System for Laravel 5.* that allows you to Approve or Reject resources like posts, comments, users, etc.

Keep your application pure by preventing offensive, irrelevant, or insulting content.

Possible Use Case

  1. User creates a resource (a post, a comment or any Eloquent Model).

  2. The resource is pending and invisible in website (ex. Post::all() returns only approved posts).

  3. Moderator decides if the resource will be approved, rejected or postponed.

  4. Approved: Resource is now public and queryable.

  5. Rejected: Resource will be excluded from all queries. Rejected resources will be returned only if you scope a query to include them. (scope: withRejected)

  6. Postponed: Resource will be excluded from all queries until Moderator decides to approve it.

  7. You application is clean.

Installation

First, install the package through Composer.

composer require hootlex/laravel-moderation

If you are using Laravel < 5.5, you need to add Hootlex\Moderation\ModerationServiceProvider to your config/app.php providers array:

'providers' => [
    ...
    Hootlex\Moderation\ModerationServiceProvider::class,
    ...
];

Lastly you publish the config file.

php artisan vendor:publish --provider="Hootlex\Moderation\ModerationServiceProvider" --tag=config

Prepare Model

To enable moderation for a model, use the Hootlex\Moderation\Moderatable trait on the model and add the status, moderated_by and moderated_at columns to your model's table.

use Hootlex\Moderation\Moderatable;
class Post extends Model
{
    use Moderatable;
    ...
}

Create a migration to add the new columns. (You can use custom names for the moderation columns)

Example Migration:

class AddModerationColumnsToPostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->smallInteger('status')->default(0);
            $table->dateTime('moderated_at')->nullable();
            //To track who moderated the Model, add 'moderated_by' and set the column name in the config file.
            //$table->integer('moderated_by')->nullable()->unsigned();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('posts', function(Blueprint $table)
        {
            $table->dropColumn('status');
            $table->dropColumn('moderated_at');
            //$table->dropColumn('moderated_by');
        });
    }
}

You are ready to go!

Usage

Note: In next examples I will use Post model to demonstrate how the query builder works. You can Moderate any Eloquent Model, even User.

Moderate Models

You can moderate a model Instance:

$post->markApproved();

$post->markRejected();

$post->markPostponed();

$post->markPending();

or by referencing it's id

Post::approve($post->id);

Post::reject($post->id);

Post::postpone($post->id);

or by making a query.

Post::where('title', 'Horse')->approve();

Post::where('title', 'Horse')->reject();

Post::where('title', 'Horse')->postpone();

Query Models

By default only Approved models will be returned on queries. To change this behavior check the configuration.

To query the Approved Posts, run your queries as always.
//it will return all Approved Posts (strict mode)
Post::all();

// when not in strict mode
Post::approved()->get();

//it will return Approved Posts where title is Horse
Post::where('title', 'Horse')->get();
Query pending or rejected models.
//it will return all Pending Posts
Post::pending()->get();

//it will return all Rejected Posts
Post::rejected()->get();

//it will return all Postponed Posts
Post::postponed()->get();

//it will return Approved and Pending Posts
Post::withPending()->get();

//it will return Approved and Rejected Posts
Post::withRejected()->get();

//it will return Approved and Postponed Posts
Post::withPostponed()->get();
Query ALL models
//it will return all Posts
Post::withAnyStatus()->get();

//it will return all Posts where title is Horse
Post::withAnyStatus()->where('title', 'Horse')->get();

Model Status

To check the status of a model there are 3 helper methods which return a boolean value.

//check if a model is pending
$post->isPending();

//check if a model is approved
$post->isApproved();

//check if a model is rejected
$post->isRejected();

//check if a model is rejected
$post->isPostponed();

Strict Moderation

Strict Moderation means that only Approved resource will be queried. To query Pending resources along with Approved you have to disable Strict Moderation. See how you can do this in the configuration.

Configuration

Global Configuration

To configuration Moderation package globally you have to edit config/moderation.php. Inside moderation.php you can configure the following:

  1. status_column represents the default column 'status' in the database.
  2. moderated_at_column represents the default column 'moderated_at' in the database.
  3. moderated_by_column represents the default column 'moderated_by' in the database.
  4. strict represents Strict Moderation.

Model Configuration

Inside your Model you can define some variables to overwrite Global Settings.

To overwrite status column define:

const MODERATION_STATUS = 'moderation_status';

To overwrite moderated_at column define:

const MODERATED_AT = 'mod_at';

To overwrite moderated_by column define:

const MODERATED_BY = 'mod_by';

To enable or disable Strict Moderation:

public static $strictModeration = true;
Comments
  • Actions on a single instance

    Actions on a single instance

    Perhaps an idea to allow $user->approve(), $user->reject, $user->postpone(), et cetera? :)

    Oh, and scopes! That way it can be combined with other query limitations like wheres and whatnot.

    enhancement 
    opened by sebastiaanluca 16
  • Possibility to use custom status

    Possibility to use custom status

    Hey, very nice package. However, if this flow does not work with your process, you need to hack it.

    What do you think about adding a possibility to add a custom status?

    E.g.

    $post->setStatus('custom');
    
    Post::all()->withStatus('custom');
    

    Maybe the user can set those status and decide if they should be queried in strict mode or not.

    You could even use magic methods to build markCustom methods.

    What do you think?

    enhancement 
    opened by lukasoppermann 10
  • Deletion of moderatable objects

    Deletion of moderatable objects

    Hi,

    I think that there is a little when trying to delete a moderatable object by ising the delete() method. Indeed the eloquent delete method applies again the query scopes, so it is impossible to perform the delete on "rejected" adn "pending" objects. I simply redefined the performDeleteOnModel in teh emoderatable class. Possibly there is a more elegant solution.

    opened by gecche 9
  • Support Auto-Discovery / Fix missing lib for testing / Upgrade phpunit / Make it compatible with PHP 7.2

    Support Auto-Discovery / Fix missing lib for testing / Upgrade phpunit / Make it compatible with PHP 7.2

    • Support Auto-Discovery
    • Fix missing lib for testing
    • Upgrade phpunit
    • Make it compatible with PHP 7.2 (related to #29)
    • Remove php 5.6 7.0 compatibility

    We have to remove PHP 5.6, 7.0 compatibility because laravel 5.6 and phpunit 7 require php ^7.1.3 . Maybe create a branch before merging this PR to keep a old support branch for old version. @hootlex What do you think about it ?

    opened by stephane-monnot 5
  • Trait method performDeleteOnModel collides with SoftDelete trait

    Trait method performDeleteOnModel collides with SoftDelete trait

    Trait method performDeleteOnModel has not been applied, because there are collisions with other trait methods on User.

    \Illuminate\Database\Eloquent\SoftDeletes has the same method protected function performDeleteOnModel(). Can I use these together somehow? Should I just use the method from the soft delete trait?


    Small update: both traits also define the $forceDeleting property, which cannot be rewritten or aliased. Why exactly is it being use? There's no need for it?

    bug 
    opened by sebastiaanluca 5
  • Added Postpone Status and also moderated_by column

    Added Postpone Status and also moderated_by column

    Sometimes I may need to postpone some records or the record has to be review by another guy so I need one more status which is postpone.

    Also I need to see who approved the record which admin or mod.

    opened by zek 5
  • Moderation Trait Issue

    Moderation Trait Issue

    I have a model and I added the Hootlex\Moderation\Moderatable trait as below

    use Hootlex\Moderation\Moderatable;
    class Post extends Model
    {
        use Moderatable;
        ...
    }
    

    But my index blade that returns a list of submitted posts does not show unless I remove use Moderatable; from my model. So instead I added the trait to my controller, but now when I try to approve the post it gives this error Call to undefined method pending() reject() or postpone() . I also tried other ways to moderate an instance of a model provided in the documentation, and I get the same error. Please assist on a solution for thus error

    opened by lawkunchi 2
  • Make it compatible with PHP 7.2

    Make it compatible with PHP 7.2

    Check if $builder->getQuery()->joins is not null due to scalar or object that doesn't implement the Countable interface: https://wiki.php.net/rfc/counting_non_countables

    opened by rahaug 2
  • Adding events

    Adding events

    Thinking about status, etc. it might be a good idea to add events for when a status changes.

    Think about an author getting a notification that his article is back from a review. Or maybe it is published now, etc.

    Using the laravel event system other parts of the app can easily subscribe to the statusHasChanged event and act on it, e.g. send out a notification, log something to a database, add something to a queue, ...

    enhancement 
    opened by lukasoppermann 2
  • Difference Postponed/Pending

    Difference Postponed/Pending

    Hello Hotlex, thanks for this package, I'm interesting to adopt it in my project.

    I have not a lot of experience in content moderation so can you give more details about difference from Postponed and Pending status? It seams a redundant definition.

    Really thanks Valerio

    opened by ilvalerione 1
  • Remove references to AppUser to allow using custom models structure

    Remove references to AppUser to allow using custom models structure

    Hey there :)

    We're using a custom-but-quite-common models structure, using App\Models instead of App as base namespace. Thus, ModerationScope using App\User is raising errors in our case, and so is the BaseTestCase acting as App\User.

    Therefore, I only removed the use statement in ModerationScope (wasn't used), and used adamwathan/eloquent-oauth method of retrieving the user class from config('auth.providers.users.model', config('auth.model', 'App\User')) for BaseTestCase.

    Hope it's okay, and thanks for this great package. Cheers,

    opened by superbiche 1
  • Building a Filter Query for ModerationStatus::APPROVED

    Building a Filter Query for ModerationStatus::APPROVED

    Hello I am maintaining a project that uses this library for moderation, and on some of our content we like to filter by 'Approved', 'Pending' , 'Rejected', and 'Postponed'.

    We have a custom Status Filter that extends Laravel\Nova\Filters\Filter. In this class, we define an apply method as such:

        public function apply(Request $request, $query, $value)
        {
            switch($value) {
                case $this->all:
                default:
                    $query = $query->withAnyStatus();
                    break;
                case ModerationStatus::PENDING:
                    $query = $query->pending();
                    break;
                case ModerationStatus::APPROVED:
                    break;
                case ModerationStatus::REJECTED:
                    $query = $query->rejected();
                    break;
                case ModerationStatus::POSTPONED:
                    $query = $query->postponed();
                    break;
            }
    
            return $query;
        }
    

    Now I am sorry if this is the wrong place to be asking this, but as it pertains to Laravel and Nova, how can I add an approved() filter to the $query() that is being returned? I see this query is of type \Illuminate\Database\Eloquent\Builder and I kind of half expected to see this library extend that somewhere in the code. This however is not the case and digging through the API reference for \Illuminate\Database\Eloquent\Builder I don't see any reference to these methods being performed on the $query in the above function.

    Could someone maybe point me in the right direction of where to look? Is hootlex not fully compatible with Laravel and Nova and therefore doesn't offer a way to filter by ModerationStatus::APPROVED ?

    Any help would be greatly appreciated

    opened by dev-ns8 0
  • Laravel 7

    Laravel 7

    Hi,

    may i know if this plugin compatible with Laravel 7?

    I have this error whenever I try to get the row data.

       $post = Post::where('id', $id)->first();
    

    Illuminate\Database\QueryException SQLSTATE[42S22]: Column not found: 1054 Unknown column 'posts.' in 'where clause' (SQL: select * from posts where id = 1 and posts.`` != 2 limit 1)

    opened by nufasalam 0
  • [enhancement] make moderation to be a morph relationship

    [enhancement] make moderation to be a morph relationship

    hi hootlex.. can i make a fork of the package to use a moderatable morph relationship. i believe it will be much more refactored if we adopted that approach?

    opened by simphiwehlabisa 0
Releases(v1.1.0)
Owner
Alex Kyriakidis
Developer - Teacher - Author- Consultant
Alex Kyriakidis
Laravel comments - This package enables to easily associate comments to any Eloquent model in your Laravel application

Laravel comments - This package enables to easily associate comments to any Eloquent model in your Laravel application

Rubik 4 May 12, 2022
This package allows you to render livewire components like a blade component, giving it attributes, slots etc

X-livewire This package allows you to render livewire components like a blade component, giving it attributes, slots etc. Assuming you wanted to creat

null 7 Nov 15, 2022
Simple MyBB 1.8 plugin to force moderation of first user post.

MyBB-Moderate-First-Post Simple MyBB 1.8 plugin to force moderation of first user post. Installation: unzip package copy content from "UPLOAD" folder

Sven 3 Jan 2, 2023
cybercog 996 Dec 28, 2022
Interact with posts, terms & users in a OOP way

Installation composer require tombroucke/wp-models Interacting with models Create a new class for your custom post type namespace Otomaties\Events\Mod

null 2 Jul 14, 2022
Eloquent Befriended brings social media-like features like following, blocking and filtering content based on following or blocked models.

Laravel Befriended Eloquent Befriended brings social media-like features like following, blocking and filtering content based on following or blocked

Renoki Co. 720 Jan 3, 2023
A filesystem-like repository for storing arbitrary resources.

The Puli Repository Component Latest release: 1.0.0-beta10 PHP >= 5.3.9 The Puli Repository Component provides an API for storing arbitrary resources

Puli 435 Nov 20, 2022
Removes whitelisted unnecessary files (like tests/docs etc.) from vendor directory

Composer vendor cleanup This is a simple script for the Composer to remove unnecessary files (documentation/examples/tests etc.) from included vendor

Chris 2 Nov 14, 2022
A dead-simple comments package for Laravel.

A dead-simple comments package for Laravel. This package provides an incredibly simple comment system for your Laravel applications. If you're looking

Ryan Chandler 120 Dec 4, 2022
Laravel Impersonate is a plugin that allows you to authenticate as your users.

Laravel Impersonate Laravel Impersonate makes it easy to authenticate as your users. Add a simple trait to your user model and impersonate as one of y

404lab 1.6k Dec 30, 2022
Laravel Users | A Laravel Users CRUD Management Package

A Users Management Package that includes all necessary routes, views, models, and controllers for a user management dashboard and associated pages for managing Laravels built in user scaffolding. Built for Laravel 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 6.0, 7.0 and 8.0.

Jeremy Kenedy 393 Nov 28, 2022
Native comments for your Laravel application.

Comments Comments is a Laravel package. With it you can easily implement native comments for your application. Overview This package can be used to co

Laravelista 626 Dec 30, 2022
An index of Laravel's cascading comments

Cascading Comments An index of Laravel's cascading comments. Visit the site at cascading-comments.sjorso.com. About This is a cascading comment: casca

Sjors Ottjes 4 Apr 28, 2022
Locust are malware that can delete all folders, files, etc. on the system; I

Locust are malware that can delete all folders, files, etc. on the system; It was originally designed for web systems.

Md. Ridwanul Islam Muntakim 21 Dec 9, 2022
Fast and simple implementation of a REST API based on the Laravel Framework, Repository Pattern, Eloquent Resources, Translatability, and Swagger.

Laravel Headless What about? This allows a fast and simple implementation of a REST API based on the Laravel Framework, Repository Pattern, Eloquent R

Julien SCHMITT 6 Dec 30, 2022
Simplifies writing DocBlock comments in Javascript, PHP, CoffeeScript, Actionscript, C & C++

DocBlockr DocBlockr is a package for Sublime Text 2 & 3 which makes writing documentation a breeze. DocBlockr supports JavaScript (including ES6), PHP

Nick Fisher 3.1k Nov 25, 2022
Madison is a platform for lawmakers to share legislation with their citizens, allowing the community to add comments and suggest improvements.

Madison Madison is an open-source document engagement and feedback platform. While Madison can be used to collaborate on many different kinds of docum

OpenGov Foundation 591 Dec 17, 2022
Durable workflow engine that allows users to write long running persistent distributed workflows in PHP powered by Laravel queues

Durable workflow engine that allows users to write long running persistent distributed workflows (orchestrations) in PHP powered by Laravel queues. Inspired by Temporal and Azure Durable Functions.

null 268 Dec 27, 2022
Rede Social para o mundo fitness que possibilitara as pessoas compartilharem seus treinos,dietas e posts com os amigos.

Myfit Rede Social para o mundo fitness que possibilitara as pessoas compartilharem seus treinos,dietas e posts com os amigos. Sistema de compartilhame

Alan de Medeiros Tavares 1 Dec 1, 2021