mirror of
https://github.com/silverstripe/silverstripe-subsites
synced 2024-10-22 11:05:55 +02:00
Merge pull request #397 from silverstripe/revert-388-pulls/2.1/fix-role-permissions
Revert "FIX CMS permission checks for subsite are now handled in the state context"
This commit is contained in:
commit
bbfb93d50d
@ -27,13 +27,25 @@ class SubsiteXHRController extends LeftAndMain
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Subsite::all_accessible_sites(true, 'Main site', $member)->count() > 0) {
|
if (Subsite::all_accessible_sites()->count() > 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow access if user allowed into the CMS at all.
|
||||||
|
*/
|
||||||
|
public function canAccess()
|
||||||
|
{
|
||||||
|
// Allow if any cms access is available
|
||||||
|
return Permission::check([
|
||||||
|
'CMS_ACCESS', // Supported by 3.1.14 and up
|
||||||
|
'CMS_ACCESS_LeftAndMain'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function getResponseNegotiator()
|
public function getResponseNegotiator()
|
||||||
{
|
{
|
||||||
$negotiator = parent::getResponseNegotiator();
|
$negotiator = parent::getResponseNegotiator();
|
||||||
|
@ -90,7 +90,7 @@ class GroupSubsites extends DataExtension implements PermissionProvider
|
|||||||
// Interface is different if you have the rights to modify subsite group values on
|
// Interface is different if you have the rights to modify subsite group values on
|
||||||
// all subsites
|
// all subsites
|
||||||
if (isset($subsiteMap[0])) {
|
if (isset($subsiteMap[0])) {
|
||||||
$fields->addFieldToTab('Root.Subsites', OptionsetField::create(
|
$fields->addFieldToTab('Root.Subsites', new OptionsetField(
|
||||||
'AccessAllSubsites',
|
'AccessAllSubsites',
|
||||||
_t(__CLASS__ . '.ACCESSRADIOTITLE', 'Give this group access to'),
|
_t(__CLASS__ . '.ACCESSRADIOTITLE', 'Give this group access to'),
|
||||||
[
|
[
|
||||||
@ -100,20 +100,20 @@ class GroupSubsites extends DataExtension implements PermissionProvider
|
|||||||
));
|
));
|
||||||
|
|
||||||
unset($subsiteMap[0]);
|
unset($subsiteMap[0]);
|
||||||
$fields->addFieldToTab('Root.Subsites', CheckboxSetField::create(
|
$fields->addFieldToTab('Root.Subsites', new CheckboxSetField(
|
||||||
'Subsites',
|
'Subsites',
|
||||||
'',
|
'',
|
||||||
$subsiteMap
|
$subsiteMap
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
if (sizeof($subsiteMap) <= 1) {
|
if (sizeof($subsiteMap) <= 1) {
|
||||||
$fields->addFieldToTab('Root.Subsites', ReadonlyField::create(
|
$fields->addFieldToTab('Root.Subsites', new ReadonlyField(
|
||||||
'SubsitesHuman',
|
'SubsitesHuman',
|
||||||
_t(__CLASS__ . '.ACCESSRADIOTITLE', 'Give this group access to'),
|
_t(__CLASS__ . '.ACCESSRADIOTITLE', 'Give this group access to'),
|
||||||
reset($subsiteMap)
|
reset($subsiteMap)
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
$fields->addFieldToTab('Root.Subsites', CheckboxSetField::create(
|
$fields->addFieldToTab('Root.Subsites', new CheckboxSetField(
|
||||||
'Subsites',
|
'Subsites',
|
||||||
_t(__CLASS__ . '.ACCESSRADIOTITLE', 'Give this group access to'),
|
_t(__CLASS__ . '.ACCESSRADIOTITLE', 'Give this group access to'),
|
||||||
$subsiteMap
|
$subsiteMap
|
||||||
|
@ -5,9 +5,9 @@ namespace SilverStripe\Subsites\Extensions;
|
|||||||
use SilverStripe\Admin\AdminRootController;
|
use SilverStripe\Admin\AdminRootController;
|
||||||
use SilverStripe\Admin\CMSMenu;
|
use SilverStripe\Admin\CMSMenu;
|
||||||
use SilverStripe\Admin\LeftAndMainExtension;
|
use SilverStripe\Admin\LeftAndMainExtension;
|
||||||
use SilverStripe\CMS\Controllers\CMSPageEditController;
|
|
||||||
use SilverStripe\CMS\Controllers\CMSPagesController;
|
use SilverStripe\CMS\Controllers\CMSPagesController;
|
||||||
use SilverStripe\CMS\Model\SiteTree;
|
use SilverStripe\CMS\Model\SiteTree;
|
||||||
|
use SilverStripe\CMS\Controllers\CMSPageEditController;
|
||||||
use SilverStripe\Control\Controller;
|
use SilverStripe\Control\Controller;
|
||||||
use SilverStripe\Core\Config\Config;
|
use SilverStripe\Core\Config\Config;
|
||||||
use SilverStripe\Core\Convert;
|
use SilverStripe\Core\Convert;
|
||||||
@ -65,13 +65,14 @@ class LeftAndMainSubsites extends LeftAndMainExtension
|
|||||||
*
|
*
|
||||||
* @param bool $includeMainSite
|
* @param bool $includeMainSite
|
||||||
* @param string $mainSiteTitle
|
* @param string $mainSiteTitle
|
||||||
* @param Member|int|null $member
|
* @param null $member
|
||||||
* @return ArrayList List of Subsite instances
|
* @return ArrayList of <a href='psi_element://Subsite'>Subsite</a> instances.
|
||||||
|
* instances.
|
||||||
*/
|
*/
|
||||||
public function sectionSites($includeMainSite = true, $mainSiteTitle = 'Main site', $member = null)
|
public function sectionSites($includeMainSite = true, $mainSiteTitle = 'Main site', $member = null)
|
||||||
{
|
{
|
||||||
if ($mainSiteTitle === 'Main site') {
|
if ($mainSiteTitle == 'Main site') {
|
||||||
$mainSiteTitle = _t('SilverStripe\\Subsites\\Model\\Subsite.MainSiteTitle', 'Main site');
|
$mainSiteTitle = _t('Subsites.MainSiteTitle', 'Main site');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rationalise member arguments
|
// Rationalise member arguments
|
||||||
@ -85,33 +86,49 @@ class LeftAndMainSubsites extends LeftAndMainExtension
|
|||||||
$member = DataObject::get_by_id(Member::class, $member);
|
$member = DataObject::get_by_id(Member::class, $member);
|
||||||
}
|
}
|
||||||
|
|
||||||
$accessibleSubsites = ArrayList::create();
|
// Collect permissions - honour the LeftAndMain::required_permission_codes, current model requires
|
||||||
$subsites = Subsite::all_sites($includeMainSite, $mainSiteTitle);
|
// us to check if the user satisfies ALL permissions. Code partly copied from LeftAndMain::canView.
|
||||||
|
$codes = [];
|
||||||
foreach ($subsites as $subsite) {
|
$extraCodes = Config::inst()->get(get_class($this->owner), 'required_permission_codes');
|
||||||
/** @var Subsite $subsite */
|
if ($extraCodes !== false) {
|
||||||
$canAccess = SubsiteState::singleton()
|
if ($extraCodes) {
|
||||||
->withState(function (SubsiteState $newState) use ($subsite, $member) {
|
$codes = array_merge($codes, (array)$extraCodes);
|
||||||
$newState->setSubsiteId($subsite->ID);
|
} else {
|
||||||
|
$codes[] = sprintf('CMS_ACCESS_%s', get_class($this->owner));
|
||||||
return $this->canAccess($member);
|
|
||||||
});
|
|
||||||
|
|
||||||
if ($canAccess === false) {
|
|
||||||
// Explicitly denied
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
$accessibleSubsites->push($subsite);
|
} else {
|
||||||
|
// Check overriden - all subsites accessible.
|
||||||
|
return Subsite::all_sites();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $accessibleSubsites;
|
// Find subsites satisfying all permissions for the Member.
|
||||||
|
$codesPerSite = [];
|
||||||
|
$sitesArray = [];
|
||||||
|
foreach ($codes as $code) {
|
||||||
|
$sites = Subsite::accessible_sites($code, $includeMainSite, $mainSiteTitle, $member);
|
||||||
|
foreach ($sites as $site) {
|
||||||
|
// Build the structure for checking how many codes match.
|
||||||
|
$codesPerSite[$site->ID][$code] = true;
|
||||||
|
|
||||||
|
// Retain Subsite objects for later.
|
||||||
|
$sitesArray[$site->ID] = $site;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find sites that satisfy all codes conjuncitvely.
|
||||||
|
$accessibleSites = new ArrayList();
|
||||||
|
foreach ($codesPerSite as $siteID => $siteCodes) {
|
||||||
|
if (count($siteCodes) == count($codes)) {
|
||||||
|
$accessibleSites->push($sitesArray[$siteID]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $accessibleSites;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns a list of the subsites accessible to the current user.
|
* Returns a list of the subsites accessible to the current user.
|
||||||
* It's enough for any section to be accessible for the section to be included.
|
* It's enough for any section to be accessible for the section to be included.
|
||||||
*
|
|
||||||
* @return ArrayList
|
|
||||||
*/
|
*/
|
||||||
public function Subsites()
|
public function Subsites()
|
||||||
{
|
{
|
||||||
@ -121,7 +138,6 @@ class LeftAndMainSubsites extends LeftAndMainExtension
|
|||||||
/*
|
/*
|
||||||
* Generates a list of subsites with the data needed to
|
* Generates a list of subsites with the data needed to
|
||||||
* produce a dropdown site switcher
|
* produce a dropdown site switcher
|
||||||
*
|
|
||||||
* @return ArrayList
|
* @return ArrayList
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -199,17 +215,11 @@ class LeftAndMainSubsites extends LeftAndMainExtension
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the current controller is accessible for this user on this subsite.
|
* Check if the current controller is accessible for this user on this subsite.
|
||||||
*
|
|
||||||
* @param Member|int|null $member Will be added as a concrete param in 3.x
|
|
||||||
* @return false|null False if a decision was explicitly made to deny access, otherwise null to delegate to core
|
|
||||||
*/
|
*/
|
||||||
public function canAccess()
|
public function canAccess()
|
||||||
{
|
{
|
||||||
// Allow us to accept a Member object passed in as an argument without breaking semver
|
|
||||||
$passedMember = func_num_args() ? func_get_arg(0) : null;
|
|
||||||
|
|
||||||
// Admin can access everything, no point in checking.
|
// Admin can access everything, no point in checking.
|
||||||
$member = $passedMember ?: Security::getCurrentUser();
|
$member = Security::getCurrentUser();
|
||||||
if ($member
|
if ($member
|
||||||
&& (Permission::checkMember($member, 'ADMIN') // 'Full administrative rights'
|
&& (Permission::checkMember($member, 'ADMIN') // 'Full administrative rights'
|
||||||
|| Permission::checkMember($member, 'CMS_ACCESS_LeftAndMain') // 'Access to all CMS sections'
|
|| Permission::checkMember($member, 'CMS_ACCESS_LeftAndMain') // 'Access to all CMS sections'
|
||||||
@ -218,56 +228,18 @@ class LeftAndMainSubsites extends LeftAndMainExtension
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check we have a member
|
// Check if we have access to current section on the current subsite.
|
||||||
if (!$member) {
|
$accessibleSites = $this->owner->sectionSites(true, 'Main site', $member);
|
||||||
return null;
|
return $accessibleSites->count() && $accessibleSites->find('ID', SubsiteState::singleton()->getSubsiteId());
|
||||||
}
|
|
||||||
|
|
||||||
// Check that some subsites exist first
|
|
||||||
if (!Subsite::get()->exists()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the current subsite ID
|
|
||||||
$currentSubsiteId = SubsiteState::singleton()->getSubsiteId();
|
|
||||||
|
|
||||||
// Check against the current user's associated groups
|
|
||||||
$allowedInSubsite = false;
|
|
||||||
foreach ($member->Groups() as $group) {
|
|
||||||
// If any of the current user's groups have been given explicit access to the subsite, delegate to core
|
|
||||||
if ($group->AccessAllSubsites) {
|
|
||||||
$allowedInSubsite = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if any of the current user's groups have been given explicit access to the current subsite
|
|
||||||
$groupSubsiteIds = $group->Subsites()->column('ID');
|
|
||||||
if (in_array($currentSubsiteId, $groupSubsiteIds)) {
|
|
||||||
$allowedInSubsite = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we know that the user is not allowed in this subsite, explicitly say this
|
|
||||||
if (!$allowedInSubsite) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delegate to core
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prevent accessing disallowed resources. This happens after onBeforeInit has executed,
|
* Prevent accessing disallowed resources. This happens after onBeforeInit has executed,
|
||||||
* so all redirections should've already taken place.
|
* so all redirections should've already taken place.
|
||||||
*
|
|
||||||
* @return false|null
|
|
||||||
*/
|
*/
|
||||||
public function alternateAccessCheck()
|
public function alternateAccessCheck()
|
||||||
{
|
{
|
||||||
if ($this->owner->canAccess() === false) {
|
return $this->owner->canAccess();
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -359,7 +331,7 @@ class LeftAndMainSubsites extends LeftAndMainExtension
|
|||||||
|
|
||||||
// SECOND, check if we need to change subsites due to lack of permissions.
|
// SECOND, check if we need to change subsites due to lack of permissions.
|
||||||
|
|
||||||
if ($this->owner->canAccess() === false) {
|
if (!$this->owner->canAccess()) {
|
||||||
$member = Security::getCurrentUser();
|
$member = Security::getCurrentUser();
|
||||||
|
|
||||||
// Current section is not accessible, try at least to stick to the same subsite.
|
// Current section is not accessible, try at least to stick to the same subsite.
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
namespace SilverStripe\Subsites\Extensions;
|
namespace SilverStripe\Subsites\Extensions;
|
||||||
|
|
||||||
use Page;
|
use Page;
|
||||||
use SilverStripe\CMS\Controllers\CMSPagesController;
|
|
||||||
use SilverStripe\CMS\Model\SiteTree;
|
use SilverStripe\CMS\Model\SiteTree;
|
||||||
use SilverStripe\Control\Controller;
|
use SilverStripe\Control\Controller;
|
||||||
use SilverStripe\Control\Director;
|
use SilverStripe\Control\Director;
|
||||||
@ -323,11 +322,6 @@ class SiteTreeSubsites extends DataExtension
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check general subsite section access for CMS
|
|
||||||
if (CMSPagesController::singleton()->canAccess($member) === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the sites that this user has access to
|
// Find the sites that this user has access to
|
||||||
$goodSites = Subsite::accessible_sites('CMS_ACCESS_CMSMain', true, 'all', $member)->column('ID');
|
$goodSites = Subsite::accessible_sites('CMS_ACCESS_CMSMain', true, 'all', $member)->column('ID');
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
namespace SilverStripe\Subsites\Model;
|
namespace SilverStripe\Subsites\Model;
|
||||||
|
|
||||||
use SilverStripe\Admin\CMSMenu;
|
use SilverStripe\Admin\CMSMenu;
|
||||||
use SilverStripe\Admin\LeftAndMain;
|
|
||||||
use SilverStripe\CMS\Model\SiteTree;
|
use SilverStripe\CMS\Model\SiteTree;
|
||||||
use SilverStripe\Control\Director;
|
use SilverStripe\Control\Director;
|
||||||
use SilverStripe\Core\Convert;
|
use SilverStripe\Core\Convert;
|
||||||
@ -29,7 +28,6 @@ use SilverStripe\Security\Group;
|
|||||||
use SilverStripe\Security\Member;
|
use SilverStripe\Security\Member;
|
||||||
use SilverStripe\Security\Permission;
|
use SilverStripe\Security\Permission;
|
||||||
use SilverStripe\Security\Security;
|
use SilverStripe\Security\Security;
|
||||||
use SilverStripe\Subsites\Extensions\LeftAndMainSubsites;
|
|
||||||
use SilverStripe\Subsites\State\SubsiteState;
|
use SilverStripe\Subsites\State\SubsiteState;
|
||||||
use SilverStripe\Versioned\Versioned;
|
use SilverStripe\Versioned\Versioned;
|
||||||
use UnexpectedValueException;
|
use UnexpectedValueException;
|
||||||
@ -374,7 +372,7 @@ class Subsite extends DataObject
|
|||||||
if ($includeMainSite) {
|
if ($includeMainSite) {
|
||||||
$subsites = $subsites->toArray();
|
$subsites = $subsites->toArray();
|
||||||
|
|
||||||
$mainSite = Subsite::create();
|
$mainSite = new Subsite();
|
||||||
$mainSite->Title = $mainSiteTitle;
|
$mainSite->Title = $mainSiteTitle;
|
||||||
array_unshift($subsites, $mainSite);
|
array_unshift($subsites, $mainSite);
|
||||||
|
|
||||||
@ -384,7 +382,7 @@ class Subsite extends DataObject
|
|||||||
return $subsites;
|
return $subsites;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Returns an ArrayList of the subsites accessible to the current user.
|
* Returns an ArrayList of the subsites accessible to the current user.
|
||||||
* It's enough for any section to be accessible for the site to be included.
|
* It's enough for any section to be accessible for the site to be included.
|
||||||
*
|
*
|
||||||
@ -392,26 +390,32 @@ class Subsite extends DataObject
|
|||||||
*/
|
*/
|
||||||
public static function all_accessible_sites($includeMainSite = true, $mainSiteTitle = 'Main site', $member = null)
|
public static function all_accessible_sites($includeMainSite = true, $mainSiteTitle = 'Main site', $member = null)
|
||||||
{
|
{
|
||||||
|
// Rationalise member arguments
|
||||||
|
if (!$member) {
|
||||||
|
$member = Security::getCurrentUser();
|
||||||
|
}
|
||||||
|
if (!$member) {
|
||||||
|
return ArrayList::create();
|
||||||
|
}
|
||||||
|
if (!is_object($member)) {
|
||||||
|
$member = DataObject::get_by_id(Member::class, $member);
|
||||||
|
}
|
||||||
|
|
||||||
$subsites = ArrayList::create();
|
$subsites = ArrayList::create();
|
||||||
|
|
||||||
// Collect subsites for all sections.
|
// Collect subsites for all sections.
|
||||||
$menu = CMSMenu::get_viewable_menu_items();
|
$menu = CMSMenu::get_viewable_menu_items();
|
||||||
foreach ($menu as $candidate) {
|
foreach ($menu as $candidate) {
|
||||||
if (!$candidate->controller) {
|
if ($candidate->controller) {
|
||||||
continue;
|
$accessibleSites = singleton($candidate->controller)->sectionSites(
|
||||||
|
$includeMainSite,
|
||||||
|
$mainSiteTitle,
|
||||||
|
$member
|
||||||
|
);
|
||||||
|
|
||||||
|
// Replace existing keys so no one site appears twice.
|
||||||
|
$subsites->merge($accessibleSites);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine which subsites can access the current admin section
|
|
||||||
/** @var LeftAndMain|LeftAndMainSubsites $controller */
|
|
||||||
$controller = singleton($candidate->controller);
|
|
||||||
$accessibleSites = $controller->sectionSites(
|
|
||||||
$includeMainSite,
|
|
||||||
$mainSiteTitle,
|
|
||||||
$member
|
|
||||||
);
|
|
||||||
|
|
||||||
// Replace existing keys so no one site appears twice.
|
|
||||||
$subsites->merge($accessibleSites);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$subsites->removeDuplicates();
|
$subsites->removeDuplicates();
|
||||||
@ -423,11 +427,11 @@ class Subsite extends DataObject
|
|||||||
* Return the subsites that the current user can access by given permission.
|
* Return the subsites that the current user can access by given permission.
|
||||||
* Sites will only be included if they have a Title.
|
* Sites will only be included if they have a Title.
|
||||||
*
|
*
|
||||||
* @param array|string $permCode Either a single permission code or an array of permission codes.
|
* @param $permCode array|string Either a single permission code or an array of permission codes.
|
||||||
* @param bool $includeMainSite If true, the main site will be included if appropriate.
|
* @param $includeMainSite bool If true, the main site will be included if appropriate.
|
||||||
* @param string $mainSiteTitle The label to give to the main site
|
* @param $mainSiteTitle string The label to give to the main site
|
||||||
* @param Member|int $member The member attempting to access the sites
|
* @param $member int|Member The member attempting to access the sites
|
||||||
* @return ArrayList List of {@link Subsite} instances
|
* @return DataList|ArrayList of {@link Subsite} instances
|
||||||
*/
|
*/
|
||||||
public static function accessible_sites(
|
public static function accessible_sites(
|
||||||
$permCode,
|
$permCode,
|
||||||
@ -435,42 +439,107 @@ class Subsite extends DataObject
|
|||||||
$mainSiteTitle = 'Main site',
|
$mainSiteTitle = 'Main site',
|
||||||
$member = null
|
$member = null
|
||||||
) {
|
) {
|
||||||
$memberCacheKey = is_object($member) ? $member->ID : 0;
|
|
||||||
|
// Rationalise member arguments
|
||||||
|
if (!$member) {
|
||||||
|
$member = Member::currentUser();
|
||||||
|
}
|
||||||
|
if (!$member) {
|
||||||
|
return new ArrayList();
|
||||||
|
}
|
||||||
|
if (!is_object($member)) {
|
||||||
|
$member = DataObject::get_by_id(Member::class, $member);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rationalise permCode argument
|
||||||
|
if (is_array($permCode)) {
|
||||||
|
$SQL_codes = "'" . implode("', '", Convert::raw2sql($permCode)) . "'";
|
||||||
|
} else {
|
||||||
|
$SQL_codes = "'" . Convert::raw2sql($permCode) . "'";
|
||||||
|
}
|
||||||
|
|
||||||
// Cache handling
|
// Cache handling
|
||||||
$cacheKey = json_encode($permCode) . '-' . $memberCacheKey . '-' . $includeMainSite . '-' . $mainSiteTitle;
|
$cacheKey = $SQL_codes . '-' . $member->ID . '-' . $includeMainSite . '-' . $mainSiteTitle;
|
||||||
if (isset(self::$cache_accessible_sites[$cacheKey])) {
|
if (isset(self::$cache_accessible_sites[$cacheKey])) {
|
||||||
return self::$cache_accessible_sites[$cacheKey];
|
return self::$cache_accessible_sites[$cacheKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
$accessibleSubsites = ArrayList::create();
|
/** @skipUpgrade */
|
||||||
$subsites = self::all_sites($includeMainSite, $mainSiteTitle);
|
$subsites = DataList::create(Subsite::class)
|
||||||
foreach ($subsites as $subsite) {
|
->where("\"Subsite\".\"Title\" != ''")
|
||||||
// Exclude subsites with no title
|
->leftJoin('Group_Subsites', '"Group_Subsites"."SubsiteID" = "Subsite"."ID"')
|
||||||
if (empty($subsite->Title)) {
|
->innerJoin(
|
||||||
continue;
|
'Group',
|
||||||
}
|
'"Group"."ID" = "Group_Subsites"."GroupID" OR "Group"."AccessAllSubsites" = 1'
|
||||||
|
)
|
||||||
|
->innerJoin(
|
||||||
|
'Group_Members',
|
||||||
|
"\"Group_Members\".\"GroupID\"=\"Group\".\"ID\" AND \"Group_Members\".\"MemberID\" = $member->ID"
|
||||||
|
)
|
||||||
|
->innerJoin(
|
||||||
|
'Permission',
|
||||||
|
"\"Group\".\"ID\"=\"Permission\".\"GroupID\"
|
||||||
|
AND \"Permission\".\"Code\"
|
||||||
|
IN ($SQL_codes, 'CMS_ACCESS_LeftAndMain', 'ADMIN')"
|
||||||
|
);
|
||||||
|
|
||||||
/** @var Subsite $subsite */
|
if (!$subsites) {
|
||||||
$canAccess = SubsiteState::singleton()
|
$subsites = new ArrayList();
|
||||||
->withState(function (SubsiteState $newState) use ($member, $subsite, $permCode) {
|
|
||||||
// Mock each individual subsite and run permission checks in it
|
|
||||||
$newState->setSubsiteId($subsite->ID);
|
|
||||||
|
|
||||||
return Permission::checkMember($member, $permCode);
|
|
||||||
});
|
|
||||||
|
|
||||||
if ($canAccess === false) {
|
|
||||||
// Explicitly denied access
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$accessibleSubsites->push($subsite);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self::$cache_accessible_sites[$cacheKey] = $accessibleSubsites;
|
/** @var DataList $rolesSubsites */
|
||||||
|
/** @skipUpgrade */
|
||||||
|
$rolesSubsites = DataList::create(Subsite::class)
|
||||||
|
->where("\"Subsite\".\"Title\" != ''")
|
||||||
|
->leftJoin('Group_Subsites', '"Group_Subsites"."SubsiteID" = "Subsite"."ID"')
|
||||||
|
->innerJoin(
|
||||||
|
'Group',
|
||||||
|
'"Group"."ID" = "Group_Subsites"."GroupID" OR "Group"."AccessAllSubsites" = 1'
|
||||||
|
)
|
||||||
|
->innerJoin(
|
||||||
|
'Group_Members',
|
||||||
|
"\"Group_Members\".\"GroupID\"=\"Group\".\"ID\" AND \"Group_Members\".\"MemberID\" = $member->ID"
|
||||||
|
)
|
||||||
|
->innerJoin('Group_Roles', '"Group_Roles"."GroupID"="Group"."ID"')
|
||||||
|
->innerJoin('PermissionRole', '"Group_Roles"."PermissionRoleID"="PermissionRole"."ID"')
|
||||||
|
->innerJoin(
|
||||||
|
'PermissionRoleCode',
|
||||||
|
"\"PermissionRole\".\"ID\"=\"PermissionRoleCode\".\"RoleID\"
|
||||||
|
AND \"PermissionRoleCode\".\"Code\"
|
||||||
|
IN ($SQL_codes, 'CMS_ACCESS_LeftAndMain', 'ADMIN')"
|
||||||
|
);
|
||||||
|
|
||||||
return $accessibleSubsites;
|
if (!$subsites && $rolesSubsites) {
|
||||||
|
return $rolesSubsites;
|
||||||
|
}
|
||||||
|
|
||||||
|
$subsites = new ArrayList($subsites->toArray());
|
||||||
|
|
||||||
|
if ($rolesSubsites) {
|
||||||
|
foreach ($rolesSubsites as $subsite) {
|
||||||
|
if (!$subsites->find('ID', $subsite->ID)) {
|
||||||
|
$subsites->push($subsite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($includeMainSite) {
|
||||||
|
if (!is_array($permCode)) {
|
||||||
|
$permCode = [$permCode];
|
||||||
|
}
|
||||||
|
if (self::hasMainSitePermission($member, $permCode)) {
|
||||||
|
$subsites = $subsites->toArray();
|
||||||
|
|
||||||
|
$mainSite = new Subsite();
|
||||||
|
$mainSite->Title = $mainSiteTitle;
|
||||||
|
array_unshift($subsites, $mainSite);
|
||||||
|
$subsites = ArrayList::create($subsites);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$cache_accessible_sites[$cacheKey] = $subsites;
|
||||||
|
|
||||||
|
return $subsites;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,10 +7,8 @@ use SilverStripe\AssetAdmin\Controller\AssetAdmin;
|
|||||||
use SilverStripe\CMS\Controllers\CMSMain;
|
use SilverStripe\CMS\Controllers\CMSMain;
|
||||||
use SilverStripe\CMS\Controllers\CMSPageEditController;
|
use SilverStripe\CMS\Controllers\CMSPageEditController;
|
||||||
use SilverStripe\Core\Config\Config;
|
use SilverStripe\Core\Config\Config;
|
||||||
use SilverStripe\Core\Injector\Injector;
|
|
||||||
use SilverStripe\Dev\FunctionalTest;
|
use SilverStripe\Dev\FunctionalTest;
|
||||||
use SilverStripe\Security\Member;
|
use SilverStripe\Security\Member;
|
||||||
use SilverStripe\Subsites\Extensions\LeftAndMainSubsites;
|
|
||||||
use SilverStripe\Subsites\Model\Subsite;
|
use SilverStripe\Subsites\Model\Subsite;
|
||||||
use SilverStripe\Subsites\State\SubsiteState;
|
use SilverStripe\Subsites\State\SubsiteState;
|
||||||
|
|
||||||
@ -33,91 +31,57 @@ class LeftAndMainSubsitesTest extends FunctionalTest
|
|||||||
return $obj;
|
return $obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function testSectionSites()
|
||||||
* @dataProvider sectionSitesProvider
|
|
||||||
*
|
|
||||||
* @param string $identifier
|
|
||||||
* @param string $className
|
|
||||||
* @param array $expected
|
|
||||||
* @param string $message
|
|
||||||
* @param string $assertion
|
|
||||||
*/
|
|
||||||
public function testSectionSites($identifier, $className, $expected, $message, $assertion = 'assertListEquals')
|
|
||||||
{
|
{
|
||||||
$member = $this->objFromFixture(Member::class, $identifier);
|
$member = $this->objFromFixture(Member::class, 'subsite1member');
|
||||||
|
|
||||||
/** @var CMSMain|LeftAndMainSubsites $cmsmain */
|
$cmsmain = singleton(CMSMain::class);
|
||||||
$cmsMain = Injector::inst()->create($className);
|
$subsites = $cmsmain->sectionSites(true, 'Main site', $member);
|
||||||
$subsites = $cmsMain->sectionSites(true, 'Main site', $member);
|
$this->assertDOSEquals([
|
||||||
$this->$assertion($expected, $subsites, $message);
|
['Title' => 'Subsite1 Template']
|
||||||
|
], $subsites, 'Lists member-accessible sites for the accessible controller.');
|
||||||
|
|
||||||
|
$assetadmin = singleton(AssetAdmin::class);
|
||||||
|
$subsites = $assetadmin->sectionSites(true, 'Main site', $member);
|
||||||
|
$this->assertDOSEquals([], $subsites, 'Does not list any sites for forbidden controller.');
|
||||||
|
|
||||||
|
$member = $this->objFromFixture(Member::class, 'editor');
|
||||||
|
|
||||||
|
$cmsmain = singleton(CMSMain::class);
|
||||||
|
$subsites = $cmsmain->sectionSites(true, 'Main site', $member);
|
||||||
|
$this->assertDOSContains([
|
||||||
|
['Title' => 'Main site']
|
||||||
|
], $subsites, 'Includes the main site for members who can access all sites.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function testAccessChecksDontChangeCurrentSubsite()
|
||||||
* @return array[]
|
|
||||||
*/
|
|
||||||
public function sectionSitesProvider()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
[
|
|
||||||
'subsite1member',
|
|
||||||
CMSMain::class,
|
|
||||||
[['Title' => 'Subsite1 Template']],
|
|
||||||
'Lists member-accessible sites for the accessible controller.',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'subsite1member',
|
|
||||||
AssetAdmin::class,
|
|
||||||
[[]],
|
|
||||||
'Does not list any sites for forbidden controller.',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'editor',
|
|
||||||
CMSMain::class,
|
|
||||||
[['Title' => 'Main site']],
|
|
||||||
'Includes the main site for members who can access all sites.',
|
|
||||||
'assertListContains',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dataProvider accessChecksProvider
|
|
||||||
*
|
|
||||||
* @param string $identifier
|
|
||||||
*/
|
|
||||||
public function testAccessChecksDontChangeCurrentSubsite($identifier)
|
|
||||||
{
|
{
|
||||||
$this->logInAs('admin');
|
$this->logInAs('admin');
|
||||||
|
$ids = [];
|
||||||
|
|
||||||
/** @var Subsite $subsite */
|
$subsite1 = $this->objFromFixture(Subsite::class, 'domaintest1');
|
||||||
$subsite = $this->objFromFixture(Subsite::class, $identifier);
|
$subsite2 = $this->objFromFixture(Subsite::class, 'domaintest2');
|
||||||
$id = $subsite->ID;
|
$subsite3 = $this->objFromFixture(Subsite::class, 'domaintest3');
|
||||||
|
$ids[] = $subsite1->ID;
|
||||||
|
$ids[] = $subsite2->ID;
|
||||||
|
$ids[] = $subsite3->ID;
|
||||||
|
$ids[] = 0;
|
||||||
|
|
||||||
// Enable session-based subsite tracking.
|
// Enable session-based subsite tracking.
|
||||||
SubsiteState::singleton()->setUseSessions(true);
|
SubsiteState::singleton()->setUseSessions(true);
|
||||||
|
|
||||||
Subsite::changeSubsite($id);
|
foreach ($ids as $id) {
|
||||||
$this->assertEquals($id, SubsiteState::singleton()->getSubsiteId(), 'Subsite ID is in the state');
|
Subsite::changeSubsite($id);
|
||||||
|
$this->assertEquals($id, SubsiteState::singleton()->getSubsiteId());
|
||||||
|
|
||||||
$left = new LeftAndMain();
|
$left = new LeftAndMain();
|
||||||
$this->assertTrue($left->canView(), "Admin user can view subsites LeftAndMain with id = '$id'");
|
$this->assertTrue($left->canView(), "Admin user can view subsites LeftAndMain with id = '$id'");
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
$id,
|
$id,
|
||||||
SubsiteState::singleton()->getSubsiteId(),
|
SubsiteState::singleton()->getSubsiteId(),
|
||||||
'The current subsite has not been changed in the process of checking permissions for admin user.'
|
'The current subsite has not been changed in the process of checking permissions for admin user.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array[]
|
|
||||||
*/
|
|
||||||
public function accessChecksProvider()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
['domaintest1'],
|
|
||||||
['domaintest3'],
|
|
||||||
['domaintest3'],
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testShouldChangeSubsite()
|
public function testShouldChangeSubsite()
|
||||||
|
@ -112,41 +112,46 @@ class SiteTreeSubsitesTest extends BaseSubsiteTest
|
|||||||
$this->assertEquals($expected_path, $path);
|
$this->assertEquals($expected_path, $path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function testCanEditSiteTree()
|
||||||
* @dataProvider canEditProvider
|
|
||||||
*
|
|
||||||
* @param string $memberIdentifier
|
|
||||||
* @param string $subsiteIdentifier
|
|
||||||
* @param string $pageIdentifier
|
|
||||||
* @param bool $expected
|
|
||||||
* @param string $message
|
|
||||||
*/
|
|
||||||
public function testCanEditSiteTree($memberIdentifier, $subsiteIdentifier, $pageIdentifier, $expected, $message)
|
|
||||||
{
|
{
|
||||||
$this->logInAs($memberIdentifier);
|
$admin = $this->objFromFixture(Member::class, 'admin');
|
||||||
|
$subsite1member = $this->objFromFixture(Member::class, 'subsite1member');
|
||||||
|
$subsite2member = $this->objFromFixture(Member::class, 'subsite2member');
|
||||||
|
$mainpage = $this->objFromFixture('Page', 'home');
|
||||||
|
$subsite1page = $this->objFromFixture('Page', 'subsite1_home');
|
||||||
|
$subsite2page = $this->objFromFixture('Page', 'subsite2_home');
|
||||||
|
$subsite1 = $this->objFromFixture(Subsite::class, 'subsite1');
|
||||||
|
$subsite2 = $this->objFromFixture(Subsite::class, 'subsite2');
|
||||||
|
|
||||||
/** @var Page $page */
|
// Cant pass member as arguments to canEdit() because of GroupSubsites
|
||||||
$page = $this->objFromFixture(Page::class, $pageIdentifier);
|
$this->logInAs($admin);
|
||||||
|
|
||||||
if (is_string($subsiteIdentifier)) {
|
$this->assertTrue(
|
||||||
$subsiteIdentifier = $this->idFromFixture(Subsite::class, $subsiteIdentifier);
|
(bool)$subsite1page->canEdit(),
|
||||||
}
|
'Administrators can edit all subsites'
|
||||||
Subsite::changeSubsite($subsiteIdentifier);
|
);
|
||||||
|
|
||||||
$this->assertSame($expected, (bool) $page->canEdit(), $message);
|
// @todo: Workaround because GroupSubsites->augmentSQL() is relying on session state
|
||||||
}
|
Subsite::changeSubsite($subsite1);
|
||||||
|
|
||||||
/**
|
$this->logInAs($subsite1member->ID);
|
||||||
* @return array[]
|
$this->assertTrue(
|
||||||
*/
|
(bool)$subsite1page->canEdit(),
|
||||||
public function canEditProvider()
|
'Members can edit pages on a subsite if they are in a group belonging to this subsite'
|
||||||
{
|
);
|
||||||
return [
|
|
||||||
['admin', 0, 'subsite1_home', true, 'Administrators can edit all subsites'],
|
$this->logInAs($subsite2member->ID);
|
||||||
['subsite1member', 'subsite1', 'subsite1_home', true, 'Can edit on subsite if group belongs to subsite'],
|
$this->assertFalse(
|
||||||
['subsite2member', 'subsite1', 'subsite1_home', false, 'Cannot edit on subsite if group doesn\'t belong'],
|
(bool)$subsite1page->canEdit(),
|
||||||
['subsite2member', 0, 'home', false, 'Cannot edit pages on main site if not in correct group'],
|
'Members cant edit pages on a subsite if they are not in a group belonging to this subsite'
|
||||||
];
|
);
|
||||||
|
|
||||||
|
// @todo: Workaround because GroupSubsites->augmentSQL() is relying on session state
|
||||||
|
Subsite::changeSubsite(0);
|
||||||
|
$this->assertFalse(
|
||||||
|
$mainpage->canEdit(),
|
||||||
|
'Members cant edit pages on the main site if they are not in a group allowing this'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user