Initial Upload
This commit is contained in:
607
lib/Controller/Action.php
Normal file
607
lib/Controller/Action.php
Normal file
@@ -0,0 +1,607 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2023 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\Controller;
|
||||
|
||||
use Slim\Http\Response as Response;
|
||||
use Slim\Http\ServerRequest as Request;
|
||||
use Xibo\Factory\ActionFactory;
|
||||
use Xibo\Factory\LayoutFactory;
|
||||
use Xibo\Factory\ModuleFactory;
|
||||
use Xibo\Factory\RegionFactory;
|
||||
use Xibo\Factory\WidgetFactory;
|
||||
use Xibo\Support\Exception\GeneralException;
|
||||
use Xibo\Support\Exception\InvalidArgumentException;
|
||||
use Xibo\Support\Exception\NotFoundException;
|
||||
|
||||
/**
|
||||
* Class Action
|
||||
* @package Xibo\Controller
|
||||
*/
|
||||
class Action extends Base
|
||||
{
|
||||
|
||||
/**
|
||||
* @var ActionFactory
|
||||
*/
|
||||
private $actionFactory;
|
||||
|
||||
/** @var LayoutFactory */
|
||||
private $layoutFactory;
|
||||
|
||||
/** @var RegionFactory */
|
||||
private $regionFactory;
|
||||
|
||||
/** @var WidgetFactory */
|
||||
private $widgetFactory;
|
||||
|
||||
/** @var ModuleFactory */
|
||||
private $moduleFactory;
|
||||
|
||||
/**
|
||||
* Set common dependencies.
|
||||
* @param ActionFactory $actionFactory
|
||||
* @param LayoutFactory $layoutFactory
|
||||
* @param RegionFactory $regionFactory
|
||||
* @param WidgetFactory $widgetFactory
|
||||
* @param ModuleFactory $moduleFactory
|
||||
*/
|
||||
public function __construct($actionFactory, $layoutFactory, $regionFactory, $widgetFactory, $moduleFactory)
|
||||
{
|
||||
$this->actionFactory = $actionFactory;
|
||||
$this->layoutFactory = $layoutFactory;
|
||||
$this->regionFactory = $regionFactory;
|
||||
$this->widgetFactory = $widgetFactory;
|
||||
$this->moduleFactory = $moduleFactory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a Grid of Actions
|
||||
*
|
||||
* @SWG\Get(
|
||||
* path="/action",
|
||||
* operationId="actionSearch",
|
||||
* tags={"action"},
|
||||
* summary="Search Actions",
|
||||
* description="Search all Actions this user has access to",
|
||||
* @SWG\Parameter(
|
||||
* name="actionId",
|
||||
* in="query",
|
||||
* description="Filter by Action Id",
|
||||
* type="integer",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="ownerId",
|
||||
* in="query",
|
||||
* description="Filter by Owner Id",
|
||||
* type="integer",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="triggerType",
|
||||
* in="query",
|
||||
* description="Filter by Action trigger type",
|
||||
* type="string",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="triggerCode",
|
||||
* in="query",
|
||||
* description="Filter by Action trigger code",
|
||||
* type="string",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="actionType",
|
||||
* in="query",
|
||||
* description="Filter by Action type",
|
||||
* type="string",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="source",
|
||||
* in="query",
|
||||
* description="Filter by Action source",
|
||||
* type="string",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="sourceId",
|
||||
* in="query",
|
||||
* description="Filter by Action source Id",
|
||||
* type="integer",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="target",
|
||||
* in="query",
|
||||
* description="Filter by Action target",
|
||||
* type="string",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="targetId",
|
||||
* in="query",
|
||||
* description="Filter by Action target Id",
|
||||
* type="integer",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="layoutId",
|
||||
* in="query",
|
||||
* description="Return all actions pertaining to a particular Layout",
|
||||
* type="integer",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="sourceOrTargetId",
|
||||
* in="query",
|
||||
* description="Return all actions related to a source or target with the provided ID",
|
||||
* type="integer",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Response(
|
||||
* response=200,
|
||||
* description="successful operation",
|
||||
* @SWG\Schema(
|
||||
* type="array",
|
||||
* @SWG\Items(ref="#/definitions/Action")
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @return \Psr\Http\Message\ResponseInterface|Response
|
||||
* @throws GeneralException
|
||||
*/
|
||||
public function grid(Request $request, Response $response) : Response
|
||||
{
|
||||
$parsedParams = $this->getSanitizer($request->getQueryParams());
|
||||
|
||||
$filter = [
|
||||
'actionId' => $parsedParams->getInt('actionId'),
|
||||
'ownerId' => $parsedParams->getInt('ownerId'),
|
||||
'triggerType' => $parsedParams->getString('triggerType'),
|
||||
'triggerCode' => $parsedParams->getString('triggerCode'),
|
||||
'actionType' => $parsedParams->getString('actionType'),
|
||||
'source' => $parsedParams->getString('source'),
|
||||
'sourceId' => $parsedParams->getInt('sourceId'),
|
||||
'target' => $parsedParams->getString('target'),
|
||||
'targetId' => $parsedParams->getInt('targetId'),
|
||||
'widgetId' => $parsedParams->getInt('widgetId'),
|
||||
'layoutCode' => $parsedParams->getString('layoutCode'),
|
||||
'layoutId' => $parsedParams->getInt('layoutId'),
|
||||
'sourceOrTargetId' => $parsedParams->getInt('sourceOrTargetId'),
|
||||
];
|
||||
|
||||
$actions = $this->actionFactory->query(
|
||||
$this->gridRenderSort($parsedParams),
|
||||
$this->gridRenderFilter($filter, $parsedParams)
|
||||
);
|
||||
|
||||
foreach ($actions as $action) {
|
||||
$action->setUnmatchedProperty('widgetName', null);
|
||||
$action->setUnmatchedProperty('regionName', null);
|
||||
|
||||
if ($action->actionType === 'navWidget' && $action->widgetId != null) {
|
||||
try {
|
||||
$widget = $this->widgetFactory->loadByWidgetId($action->widgetId);
|
||||
$module = $this->moduleFactory->getByType($widget->type);
|
||||
|
||||
// dynamic field to display in the grid instead of widgetId
|
||||
$action->setUnmatchedProperty('widgetName', $widget->getOptionValue('name', $module->name));
|
||||
} catch (NotFoundException $e) {
|
||||
// Widget not found, leave widgetName as null
|
||||
}
|
||||
}
|
||||
|
||||
if ($action->target === 'region' && $action->targetId != null) {
|
||||
try {
|
||||
$region = $this->regionFactory->getById($action->targetId);
|
||||
|
||||
// dynamic field to display in the grid instead of regionId
|
||||
$action->setUnmatchedProperty('regionName', $region->name);
|
||||
} catch (NotFoundException $e) {
|
||||
// Region not found, leave regionName as null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->getState()->template = 'grid';
|
||||
$this->getState()->recordsTotal = $this->actionFactory->countLast();
|
||||
$this->getState()->setData($actions);
|
||||
|
||||
return $this->render($request, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new Action
|
||||
*
|
||||
* @SWG\Post(
|
||||
* path="/action",
|
||||
* operationId="actionAdd",
|
||||
* tags={"action"},
|
||||
* summary="Add Action",
|
||||
* description="Add a new Action",
|
||||
* @SWG\Parameter(
|
||||
* name="layoutId",
|
||||
* in="formData",
|
||||
* description="LayoutId associted with this Action",
|
||||
* type="integer",
|
||||
* required=true
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="actionType",
|
||||
* in="formData",
|
||||
* description="Action type, next, previous, navLayout, navWidget",
|
||||
* type="string",
|
||||
* required=true
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="target",
|
||||
* in="formData",
|
||||
* description="Target for this action, screen or region",
|
||||
* type="string",
|
||||
* required=true
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="targetId",
|
||||
* in="formData",
|
||||
* description="The id of the target for this action - regionId if the target is set to region",
|
||||
* type="string",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="source",
|
||||
* in="formData",
|
||||
* description="Source for this action layout, region or widget",
|
||||
* type="string",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="sourceId",
|
||||
* in="formData",
|
||||
* description="The id of the source object, layoutId, regionId or widgetId",
|
||||
* type="integer",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="triggerType",
|
||||
* in="formData",
|
||||
* description="Action trigger type, touch or webhook",
|
||||
* type="string",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="triggerCode",
|
||||
* in="formData",
|
||||
* description="Action trigger code",
|
||||
* type="string",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="widgetId",
|
||||
* in="formData",
|
||||
* description="For navWidget actionType, the WidgetId to navigate to",
|
||||
* type="integer",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="layoutCode",
|
||||
* in="formData",
|
||||
* description="For navLayout, the Layout Code identifier to navigate to",
|
||||
* type="string",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Response(
|
||||
* response=201,
|
||||
* description="successful operation",
|
||||
* @SWG\Schema(ref="#/definitions/Action"),
|
||||
* @SWG\Header(
|
||||
* header="Location",
|
||||
* description="Location of the new record",
|
||||
* type="string"
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @return \Psr\Http\Message\ResponseInterface|Response
|
||||
* @throws GeneralException
|
||||
*/
|
||||
public function add(Request $request, Response $response) : Response
|
||||
{
|
||||
$sanitizedParams = $this->getSanitizer($request->getParams());
|
||||
|
||||
$triggerType = $sanitizedParams->getString('triggerType');
|
||||
$triggerCode = $sanitizedParams->getString('triggerCode', ['defaultOnEmptyString' => true]);
|
||||
$actionType = $sanitizedParams->getString('actionType');
|
||||
$target = $sanitizedParams->getString('target');
|
||||
$targetId = $sanitizedParams->getInt('targetId');
|
||||
$widgetId = $sanitizedParams->getInt('widgetId');
|
||||
$layoutCode = $sanitizedParams->getString('layoutCode');
|
||||
$layoutId = $sanitizedParams->getInt('layoutId');
|
||||
$source = $sanitizedParams->getString('source');
|
||||
$sourceId = $sanitizedParams->getInt('sourceId');
|
||||
|
||||
if ($layoutId === null) {
|
||||
throw new InvalidArgumentException(__('Please provide LayoutId'), 'layoutId');
|
||||
}
|
||||
|
||||
$layout = $this->layoutFactory->getById($layoutId);
|
||||
|
||||
// Make sure the Layout is checked out to begin with
|
||||
if (!$layout->isEditable()) {
|
||||
throw new InvalidArgumentException(__('Layout is not checked out'), 'statusId');
|
||||
}
|
||||
|
||||
// restrict to one touch Action per source
|
||||
if (
|
||||
(!empty($source) && $sourceId !== null && !empty($triggerType))
|
||||
&& $this->actionFactory->checkIfActionExist($source, $sourceId, $triggerType)
|
||||
) {
|
||||
throw new InvalidArgumentException(__('Action with specified Trigger Type already exists'), 'triggerType');
|
||||
}
|
||||
|
||||
$action = $this->actionFactory->create(
|
||||
$triggerType,
|
||||
$triggerCode,
|
||||
$actionType,
|
||||
$source,
|
||||
$sourceId,
|
||||
$target,
|
||||
$targetId,
|
||||
$widgetId,
|
||||
$layoutCode,
|
||||
$layoutId
|
||||
);
|
||||
|
||||
$action->save(['notifyLayout' => true]);
|
||||
|
||||
// Return
|
||||
$this->getState()->hydrate([
|
||||
'message' => __('Added Action'),
|
||||
'httpStatus' => 201,
|
||||
'id' => $action->actionId,
|
||||
'data' => $action,
|
||||
]);
|
||||
|
||||
return $this->render($request, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit Action
|
||||
*
|
||||
* @SWG\PUT(
|
||||
* path="/action/{actionId}",
|
||||
* operationId="actionAdd",
|
||||
* tags={"action"},
|
||||
* summary="Add Action",
|
||||
* description="Add a new Action",
|
||||
* @SWG\Parameter(
|
||||
* name="actionId",
|
||||
* in="path",
|
||||
* description="Action ID to edit",
|
||||
* type="integer",
|
||||
* required=true
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="layoutId",
|
||||
* in="formData",
|
||||
* description="LayoutId associted with this Action",
|
||||
* type="integer",
|
||||
* required=true
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="actionType",
|
||||
* in="formData",
|
||||
* description="Action type, next, previous, navLayout, navWidget",
|
||||
* type="string",
|
||||
* required=true
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="target",
|
||||
* in="formData",
|
||||
* description="Target for this action, screen or region",
|
||||
* type="string",
|
||||
* required=true
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="targetId",
|
||||
* in="formData",
|
||||
* description="The id of the target for this action - regionId if the target is set to region",
|
||||
* type="string",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="source",
|
||||
* in="formData",
|
||||
* description="Source for this action layout, region or widget",
|
||||
* type="string",
|
||||
* required=true
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="sourceId",
|
||||
* in="formData",
|
||||
* description="The id of the source object, layoutId, regionId or widgetId",
|
||||
* type="integer",
|
||||
* required=true
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="triggerType",
|
||||
* in="formData",
|
||||
* description="Action trigger type, touch or webhook",
|
||||
* type="string",
|
||||
* required=true
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="triggerCode",
|
||||
* in="formData",
|
||||
* description="Action trigger code",
|
||||
* type="string",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="widgetId",
|
||||
* in="formData",
|
||||
* description="For navWidget actionType, the WidgetId to navigate to",
|
||||
* type="integer",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Parameter(
|
||||
* name="layoutCode",
|
||||
* in="formData",
|
||||
* description="For navLayout, the Layout Code identifier to navigate to",
|
||||
* type="string",
|
||||
* required=false
|
||||
* ),
|
||||
* @SWG\Response(
|
||||
* response=201,
|
||||
* description="successful operation",
|
||||
* @SWG\Schema(ref="#/definitions/Action"),
|
||||
* @SWG\Header(
|
||||
* header="Location",
|
||||
* description="Location of the new record",
|
||||
* type="string"
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @param int $id
|
||||
* @return Response
|
||||
* @throws GeneralException
|
||||
*/
|
||||
public function edit(Request $request, Response $response, int $id) : Response
|
||||
{
|
||||
$action = $this->actionFactory->getById($id);
|
||||
|
||||
$sanitizedParams = $this->getSanitizer($request->getParams());
|
||||
$layout = $this->layoutFactory->getById($action->layoutId);
|
||||
|
||||
// Make sure the Layout is checked out to begin with
|
||||
if (!$layout->isEditable()) {
|
||||
throw new InvalidArgumentException(__('Layout is not checked out'), 'statusId');
|
||||
}
|
||||
|
||||
$action->source = $sanitizedParams->getString('source');
|
||||
$action->sourceId = $sanitizedParams->getInt('sourceId');
|
||||
$action->triggerType = $sanitizedParams->getString('triggerType');
|
||||
$action->triggerCode = $sanitizedParams->getString('triggerCode', ['defaultOnEmptyString' => true]);
|
||||
$action->actionType = $sanitizedParams->getString('actionType');
|
||||
$action->target = $sanitizedParams->getString('target');
|
||||
$action->targetId = $sanitizedParams->getInt('targetId');
|
||||
$action->widgetId = $sanitizedParams->getInt('widgetId');
|
||||
$action->layoutCode = $sanitizedParams->getString('layoutCode');
|
||||
$action->validate();
|
||||
// restrict to one touch Action per source
|
||||
if ($this->actionFactory->checkIfActionExist($action->source, $action->sourceId, $action->triggerType, $action->actionId)) {
|
||||
throw new InvalidArgumentException(__('Action with specified Trigger Type already exists'), 'triggerType');
|
||||
}
|
||||
|
||||
$action->save(['notifyLayout' => true, 'validate' => false]);
|
||||
|
||||
// Return
|
||||
$this->getState()->hydrate([
|
||||
'message' => __('Edited Action'),
|
||||
'id' => $action->actionId,
|
||||
'data' => $action
|
||||
]);
|
||||
|
||||
return $this->render($request, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Action
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @param int $id
|
||||
* @return \Psr\Http\Message\ResponseInterface|Response
|
||||
* @throws GeneralException
|
||||
*
|
||||
* @SWG\Delete(
|
||||
* path="/action/{actionId}",
|
||||
* operationId="actionDelete",
|
||||
* tags={"action"},
|
||||
* summary="Delete Action",
|
||||
* description="Delete an existing Action",
|
||||
* @SWG\Parameter(
|
||||
* name="actionId",
|
||||
* in="path",
|
||||
* description="The Action ID to Delete",
|
||||
* type="integer",
|
||||
* required=true
|
||||
* ),
|
||||
* @SWG\Response(
|
||||
* response=204,
|
||||
* description="successful operation"
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
public function delete(Request $request, Response $response, int $id) : Response
|
||||
{
|
||||
$action = $this->actionFactory->getById($id);
|
||||
$layout = $this->layoutFactory->getById($action->layoutId);
|
||||
|
||||
// Make sure the Layout is checked out to begin with
|
||||
if (!$layout->isEditable()) {
|
||||
throw new InvalidArgumentException(__('Layout is not checked out'), 'statusId');
|
||||
}
|
||||
|
||||
$action->notifyLayout($layout->layoutId);
|
||||
$action->delete();
|
||||
|
||||
// Return
|
||||
$this->getState()->hydrate([
|
||||
'httpStatus' => 204,
|
||||
'message' => sprintf(__('Deleted Action'))
|
||||
]);
|
||||
|
||||
return $this->render($request, $response);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $source
|
||||
* @param int $sourceId
|
||||
* @return \Xibo\Entity\Layout|\Xibo\Entity\Region|\Xibo\Entity\Widget
|
||||
* @throws InvalidArgumentException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function checkIfSourceExists(string $source, int $sourceId)
|
||||
{
|
||||
if (strtolower($source) === 'layout') {
|
||||
$object = $this->layoutFactory->getById($sourceId);
|
||||
} elseif (strtolower($source) === 'region') {
|
||||
$object = $this->regionFactory->getById($sourceId);
|
||||
} elseif (strtolower($source) === 'widget') {
|
||||
$object = $this->widgetFactory->getById($sourceId);
|
||||
} else {
|
||||
throw new InvalidArgumentException(__('Provided source is invalid. ') , 'source');
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user