DragonByte Tech
Well-known member
At the moment, it is only possible to quickly create custom permissions for things that use a tree structure, such as categories or nodes. There's plenty of reasons why developers may want to create per-entry permissions for things that aren't trees.
Use case: I'm creating an eCommerce tool that will allow admins to set up coupons to provide discounts for products. However, admins may wish to restrict the coupon to only specific users, or only specific user groups.
I had to create a new macro to list & edit permissions (as you would expect).
Nothing has to change on your end to support this. This requires absolutely no modification of existing XenForo code, and is fully stand-alone.
Tests ran:
It is my belief that adding this to the core would provide a significant benefit to 3rd party developers who would want to implement custom per-item permissions for things that are not tree structures, while also enabling the XF core team to do the same.
In short, here's my proposal for a new abstract permission class:
If anyone is reading this and wish to use this code in their own projects, they are of course free to do so
(Just remember to change the namespace and import the
Fillip
Use case: I'm creating an eCommerce tool that will allow admins to set up coupons to provide discounts for products. However, admins may wish to restrict the coupon to only specific users, or only specific user groups.
I had to create a new macro to list & edit permissions (as you would expect).
Nothing has to change on your end to support this. This requires absolutely no modification of existing XenForo code, and is fully stand-alone.
Tests ran:
- Private toggle
- Per-usergroup permission, add custom / set back to inherit
- Per-user permission, add custom / set back to inherit
- Analysis (private on/off, UG on/off, per-user on/off)
It is my belief that adding this to the core would provide a significant benefit to 3rd party developers who would want to implement custom per-item permissions for things that are not tree structures, while also enabling the XF core team to do the same.
In short, here's my proposal for a new abstract permission class:
PHP:
<?php
namespace XF\Permission;
use XF\Mvc\Entity\Entity;
/**
* Class AbstractFlatPermissions
*
* @package XF\Permission
*/
abstract class AbstractFlatPermissions extends AbstractContentPermissions
{
/**
* @var \XF\Mvc\Entity\ArrayCollection
*/
protected $entries;
/**
* @var string
*/
protected $repoIdentifier = '';
/**
*
*/
protected function setupBuildTypeData()
{
$entryRepo = $this->builder->em()->getRepository($this->repoIdentifier);
$this->entries = $entryRepo->findEntriesForPermissionList()->fetch();
}
/**
* @param \XF\Entity\PermissionCombination $combination
* @param array $basePerms
*
* @return array
*/
public function rebuildCombination(\XF\Entity\PermissionCombination $combination, array $basePerms)
{
$entryIds = $this->entries->keys();
if (!$entryIds)
{
return [];
}
$basePerms = $this->adjustBasePermissionAllows($basePerms);
$built = [];
foreach ($entryIds AS $entryId)
{
$built += $this->buildForContent($entryId, $combination->user_group_list, $combination->user_id, $basePerms);
}
$this->writeBuiltCombination($combination, $built);
}
/**
* @param $contentId
* @param array $userGroupIds
* @param int $userId
* @param array $basePerms
*
* @return array
*/
protected function buildForContent($contentId, array $userGroupIds, $userId = 0, array $basePerms)
{
$sets = $this->getApplicablePermissionSets($contentId, $userGroupIds, $userId);
$childPerms = $this->builder->calculatePermissions($sets, $this->permissionsGrouped, $basePerms);
$calculated = $this->builder->applyPermissionDependencies($childPerms, $this->permissionsGrouped);
$finalPerms = $this->builder->finalizePermissionValues($calculated);
$output = [];
$output[$contentId] = $finalPerms;
return $output;
}
/**
* @param \XF\Entity\PermissionCombination $combination
* @param $contentId
* @param array $basePerms
* @param array $baseIntermediates
*
* @return array
*/
public function analyzeCombination(
\XF\Entity\PermissionCombination $combination, $contentId, array $basePerms, array $baseIntermediates
)
{
$groupIds = $combination->user_group_list;
$userId = $combination->user_id;
$intermediates = $baseIntermediates;
$permissions = $basePerms;
$dependChanges = [];
$titles = $this->getAnalysisContentPairs();
$permissions = $this->adjustBasePermissionAllows($permissions);
$sets = $this->getApplicablePermissionSets($contentId, $groupIds, $userId);
$permissions = $this->builder->calculatePermissions($sets, $this->permissionsGrouped, $permissions);
$calculated = $this->builder->applyPermissionDependencies(
$permissions, $this->permissionsGrouped, $dependChanges
);
$finalPerms = $this->builder->finalizePermissionValues($calculated);
$thisIntermediates = $this->builder->collectIntermediates(
$combination, $permissions, $sets, $contentId, $titles[$contentId]
);
$intermediates = $this->builder->pushIntermediates($intermediates, $thisIntermediates);
return $this->builder->getFinalAnalysis($finalPerms, $intermediates, $dependChanges);
}
/**
* @return array
*/
public function getAnalysisContentPairs()
{
$pairs = [];
foreach ($this->entries AS $id => $value)
{
$pairs[$id] = $this->getContentTitle($value);
}
return $pairs;
}
/**
* @param Entity $entity
*
* @return mixed|null
*/
public function getContentTitle(Entity $entity)
{
return $entity->title;
}
}
If anyone is reading this and wish to use this code in their own projects, they are of course free to do so
(Just remember to change the namespace and import the
AbstractContentPermissions
class.)Fillip
Upvote
2