Skip to content

Commit

Permalink
Merge branch 'release-7.4.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions committed Nov 15, 2021
2 parents e702932 + 95e6650 commit 5556b2f
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 137 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
},
"minimum-stability" : "dev",
"require": {
"php": ">=7.1",
"oat-sa/oatbox-extension-installer": "~1.1||dev-master",
"oat-sa/generis" : ">=14.0.0",
"oat-sa/tao-core" : ">=48.0.0",
Expand Down
155 changes: 115 additions & 40 deletions model/DataBaseAccess.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2014 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
*
*
* Copyright (c) 2014-2021 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
*/

namespace oat\taoDacSimple\model;
Expand All @@ -29,6 +27,7 @@
use oat\taoDacSimple\model\event\DacRemovedEvent;
use oat\generis\persistence\PersistenceManager;
use PDO;
use Throwable;

/**
* Class to handle the storage and retrieval of permissions
Expand All @@ -38,19 +37,24 @@
*/
class DataBaseAccess extends ConfigurableService
{
public const SERVICE_ID = 'taoDacSimple/DataBaseAccess';

const SERVICE_ID = 'taoDacSimple/DataBaseAccess';
public const OPTION_PERSISTENCE = 'persistence';

const OPTION_PERSISTENCE = 'persistence';
public const COLUMN_USER_ID = 'user_id';
public const COLUMN_RESOURCE_ID = 'resource_id';
public const COLUMN_PRIVILEGE = 'privilege';
public const TABLE_PRIVILEGES_NAME = 'data_privileges';
public const INDEX_RESOURCE_ID = 'data_privileges_resource_id_index';

const COLUMN_USER_ID = 'user_id';
const COLUMN_RESOURCE_ID = 'resource_id';
const COLUMN_PRIVILEGE = 'privilege';
const TABLE_PRIVILEGES_NAME = 'data_privileges';
const INDEX_RESOURCE_ID = 'data_privileges_resource_id_index';
private $insertChunkSize = 20000;

private $persistence;

public function setInsertChunkSize(int $size): void
{
$this->insertChunkSize = $size;
}

/**
* @return EventManager
Expand All @@ -61,9 +65,10 @@ protected function getEventManager()
}

/**
* We can know which users have a privilege on a resource
* @param array $resourceIds
* @return array list of users
* Retrieve info on users having privileges on a set of resources
*
* @param array $resourceIds IDs of resources to fetch privileges for
* @return array A list of rows containing resource ID, user ID and privilege name
*/
public function getUsersWithPermissions($resourceIds)
{
Expand All @@ -77,6 +82,7 @@ public function getUsersWithPermissions($resourceIds)
self::COLUMN_RESOURCE_ID,
$inQuery
);

return $this->fetchQuery($query, $resourceIds);
}

Expand All @@ -88,13 +94,13 @@ public function getUsersWithPermissions($resourceIds)
* @param array $resourceIds
* @return array
*/
public function getPermissions($userIds, array $resourceIds)
public function getPermissions(array $userIds, array $resourceIds): array
{
// permission request for empty resources must return an empty array
// Permissions for an empty set of resources must be an empty array
if (!count($resourceIds)) {
return [];
}
// get privileges for a user/roles and a resource

$inQueryResource = implode(',', array_fill(0, count($resourceIds), '?'));
$inQueryUser = implode(',', array_fill(0, count($userIds), '?'));
$query = sprintf(
Expand Down Expand Up @@ -122,17 +128,19 @@ public function getPermissions($userIds, array $resourceIds)

public function getResourcesPermissions(array $resourceIds)
{
//If resource doesn't have permission don't return null
$returnValue = array_fill_keys($resourceIds, []);
$results = $this->getUsersWithPermissions($resourceIds);
foreach ($results as $result) {
$returnValue[$result[self::COLUMN_RESOURCE_ID]][$result[self::COLUMN_USER_ID]][] = $result[self::COLUMN_PRIVILEGE];
// Return an empty array for resources not having permissions data
$grants = array_fill_keys($resourceIds, []);

foreach ($this->getUsersWithPermissions($resourceIds) as $entry) {
$grants[$entry[self::COLUMN_RESOURCE_ID]][$entry[self::COLUMN_USER_ID]][]
= $entry[self::COLUMN_PRIVILEGE];
}
return $returnValue;

return $grants;
}

/**
* add permissions of a user to a resource
* Add permissions of a user to a resource
*
* @access public
* @param string $user
Expand All @@ -143,23 +151,34 @@ public function getResourcesPermissions(array $resourceIds)
*/
public function addPermissions($user, $resourceId, $rights)
{
// Add an ACL item for each user URI, resource ID and privilege combination
foreach ($rights as $privilege) {
// add a line with user URI, resource Id and privilege
$this->getPersistence()->insert(
self::TABLE_PRIVILEGES_NAME,
[self::COLUMN_USER_ID => $user, self::COLUMN_RESOURCE_ID => $resourceId, self::COLUMN_PRIVILEGE => $privilege]
[
self::COLUMN_USER_ID => $user,
self::COLUMN_RESOURCE_ID => $resourceId,
self::COLUMN_PRIVILEGE => $privilege
]
);
}
$this->getEventManager()->trigger(new DacAddedEvent($user, $resourceId, (array)$rights));

$this->getEventManager()->trigger(new DacAddedEvent(
$user,
$resourceId,
(array)$rights
));

return true;
}

/**
* add batch permissions
* Add batch permissions
*
* @access public
* @param array $permissionData
* @return void
* @throws Throwable
*/
public function addMultiplePermissions(array $permissionData)
{
Expand All @@ -177,7 +196,9 @@ public function addMultiplePermissions(array $permissionData)
}
}
}
$this->getPersistence()->insertMultiple(self::TABLE_PRIVILEGES_NAME, $insert);

$this->insertPermissions($insert);

foreach ($insert as $inserted) {
$this->getEventManager()->trigger(new DacAddedEvent(
$inserted[self::COLUMN_USER_ID],
Expand All @@ -196,7 +217,7 @@ public function addMultiplePermissions(array $permissionData)
*/
public function getResourcePermissions($resourceId)
{
// get privileges for a user/roles and a resource
$grants = [];
$query = sprintf(
'SELECT %s, %s FROM %s WHERE %s = ?',
self::COLUMN_USER_ID,
Expand All @@ -205,11 +226,11 @@ public function getResourcePermissions($resourceId)
self::COLUMN_RESOURCE_ID
);

$results = $this->fetchQuery($query, [$resourceId]);
foreach ($results as $result) {
$returnValue[$result[self::COLUMN_USER_ID]][] = $result[self::COLUMN_PRIVILEGE];
foreach ($this->fetchQuery($query, [$resourceId]) as $entry) {
$grants[$entry[self::COLUMN_USER_ID]][] = $entry[self::COLUMN_PRIVILEGE];
}
return $returnValue ?? [];

return $grants;
}

/**
Expand All @@ -233,15 +254,21 @@ public function removePermissions($user, $resourceId, $rights)
$inQueryPrivilege,
self::COLUMN_USER_ID
);

$params = array_merge([$resourceId], array_values($rights), [$user]);
$this->getPersistence()->exec($query, $params);
$this->getEventManager()->trigger(new DacRemovedEvent($user, $resourceId, $rights));

$this->getEventManager()->trigger(new DacRemovedEvent(
$user,
$resourceId,
$rights
));

return true;
}

/**
* remove batch permissions
* Remove batch permissions
*
* @access public
* @param array $data
Expand All @@ -252,11 +279,19 @@ public function removeMultiplePermissions(array $data)
$groupedRemove = [];
$eventsData = [];
foreach ($data as $permissionItem) {
$resource = &$permissionItem['resource'];
foreach ($permissionItem['permissions'] as $userId => $privilegeIds) {
if (!empty($privilegeIds)) {
$groupedRemove[$userId][implode($privilegeIds)]['resources'][] = $permissionItem['resource']->getUri();
$groupedRemove[$userId][implode($privilegeIds)]['privileges'] = $privilegeIds;
$eventsData[] = ['userId' => $userId, 'resourceId' => $permissionItem['resource']->getUri(), 'privileges' => $privilegeIds];
$idString = implode($privilegeIds);

$groupedRemove[$userId][$idString]['resources'][] = $resource->getUri();
$groupedRemove[$userId][$idString]['privileges'] = $privilegeIds;

$eventsData[] = [
'userId' => $userId,
'resourceId' => $resource->getUri(),
'privileges' => $privilegeIds
];
}
}
}
Expand All @@ -273,12 +308,23 @@ public function removeMultiplePermissions(array $data)
$inQueryPrivilege,
self::COLUMN_USER_ID
);
$params = array_merge(array_values($permissions['resources']), array_values($permissions['privileges']), [$userId]);

$params = array_merge(
array_values($permissions['resources']),
array_values($permissions['privileges']),
[$userId]
);

$this->getPersistence()->exec($query, $params);
}
}

foreach ($eventsData as $eventData) {
$this->getEventManager()->trigger(new DacRemovedEvent($eventData['userId'], $eventData['resourceId'], $eventData['privileges']));
$this->getEventManager()->trigger(new DacRemovedEvent(
$eventData['userId'],
$eventData['resourceId'],
$eventData['privileges']
));
}
}

Expand Down Expand Up @@ -385,4 +431,33 @@ public function removeTables()
$persistence->exec($query);
}
}

/**
* @throws Throwable
*/
private function insertPermissions(array $insert): void
{
if (empty($insert)) {
return;
}

$logger = $this->getLogger();
$insertCount = count($insert);
$persistence = $this->getPersistence();

$persistence->transactional(function () use ($insert, $logger, $insertCount, $persistence) {
foreach (array_chunk($insert, $this->insertChunkSize) as $index => $batch) {
$logger->debug(
'Processing chunk {index}/{total} with {items} ACL entries',
[
'index' => $index + 1,
'total' => ceil($insertCount / $this->insertChunkSize),
'items' => count($batch)
]
);

$persistence->insertMultiple(self::TABLE_PRIVILEGES_NAME, $batch);
}
});
}
}
Loading

0 comments on commit 5556b2f

Please sign in to comment.