tao-test/app/taoDacSimple/model/DataBaseAccess.php

389 lines
13 KiB
PHP

<?php
/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* 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);
*
*
*/
namespace oat\taoDacSimple\model;
use common_persistence_SqlPersistence;
use oat\oatbox\event\EventManager;
use oat\oatbox\service\ConfigurableService;
use oat\taoDacSimple\model\event\DacAddedEvent;
use oat\taoDacSimple\model\event\DacRemovedEvent;
use oat\generis\persistence\PersistenceManager;
use PDO;
/**
* Class to handle the storage and retrieval of permissions
*
* @author Antoine Robin <antoine.robin@vesperiagroup.com>
* @author Joel Bout <joel@taotesting.com>
*/
class DataBaseAccess extends ConfigurableService
{
const SERVICE_ID = 'taoDacSimple/DataBaseAccess';
const OPTION_PERSISTENCE = 'persistence';
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 $persistence;
/**
* @return EventManager
*/
protected function getEventManager()
{
return $this->getServiceLocator()->get(EventManager::SERVICE_ID);
}
/**
* We can know which users have a privilege on a resource
* @param array $resourceIds
* @return array list of users
*/
public function getUsersWithPermissions($resourceIds)
{
$inQuery = implode(',', array_fill(0, count($resourceIds), '?'));
$query = sprintf(
'SELECT %s, %s, %s FROM %s WHERE %s IN (%s)',
self::COLUMN_RESOURCE_ID,
self::COLUMN_USER_ID,
self::COLUMN_PRIVILEGE,
self::TABLE_PRIVILEGES_NAME,
self::COLUMN_RESOURCE_ID,
$inQuery
);
return $this->fetchQuery($query, $resourceIds);
}
/**
* Get the permissions for a list of resources and users
*
* @access public
* @param array $userIds
* @param array $resourceIds
* @return array
*/
public function getPermissions($userIds, array $resourceIds)
{
// permission request for empty resources must return 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(
'SELECT %s, %s FROM %s WHERE %s IN (%s) AND %s IN (%s)',
self::COLUMN_RESOURCE_ID,
self::COLUMN_PRIVILEGE,
self::TABLE_PRIVILEGES_NAME,
self::COLUMN_RESOURCE_ID,
$inQueryResource,
self::COLUMN_USER_ID,
$inQueryUser
);
$params = array_merge(array_values($resourceIds), array_values($userIds));
//If resource doesn't have permission don't return null
$returnValue = array_fill_keys($resourceIds, []);
$results = $this->fetchQuery($query, $params);
foreach ($results as $result) {
$returnValue[$result[self::COLUMN_RESOURCE_ID]][] = $result[self::COLUMN_PRIVILEGE];
}
return $returnValue;
}
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 $returnValue;
}
/**
* add permissions of a user to a resource
*
* @access public
* @param string $user
* @param string $resourceId
* @param array $rights
*
* @return bool
*/
public function addPermissions($user, $resourceId, $rights)
{
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]
);
}
$this->getEventManager()->trigger(new DacAddedEvent($user, $resourceId, (array)$rights));
return true;
}
/**
* add batch permissions
*
* @access public
* @param array $permissionData
* @return void
*/
public function addMultiplePermissions(array $permissionData)
{
$insert = [];
foreach ($permissionData as $permissionItem) {
foreach ($permissionItem['permissions'] as $userId => $privilegeIds) {
if (!empty($privilegeIds)) {
foreach ($privilegeIds as $privilegeId) {
$insert [] = [
self::COLUMN_USER_ID => $userId,
self::COLUMN_RESOURCE_ID => $permissionItem['resource']->getUri(),
self::COLUMN_PRIVILEGE => $privilegeId
];
}
}
}
}
$this->getPersistence()->insertMultiple(self::TABLE_PRIVILEGES_NAME, $insert);
foreach ($insert as $inserted) {
$this->getEventManager()->trigger(new DacAddedEvent(
$inserted[self::COLUMN_USER_ID],
$inserted[self::COLUMN_RESOURCE_ID],
(array)$inserted[self::COLUMN_PRIVILEGE]
));
}
}
/**
* Get the permissions to resource
*
* @access public
* @param string $resourceId
* @return array
*/
public function getResourcePermissions($resourceId)
{
// get privileges for a user/roles and a resource
$query = sprintf(
'SELECT %s, %s FROM %s WHERE %s = ?',
self::COLUMN_USER_ID,
self::COLUMN_PRIVILEGE,
self::TABLE_PRIVILEGES_NAME,
self::COLUMN_RESOURCE_ID
);
$results = $this->fetchQuery($query, [$resourceId]);
foreach ($results as $result) {
$returnValue[$result[self::COLUMN_USER_ID]][] = $result[self::COLUMN_PRIVILEGE];
}
return $returnValue ?? [];
}
/**
* remove permissions to a resource for a user
*
* @access public
* @param string $user
* @param string $resourceId
* @param array $rights
* @return boolean
*/
public function removePermissions($user, $resourceId, $rights)
{
//get all entries that match (user,resourceId) and remove them
$inQueryPrivilege = implode(',', array_fill(0, count($rights), ' ? '));
$query = sprintf(
'DELETE FROM %s WHERE %s = ? AND %s IN (%s) AND %s = ?',
self::TABLE_PRIVILEGES_NAME,
self::COLUMN_RESOURCE_ID,
self::COLUMN_PRIVILEGE,
$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));
return true;
}
/**
* remove batch permissions
*
* @access public
* @param array $data
* @return void
*/
public function removeMultiplePermissions(array $data)
{
$groupedRemove = [];
$eventsData = [];
foreach ($data as $permissionItem) {
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];
}
}
}
foreach ($groupedRemove as $userId => $resources) {
foreach ($resources as $permissions) {
$inQueryPrivilege = implode(',', array_fill(0, count($permissions['privileges']), ' ? '));
$inQueryResources = implode(',', array_fill(0, count($permissions['resources']), ' ? '));
$query = sprintf(
'DELETE FROM %s WHERE %s IN (%s) AND %s IN (%s) AND %s = ?',
self::TABLE_PRIVILEGES_NAME,
self::COLUMN_RESOURCE_ID,
$inQueryResources,
self::COLUMN_PRIVILEGE,
$inQueryPrivilege,
self::COLUMN_USER_ID
);
$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']));
}
}
/**
* Remove all permissions from a resource
*
* @access public
* @param array $resourceIds
* @return boolean
*/
public function removeAllPermissions($resourceIds)
{
//get all entries that match (resourceId) and remove them
$inQuery = implode(',', array_fill(0, count($resourceIds), ' ? '));
$query = sprintf(
'DELETE FROM %s WHERE %s IN (%s)',
self::TABLE_PRIVILEGES_NAME,
self::COLUMN_RESOURCE_ID,
$inQuery
);
$this->getPersistence()->exec($query, $resourceIds);
foreach ($resourceIds as $resourceId) {
$this->getEventManager()->trigger(new DacRemovedEvent('-', $resourceId, '-'));
}
return true;
}
/**
* Filter users\roles that have no permissions
*
* @access public
* @param array $userIds
* @return array
*/
public function checkPermissions($userIds)
{
$inQueryUser = implode(',', array_fill(0, count($userIds), ' ? '));
$query = sprintf(
'SELECT %s FROM %s WHERE %s IN (%s)',
self::COLUMN_USER_ID,
self::TABLE_PRIVILEGES_NAME,
self::COLUMN_USER_ID,
$inQueryUser
);
$results = $this->fetchQuery($query, array_values($userIds));
foreach ($results as $result) {
$existsUsers[$result[self::COLUMN_USER_ID]] = $result[self::COLUMN_USER_ID];
}
return $existsUsers ?? [];
}
/**
* @return common_persistence_SqlPersistence
*/
private function getPersistence()
{
if (!$this->persistence) {
$this->persistence = $this->getServiceLocator()->get(PersistenceManager::SERVICE_ID)
->getPersistenceById($this->getOption(self::OPTION_PERSISTENCE));
}
return $this->persistence;
}
/**
* @param string $query
* @param array $params
* @return array
*/
private function fetchQuery($query, $params)
{
$statement = $this->getPersistence()->query($query, $params);
return $statement->fetchAll(PDO::FETCH_ASSOC);
}
public function createTables()
{
$schemaManager = $this->getPersistence()->getDriver()->getSchemaManager();
$schema = $schemaManager->createSchema();
$fromSchema = clone $schema;
$table = $schema->createtable(self::TABLE_PRIVILEGES_NAME);
$table->addColumn(self::COLUMN_USER_ID, 'string', ['notnull' => null, 'length' => 255]);
$table->addColumn(self::COLUMN_RESOURCE_ID, 'string', ['notnull' => null, 'length' => 255]);
$table->addColumn(self::COLUMN_PRIVILEGE, 'string', ['notnull' => null, 'length' => 255]);
$table->setPrimaryKey([self::COLUMN_USER_ID, self::COLUMN_RESOURCE_ID, self::COLUMN_PRIVILEGE]);
$table->addIndex([self::COLUMN_RESOURCE_ID], self::INDEX_RESOURCE_ID);
$queries = $this->getPersistence()->getPlatform()->getMigrateSchemaSql($fromSchema, $schema);
foreach ($queries as $query) {
$this->getPersistence()->exec($query);
}
}
public function removeTables()
{
$persistence = $this->getPersistence();
$schema = $persistence->getDriver()->getSchemaManager()->createSchema();
$fromSchema = clone $schema;
$table = $schema->dropTable(self::TABLE_PRIVILEGES_NAME);
$queries = $persistence->getPlatform()->getMigrateSchemaSql($fromSchema, $schema);
foreach ($queries as $query) {
$persistence->exec($query);
}
}
}