2007-08-16 08:38:29 +02:00
|
|
|
<?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;
|
2018-06-01 05:11:25 +02:00
|
|
|
use SilverStripe\ORM\DataObject;
|
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;
|
2017-08-30 01:06:07 +02:00
|
|
|
use SilverStripe\Subsites\State\SubsiteState;
|
2017-05-24 13:36:04 +02:00
|
|
|
|
2007-08-16 08:38:29 +02:00
|
|
|
/**
|
|
|
|
* Extension for the Group object to add subsites support
|
2009-05-04 07:03:44 +02:00
|
|
|
*
|
2023-12-14 03:21:15 +01:00
|
|
|
* @method SilverStripe\ORM\ManyManyList<Subsite> Subsites()
|
2024-01-23 01:20:03 +01:00
|
|
|
*
|
|
|
|
* @extends DataExtension<Group&static>
|
2007-08-16 08:38:29 +02:00
|
|
|
*/
|
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
|
|
|
{
|
2017-05-30 17:35:02 +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
|
2018-06-01 05:11:25 +02:00
|
|
|
$schema = DataObject::getSchema();
|
2018-07-16 01:22:58 +02:00
|
|
|
$groupTable = Convert::raw2sql($schema->tableName(Group::class));
|
2018-06-01 05:11:25 +02:00
|
|
|
$groupFields = DB::field_list($groupTable);
|
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")
|
2018-06-01 05:11:25 +02:00
|
|
|
SELECT "ID", "SubsiteID" FROM "' . $groupTable . '" WHERE "SubsiteID" > 0');
|
2016-09-22 16:38:29 +02:00
|
|
|
|
2017-05-24 15:26:28 +02:00
|
|
|
// Migrate global-access data
|
2018-06-01 05:11:25 +02:00
|
|
|
DB::query('UPDATE "' . $groupTable . '" 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
|
2018-06-01 05:11:25 +02:00
|
|
|
DB::get_schema()->renameField($groupTable, '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 {
|
2018-06-01 05:11:25 +02:00
|
|
|
if (!DB::query('SELECT "Group"."ID" FROM "' . $groupTable . '"
|
2010-03-01 22:39:04 +01:00
|
|
|
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()
|
|
|
|
) {
|
2018-06-01 05:11:25 +02:00
|
|
|
DB::query('UPDATE "' . $groupTable . '" SET "AccessAllSubsites" = 1');
|
2017-05-24 15:26:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
2017-09-07 06:38:20 +02:00
|
|
|
$fields->findOrMakeTab('Root.Subsites', _t(__CLASS__ . '.SECURITYTABTITLE', 'Subsites'));
|
2017-05-24 15:26:28 +02:00
|
|
|
|
|
|
|
$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])) {
|
2017-08-29 07:07:24 +02:00
|
|
|
$fields->addFieldToTab('Root.Subsites', new OptionsetField(
|
|
|
|
'AccessAllSubsites',
|
2017-09-07 06:38:20 +02:00
|
|
|
_t(__CLASS__ . '.ACCESSRADIOTITLE', 'Give this group access to'),
|
2017-06-01 15:57:53 +02:00
|
|
|
[
|
2017-09-07 06:38:20 +02:00
|
|
|
1 => _t(__CLASS__ . '.ACCESSALL', 'All subsites'),
|
|
|
|
0 => _t(__CLASS__ . '.ACCESSONLY', 'Only these subsites'),
|
2017-06-01 15:57:53 +02:00
|
|
|
]
|
|
|
|
));
|
|
|
|
|
|
|
|
unset($subsiteMap[0]);
|
2017-08-29 07:07:24 +02:00
|
|
|
$fields->addFieldToTab('Root.Subsites', new CheckboxSetField(
|
|
|
|
'Subsites',
|
|
|
|
'',
|
|
|
|
$subsiteMap
|
|
|
|
));
|
2017-06-01 15:57:53 +02:00
|
|
|
} else {
|
2022-04-13 03:49:48 +02:00
|
|
|
if (sizeof($subsiteMap ?? []) <= 1) {
|
2017-08-29 07:07:24 +02:00
|
|
|
$fields->addFieldToTab('Root.Subsites', new ReadonlyField(
|
|
|
|
'SubsitesHuman',
|
2017-09-07 06:38:20 +02:00
|
|
|
_t(__CLASS__ . '.ACCESSRADIOTITLE', 'Give this group access to'),
|
2017-08-29 07:07:24 +02:00
|
|
|
reset($subsiteMap)
|
|
|
|
));
|
2017-06-01 15:57:53 +02:00
|
|
|
} else {
|
2017-08-29 07:07:24 +02:00
|
|
|
$fields->addFieldToTab('Root.Subsites', new CheckboxSetField(
|
|
|
|
'Subsites',
|
2017-09-07 06:38:20 +02:00
|
|
|
_t(__CLASS__ . '.ACCESSRADIOTITLE', 'Give this group access to'),
|
2017-08-29 07:07:24 +02:00
|
|
|
$subsiteMap
|
|
|
|
));
|
2017-06-01 15:57:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-05-24 15:26:28 +02:00
|
|
|
|
|
|
|
/**
|
2017-08-30 01:54:42 +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.
|
|
|
|
*
|
|
|
|
* @param string $title
|
2017-05-24 15:26:28 +02:00
|
|
|
*/
|
2017-08-30 01:54:42 +02:00
|
|
|
public function updateTreeTitle(&$title)
|
2017-05-24 15:26:28 +02:00
|
|
|
{
|
|
|
|
if ($this->owner->AccessAllSubsites) {
|
2017-09-07 06:38:20 +02:00
|
|
|
$title = _t(__CLASS__ . '.GlobalGroup', 'global group');
|
2022-04-13 03:49:48 +02:00
|
|
|
$title = htmlspecialchars($this->owner->Title ?? '', ENT_QUOTES) . ' <i>(' . $title . ')</i>';
|
2017-08-30 01:54:42 +02:00
|
|
|
} else {
|
|
|
|
$subsites = Convert::raw2xml(implode(', ', $this->owner->Subsites()->column('Title')));
|
2022-04-13 03:49:48 +02:00
|
|
|
$title = 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;
|
|
|
|
}
|
2018-08-16 16:20:48 +02:00
|
|
|
if ($dataQuery && $dataQuery->getQueryParam('Subsite.filter') === false) {
|
|
|
|
return;
|
|
|
|
}
|
2017-05-24 15:26:28 +02:00
|
|
|
|
|
|
|
// If you're querying by ID, ignore the sub-site - this is a bit ugly...
|
|
|
|
if (!$query->filtersOnID()) {
|
2017-08-30 01:06:07 +02:00
|
|
|
$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) {
|
2017-08-29 07:07:24 +02:00
|
|
|
if ((is_array($item) && strpos(
|
2022-04-13 03:49:48 +02:00
|
|
|
$item['table'] ?? '',
|
2017-08-29 07:07:24 +02:00
|
|
|
'Group_Subsites'
|
|
|
|
) !== false) || (!is_array($item) && strpos(
|
2022-04-13 03:49:48 +02:00
|
|
|
$item ?? '',
|
2017-08-29 07:07:24 +02:00
|
|
|
'Group_Subsites'
|
|
|
|
) !== false)
|
2017-05-24 15:26:28 +02:00
|
|
|
) {
|
|
|
|
$hasGroupSubsites = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$hasGroupSubsites) {
|
|
|
|
if ($subsiteID) {
|
2017-06-01 14:49:55 +02:00
|
|
|
$query->addLeftJoin('Group_Subsites', "\"Group_Subsites\".\"GroupID\"
|
2017-08-28 11:52:32 +02:00
|
|
|
= \"Group\".\"ID\" AND \"Group_Subsites\".\"SubsiteID\" = $subsiteID");
|
2017-06-01 14:49:55 +02:00
|
|
|
$query->addWhere('("Group_Subsites"."SubsiteID" IS NOT NULL OR
|
2017-08-28 11:52:32 +02:00
|
|
|
"Group"."AccessAllSubsites" = 1)');
|
2017-05-24 15:26:28 +02:00
|
|
|
} else {
|
2017-06-01 14:49:55 +02:00
|
|
|
$query->addWhere('"Group"."AccessAllSubsites" = 1');
|
2017-05-24 15:26:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-01 01:19:02 +01:00
|
|
|
// WORKAROUND for databases that complain about an ORDER BY when the column wasn't selected
|
|
|
|
// (e.g. SQL Server)
|
2017-05-24 15:26:28 +02:00
|
|
|
$select = $query->getSelect();
|
|
|
|
if (isset($select[0]) && !$select[0] == 'COUNT(*)') {
|
2017-06-01 14:49:55 +02:00
|
|
|
$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
|
2017-08-30 01:06:07 +02:00
|
|
|
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
|
2017-08-30 01:06:07 +02:00
|
|
|
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
|
2022-04-13 03:49:48 +02:00
|
|
|
return (bool)array_intersect($accessibleSites ?? [], $linkedSites);
|
2017-05-24 15:26:28 +02:00
|
|
|
}
|
|
|
|
|
2017-05-29 13:42:42 +02:00
|
|
|
public function providePermissions()
|
2017-05-24 15:26:28 +02:00
|
|
|
{
|
|
|
|
return [
|
|
|
|
'SECURITY_SUBSITE_GROUP' => [
|
2017-09-07 06:38:20 +02:00
|
|
|
'name' => _t(__CLASS__ . '.MANAGE_SUBSITES', 'Manage subsites for groups'),
|
2018-02-01 01:19:02 +01:00
|
|
|
'category' => _t(
|
|
|
|
'SilverStripe\\Security\\Permission.PERMISSIONS_CATEGORY',
|
|
|
|
'Roles and access permissions'
|
|
|
|
),
|
2017-08-29 07:07:24 +02:00
|
|
|
'help' => _t(
|
2017-09-07 06:38:20 +02:00
|
|
|
__CLASS__ . '.MANAGE_SUBSITES_HELP',
|
2017-08-29 07:07:24 +02:00
|
|
|
'Ability to limit the permissions for a group to one or more subsites.'
|
|
|
|
),
|
2017-05-24 15:26:28 +02:00
|
|
|
'sort' => 200
|
|
|
|
]
|
|
|
|
];
|
|
|
|
}
|
2007-08-16 08:38:29 +02:00
|
|
|
}
|