chrisbryan17's picture
Upload folder using huggingface_hub
d2897cd verified
<?php
namespace Mautic\CoreBundle\Security\Permissions;
use Mautic\UserBundle\Form\Type\PermissionListType;
use Symfony\Component\Form\FormBuilderInterface;
abstract class AbstractPermissions
{
/**
* @var array
*/
protected $permissions = [];
public function __construct(
protected array $params
) {
}
/**
* This method is called before the permissions object is used.
* Define permissions with `addExtendedPermissions` here instead of constructor.
*/
public function definePermissions(): void
{
// Override this method in the final class
}
/**
* Returns bundle's permissions array.
*
* @return array
*/
public function getPermissions()
{
return $this->permissions;
}
/**
* Checks to see if the requested permission is supported by the bundle.
*
* @param string $name
* @param string $level
*
* @return bool
*/
public function isSupported($name, $level = '')
{
[$name, $level] = $this->getSynonym($name, $level);
if (empty($level)) {
// verify permission name only
return isset($this->permissions[$name]);
}
// verify permission name and level as well
return isset($this->permissions[$name][$level]);
}
/**
* Allows permission classes to be disabled if criteria is not met (such as bundle is disabled).
*/
public function isEnabled(): bool
{
return true;
}
/**
* Returns the value assigned to a specific permission.
*
* @param string $name
* @param string $perm
*
* @return int
*/
public function getValue($name, $perm)
{
return ($this->isSupported($name, $perm)) ? $this->permissions[$name][$perm] : 0;
}
/**
* Builds the bundle's specific form elements for its permissions.
*/
public function buildForm(FormBuilderInterface &$builder, array $options, array $data): void
{
}
/**
* Returns the name of the permission set (should be the bundle identifier).
*
* @return string|void
*/
abstract public function getName();
/**
* Takes an array from PermissionRepository::getPermissionsByRole() and converts the bitwise integers to an array
* of permission names that can be used in forms, for example.
*
* @return mixed
*/
public function convertBitsToPermissionNames(array $permissions)
{
static $permissionLevels = [];
$bundle = $this->getName();
if (!in_array($bundle, $permissionLevels)) {
$permissionLevels[$bundle] = [];
if (isset($permissions[$bundle])) {
if ($this->isEnabled()) {
foreach ($permissions[$bundle] as $details) {
$permName = $details['name'];
$permBitwise = $details['bitwise'];
// ensure the permission still exists
if ($this->isSupported($permName)) {
$levels = $this->permissions[$permName];
// ensure that at least keys exist
$permissionLevels[$bundle][$permName] = [];
// $permissionLevels[$bundle][$permName]["$bundle:$permName"] = $permId;
foreach ($levels as $levelName => $levelBit) {
// compare bit against levels to see if it is a match
if ($levelBit & $permBitwise) {
// bitwise compares so add the level
$permissionLevels[$bundle][$permName][] = $levelName;
continue;
}
}
}
}
}
}
}
return $permissionLevels[$bundle];
}
/**
* Allows the bundle permission class to utilize synonyms for permissions.
*
* @param string $name
* @param string $level
*
* @return array
*/
protected function getSynonym($name, $level)
{
if (in_array($level, ['viewown', 'viewother'])) {
if (isset($this->permissions[$name]['view'])) {
$level = 'view';
}
} elseif ('view' == $level) {
if (isset($this->permissions[$name]['viewown'])) {
$level = 'viewown';
}
} elseif (in_array($level, ['editown', 'editother'])) {
if (isset($this->permissions[$name]['edit'])) {
$level = 'edit';
}
} elseif ('edit' == $level) {
if (isset($this->permissions[$name]['editown'])) {
$level = 'editown';
}
} elseif (in_array($level, ['deleteown', 'deleteother'])) {
if (isset($this->permissions[$name]['delete'])) {
$level = 'delete';
}
} elseif ('delete' == $level) {
if (isset($this->permissions[$name]['deleteown'])) {
$level = 'deleteown';
}
} elseif (in_array($level, ['publishown', 'publishother'])) {
if (isset($this->permissions[$name]['publish'])) {
$level = 'publish';
}
} elseif ('publish' == $level) {
if (isset($this->permissions[$name]['publishown'])) {
$level = 'publishown';
}
}
return [$name, $level];
}
/**
* Determines if the user has access to the specified permission.
*
* @param array $userPermissions
* @param string $name
* @param string $level
*
* @return bool
*/
public function isGranted($userPermissions, $name, $level)
{
[$name, $level] = $this->getSynonym($name, $level);
if (!isset($userPermissions[$name])) {
// the user doesn't have implicit access
return false;
} elseif (isset($this->permissions[$name]['full']) && $this->permissions[$name]['full'] & $userPermissions[$name]) {
return true;
} else {
// otherwise test for specific level
$result = ($this->permissions[$name][$level] & $userPermissions[$name]);
return ($result) ? true : false;
}
}
/**
* @param bool $isSecondRound
*
* @return bool Return true if a second round is required after all other bundles have analyzed it's permissions
*/
public function analyzePermissions(array &$permissions, $allPermissions, $isSecondRound = false): bool
{
$hasViewAccess = false;
foreach ($permissions as $level => &$perms) {
foreach ($perms as $perm) {
$required = [];
switch ($perm) {
case 'editother':
case 'edit':
$required = ['viewother', 'viewown'];
break;
case 'deleteother':
case 'delete':
$required = ['editother', 'viewother', 'viewown'];
break;
case 'publishother':
case 'publish':
$required = ['viewother', 'viewown'];
break;
case 'viewother':
case 'editown':
case 'deleteown':
case 'publishown':
case 'create':
$required = ['viewown'];
break;
}
foreach ($required as $r) {
[$ignore, $r] = $this->getSynonym($level, $r);
if ($this->isSupported($level, $r) && !in_array($r, $perms)) {
$perms[] = $r;
}
}
}
$hasViewAccess = (!$hasViewAccess && (in_array('view', $perms) || in_array('viewown', $perms)));
}
// check categories for view permissions and add it if the user has view access to the other permissions
if (isset($this->permissions['categories']) && $hasViewAccess && (!isset($permissions['categories']) || !in_array('view', $permissions['categories']))) {
$permissions['categories'][] = 'view';
}
return false;
}
/**
* Generates an array of granted and total permissions.
*
* @return array
*/
public function getPermissionRatio(array $data)
{
$totalAvailable = $totalGranted = 0;
foreach ($this->permissions as $level => $perms) {
$perms = array_keys($perms);
$totalAvailable += count($perms);
if (in_array('full', $perms)) {
if (1 === count($perms)) {
// full is the only permission so count as 1
if (!empty($data[$level]) && !in_array('full', $data[$level])) {
++$totalGranted;
}
} else {
// remove full from total count
--$totalAvailable;
if (!empty($data[$level]) && in_array('full', $data[$level])) {
// user has full access so sum perms minus full
$totalGranted += count($perms) - 1;
// move on to the next level
continue;
}
}
}
if (isset($data[$level])) {
$totalGranted += count($data[$level]);
}
}
return [$totalGranted, $totalAvailable];
}
/**
* Gives the bundle an opportunity to change how JavaScript calculates permissions granted.
*/
public function parseForJavascript(array &$perms): void
{
}
/**
* @param array<int|string> $permissions
*/
protected function addCustomPermission(string $level, array $permissions): void
{
$this->permissions[$level] = $permissions;
}
/**
* Adds a custom permission to the form builder, i.e. config only bundles.
*
* @param array<string> $choices
* @param array<string> $data
*/
protected function addCustomFormFields(string $bundle, string $level, FormBuilderInterface &$builder, string $label, array $choices, array $data): void
{
$builder->add("$bundle:$level", PermissionListType::class, [
'choices' => $choices,
'label' => $label,
'data' => (!empty($data[$level]) ? $data[$level] : []),
'bundle' => $bundle,
'level' => $level,
]);
}
/**
* Adds the standard permission set of view, edit, create, delete, publish and full.
*
* @param array $permissionNames
* @param bool $includePublish
*/
protected function addStandardPermissions($permissionNames, $includePublish = true)
{
if (!is_array($permissionNames)) {
$permissionNames = [$permissionNames];
}
foreach ($permissionNames as $p) {
$this->permissions[$p] = [
'view' => 4,
'edit' => 16,
'create' => 32,
'delete' => 128,
'full' => 1024,
];
if ($includePublish) {
$this->permissions[$p]['publish'] = 512;
}
}
}
/**
* Adds the standard permission set of view, edit, create, delete, publish and full to the form builder.
*
* @param string $bundle
* @param string $level
* @param FormBuilderInterface $builder
* @param array $data
* @param bool $includePublish
*/
protected function addStandardFormFields($bundle, $level, &$builder, $data, $includePublish = true)
{
$choices = [
'mautic.core.permissions.view' => 'view',
'mautic.core.permissions.edit' => 'edit',
'mautic.core.permissions.create' => 'create',
'mautic.core.permissions.delete' => 'delete',
];
if ($includePublish) {
$choices['mautic.core.permissions.publish'] = 'publish';
}
$choices['mautic.core.permissions.full'] = 'full';
$label = ('categories' == $level) ? 'mautic.category.permissions.categories' : "mautic.$bundle.permissions.$level";
$builder->add(
"$bundle:$level",
PermissionListType::class,
[
'choices' => $choices,
'label' => $label,
'bundle' => $bundle,
'level' => $level,
'data' => (!empty($data[$level]) ? $data[$level] : []),
]
);
}
/**
* @param string $bundle
* @param string $level
*
* @return string
*/
protected function getLabel($bundle, $level)
{
return ('categories' === $level) ? 'mautic.category.permissions.categories' : "mautic.{$bundle}.permissions.{$level}";
}
/**
* Add a single full permission.
*
* @param array $permissionNames
*/
protected function addManagePermission($permissionNames)
{
if (!is_array($permissionNames)) {
$permissionNames = [$permissionNames];
}
foreach ($permissionNames as $p) {
$this->permissions[$p] = [
'manage' => 1024,
];
}
}
/**
* Adds a single full permission to the form builder, i.e. config only bundles.
*
* @param string $bundle
* @param string $level
* @param FormBuilderInterface $builder
* @param array $data
*/
protected function addManageFormFields($bundle, $level, &$builder, $data)
{
$choices = [
'mautic.core.permissions.manage' => 'manage',
];
$builder->add(
"$bundle:$level",
PermissionListType::class,
[
'choices' => $choices,
'label' => "mautic.$bundle.permissions.$level",
'data' => (!empty($data[$level]) ? $data[$level] : []),
'bundle' => $bundle,
'level' => $level,
]
);
}
/**
* Adds the standard permission set of viewown, viewother, editown, editother, create, deleteown, deleteother,
* publishown, publishother and full.
*
* @param array|string $permissionNames
* @param bool $includePublish
*/
protected function addExtendedPermissions($permissionNames, $includePublish = true)
{
if (!is_array($permissionNames)) {
$permissionNames = [$permissionNames];
}
foreach ($permissionNames as $p) {
$this->permissions[$p] = [
'viewown' => 2,
'viewother' => 4,
'editown' => 8,
'editother' => 16,
'create' => 32,
'deleteown' => 64,
'deleteother' => 128,
'full' => 1024,
];
if ($includePublish) {
$this->permissions[$p]['publishown'] = 256;
$this->permissions[$p]['publishother'] = 512;
}
}
}
/**
* Adds the standard permission set of viewown, viewother, editown, editother, create, deleteown, deleteother,
* publishown, publishother and full to the form builder.
*
* @param string $bundle
* @param string $level
* @param FormBuilderInterface $builder
* @param array $data
* @param bool $includePublish
*/
protected function addExtendedFormFields($bundle, $level, &$builder, $data, $includePublish = true)
{
$choices = [
'mautic.core.permissions.viewown' => 'viewown',
'mautic.core.permissions.viewother' => 'viewother',
'mautic.core.permissions.editown' => 'editown',
'mautic.core.permissions.editother' => 'editother',
'mautic.core.permissions.create' => 'create',
'mautic.core.permissions.deleteown' => 'deleteown',
'mautic.core.permissions.deleteother' => 'deleteother',
'mautic.core.permissions.full' => 'full',
];
if ($includePublish) {
$choices['mautic.core.permissions.publishown'] = 'publishown';
$choices['mautic.core.permissions.publishother'] = 'publishother';
}
$builder->add(
"$bundle:$level",
PermissionListType::class,
[
'choices' => $choices,
'choices_as_values' => true,
'label' => $this->getLabel($bundle, $level),
'data' => (!empty($data[$level]) ? $data[$level] : []),
'bundle' => $bundle,
'level' => $level,
]
);
}
}