Skip to content

Commit

Permalink
Merge pull request #18 from basakest/update_policies
Browse files Browse the repository at this point in the history
feat: support updateFilteredPolicies, updatePolicies method
  • Loading branch information
leeqvip committed Nov 22, 2021
2 parents 863057d + d3b232b commit 12d4807
Show file tree
Hide file tree
Showing 4 changed files with 278 additions and 11 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Expand Up @@ -123,7 +123,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: '12'
node-version: '14.17'

- name: Run semantic-release
env:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -8,3 +8,5 @@ composer.lock
.php_cs.cache
/runtime
*.log
.phpunit.result.cache
build/
124 changes: 117 additions & 7 deletions src/Adapters/DatabaseAdapter.php
Expand Up @@ -14,6 +14,7 @@
use Casbin\Persist\Adapters\Filter;
use Casbin\Exceptions\InvalidFilterTypeException;
use Casbin\Persist\UpdatableAdapter;
use EasySwoole\ORM\DbManager;

class DatabaseAdapter implements Adapter, BatchAdapter, FilteredAdapter, UpdatableAdapter
{
Expand All @@ -24,6 +25,27 @@ class DatabaseAdapter implements Adapter, BatchAdapter, FilteredAdapter, Updatab
*/
private $filtered = false;

/**
* Filter the rule.
*
* @param array $rule
*
* @return array
*/
public function filterRule(array $rule): array
{
$rule = array_values($rule);

$i = count($rule) - 1;
for (; $i >= 0; $i--) {
if ($rule[$i] != '' && !is_null($rule[$i])) {
break;
}
}

return array_slice($rule, 0, $i + 1);
}

/**
* savePolicyLine function.
*
Expand Down Expand Up @@ -129,18 +151,17 @@ public function removePolicy(string $sec, string $ptype, array $rule): void
}

/**
* RemoveFilteredPolicy removes policy rules that match the filter from the storage.
* This is part of the Auto-Save feature.
*
* @param string $sec
* @param string $ptype
* @param int $fieldIndex
* @param int $fieldIndex
* @param string ...$fieldValues
* @return array
* @throws Exception
* @throws Throwable
*/
public function removeFilteredPolicy(string $sec, string $ptype, int $fieldIndex, string ...$fieldValues): void
public function _removeFilteredPolicy(string $sec, string $ptype, int $fieldIndex, ?string ...$fieldValues): array
{
$removedRules = [];
$instance = RulesModel::create()->where(['ptype' => $ptype]);

foreach (range(0, 5) as $value) {
Expand All @@ -151,7 +172,37 @@ public function removeFilteredPolicy(string $sec, string $ptype, int $fieldIndex
}
}

$instance->destroy();
$results = (clone $instance)->all();
if (!$results instanceof Collection) {
$results = new Collection($results);
}

$oldP = $results->hidden(['id', 'ptype', 'create_time', 'update_time'])->toArray(false, false);
foreach ($oldP as &$item) {
$item = $this->filterRule($item);
$removedRules[] = $item;
}

$instance->destroy(null, true);

return $removedRules;
}

/**
* RemoveFilteredPolicy removes policy rules that match the filter from the storage.
* This is part of the Auto-Save feature.
*
* @param string $sec
* @param string $ptype
* @param int $fieldIndex
* @param string ...$fieldValues
* @return void
* @throws Exception
* @throws Throwable
*/
public function removeFilteredPolicy(string $sec, string $ptype, int $fieldIndex, string ...$fieldValues): void
{
$this->_removeFilteredPolicy($sec, $ptype, $fieldIndex, ...$fieldValues);
}

/**
Expand Down Expand Up @@ -227,7 +278,7 @@ public function loadFilteredPolicy(Model $model, $filter): void
throw new InvalidFilterTypeException('invalid filter type');
}
$rows = $instance->all();
//var_dump($rows);

foreach ($rows as $row) {
$row = $row->hidden(['create_time','update_time', 'id'])->toArray();
$row = array_filter($row, function($value) { return !is_null($value) && $value !== ''; });
Expand Down Expand Up @@ -287,4 +338,63 @@ public function updatePolicy(string $sec, string $ptype, array $oldRule, array $

$instance->update($update);
}

/**
* UpdatePolicies updates some policy rules to storage, like db, redis.
*
* @param string $sec
* @param string $ptype
* @param string[][] $oldRules
* @param string[][] $newRules
*
* @return void
*/
public function updatePolicies(string $sec, string $ptype, array $oldRules, array $newRules): void
{
try {
// start transaction
DbManager::getInstance()->startTransaction();

foreach ($oldRules as $i => $oldRule) {
$this->updatePolicy($sec, $ptype, $oldRule, $newRules[$i]);
}

// commit transaction
DbManager::getInstance()->commit();
} catch (\Throwable $e) {
// rollback transaction
DbManager::getInstance()->rollback();
}
}

/**
* UpdateFilteredPolicies deletes old rules and adds new rules.
*
* @param string $sec
* @param string $ptype
* @param array $newPolicies
* @param int $fieldIndex
* @param string ...$fieldValues
*
* @return array
*/
public function updateFilteredPolicies(string $sec, string $ptype, array $newPolicies, int $fieldIndex, string ...$fieldValues): array
{
$oldRules = [];
try {
// start transaction
DbManager::getInstance()->startTransaction();

$oldRules = $this->_removeFilteredPolicy($sec, $ptype, $fieldIndex, ...$fieldValues);
$this->addPolicies($sec, $ptype, $newPolicies);

// commit transaction
DbManager::getInstance()->commit();
} catch (\Throwable $e) {
// rollback transaction
DbManager::getInstance()->rollback();
}

return $oldRules;
}
}
161 changes: 158 additions & 3 deletions tests/DatabaseAdapterTest.php
Expand Up @@ -13,8 +13,6 @@

class DatabaseAdapterTest extends TestCase
{


public function setUp():void
{
$conf = [
Expand Down Expand Up @@ -215,4 +213,161 @@ public function testUpdatePolicy()
['data2_admin', 'data2', 'write'],
], $e->getPolicy());
}
}

public function testUpdatePolicies()
{
$e = $this->getEnforcer();

$this->assertEquals([
['alice', 'data1', 'read'],
['bob', 'data2', 'write'],
['data2_admin', 'data2', 'read'],
['data2_admin', 'data2', 'write'],
], $e->getPolicy());

$oldPolicies = [
['alice', 'data1', 'read'],
['bob', 'data2', 'write']
];
$newPolicies = [
['alice', 'data1', 'write'],
['bob', 'data2', 'read']
];

$e->updatePolicies($oldPolicies, $newPolicies);

$this->assertEquals([
['alice', 'data1', 'write'],
['bob', 'data2', 'read'],
['data2_admin', 'data2', 'read'],
['data2_admin', 'data2', 'write'],
], $e->getPolicy());
}

public function arrayEqualsWithoutOrder(array $expected, array $actual)
{
if (method_exists($this, 'assertEqualsCanonicalizing')) {
$this->assertEqualsCanonicalizing($expected, $actual);
} else {
array_multisort($expected);
array_multisort($actual);
$this->assertEquals($expected, $actual);
}
}

public function testUpdateFilteredPolicies()
{
$e = $this->getEnforcer();

$this->assertEquals([
['alice', 'data1', 'read'],
['bob', 'data2', 'write'],
['data2_admin', 'data2', 'read'],
['data2_admin', 'data2', 'write'],
], $e->getPolicy());

$e->updateFilteredPolicies([["alice", "data1", "write"]], 0, "alice", "data1", "read");
$e->updateFilteredPolicies([["bob", "data2", "read"]], 0, "bob", "data2", "write");

$policies = [
['alice', 'data1', 'write'],
['bob', 'data2', 'read'],
['data2_admin', 'data2', 'read'],
['data2_admin', 'data2', 'write']
];

$this->arrayEqualsWithoutOrder($policies, $e->getPolicy());

// test use updateFilteredPolicies to update all policies of a user
$this->initDb();
$e->loadPolicy();
$policies = [
['alice', 'data2', 'write'],
['bob', 'data1', 'read']
];
$e->addPolicies($policies);

$this->arrayEqualsWithoutOrder([
['alice', 'data1', 'read'],
['bob', 'data2', 'write'],
['data2_admin', 'data2', 'read'],
['data2_admin', 'data2', 'write'],
['alice', 'data2', 'write'],
['bob', 'data1', 'read']
], $e->getPolicy());

$e->updateFilteredPolicies([['alice', 'data1', 'write'], ['alice', 'data2', 'read']], 0, 'alice');
$e->updateFilteredPolicies([['bob', 'data1', 'write'], ["bob", "data2", "read"]], 0, 'bob');

$policies = [
['alice', 'data1', 'write'],
['alice', 'data2', 'read'],
['bob', 'data1', 'write'],
['bob', 'data2', 'read'],
['data2_admin', 'data2', 'read'],
['data2_admin', 'data2', 'write']
];

$this->arrayEqualsWithoutOrder($policies, $e->getPolicy());

// test if $fieldValues contains empty string
$this->initDb();
$e->loadPolicy();
$policies = [
['alice', 'data2', 'write'],
['bob', 'data1', 'read']
];
$e->addPolicies($policies);

$this->assertEquals([
['alice', 'data1', 'read'],
['bob', 'data2', 'write'],
['data2_admin', 'data2', 'read'],
['data2_admin', 'data2', 'write'],
['alice', 'data2', 'write'],
['bob', 'data1', 'read']
], $e->getPolicy());

$e->updateFilteredPolicies([['alice', 'data1', 'write'], ['alice', 'data2', 'read']], 0, 'alice', '', '');
$e->updateFilteredPolicies([['bob', 'data1', 'write'], ["bob", "data2", "read"]], 0, 'bob', '', '');

$policies = [
['alice', 'data1', 'write'],
['alice', 'data2', 'read'],
['bob', 'data1', 'write'],
['bob', 'data2', 'read'],
['data2_admin', 'data2', 'read'],
['data2_admin', 'data2', 'write']
];

$this->arrayEqualsWithoutOrder($policies, $e->getPolicy());

// test if $fieldIndex is not zero
$this->initDb();
$e->loadPolicy();
$policies = [
['alice', 'data2', 'write'],
['bob', 'data1', 'read']
];
$e->addPolicies($policies);

$this->assertEquals([
['alice', 'data1', 'read'],
['bob', 'data2', 'write'],
['data2_admin', 'data2', 'read'],
['data2_admin', 'data2', 'write'],
['alice', 'data2', 'write'],
['bob', 'data1', 'read']
], $e->getPolicy());

$e->updateFilteredPolicies([['alice', 'data1', 'write'], ['bob', 'data1', 'write']], 2, 'read');
$e->updateFilteredPolicies([['alice', 'data2', 'read'], ["bob", "data2", "read"]], 2, 'write');

$policies = [
['alice', 'data2', 'read'],
['bob', 'data2', 'read'],
];

$this->arrayEqualsWithoutOrder($policies, $e->getPolicy());
}
}

0 comments on commit 12d4807

Please sign in to comment.