silverstripe-subsites/code/extensions/GroupSubsites.php

243 lines
9.0 KiB
PHP
Raw Normal View History

<?php
2016-09-22 16:38:29 +02:00
2017-05-24 12:32:05 +02:00
namespace SilverStripe\Subsites\Extensions;
2017-05-24 15:26:28 +02:00
use SilverStripe\Control\Cookie;
2016-09-22 16:38:29 +02:00
use SilverStripe\Core\Convert;
use SilverStripe\Forms\CheckboxSetField;
2017-05-24 15:26:28 +02:00
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\OptionsetField;
2016-09-22 16:38:29 +02:00
use SilverStripe\Forms\ReadonlyField;
use SilverStripe\ORM\DataExtension;
2017-05-24 15:26:28 +02:00
use SilverStripe\ORM\DataQuery;
use SilverStripe\ORM\DB;
use SilverStripe\ORM\Queries\SQLSelect;
use SilverStripe\Security\Group;
2016-09-22 16:38:29 +02:00
use SilverStripe\Security\PermissionProvider;
2017-05-24 12:32:05 +02:00
use SilverStripe\Subsites\Model\Subsite;
use SilverStripe\Subsites\State\SubsiteState;
2017-05-24 13:36:04 +02:00
/**
* Extension for the Group object to add subsites support
2009-05-04 07:03:44 +02:00
*
* @package subsites
*/
2017-05-24 15:26:28 +02:00
class GroupSubsites extends DataExtension implements PermissionProvider
{
2017-06-01 15:57:53 +02:00
private static $db = [
'AccessAllSubsites' => 'Boolean'
];
2017-05-24 15:26:28 +02:00
2017-06-01 15:57:53 +02:00
private static $many_many = [
'Subsites' => Subsite::class
];
2017-05-24 15:26:28 +02:00
2017-06-01 15:57:53 +02:00
private static $defaults = [
'AccessAllSubsites' => true
];
2017-05-24 15:26:28 +02:00
/**
* Migrations for GroupSubsites data.
*/
2017-05-29 13:42:42 +02:00
public function requireDefaultRecords()
2017-05-24 15:26:28 +02:00
{
if (!$this->owner) {
return;
}
2017-05-24 15:26:28 +02:00
// Migration for Group.SubsiteID data from when Groups only had a single subsite
$ownerClass = get_class($this->owner);
$schema = $ownerClass::getSchema();
2017-05-24 15:26:28 +02:00
$groupFields = DB::field_list($schema->tableName(Group::class));
2016-09-22 16:38:29 +02:00
2017-05-24 15:26:28 +02:00
// Detection of SubsiteID field is the trigger for old-style-subsiteID migration
if (isset($groupFields['SubsiteID'])) {
// Migrate subsite-specific data
DB::query('INSERT INTO "Group_Subsites" ("GroupID", "SubsiteID")
SELECT "ID", "SubsiteID" FROM "Group" WHERE "SubsiteID" > 0');
2016-09-22 16:38:29 +02:00
2017-05-24 15:26:28 +02:00
// Migrate global-access data
DB::query('UPDATE "Group" SET "AccessAllSubsites" = 1 WHERE "SubsiteID" = 0');
2016-09-22 16:38:29 +02:00
2017-05-24 15:26:28 +02:00
// Move the field out of the way so that this migration doesn't get executed again
DB::get_schema()->renameField(Group::class, 'SubsiteID', '_obsolete_SubsiteID');
2016-09-22 16:38:29 +02:00
2017-05-24 15:26:28 +02:00
// No subsite access on anything means that we've just installed the subsites module.
// Make all previous groups global-access groups
} else {
if (!DB::query('SELECT "Group"."ID" FROM "Group"
LEFT JOIN "Group_Subsites" ON "Group_Subsites"."GroupID" = "Group"."ID" AND "Group_Subsites"."SubsiteID" > 0
WHERE "AccessAllSubsites" = 1
2017-06-01 15:57:53 +02:00
OR "Group_Subsites"."GroupID" IS NOT NULL ')->value()
) {
2017-05-24 15:26:28 +02:00
DB::query('UPDATE "Group" SET "AccessAllSubsites" = 1');
}
}
}
2017-05-29 13:42:42 +02:00
public function updateCMSFields(FieldList $fields)
2017-05-24 15:26:28 +02:00
{
if ($this->owner->canEdit()) {
// i18n tab
$fields->findOrMakeTab('Root.Subsites', _t('GroupSubsites.SECURITYTABTITLE', 'Subsites'));
$subsites = Subsite::accessible_sites(['ADMIN', 'SECURITY_SUBSITE_GROUP'], true);
$subsiteMap = $subsites->map();
2017-06-01 15:57:53 +02:00
// Prevent XSS injection
$subsiteMap = Convert::raw2xml($subsiteMap->toArray());
// Interface is different if you have the rights to modify subsite group values on
// all subsites
if (isset($subsiteMap[0])) {
$fields->addFieldToTab('Root.Subsites', new OptionsetField(
'AccessAllSubsites',
2017-06-01 15:57:53 +02:00
_t('GroupSubsites.ACCESSRADIOTITLE', 'Give this group access to'),
[
1 => _t('GroupSubsites.ACCESSALL', 'All subsites'),
0 => _t('GroupSubsites.ACCESSONLY', 'Only these subsites'),
]
));
unset($subsiteMap[0]);
$fields->addFieldToTab('Root.Subsites', new CheckboxSetField(
'Subsites',
'',
$subsiteMap
));
2017-06-01 15:57:53 +02:00
} else {
if (sizeof($subsiteMap) <= 1) {
$fields->addFieldToTab('Root.Subsites', new ReadonlyField(
'SubsitesHuman',
2017-06-01 15:57:53 +02:00
_t('GroupSubsites.ACCESSRADIOTITLE', 'Give this group access to'),
reset($subsiteMap)
));
2017-06-01 15:57:53 +02:00
} else {
$fields->addFieldToTab('Root.Subsites', new CheckboxSetField(
'Subsites',
2017-06-01 15:57:53 +02:00
_t('GroupSubsites.ACCESSRADIOTITLE', 'Give this group access to'),
$subsiteMap
));
2017-06-01 15:57:53 +02:00
}
}
}
}
2017-05-24 15:26:28 +02:00
/**
* If this group belongs to a subsite,
* append the subsites title to the group title
* to make it easy to distinguish in the tree-view
* of the security admin interface.
*/
2017-05-29 13:42:42 +02:00
public function alternateTreeTitle()
2017-05-24 15:26:28 +02:00
{
if ($this->owner->AccessAllSubsites) {
$title = _t('GroupSubsites.GlobalGroup', 'global group');
return htmlspecialchars($this->owner->Title, ENT_QUOTES) . ' <i>(' . $title . ')</i>';
}
$subsites = Convert::raw2xml(implode(', ', $this->owner->Subsites()->column('Title')));
return htmlspecialchars($this->owner->Title) . " <i>($subsites)</i>";
2017-05-24 15:26:28 +02:00
}
/**
* Update any requests to limit the results to the current site
2017-06-01 15:10:07 +02:00
* @param SQLSelect $query
* @param DataQuery|null $dataQuery
2017-05-24 15:26:28 +02:00
*/
public function augmentSQL(SQLSelect $query, DataQuery $dataQuery = null)
{
if (Subsite::$disable_subsite_filter) {
return;
}
if (Cookie::get('noSubsiteFilter') == 'true') {
return;
}
// If you're querying by ID, ignore the sub-site - this is a bit ugly...
if (!$query->filtersOnID()) {
$subsiteID = SubsiteState::singleton()->getSubsiteId();
if ($subsiteID === null) {
return;
}
2017-05-24 15:26:28 +02:00
// Don't filter by Group_Subsites if we've already done that
$hasGroupSubsites = false;
foreach ($query->getFrom() as $item) {
if ((is_array($item) && strpos(
$item['table'],
'Group_Subsites'
) !== false) || (!is_array($item) && strpos(
$item,
'Group_Subsites'
) !== false)
2017-05-24 15:26:28 +02:00
) {
$hasGroupSubsites = true;
break;
}
}
if (!$hasGroupSubsites) {
if ($subsiteID) {
$query->addLeftJoin('Group_Subsites', "\"Group_Subsites\".\"GroupID\"
= \"Group\".\"ID\" AND \"Group_Subsites\".\"SubsiteID\" = $subsiteID");
$query->addWhere('("Group_Subsites"."SubsiteID" IS NOT NULL OR
"Group"."AccessAllSubsites" = 1)');
2017-05-24 15:26:28 +02:00
} else {
$query->addWhere('"Group"."AccessAllSubsites" = 1');
2017-05-24 15:26:28 +02:00
}
}
// WORKAROUND for databases that complain about an ORDER BY when the column wasn't selected (e.g. SQL Server)
$select = $query->getSelect();
if (isset($select[0]) && !$select[0] == 'COUNT(*)') {
$query->addOrderBy('AccessAllSubsites', 'DESC');
2017-05-24 15:26:28 +02:00
}
}
}
2017-05-29 13:42:42 +02:00
public function onBeforeWrite()
2017-05-24 15:26:28 +02:00
{
// New record test approximated by checking whether the ID has changed.
// Note also that the after write test is only used when we're *not* on a subsite
if ($this->owner->isChanged('ID') && !SubsiteState::singleton()->getSubsiteId()) {
2017-05-24 15:26:28 +02:00
$this->owner->AccessAllSubsites = 1;
}
}
2017-05-29 13:42:42 +02:00
public function onAfterWrite()
2017-05-24 15:26:28 +02:00
{
// New record test approximated by checking whether the ID has changed.
// Note also that the after write test is only used when we're on a subsite
if ($this->owner->isChanged('ID') && $currentSubsiteID = SubsiteState::singleton()->getSubsiteId()) {
2017-05-24 15:26:28 +02:00
$subsites = $this->owner->Subsites();
$subsites->add($currentSubsiteID);
}
}
2017-05-29 13:42:42 +02:00
public function alternateCanEdit()
2017-05-24 15:26:28 +02:00
{
// Find the sites that this group belongs to and the sites where we have appropriate perm.
$accessibleSites = Subsite::accessible_sites('CMS_ACCESS_SecurityAdmin')->column('ID');
$linkedSites = $this->owner->Subsites()->column('ID');
// We are allowed to access this site if at we have CMS_ACCESS_SecurityAdmin permission on
// at least one of the sites
return (bool)array_intersect($accessibleSites, $linkedSites);
}
2017-05-29 13:42:42 +02:00
public function providePermissions()
2017-05-24 15:26:28 +02:00
{
return [
'SECURITY_SUBSITE_GROUP' => [
'name' => _t('GroupSubsites.MANAGE_SUBSITES', 'Manage subsites for groups'),
'category' => _t('Permissions.PERMISSIONS_CATEGORY', 'Roles and access permissions'),
'help' => _t(
'GroupSubsites.MANAGE_SUBSITES_HELP',
'Ability to limit the permissions for a group to one or more subsites.'
),
2017-05-24 15:26:28 +02:00
'sort' => 200
]
];
}
}