Commit 2f5508e1 authored by Tino Goratsch's avatar Tino Goratsch

separated the installation of the ACL resources from the SchemaInstaller

parent c2a9e49f
<?php
namespace ACP3\Core\Modules;
use ACP3\Core\Cache;
use ACP3\Core\Modules\Installer\SchemaInterface;
use Symfony\Component\DependencyInjection\Container;
use ACP3\Modules\ACP3\Permissions;
/**
* Class AclInstaller
* @package ACP3\Core\Modules
*/
class AclInstaller implements InstallerInterface
{
/**
* @var \Symfony\Component\DependencyInjection\Container
*/
protected $container;
/**
* @var \ACP3\Core\Cache
*/
protected $aclCache;
/**
* @var \ACP3\Modules\ACP3\Permissions\Model
*/
protected $permissionsModel;
/**
* @var \ACP3\Core\Modules\SchemaHelper
*/
protected $schemaHelper;
/**
* @param \Symfony\Component\DependencyInjection\Container $container
* @param \ACP3\Core\Cache $aclCache
* @param \ACP3\Core\Modules\SchemaHelper $schemaHelper
* @param \ACP3\Modules\ACP3\Permissions\Model $permissionsModel
*/
public function __construct(
Container $container,
Cache $aclCache,
SchemaHelper $schemaHelper,
Permissions\Model $permissionsModel
)
{
$this->container = $container;
$this->aclCache = $aclCache;
$this->schemaHelper = $schemaHelper;
$this->permissionsModel = $permissionsModel;
}
/**
* Fügt die zu einen Modul zugehörigen Ressourcen ein
*
* @param \ACP3\Core\Modules\Installer\SchemaInterface $schema
* @param int $mode
* 1 = Ressourcen und Regeln einlesen
* 2 = Nur die Ressourcen einlesen
*
* @return bool
*/
public function install(SchemaInterface $schema, $mode = 1)
{
$serviceIds = $this->container->getServiceIds();
foreach ($serviceIds as $serviceId) {
if (strpos($serviceId, $schema->getModuleName() . '.controller.') !== false) {
list($module, , $area, $controller) = explode('.', $serviceId);
$this->_insertAclResources($module, $controller, $area, $schema->specialResources());
}
}
// Regeln für die Rollen setzen
if ($mode === 1) {
$this->_insertAclRules($schema->getModuleName());
}
$this->aclCache->getDriver()->deleteAll();
return true;
}
/**
* Inserts a new resource into the database
*
* @param string $module
* @param string $controller
* @param string $area
* @param array $specialResources
*/
protected function _insertAclResources($module, $controller, $area, array $specialResources)
{
$controllerService = $module . '.controller.' . $area . '.' . $controller;
$actions = get_class_methods($this->container->get($controllerService));
$moduleId = $this->schemaHelper->getModuleId($module);
foreach ($actions as $action) {
// Only add the actual module actions (methods which begin with "action")
if (strpos($action, 'action') === 0) {
$actionUnderscored = strtolower(preg_replace('/\B([A-Z])/', '_$1', $action));
// Modulaktionen berücksichtigen, die mit Ziffern anfangen (Error pages)
$action = substr($actionUnderscored, strpos($actionUnderscored, '_') === 6 ? 7 : 6);
// Handle resources with differing access levels
if (isset($specialResources[$area][$controller][$action])) {
$privilegeId = $specialResources[$area][$controller][$action];
} else {
$privilegeId = $this->getDefaultAclPrivilegeId($area, $action);
}
$insertValues = [
'id' => '',
'module_id' => $moduleId,
'area' => !empty($area) ? strtolower($area) : 'frontend',
'controller' => strtolower($controller),
'page' => $action,
'params' => '',
'privilege_id' => (int)$privilegeId
];
$this->permissionsModel->insert($insertValues, Permissions\Model::TABLE_NAME_RESOURCES);
}
}
}
/**
* Insert new acl user rules
*
* @param string $moduleName
*/
protected function _insertAclRules($moduleName)
{
$roles = $this->permissionsModel->getAllRoles();
$privileges = $this->permissionsModel->getAllResourceIds();
$moduleId = $this->schemaHelper->getModuleId($moduleName);
foreach ($roles as $role) {
foreach ($privileges as $privilege) {
$insertValues = [
'id' => '',
'role_id' => $role['id'],
'module_id' => $moduleId,
'privilege_id' => $privilege['id'],
'permission' => $this->getDefaultAclRulePermission($role, $privilege)
];
$this->permissionsModel->insert($insertValues, Permissions\Model::TABLE_NAME_RULES);
}
}
}
/**
* @param string $area
* @param string $action
*
* @return int
*/
protected function getDefaultAclPrivilegeId($area, $action)
{
if ($area === 'Admin') {
if (strpos($action, 'create') === 0 || strpos($action, 'order') === 0) {
return 4;
} elseif (strpos($action, 'edit') === 0) {
return 5;
} elseif (strpos($action, 'delete') === 0) {
return 6;
} elseif (strpos($action, 'settings') === 0) {
return 7;
}
return 3;
}
// Frontend controller actions
if (strpos($action, 'create') === 0) {
return 2;
} else {
return 1;
}
}
/**
* @param array $role
* @param array $privilege
*
* @return int
*/
protected function getDefaultAclRulePermission($role, $privilege)
{
$permission = 0;
if ($role['id'] == 1 && ($privilege['id'] == 1 || $privilege['id'] == 2)) {
$permission = 1;
}
if ($role['id'] > 1 && $role['id'] < 4) {
$permission = 2;
}
if ($role['id'] == 3 && $privilege['id'] == 3) {
$permission = 1;
}
if ($role['id'] == 4) {
$permission = 1;
}
return $permission;
}
/**
* Löscht die zu einem Modul zugehörigen Ressourcen
*
* @param \ACP3\Core\Modules\Installer\SchemaInterface $schema
*
* @return bool
*/
public function uninstall(SchemaInterface $schema)
{
$bool = $this->permissionsModel->delete($this->schemaHelper->getModuleId($schema->getModuleName()), 'module_id', Permissions\Model::TABLE_NAME_RESOURCES);
$bool2 = $this->permissionsModel->delete($this->schemaHelper->getModuleId($schema->getModuleName()), 'module_id', Permissions\Model::TABLE_NAME_RULES);
$this->aclCache->getDriver()->deleteAll();
return $bool !== false && $bool2 !== false;
}
}
\ No newline at end of file
<?php
namespace ACP3\Core\Modules;
use ACP3\Core\Modules\Installer\SchemaInterface;
/**
* Interface InstallerInterface
* @package ACP3\Core\Modules
*/
interface InstallerInterface
{
/**
* @param \ACP3\Core\Modules\Installer\SchemaInterface $schema
*
* @return bool
*/
public function install(SchemaInterface $schema);
/**
* @param \ACP3\Core\Modules\Installer\SchemaInterface $schema
*
* @return bool
*/
public function uninstall(SchemaInterface $schema);
}
\ No newline at end of file
......@@ -5,69 +5,13 @@ namespace ACP3\Core\Modules;
use ACP3\Core;
use ACP3\Core\Modules\Installer\SchemaInterface;
use ACP3\Modules\ACP3\System;
use ACP3\Modules\ACP3\Permissions;
/**
* Class SchemaInstaller
* @package ACP3\Core\Modules
*/
class SchemaInstaller extends SchemaHelper
class SchemaInstaller extends SchemaHelper implements InstallerInterface
{
/**
* @var \ACP3\Core\XML
*/
protected $xml;
/**
* @var \ACP3\Core\Cache
*/
protected $aclCache;
/**
* @var \ACP3\Modules\ACP3\Permissions\Model
*/
protected $permissionsModel;
/**
* @param \ACP3\Core\DB $db
* @param \ACP3\Core\XML $xml
* @param \ACP3\Core\Cache $aclCache
* @param \ACP3\Modules\ACP3\System\Model $systemModel
* @param \ACP3\Modules\ACP3\Permissions\Model $permissionsModel
*/
public function __construct(
Core\DB $db,
Core\XML $xml,
Core\Cache $aclCache,
System\Model $systemModel,
Permissions\Model $permissionsModel
)
{
parent::__construct($db, $systemModel);
$this->xml = $xml;
$this->aclCache = $aclCache;
$this->permissionsModel = $permissionsModel;
}
/**
* Gibt ein Array mit den Abhängigkeiten zu anderen Modulen eines Moduls zurück
*
* @param string $moduleName
*
* @return array
*/
public function getDependencies($moduleName)
{
if ((bool)preg_match('=/=', $moduleName) === false) {
$path = MODULES_DIR . ucfirst($moduleName) . '/config/module.xml';
if (is_file($path) === true) {
$deps = $this->xml->parseXmlFile($path, '/module/info/dependencies');
return array_values($deps);
}
}
return [];
}
/**
* Installs a module
*
......@@ -80,8 +24,7 @@ class SchemaInstaller extends SchemaHelper
return
$this->executeSqlQueries($schema->createTables(), $schema->getModuleName()) &&
$this->addToModulesTable($schema->getModuleName(), $schema->getSchemaVersion()) &&
$this->installSettings($schema->getModuleName(), $schema->settings()) &&
$this->addResources($schema);
$this->installSettings($schema->getModuleName(), $schema->settings());
}
/**
......@@ -140,104 +83,6 @@ class SchemaInstaller extends SchemaHelper
return true;
}
/**
* Fügt die zu einen Modul zugehörigen Ressourcen ein
*
* @param \ACP3\Core\Modules\Installer\SchemaInterface $schema
* @param int $mode
* 1 = Ressourcen und Regeln einlesen
* 2 = Nur die Ressourcen einlesen
*
* @return bool
*/
public function addResources(SchemaInterface $schema, $mode = 1)
{
$serviceIds = $this->container->getServiceIds();
foreach ($serviceIds as $serviceId) {
if (strpos($serviceId, $schema->getModuleName() . '.controller.') !== false) {
list($module, , $area, $controller) = explode('.', $serviceId);
$this->_insertAclResources($module, $controller, $area, $schema->specialResources());
}
}
// Regeln für die Rollen setzen
if ($mode === 1) {
$this->_insertAclRules($schema->getModuleName());
}
$this->aclCache->getDriver()->deleteAll();
return true;
}
/**
* Inserts a new resource into the database
*
* @param string $module
* @param string $controller
* @param string $area
* @param array $specialResources
*/
protected function _insertAclResources($module, $controller, $area, array $specialResources)
{
$controllerService = $module . '.controller.' . $area . '.' . $controller;
$actions = get_class_methods($this->container->get($controllerService));
$moduleId = $this->getModuleId($module);
foreach ($actions as $action) {
// Only add the actual module actions (methods which begin with "action")
if (strpos($action, 'action') === 0) {
$actionUnderscored = strtolower(preg_replace('/\B([A-Z])/', '_$1', $action));
// Modulaktionen berücksichtigen, die mit Ziffern anfangen (Error pages)
$action = substr($actionUnderscored, strpos($actionUnderscored, '_') === 6 ? 7 : 6);
// Handle resources with differing access levels
if (isset($specialResources[$area][$controller][$action])) {
$privilegeId = $specialResources[$area][$controller][$action];
} else {
$privilegeId = $this->getDefaultAclPrivilegeId($area, $action);
}
$insertValues = [
'id' => '',
'module_id' => $moduleId,
'area' => !empty($area) ? strtolower($area) : 'frontend',
'controller' => strtolower($controller),
'page' => $action,
'params' => '',
'privilege_id' => (int)$privilegeId
];
$this->permissionsModel->insert($insertValues, Permissions\Model::TABLE_NAME_RESOURCES);
}
}
}
/**
* Insert new acl user rules
*
* @param string $moduleName
*/
protected function _insertAclRules($moduleName)
{
$roles = $this->permissionsModel->getAllRoles();
$privileges = $this->permissionsModel->getAllResourceIds();
$moduleId = $this->getModuleId($moduleName);
foreach ($roles as $role) {
foreach ($privileges as $privilege) {
$insertValues = [
'id' => '',
'role_id' => $role['id'],
'module_id' => $moduleId,
'privilege_id' => $privilege['id'],
'permission' => $this->getDefaultAclRulePermission($role, $privilege)
];
$this->permissionsModel->insert($insertValues, Permissions\Model::TABLE_NAME_RULES);
}
}
}
/**
* Method for uninstalling a module
*
......@@ -247,12 +92,9 @@ class SchemaInstaller extends SchemaHelper
*/
public function uninstall(SchemaInterface $schema)
{
$bool1 = $this->executeSqlQueries($schema->removeTables(), $schema->getModuleName());
$bool2 = $this->removeFromModulesTable($schema->getModuleName());
$bool3 = $this->removeSettings($schema->getModuleName());
$bool4 = $this->removeResources($schema->getModuleName());
return $bool1 && $bool2 && $bool3 && $bool4;
return $this->executeSqlQueries($schema->removeTables(), $schema->getModuleName()) &&
$this->removeFromModulesTable($schema->getModuleName()) &&
$this->removeSettings($schema->getModuleName());
}
/**
......@@ -278,76 +120,4 @@ class SchemaInstaller extends SchemaHelper
{
return $this->systemModel->delete((int)$this->getModuleId($moduleName), 'module_id', System\Model::TABLE_NAME_SETTINGS) !== false;
}
/**
* Löscht die zu einem Modul zugehörigen Ressourcen
*
* @param string $moduleName
*
* @return bool
*/
protected function removeResources($moduleName)
{
$bool = $this->permissionsModel->delete($this->getModuleId($moduleName), 'module_id', Permissions\Model::TABLE_NAME_RESOURCES);
$bool2 = $this->permissionsModel->delete($this->getModuleId($moduleName), 'module_id', Permissions\Model::TABLE_NAME_RULES);
$this->aclCache->getDriver()->deleteAll();
return $bool !== false && $bool2 !== false;
}
/**
* @param string $area
* @param string $action
*
* @return int
*/
protected function getDefaultAclPrivilegeId($area, $action)
{
if ($area === 'Admin') {
if (strpos($action, 'create') === 0 || strpos($action, 'order') === 0) {
return 4;
} elseif (strpos($action, 'edit') === 0) {
return 5;
} elseif (strpos($action, 'delete') === 0) {
return 6;
} elseif (strpos($action, 'settings') === 0) {
return 7;
}
return 3;
}
// Frontend controller actions
if (strpos($action, 'create') === 0) {
return 2;
} else {
return 1;
}
}
/**
* @param array $role
* @param array $privilege
*
* @return int
*/
protected function getDefaultAclRulePermission($role, $privilege)
{
$permission = 0;
if ($role['id'] == 1 && ($privilege['id'] == 1 || $privilege['id'] == 2)) {
$permission = 1;
}
if ($role['id'] > 1 && $role['id'] < 4) {
$permission = 2;
}
if ($role['id'] == 3 && $privilege['id'] == 3) {
$permission = 1;
}
if ($role['id'] == 4) {
$permission = 1;
}
return $permission;
}
}
......@@ -18,6 +18,10 @@ services:
class: ACP3\Core\Modules
arguments: ['@service_container', @core.modules.moduleInfoCache, @core.modules.vendors]
core.modules.aclInstaller:
class: ACP3\Core\Modules\AclInstaller
arguments: [@service_container, @core.cache.system, @core.modules.schemaHelper, @permissions.model]
core.modules.controller:
abstract: true
arguments: ['@core.context']
......@@ -50,9 +54,7 @@ services:
core.modules.schemaInstaller:
class: ACP3\Core\Modules\SchemaInstaller
arguments: ['@core.db', '@core.xml', '@core.cache.system', '@system.model', '@permissions.model']
calls:
- ['setContainer', ['@service_container']]
parent: core.modules.schemaHelper
core.modules.schemaUpdater:
class: ACP3\Core\Modules\SchemaUpdater
......
......@@ -14,13 +14,13 @@ class Cache extends Core\Modules\AbstractCacheStorage
const CACHE_ID_RULES = 'acl_rules_';
/**
* @var Model
* @var \ACP3\Modules\ACP3\Permissions\Model
*/
protected $permissionsModel;
/**
* @param Core\Cache $cache
* @param Model $permissionsModel
* @param \ACP3\Core\Cache $cache
* @param \ACP3\Modules\ACP3\Permissions\Model $permissionsModel
*/
public function __construct(
Core\Cache $cache,
......
......@@ -39,7 +39,62 @@ class Schema implements Modules\Installer\SchemaInterface
*/
public function createTables()
{
return [];
return [
"CREATE TABLE `{pre}acl_privileges` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`key` VARCHAR(100) NOT NULL,
`description` VARCHAR(100) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `key` (`key`)
) {ENGINE} {CHARSET};",
"CREATE TABLE`{pre}acl_resources` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`module_id` int(10) unsigned NOT NULL,
`area` VARCHAR(255) NOT NULL,
`controller` VARCHAR(255) NOT NULL,
`page` varchar(255) NOT NULL,
`params` varchar(255) NOT NULL,
`privilege_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
) {engine} {charset};",
"CREATE TABLE`{pre}acl_roles` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`root_id` int(10) unsigned NOT NULL,
`parent_id` int(10) unsigned NOT NULL,
`left_id` int(10) unsigned NOT NULL,
`right_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
) {engine} {charset};",
"CREATE TABLE`{pre}acl_rules` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`role_id` int(10) unsigned NOT NULL,
`module_id` int(10) unsigned NOT NULL,
`privilege_id` int(10) unsigned NOT NULL,
`permission` tinyint(1) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `role_id` (`role_id`,`module_id`,`privilege_id`)
) {engine} {charset};",
"CREATE TABLE`{pre}acl_user_roles` (
`user_id` int(10) unsigned NOT NULL,
`role_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`user_id`,`role_id`)
) {engine} {charset};",
// Default Privileges and user roles
"INSERT INTO `{pre}acl_privileges` (`id`, `key`, `description`) VALUES (1, 'view', '')",
"INSERT INTO `{pre}acl_privileges` (`id`, `key`, `description`) VALUES (2, 'create', '')",
"INSERT INTO `{pre}acl_privileges` (`id`, `key`, `description`) VALUES (3, 'admin_view', '')",
"INSERT INTO `{pre}acl_privileges` (`id`, `key`, `description`) VALUES (4, 'admin_create', '')",
"INSERT INTO `{pre}acl_privileges` (`id`, `key`, `description`) VALUES (5, 'admin_edit', '')",
"INSERT INTO `{pre}acl_privileges` (`id`, `key`, `description`) VALUES (6, 'admin_delete', '')",
"INSERT INTO `{pre}acl_privileges` (`id`, `key`, `description`) VALUES (7, 'admin_settings', '');",
"INSERT INTO `{pre}acl_roles` (`id`, `name`, `root_id`, `parent_id`, `left_id`, `right_id`) VALUES (1, 'Gast', 1, 0, 1, 8)",
"INSERT INTO `{pre}acl_roles` (`id`, `name`, `root_id`, `parent_id`, `left_id`, `right_id`) VALUES (2, 'Mitglied', 1, 1, 2, 7)",
"INSERT INTO `{pre}acl_roles` (`id`, `name`, `root_id`, `parent_id`, `left_id`, `right_id`) VALUES (3, 'Autor', 1, 2, 3, 6)",
"INSERT INTO `{pre}acl_roles` (`id`, `name`, `root_id`, `parent_id`, `left_id`, `right_id`) VALUES (4, 'Administrator', 1, 3, 4, 5);",
"INSERT INTO `{pre}acl_user_roles` (`user_id`, `role_id`) VALUES (0, 1)",
"INSERT INTO `{pre}acl_user_roles` (`user_id`, `role_id`) VALUES (1, 4);"
];
}
/**
......
......@@ -267,11 +267,12 @@ class Extensions extends Core\Modules\AdminController
// Modul installieren
if (empty($deps)) {
$bool = $this->container->get('core.modules.schemaInstaller')->install($moduleSchema);
$bool2 = $this->container->get('core.modules.aclInstaller')->install($moduleSchema);
$this->_renewCaches();
Core\Cache::purge(CACHE_DIR . 'sql/container.php');
$text = $this->lang->t('system', 'mod_installation_' . ($bool !== false ? 'success' : 'error'));
$text = $this->lang->t('system', 'mod_installation_' . ($bool !== false && $bool2 !== false ? 'success' : 'error'));
} else {
$text = sprintf($this->lang->t('system', 'enable_following_modules_first'), implode(', ', $deps));
}
......@@ -311,13 +312,14 @@ class Extensions extends Core\Modules\AdminController
// Modul deinstallieren
if (empty($deps)) {
$bool = $this->container->get('core.modules.schemaInstaller')->uninstall($moduleSchema);
$bool2 = $this->container->get('core.modules.aclInstaller')->uninstall($moduleSchema);
$this->_renewCaches();
Core\Cache::purge(CACHE_DIR . 'tpl_compiled');
Core\Cache::purge(CACHE_DIR . 'tpl_cached');
Core\Cache::purge(CACHE_DIR . 'sql/container.php');
$text = $this->lang->t('system', 'mod_uninstallation_' . ($bool !== false ? 'success' : 'error'));
$text = $this->lang->t('system', 'mod_uninstallation_' . ($bool !== false && $bool2 !== false ? 'success' : 'error'));
} else {
$text = sprintf($this->lang->t('system', 'uninstall_following_modules_first'), implode(', ', $deps));
}
......
......@@ -29,24 +29,31 @@ class Helpers
* @var \ACP3\Core\Modules\Vendors
*/
protected $vendors;
/**
* @var \ACP3\Core\XML
*/
protected $xml;
/**
* @param Core\DB $db
* @param Core\Modules $modules
* @param \ACP3\Core\DB $db
* @param \ACP3\Core\Modules $modules
* @param \ACP3\Core\Modules\Vendors $vendors
* @param \ACP3\Core\Modules\SchemaInstaller $schemaInstaller
* @param \ACP3\Core\XML $xml
*/
public function __construct(
Core\DB $db,
Core\Modules $modules,
Core\Modules\Vendors $vendors,
Core\Modules\SchemaInstaller $schemaInstaller
Core\Modules\SchemaInstaller $schemaInstaller,
Core\XML $xml
)
{
$this->db = $db;
$this->modules = $modules;
$this->vendors = $vendors;
$this->schemaInstaller = $schemaInstaller;
$this->xml = $xml;
}
/**
......@@ -58,7 +65,7 @@ class Helpers
*/
public function checkInstallDependencies(Core\Modules\Installer\SchemaInterface $schema)
{
$dependencies = $this->schemaInstaller->getDependencies($schema->getModuleName());
$dependencies = $this->getDependencies($schema->getModuleName());
$modulesToEnable = [];
if (!empty($dependencies)) {
foreach ($dependencies as $dependency) {
......@@ -88,7 +95,7 @@ class Helpers
$service = $moduleName . '.installer.schema';
if ($container->has($service) === true) {
$deps = $this->schemaInstaller->getDependencies($moduleToBeUninstalled);
$deps = $this->getDependencies($moduleToBeUninstalled);
if (!empty($deps) && in_array($moduleToBeUninstalled, $deps) === true) {
$moduleDependencies[] = $module['name'];
}
......@@ -98,6 +105,25 @@ class Helpers
return $moduleDependencies;
}