Files
Cloud-CMS/lib/Factory/UserGroupFactory.php
Matt Batchelder 05ce0da296 Initial Upload
2025-12-02 10:32:59 -05:00

1071 lines
43 KiB
PHP

<?php
/*
* Copyright (C) 2025 Xibo Signage Ltd
*
* Xibo - Digital Signage - https://xibosignage.com
*
* This file is part of Xibo.
*
* Xibo is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* Xibo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Xibo. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Xibo\Factory;
use Xibo\Entity\Homepage;
use Xibo\Entity\User;
use Xibo\Entity\UserGroup;
use Xibo\Support\Exception\NotFoundException;
/**
* Class UserGroupFactory
* @package Xibo\Factory
*/
class UserGroupFactory extends BaseFactory
{
/** @var array */
private $features = null;
/** @var array */
private $homepages = null;
/**
* Construct a factory
* @param User $user
* @param UserFactory $userFactory
*/
public function __construct($user, $userFactory)
{
$this->setAclDependencies($user, $userFactory);
}
/**
* Create Empty User Group Object
* @return UserGroup
*/
public function createEmpty()
{
return new UserGroup($this->getStore(), $this->getLog(), $this->getDispatcher(), $this, $this->getUserFactory());
}
/**
* Create User Group
* @param $userGroup
* @param $libraryQuota
* @return UserGroup
*/
public function create($userGroup, $libraryQuota)
{
$group = $this->createEmpty();
$group->group = $userGroup;
$group->libraryQuota = $libraryQuota;
return $group;
}
/**
* Get by Group Id
* @param int $groupId
* @return UserGroup
* @throws NotFoundException
*/
public function getById($groupId)
{
$groups = $this->query(null, ['disableUserCheck' => 1, 'groupId' => $groupId, 'isUserSpecific' => -1]);
if (count($groups) <= 0)
throw new NotFoundException(__('Group not found'));
return $groups[0];
}
/**
* Get by Group Name
* @param string $group
* @param int $isUserSpecific
* @return UserGroup
* @throws NotFoundException
*/
public function getByName($group, $isUserSpecific = 0)
{
$groups = $this->query(null, ['disableUserCheck' => 1, 'exactGroup' => $group, 'isUserSpecific' => $isUserSpecific]);
if (count($groups) <= 0)
throw new NotFoundException(__('Group not found'));
return $groups[0];
}
/**
* Get Everyone Group
* @return UserGroup
* @throws NotFoundException
*/
public function getEveryone()
{
$groups = $this->query(null, ['disableUserCheck' => 1, 'isEveryone' => 1]);
if (count($groups) <= 0)
throw new NotFoundException(__('Group not found'));
return $groups[0];
}
/**
* Get isSystemNotification Group
* @return UserGroup[]
*/
public function getSystemNotificationGroups()
{
return $this->query(null, ['disableUserCheck' => 1, 'isSystemNotification' => 1, 'isUserSpecific' => -1, 'checkRetired' => 1]);
}
/**
* Get isDisplayNotification Group
* @param int|null $displayGroupId Optionally provide a displayGroupId to restrict to view permissions.
* @return UserGroup[]
*/
public function getDisplayNotificationGroups($displayGroupId = null)
{
return $this->query(null, [
'disableUserCheck' => 1,
'isDisplayNotification' => 1,
'isUserSpecific' => -1,
'displayGroupId' => $displayGroupId,
'checkRetired' => 1
]);
}
/**
* Get by User Id
* @param int $userId
* @return \Xibo\Entity\UserGroup[]
*/
public function getByUserId($userId)
{
return $this->query(null, ['disableUserCheck' => 1, 'userId' => $userId, 'isUserSpecific' => 0]);
}
/**
* Get User Groups assigned to Notifications
* @param int $notificationId
* @return array[UserGroup]
*/
public function getByNotificationId($notificationId)
{
return $this->query(
null,
['disableUserCheck' => 1, 'notificationId' => $notificationId, 'isUserSpecific' => -1]
);
}
/**
* Get by Display Group
* @param int $displayGroupId
* @return UserGroup[]
*/
public function getByDisplayGroupId($displayGroupId)
{
return $this->query(null, ['disableUserCheck' => 1, 'displayGroupId' => $displayGroupId]);
}
/**
* @param int $userId
* @param string $type
* @return bool
*/
public function checkNotificationEmailPreferences(int $userId, string $type): bool
{
// We should include all groups this user is in (including their user specific one).
// therefore isUserSpecific should be -1 otherwise it defaults to 0.
$groups = $this->query(null, [
'disableUserCheck' => 1,
'isUserSpecific' => -1,
'userId' => $userId,
'notificationType' => $type,
]);
return count($groups) > 0;
}
/**
* @param array $sortOrder
* @param array $filterBy
* @return UserGroup[]
*/
public function query($sortOrder = null, $filterBy = [])
{
$parsedFilter = $this->getSanitizer($filterBy);
$entries = [];
$params = [];
if ($sortOrder === null) {
$sortOrder = ['`group`'];
}
$select = '
SELECT `group`.group,
`group`.description,
`group`.groupId,
`group`.isUserSpecific,
`group`.isEveryone,
`group`.libraryQuota,
`group`.isSystemNotification,
`group`.isDisplayNotification,
`group`.isDataSetNotification,
`group`.isLayoutNotification,
`group`.isLibraryNotification,
`group`.isReportNotification,
`group`.isScheduleNotification,
`group`.isCustomNotification,
`group`.isShownForAddUser,
`group`.defaultHomepageId,
`group`.features
';
$body = '
FROM `group`
WHERE 1 = 1
';
// Permissions
if ($parsedFilter->getCheckbox('disableUserCheck') == 0) {
// Normal users can only see their group
if ($this->getUser()->userTypeId != 1) {
$body .= '
AND `group`.groupId IN (
SELECT `group`.groupId
FROM `lkusergroup`
INNER JOIN `group`
ON `group`.groupId = `lkusergroup`.groupId
AND `group`.isUserSpecific = 0
WHERE `lkusergroup`.userId = :currentUserId
)
';
$params['currentUserId'] = $this->getUser()->userId;
}
}
if ($parsedFilter->getInt('checkRetired') === 1) {
$body .= '
AND `group`.groupId NOT IN (
SELECT `group`.groupId
FROM `user`
INNER JOIN `lkusergroup`
ON `lkusergroup`.userId = `user`.userId
INNER JOIN `group`
ON `group`.groupId = `lkusergroup`.groupId
AND isUserSpecific = 1
WHERE user.retired = 1
)
';
}
// Filter by Group Id
if ($parsedFilter->getInt('groupId') !== null) {
$body .= ' AND `group`.groupId = :groupId ';
$params['groupId'] = $parsedFilter->getInt('groupId');
}
// Filter by Group Name
if ($parsedFilter->getString('group') != null) {
$terms = explode(',', $parsedFilter->getString('group'));
$logicalOperator = $parsedFilter->getString('logicalOperatorName', ['default' => 'OR']);
$this->nameFilter(
'group',
'group',
$terms,
$body,
$params,
($parsedFilter->getCheckbox('useRegexForName') == 1),
$logicalOperator
);
}
if ($parsedFilter->getString('exactGroup') != null) {
$body .= ' AND `group`.group = :exactGroup ';
$params['exactGroup'] = $parsedFilter->getString('exactGroup');
}
// Filter by User Id
if ($parsedFilter->getInt('userId') !== null) {
$body .= ' AND `group`.groupId IN (SELECT groupId FROM `lkusergroup` WHERE userId = :userId) ';
$params['userId'] = $parsedFilter->getInt('userId');
}
if ($parsedFilter->getInt('isUserSpecific') !== -1) {
$body .= ' AND isUserSpecific = :isUserSpecific ';
$params['isUserSpecific'] = $parsedFilter->getInt('isUserSpecific', ['default' => 0]);
}
// Always apply isEveryone=0 unless its been provided otherwise.
$body .= ' AND isEveryone = :isEveryone ';
$params['isEveryone'] = $parsedFilter->getInt('isEveryone', ['default' => 0]);
if ($parsedFilter->getInt('isSystemNotification') !== null) {
$body .= ' AND isSystemNotification = :isSystemNotification ';
$params['isSystemNotification'] = $parsedFilter->getInt('isSystemNotification');
}
if ($parsedFilter->getInt('isDisplayNotification') !== null) {
$body .= ' AND isDisplayNotification = :isDisplayNotification ';
$params['isDisplayNotification'] = $parsedFilter->getInt('isDisplayNotification');
}
if (!empty($parsedFilter->getString('notificationType'))) {
$body .= ' AND ' . $parsedFilter->getString('notificationType') . ' = 1 ';
}
if ($parsedFilter->getInt('notificationId') !== null) {
$body .= ' AND `group`.groupId IN (
SELECT groupId FROM `lknotificationgroup` WHERE notificationId = :notificationId
) ';
$params['notificationId'] = $parsedFilter->getInt('notificationId');
}
if ($parsedFilter->getInt('isShownForAddUser') !== null) {
$body .= ' AND `group`.isShownForAddUser = :isShownForAddUser ';
$params['isShownForAddUser'] = $parsedFilter->getInt('isShownForAddUser');
}
if ($parsedFilter->getInt('displayGroupId') !== null) {
$body .= '
AND `group`.groupId IN (
SELECT DISTINCT `permission`.groupId
FROM `permission`
INNER JOIN `permissionentity`
ON `permissionentity`.entityId = permission.entityId
AND `permissionentity`.entity = \'Xibo\\Entity\\DisplayGroup\'
WHERE `permission`.objectId = :displayGroupId
AND `permission`.view = 1
)
';
$params['displayGroupId'] = $parsedFilter->getInt('displayGroupId');
}
if (in_array('`member`', $sortOrder) || in_array('`member` DESC', $sortOrder)) {
$members = [];
// DisplayGroup members with provided Display Group ID
if ($parsedFilter->getInt('userIdMember') !== null) {
foreach ($this->getStore()->select($select . $body, $params) as $row) {
$userGroupId = $this->getSanitizer($row)->getInt('groupId');
if ($this->getStore()->exists(
'SELECT groupId FROM `lkusergroup` WHERE userId = :userId AND groupId = :groupId ',
[
'groupId' => $userGroupId,
'userId' => $parsedFilter->getInt('userIdMember')
]
)) {
$members[] = $userGroupId;
}
}
}
}
// Sorting?
$order = '';
if (isset($members) && $members != []) {
$sqlOrderMembers = 'ORDER BY FIELD(group.groupId,' . implode(',', $members) . ')';
foreach ($sortOrder as $sort) {
if ($sort == '`member`') {
$order .= $sqlOrderMembers;
continue;
}
if ($sort == '`member` DESC') {
$order .= $sqlOrderMembers . ' DESC';
continue;
}
}
}
if (is_array($sortOrder) && (!in_array('`member`', $sortOrder) && !in_array('`member` DESC', $sortOrder))) {
$order .= ' ORDER BY ' . implode(',', $sortOrder);
}
$limit = '';
// Paging
if ($parsedFilter->hasParam('start') && $parsedFilter->hasParam('length')) {
$limit = ' LIMIT ' . $parsedFilter->getInt('start', ['default' => 0])
. ', ' . $parsedFilter->getInt('length', ['default' => 10]);
}
$sql = $select . $body . $order . $limit;
foreach ($this->getStore()->select($sql, $params) as $row) {
$group = $this->createEmpty()->hydrate($row, [
'intProperties' => [
'isUserSpecific',
'isEveryone',
'libraryQuota',
'isSystemNotification',
'isDisplayNotification',
'isDataSetNotification',
'isLayoutNotification',
'isReportNotification',
'isScheduleNotification',
'isCustomNotification',
'isShownForAddUser'
],
'stringProperties' => [
'defaultHomepageId'
]
]);
// Parse the features JSON string stored in database
$group->features = ($group->features === null) ? [] : json_decode($group->features, true);
$entries[] = $group;
}
// Paging
if ($limit != '' && count($entries) > 0) {
$results = $this->getStore()->select('SELECT COUNT(*) AS total ' . $body, $params);
$this->_countLast = intval($results[0]['total']);
}
return $entries;
}
/**
* @param \Xibo\Entity\User $user The User
* @param bool $includeIsUser
* @return array
*/
public function getGroupFeaturesForUser($user, $includeIsUser = true)
{
$features = [];
foreach ($this->getStore()->select('
SELECT `group`.groupId, `group`.features
FROM `group`
WHERE `group`.groupId = :groupId
OR `group`.groupId IN (SELECT groupId FROM lkusergroup WHERE userId = :userId)
', [
'userId' => $user->userId,
'groupId' => $user->groupId
]) as $featureString
) {
if (!$includeIsUser && $user->groupId == $featureString['groupId']) {
continue;
}
$feature = ($featureString['features'] == null) ? [] : json_decode($featureString['features'], true);
$features = array_merge($feature, $features);
}
return $features;
}
/**
* @param string $group
* @return array
*/
public function getFeaturesByGroup(string $group)
{
$groupFeatures = [];
foreach ($this->getFeatures() as $feature) {
if ($feature['group'] === $group) {
$groupFeatures[] = $feature;
}
}
return $groupFeatures;
}
/**
* Populate the core system features and homepages
* @return array
*/
public function getFeatures()
{
if ($this->features === null) {
$this->features = [
'schedule.view' => [
'feature' => 'schedule.view',
'group' => 'scheduling',
'title' => __('Page which shows all Events added to the Calendar for the purposes of Schedule Management')
],
'schedule.agenda' => [
'feature' => 'schedule.agenda',
'group' => 'scheduling',
'title' => __('Include the Agenda View on the Calendar')
],
'schedule.add' => [
'feature' => 'schedule.add',
'group' => 'scheduling',
'title' => __('Include "Add Event" button to allow for the creation of new Scheduled Events')
],
'schedule.modify' => [
'feature' => 'schedule.modify',
'group' => 'scheduling',
'title' => __('Allow edits including deletion of existing Scheduled Events')
],
'schedule.sync' => [
'feature' => 'schedule.sync',
'group' => 'scheduling',
'title' => __('Allow creation of Synchronised Schedules')
],
'schedule.dataConnector' => [
'feature' => 'schedule.dataConnector',
'group' => 'scheduling',
'title' => __('Allow creation of Data Connector Schedules')
],
'schedule.geoLocation' => [
'feature' => 'schedule.geoLocation',
'group' => 'scheduling',
'title' => __('Geo Schedule - allow events to be location aware when scheduling')
],
'schedule.reminders' => [
'feature' => 'schedule.reminders',
'group' => 'scheduling',
'title' => __('Reminders - allow reminders to be added to events when scheduling')
],
'schedule.criteria' => [
'feature' => 'schedule.criteria',
'group' => 'scheduling',
'title' => __('Criteria - allow criteria to be set to determine when the event is active when scheduling')
],
'daypart.view' => [
'feature' => 'daypart.view',
'group' => 'scheduling',
'title' => __('Page which shows all Dayparts that have been created')
],
'daypart.add' => [
'feature' => 'daypart.add',
'group' => 'scheduling',
'title' => __('Include "Add Daypart" button to allow for the creation of new Dayparts')
],
'daypart.modify' => [
'feature' => 'daypart.modify',
'group' => 'scheduling',
'title' => __('Allow edits including deletion to be made to all created Dayparts')
],
'library.view' => [
'feature' => 'library.view',
'group' => 'library',
'title' => __('Page which shows all items that have been uploaded to the Library for the purposes of Media Management')
],
'library.add' => [
'feature' => 'library.add',
'group' => 'library',
'title' => __('Include "Add Media" buttons to allow for additional content to be uploaded to the Media Library')
],
'library.modify' => [
'feature' => 'library.modify',
'group' => 'library',
'title' => __('Allow edits including deletion to all items uploaded to the Media Library')
],
'dataset.view' => [
'feature' => 'dataset.view',
'group' => 'library',
'title' => __('Page which shows all DataSets that have been created which can be used in multiple Layouts')
],
'dataset.add' => [
'feature' => 'dataset.add',
'group' => 'library',
'title' => __('Include "Add DataSet" button to allow for additional DataSets to be created independently to Layouts')
],
'dataset.modify' => [
'feature' => 'dataset.modify',
'group' => 'library',
'title' => __('Allow edits including deletion to all created DataSets independently to Layouts')
],
'dataset.data' => [
'feature' => 'dataset.data',
'group' => 'library',
'title' => __('Allow edits including deletion to all data contained within a DataSet independently to Layouts')
],
'dataset.dataConnector' => [
'feature' => 'dataset.realtime',
'group' => 'library',
'title' => __('Create and update real time DataSets')
],
'layout.view' => [
'feature' => 'layout.view',
'group' => 'layout-design',
'title' => __('Page which shows all Layouts that have been created for the purposes of Layout Management')
],
'layout.add' => [
'feature' => 'layout.add',
'group' => 'layout-design',
'title' => __('Include "Add Layout" button to allow for additional Layouts to be created')
],
'layout.modify' => [
'feature' => 'layout.modify',
'group' => 'layout-design',
'title' => __('Allow edits including deletion to be made to all created Layouts')
],
'layout.export' => [
'feature' => 'layout.export',
'group' => 'layout-design',
'title' => __('Include the Export function for all editable Layouts to allow a User to export a Layout and its contents regardless of the share options that have been set')
],
'campaign.view' => [
'feature' => 'campaign.view',
'group' => 'campaigns',
'title' => __('Page which shows all Campaigns that have been created for the purposes of Campaign Management')
],
'campaign.add' => [
'feature' => 'campaign.add',
'group' => 'campaigns',
'title' => __('Include "Add Campaign" button to allow for additional Campaigns to be created')
],
'campaign.modify' => [
'feature' => 'campaign.modify',
'group' => 'campaigns',
'title' => __('Allow edits including deletion to all created Campaigns')
],
'ad.campaign' => [
'feature' => 'ad.campaign',
'group' => 'campaigns',
'title' => __('Access to Ad Campaigns')
],
'template.view' => [
'feature' => 'template.view',
'group' => 'layout-design',
'title' => __('Page which shows all Templates that have been saved')
],
'template.add' => [
'feature' => 'template.add',
'group' => 'layout-design',
'title' => __('Add "Save Template" function for all Layouts')
],
'template.modify' => [
'feature' => 'template.modify',
'group' => 'layout-design',
'title' => __('Allow edits to be made to all saved Templates')
],
'resolution.view' => [
'feature' => 'resolution.view',
'group' => 'layout-design',
'title' => __('Page which shows all Resolutions that have been added to the platform')
],
'resolution.add' => [
'feature' => 'resolution.add',
'group' => 'layout-design',
'title' => __('Add Resolution button to allow for additional Resolutions to be added')
],
'resolution.modify' => [
'feature' => 'resolution.modify',
'group' => 'layout-design',
'title' => __('Allow edits including deletion to all added Resolutions')
],
'tag.view' => [
'feature' => 'tag.view',
'group' => 'tagging',
'title' => __('Page which shows all Tags that have been added for the purposes of Tag Management')
],
'tag.tagging' => [
'feature' => 'tag.tagging',
'group' => 'tagging',
'title' => __('Ability to add and edit Tags when assigning to items')
],
'playlist.view' => [
'feature' => 'playlist.view',
'group' => 'playlist-design',
'title' => __('Page which shows all Playlists that have been created which can be used in multiple Layouts')
],
'playlist.add' => [
'feature' => 'playlist.add',
'group' => 'playlist-design',
'title' => __('Include "Add Playlist" button to allow for additional Playlists to be created independently to Layouts')
],
'playlist.modify' => [
'feature' => 'playlist.modify',
'group' => 'playlist-design',
'title' => __('Allow edits including deletion to all created Playlists independently to Layouts')
],
'user.profile' => [
'feature' => 'user.profile',
'group' => 'users',
'title' => __('Ability to update own Profile, including changing passwords and authentication preferences')
],
'drawer' => [
'feature' => 'drawer',
'group' => 'users',
'title' => __('Notifications appear in the navigation bar')
],
'notification.centre' => [
'feature' => 'notification.centre',
'group' => 'notifications',
'title' => __('Access to the Notification Centre to view past notifications')
],
'application.view' => [
'feature' => 'application.view',
'group' => 'users',
'title' => __('Access to API applications')
],
'user.sharing' => [
'feature' => 'user.sharing',
'group' => 'users',
'title' => __('Allow Sharing capabilities for all User objects')
],
'notification.add' => [
'feature' => 'notification.add',
'group' => 'notifications',
'title' => __('Include "Add Notification" button to allow for the creation of new notifications')
],
'notification.modify' => [
'feature' => 'notification.modify',
'group' => 'notifications',
'title' => __('Allow edits including deletion for all notifications in the Notification Centre')
],
'users.view' => [
'feature' => 'users.view',
'group' => 'users-management',
'title' => __('Page which shows all Users in the platform for the purposes of User Management')
],
'users.add' => [
'feature' => 'users.add',
'group' => 'users-management',
'title' => __('Include "Add User" button to allow for additional Users to be added to the platform')
],
'users.modify' => [
'feature' => 'users.modify',
'group' => 'users-management',
'title' => __('Allow Group Admins to edit including deletion, for all added Users within their group')
],
'usergroup.view' => [
'feature' => 'usergroup.view',
'group' => 'users-management',
'title' => __('Page which shows all User Groups that have been created')
],
'usergroup.modify' => [
'feature' => 'usergroup.modify',
'group' => 'users-management',
'title' => __('Allow edits including deletion for all created User Groups')
],
'dashboard.status' => [
'feature' => 'dashboard.status',
'group' => 'dashboards',
'title' => __('Status Dashboard showing key platform metrics, suitable for an Administrator.')
],
'dashboard.media.manager' => [
'feature' => 'dashboard.media.manager',
'group' => 'dashboards',
'title' => __('Media Manager Dashboard showing only the Widgets the user has access to modify.')
],
'dashboard.playlist' => [
'feature' => 'dashboard.playlist',
'group' => 'dashboards',
'title' => __('Playlist Dashboard showing only the Playlists configured in Layouts the user has access to modify.')
],
'displays.view' => [
'feature' => 'displays.view',
'group' => 'displays',
'title' => __('Page which shows all Displays added to the platform for the purposes of Display Management')
],
'displays.add' => [
'feature' => 'displays.add',
'group' => 'displays',
'title' => __('Include "Add Display" button to allow additional Displays to be added to the platform')
],
'displays.modify' => [
'feature' => 'displays.modify',
'group' => 'displays',
'title' => __('Allow edits including deletion for all added Displays')
],
'displays.limitedView' => [
'feature' => 'displays.limitedView',
'group' => 'displays',
'title' => __('Allow access to non-destructive edit-only features')
],
'displaygroup.view' => [
'feature' => 'displaygroup.view',
'group' => 'displays',
'title' => __('Page which shows all Display Groups that have been created')
],
'displaygroup.add' => [
'feature' => 'displaygroup.add',
'group' => 'displays',
'title' => __('Include "Add Display Group" button to allow for the creation of additional Display Groups')
],
'displaygroup.modify' => [
'feature' => 'displaygroup.modify',
'group' => 'displays',
'title' => __('Allow edits including deletion for all created Display Groups')
],
'displaygroup.limitedView' => [
'feature' => 'displaygroup.limitedView',
'group' => 'displays',
'title' => __('Allow access to non-destructive edit-only features in a Display Group')
],
'displayprofile.view' => [
'feature' => 'displayprofile.view',
'group' => 'displays',
'title' => __('Page which shows all Display Setting Profiles that have been added')
],
'displayprofile.add' => [
'feature' => 'displayprofile.add',
'group' => 'displays',
'title' => __('Include "Add Profile" button to allow for additional Display Setting Profiles to be added to the platform')
],
'displayprofile.modify' => [
'feature' => 'displayprofile.modify',
'group' => 'displays',
'title' => __('Allow edits including deletion for all created Display Setting Profiles')
],
'playersoftware.view' => [
'feature' => 'playersoftware.view',
'group' => 'displays',
'title' => __('Page to view/add/edit/delete/download Player Software Versions')
],
'command.view' => [
'feature' => 'command.view',
'group' => 'displays',
'title' => __('Page to view/add/edit/delete Commands')
],
'display.syncView' => [
'feature' => 'display.syncView',
'group' => 'displays',
'title' => __('Page which shows all Sync Groups added to the platform for the purposes of Sync Group Management')
],
'display.syncAdd' => [
'feature' => 'display.syncAdd',
'group' => 'displays',
'title' => __('Allow creation of Synchronised Groups')
],
'display.syncModify' => [
'feature' => 'display.syncModify',
'group' => 'displays',
'title' => __('Allow edits of Synchronised Groups')
],
'fault.view' => [
'feature' => 'fault.view',
'group' => 'troubleshooting',
'title' => __('Access to a Report Fault wizard for collecting reports to forward to the support team for analysis, which may contain sensitive data.')
],
'log.view' => [
'feature' => 'log.view',
'group' => 'troubleshooting',
'title' => __('Page to show debug and error logging which may contain sensitive data')
],
'session.view' => [
'feature' => 'session.view',
'group' => 'troubleshooting',
'title' => __('Page to show all User Sessions throughout the platform')
],
'auditlog.view' => [
'feature' => 'auditlog.view',
'group' => 'troubleshooting',
'title' => __('Page to show the Audit Trail for all created/modified and removed items throughout the platform')
],
'module.view' => [
'feature' => 'module.view',
'group' => 'system',
'title' => __('Page which allows for Module Management for the platform')
],
'developer.edit' => [
'feature' => 'developer.edit',
'group' => 'system',
'title' => __('Add/Edit custom modules and templates'),
],
'developer.delete' => [
'feature' => 'developer.delete',
'group' => 'system',
'title' => __('Delete custom modules and templates'),
],
'transition.view' => [
'feature' => 'transition.view',
'group' => 'system',
'title' => __('Page which allows for Transition Management for the platform')
],
'task.view' => [
'feature' => 'task.view',
'group' => 'system',
'title' => __('Page which allows for Task Management for the platform')
],
'report.view' => [
'feature' => 'report.view',
'group' => 'reporting',
'title' => __('Dashboard which shows all available Reports')
],
'displays.reporting' => [
'feature' => 'displays.reporting',
'group' => 'reporting',
'title' => __('Display Reports to show bandwidth usage and time connected / disconnected')
],
'proof-of-play' => [
'feature' => 'proof-of-play',
'group' => 'reporting',
'title' => __('Proof of Play Reports which include summary and distribution by Layout, Media or Event')
],
'report.scheduling' => [
'feature' => 'report.scheduling',
'group' => 'reporting',
'title' => __('Page which shows all Reports that have been Scheduled')
],
'report.saving' => [
'feature' => 'report.saving',
'group' => 'reporting',
'title' => __('Page which shows all Reports that have been Saved')
],
'folder.view' => [
'feature' => 'folder.view',
'group' => 'folders',
'title' => __('View Folder Tree on Grids and Forms')
],
'folder.add' => [
'feature' => 'folder.add',
'group' => 'folders',
'title' => __('Allow users to create Sub-Folders under Folders they have access to. (Except the Root Folder)')
],
'folder.modify' => [
'feature' => 'folder.modify',
'group' => 'folders',
'title' => __('Rename and Delete existing Folders')
],
'folder.userHome' => [
'feature' => 'folder.userHome',
'group' => 'folders',
'title' => __('Set a home folder for a user')
],
'menuBoard.view' => [
'feature' => 'menuBoard.view',
'group' => 'menuboard-design',
'title' => __('View the Menu Board page')
],
'menuBoard.add' => [
'feature' => 'menuBoard.add',
'group' => 'menuboard-design',
'title' => __('Include "Add Menu Board" button to allow for additional Menu Boards to be added to the platform')
],
'menuBoard.modify' => [
'feature' => 'menuBoard.modify',
'group' => 'menuboard-design',
'title' => __('Allow edits, creation of Menu Board Categories and Products including deletion for all created Menu Board content')
],
'font.view' => [
'feature' => 'font.view',
'group' => 'fonts',
'title' => __('View the Fonts page')
],
'font.add' => [
'feature' => 'font.add',
'group' => 'fonts',
'title' => __('Upload new Fonts')
],
'font.delete' => [
'feature' => 'font.delete',
'group' => 'fonts',
'title' => __('Delete existing Fonts')
]
];
}
return $this->features;
}
/**
* @param string|null $homepage The home page id
* @return \Xibo\Entity\Homepage
* @throws \Xibo\Support\Exception\NotFoundException
*/
public function getHomepageByName(?string $homepage): Homepage
{
if (empty($homepage)) {
throw new NotFoundException(__('Homepage has not been set'));
}
$homepages = $this->getHomepages();
if (!array_key_exists($homepage, $homepages)) {
throw new NotFoundException(sprintf(__('Homepage %s not found.'), $homepage));
}
return $homepages[$homepage];
}
/**
* @return \Xibo\Entity\Homepage[]
*/
public function getHomepages()
{
if ($this->homepages === null) {
$this->homepages = [
'statusdashboard.view' => new Homepage(
'statusdashboard.view',
'dashboard.status',
__('Status Dashboard'),
__('Status Dashboard showing key platform metrics, usually for an administrator.')
),
'icondashboard.view' => new Homepage(
'icondashboard.view',
'',
__('Icon Dashboard'),
__('Icon Dashboard showing an easy access set of feature icons the user can access.')
),
'mediamanager.view' => new Homepage(
'mediamanager.view',
'dashboard.media.manager',
__('Media Manager Dashboard'),
__('Media Manager Dashboard showing all Widgets the user has access to modify.')
),
'playlistdashboard.view' => new Homepage(
'playlistdashboard.view',
'dashboard.playlist',
__('Playlist Dashboard'),
__('Playlist Dashboard showing all Playlists configured in Layouts the user has access to modify.')
),
];
}
return $this->homepages;
}
/**
* @param string $feature
* @param string $title
* @return $this
*/
public function registerCustomFeature(string $feature, string $title)
{
$this->getFeatures();
if (!array_key_exists($feature, $this->features)) {
$this->features[$feature] = [
'feature' => $feature,
'group' => 'custom',
'title' => $title
];
}
return $this;
}
/**
* @param string $homepage
* @param string $title
* @param string $description
* @param string $feature
* @return $this
*/
public function registerCustomHomepage(string $homepage, string $title, string $description, string $feature)
{
$this->getHomepages();
if (!array_key_exists($homepage, $this->homepages)) {
$this->homepages[$homepage] = new Homepage(
$homepage,
$feature,
$title,
$description
);
}
return $this;
}
}