Skip to content

Commit

Permalink
Merge pull request #16 from cvyz/allow_user_roles
Browse files Browse the repository at this point in the history
Added functionality to support user roles in feature flag configuration
  • Loading branch information
luisdalmolin committed Oct 1, 2020
2 parents 950b3a1 + 326c85b commit fceaa32
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 7 deletions.
9 changes: 5 additions & 4 deletions composer.json
Expand Up @@ -26,17 +26,18 @@
"toggles"
],
"require": {
"php": "^7.1.3"
"php": "^7.1.3"
},
"require-dev": {
"doctrine/dbal": "2.9.3",
"illuminate/support": "^5.6",
"mockery/mockery": "0.9.*",
"orchestra/database": "^3.6.0",
"orchestra/testbench": "^3.6",
"php-coveralls/php-coveralls": "^2.1",
"phpunit/phpunit": "^7.0",
"ramsey/uuid": "^3.0",
"orchestra/database": "^3.6.0",
"squizlabs/php_codesniffer": "^2.3",
"php-coveralls/php-coveralls": "^2.1"
"squizlabs/php_codesniffer": "^2.3"
},
"autoload": {
"psr-4": {
Expand Down
3 changes: 2 additions & 1 deletion database/factories/ModelFactory.php
Expand Up @@ -14,6 +14,7 @@
return [
'name' => $faker->word,
'email' => $faker->email,
'password' => bcrypt(str_random(25))
'password' => bcrypt(str_random(25)),
'roles' => "['admin']"
];
});
20 changes: 20 additions & 0 deletions readme.md
Expand Up @@ -129,6 +129,26 @@ if(\FriendsOfCat\LaravelFeatureFlags\Feature::exists('see-twitter-field'))
}
~~~

### Enable for User Roles
You can enable a feature flag for specific user roles, by using the **roles** variant in the configuration form

i.e.

~~~
{ "roles": ["admin", "dev"]}
~~~

If you don't have a roles property in your User model, you just need to implement the **FeatureFlagsEnabler** Interface and use **FeatureFlagUserRoleTrait**

~~~
use FriendsOfCat\LaravelFeatureFlags\FeatureFlagsEnabler;
use FriendsOfCat\LaravelFeatureFlags\FeatureFlagUserRoleTrait;
class User extends Authenticatable implements FeatureFlagsUserRoles
{
use AuthenticableTrait, FeatureFlagUserRoleTrait;
}
~~~

## Usage Non Auth

Expand Down
37 changes: 35 additions & 2 deletions src/Feature.php
Expand Up @@ -2,8 +2,10 @@

namespace FriendsOfCat\LaravelFeatureFlags;

use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use FriendsOfCat\LaravelFeatureFlags\FeatureFlagsEnabler;

class Feature
{
Expand Down Expand Up @@ -48,7 +50,7 @@ public function isEnabled($featureKey, $variant = null, $user = null)
}

if ($variant != self::ON and $variant != self::OFF) {
return $this->isUserEnabled($variant, $user);
return $this->isUserEnabled($variant, $user) || $this->isRoleEnabled($variant, $user);
}

return $variant == self::ON;
Expand Down Expand Up @@ -95,7 +97,6 @@ protected function isUserEnabled($feature_variant, $user = null)
return false;
}


/**
* @param \Illuminate\Contracts\Auth\Access\Authorizable $user (optional)
* @return string
Expand All @@ -112,4 +113,36 @@ public function getUserEmail($user)

return Auth::user()->email;
}

private function getUserRoles($user)
{
return ($user && $user->roles) ? $user->roles : false;
}

public function isRoleEnabled($feature_variant, $user = null)
{
$fieldName = 'roles';

if (empty($feature_variant[$fieldName])) {
return false;
}

$user = $user ?? Auth::user();
if ($user_roles =
($user instanceof FeatureFlagsEnabler)
? $user->getFieldValueForFeatureFlags($fieldName)
: $this->getUserRoles($user)
) {
$filtered = Arr::where(
array_map('strtolower', $user_roles),
function ($value, $key) use ($feature_variant, $fieldName) {
return in_array($value, $feature_variant[$fieldName], true);
}
);

return ! empty($filtered);
}

return false;
}
}
4 changes: 4 additions & 0 deletions src/FeatureFlagHelper.php
Expand Up @@ -46,6 +46,10 @@ private function transformFeatures($features, $value, $key)
$features[$value['key']]['users'] = $value['variants']['users'];
}

if (isset($value['variants']['roles'])) {
$features[$value['key']]['roles'] = $value['variants']['roles'];
}

return $features;
}

Expand Down
11 changes: 11 additions & 0 deletions src/FeatureFlagUserRoleTrait.php
@@ -0,0 +1,11 @@
<?php

namespace FriendsOfCat\LaravelFeatureFlags;

trait FeatureFlagUserRoleTrait
{
public function getFieldValueForFeatureFlags(string $fieldName): ?array
{
return (array) json_decode($this->$fieldName, true);
}
}
8 changes: 8 additions & 0 deletions src/FeatureFlagsEnabler.php
@@ -0,0 +1,8 @@
<?php

namespace FriendsOfCat\LaravelFeatureFlags;

interface FeatureFlagsEnabler
{
public function getFieldValueForFeatureFlags(string $fieldName): ?array;
}
45 changes: 45 additions & 0 deletions tests/FeatureFlagTest.php
Expand Up @@ -111,4 +111,49 @@ public function testForNotFindFeature()
$this->assertFalse($this->app->get(Gate::class)->allows('feature-flag', 'testing'));
}

public function testOnForUserRole()
{
$this->user = factory(FeatureFlagUser::class)->create(['email' => 'foo2@gmail.com']);
$this->user->setRawAttributes(['roles' => ['admin', 'editor']]);

$this->be($this->user);

factory(FeatureFlag::class)->create(
[
'key' => 'testing',
'variants' => [
'roles' => [
'admin'
]
]
]
);

$this->registerFeatureFlags();

$this->assertTrue($this->app->get(Gate::class)->allows('feature-flag', 'testing'));
}

public function testOffForUserRole()
{
$this->user = factory(FeatureFlagUser::class)->create(['email' => 'foo2@gmail.com']);
$this->user->setRawAttributes(['roles' => ['editor']]);

$this->be($this->user);

factory(FeatureFlag::class)->create(
[
'key' => 'testing',
'variants' => [
'roles' => [
'admin', 'manager'
]
]
]
);

$this->registerFeatureFlags();

$this->assertFalse($this->app->get(Gate::class)->allows('feature-flag', 'testing'));
}
}
61 changes: 61 additions & 0 deletions tests/FeatureFlagsEnablerTest.php
@@ -0,0 +1,61 @@
<?php

namespace Tests;

use Illuminate\Contracts\Auth\Access\Gate;
use Illuminate\Foundation\Testing\WithFaker;
use FriendsOfCat\LaravelFeatureFlags\FeatureFlag;
use Illuminate\Foundation\Testing\RefreshDatabase;
use FriendsOfCat\LaravelFeatureFlags\FeatureFlagHelper;
use Tests\fixtures\UserWithFeatureFlagsEnablerInterface;

class FeatureFlagsEnablerTest extends TestCase
{
use RefreshDatabase, WithFaker, FeatureFlagHelper;

/**
* @dataProvider validData
*/
public function testItWorksWhenInterfaceImplented($userRoles)
{
$user = new UserWithFeatureFlagsEnablerInterface([
'name' => $this->faker->word,
'email' => $this->faker->email,
'password' => bcrypt(str_random(25)),
'roles' => json_encode($userRoles)
]);
$user->save();

$this->be($user);

factory(FeatureFlag::class)->create(
[
'key' => 'testing',
'variants' => [
'roles' => [
'developer', 'admin'
]
]
]
);

$this->registerFeatureFlags();

$this->assertTrue($this->app->get(Gate::class)->allows('feature-flag', 'testing'));
}

public function validData()
{
return [
[
'admin'
],
[
['admin', 'developer']
],
[
'developer'
]
];
}
}
22 changes: 22 additions & 0 deletions tests/fixtures/UserWithFeatureFlagsEnablerInterface.php
@@ -0,0 +1,22 @@
<?php

namespace Tests\fixtures;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable;
use FriendsOfCat\LaravelFeatureFlags\FeatureFlagsEnabler;
use FriendsOfCat\LaravelFeatureFlags\FeatureFlagUserRoleTrait;
use Illuminate\Auth\Authenticatable as AuthenticableTrait;

class UserWithFeatureFlagsEnablerInterface extends Model implements Authenticatable, FeatureFlagsEnabler
{
use AuthenticableTrait, FeatureFlagUserRoleTrait;

protected $table = 'users';
protected $fillable = ['name', 'email', 'password', 'roles'];

public function __construct(array $attributes = [ ])
{
parent::__construct($attributes);
}
}
24 changes: 24 additions & 0 deletions tests/migrations/2020_09_11_1141689_add_roles_in_users_table.php
@@ -0,0 +1,24 @@
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddRolesInUsersTable extends Migration
{
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('roles')->nullable();
});
}

public function down()
{
if (Schema::hasColumn('users', 'roles')) {
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('roles');
});
}
}
}
6 changes: 6 additions & 0 deletions views/form.blade.php
Expand Up @@ -21,6 +21,12 @@
<pre>{ "users": [ "foo@gmail.com" ] }</pre>
or
<br>
<pre>{ "roles": [ "developer" ] }</pre>
or
<br>
<pre>{ "roles": [ "developer" ], "users": [ "foo@bar.com" ] }</pre>
or
<br>
<pre>"off"</pre>
</div>
</div>
Expand Down

0 comments on commit fceaa32

Please sign in to comment.