icingaweb2-module-director/library/Director/Web/Controller/ObjectController.php

459 lines
14 KiB
PHP

<?php
namespace Icinga\Module\Director\Web\Controller;
use Exception;
use Icinga\Exception\IcingaException;
use Icinga\Exception\InvalidPropertyException;
use Icinga\Exception\NotFoundError;
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
use Icinga\Module\Director\Objects\IcingaObject;
use Icinga\Web\Url;
abstract class ObjectController extends ActionController
{
protected $object;
protected $isApified = true;
protected $allowedExternals = array(
'apiuser',
'endpoint'
);
public function init()
{
parent::init();
$type = $this->getType();
if ($object = $this->loadObject()) {
$this->beforeTabs();
$params = $object->getUrlParams();
if ($object->isExternal()
&& ! in_array($object->getShortTableName(), $this->allowedExternals)
) {
$tabs = $this->getTabs();
} else {
$tabs = $this->getTabs()->add('modify', array(
'url' => sprintf('director/%s', $type),
'urlParams' => $params,
'label' => $this->translate(ucfirst($type))
));
}
$tabs->add('render', array(
'url' => sprintf('director/%s/render', $type),
'urlParams' => $params,
'label' => $this->translate('Preview'),
))->add('history', array(
'url' => sprintf('director/%s/history', $type),
'urlParams' => $params,
'label' => $this->translate('History')
));
if ($this->hasFields()) {
$tabs->add('fields', array(
'url' => sprintf('director/%s/fields', $type),
'urlParams' => $params,
'label' => $this->translate('Fields')
));
}
} else {
$this->beforeTabs();
$this->getTabs()->add('add', array(
'url' => sprintf('director/%s/add', $type),
'label' => sprintf($this->translate('Add %s'), ucfirst($type)),
));
}
}
public function indexAction()
{
if ($this->getRequest()->isApiRequest()) {
try {
return $this->handleApiRequest();
} catch (Exception $e) {
$response = $this->getResponse();
if ($response->getHttpResponseCode() === 200) {
$response->setHttpResponseCode(500);
}
return $this->sendJson((object) array('error' => $e->getMessage()));
}
}
if ($this->object
&& $this->object->isExternal()
&& ! in_array($this->object->getShortTableName(), $this->allowedExternals)
) {
$this->redirectNow(
$this->getRequest()->getUrl()->setPath(sprintf('director/%s/render', $this->getType()))
);
}
return $this->editAction();
}
public function renderAction()
{
$type = $this->getType();
$this->getTabs()->activate('render');
$object = $this->object;
$this->view->isExternal = $object->isExternal();
if ($this->params->shift('resolved')) {
$object = $object::fromPlainObject(
$object->toPlainObject(true),
$object->getConnection()
);
$this->view->actionLinks = $this->view->qlink(
$this->translate('Show normal'),
$this->getRequest()->getUrl()->without('resolved'),
null,
array('class' => 'icon-resize-small state-warning')
);
} else {
if ($object->supportsImports() && $object->imports()->count() > 0) {
$this->view->actionLinks = $this->view->qlink(
$this->translate('Show resolved'),
$this->getRequest()->getUrl()->with('resolved', true),
null,
array('class' => 'icon-resize-full')
);
}
}
if ($this->view->isExternal) {
$object->object_type = 'object';
}
$this->view->object = $object;
$this->view->config = new IcingaConfig($this->db());
$object->renderToConfig($this->view->config);
$this->view->title = sprintf(
$this->translate('Config preview: %s'),
$object->object_name
);
$this->setViewScript('object/show');
}
public function editAction()
{
$object = $this->object;
$this->getTabs()->activate('modify');
$ltype = $this->getType();
$type = ucfirst($ltype);
$formName = 'icinga' . $type;
$this->view->form = $form = $this->loadForm($formName)
->setDb($this->db())
->setApi($this->getApiIfAvailable());
$form->setObject($object);
$this->view->title = $object->object_name;
$this->view->form->handleRequest();
$this->view->actionLinks = $this->createCloneLink();
$this->setViewScript('object/form');
}
protected function createCloneLink()
{
return $this->view->qlink(
$this->translate('Clone'),
'director/' . $this->getType() .'/clone',
$this->object->getUrlParams(),
array('class' => 'icon-paste')
);
}
public function addAction()
{
$this->getTabs()->activate('add');
$type = $this->getType();
$ltype = strtolower($type);
$url = sprintf('director/%ss', $ltype);
$form = $this->view->form = $this->loadForm('icinga' . ucfirst($type))
->setDb($this->db())
->setApi($this->getApiIfAvailable())
->setSuccessUrl($url);
$this->view->title = sprintf(
$this->translate('Add new Icinga %s'),
ucfirst($ltype)
);
$this->beforeHandlingAddRequest($form);
$form->handleRequest();
$this->setViewScript('object/form');
}
protected function beforeHandlingAddRequest($form)
{
}
public function cloneAction()
{
$type = $this->getType();
$ltype = strtolower($type);
$this->getTabs()->activate('modify');
$this->view->form = $form = $this->loadForm(
'icingaCloneObject'
)->setObject($this->object);
$this->view->title = sprintf(
$this->translate('Clone Icinga %s'),
ucfirst($type)
);
$this->view->form->handleRequest();
$this->view->actionLinks = $this->view->qlink(
$this->translate('back'),
'director/' . $ltype,
array('name' => $this->object->object_name),
array('class' => 'icon-left-big')
);
$this->setViewScript('object/form');
}
public function fieldsAction()
{
$object = $this->object;
$type = $this->getType();
$this->getTabs()->activate('fields');
$this->view->title = sprintf(
$this->translate('Custom fields: %s'),
$object->object_name
);
$form = $this->view->form = $this
->loadForm('icingaObjectField')
->setDb($this->db)
->setIcingaObject($object);
if ($id = $this->params->get('field_id')) {
$form->loadObject(array(
$type . '_id' => $object->id,
'datafield_id' => $id
));
$this->view->actionLinks = $this->view->qlink(
$this->translate('back'),
$this->getRequest()->getUrl()->without('field_id'),
null,
array('class' => 'icon-left-big')
);
}
$form->handleRequest();
$this->view->table = $this
->loadTable('icingaObjectDatafield')
->setObject($object);
$this->setViewScript('object/fields');
}
public function historyAction()
{
$this->setAutorefreshInterval(10);
$db = $this->db();
$type = $this->getType();
$this->getTabs()->activate('history');
$this->view->title = sprintf(
$this->translate('Activity Log: %s'),
$this->object->object_name
);
$lastDeployedId = $db->getLastDeploymentActivityLogId();
$this->view->table = $this->applyPaginationLimits(
$this->loadTable('activityLog')
->setConnection($db)
->setLastDeployedId($lastDeployedId)
->filterObject('icinga_' . $type, $this->object->object_name)
);
$this->setViewScript('object/history');
}
protected function getType()
{
// Strip final 's' and upcase an eventual 'group'
return preg_replace(
array('/group$/', '/period$/', '/argument$/', '/apiuser$/'),
array('Group', 'Period', 'Argument', 'ApiUser'),
$this->getRequest()->getControllerName()
);
}
protected function loadObject()
{
if ($this->object === null) {
if ($name = $this->params->get('name')) {
$this->object = IcingaObject::loadByType(
$this->getType(),
$name,
$this->db()
);
} elseif ($id = $this->params->get('id')) {
$this->object = IcingaObject::loadByType(
$this->getType(),
(int) $id,
$this->db()
);
} elseif ($this->getRequest()->isApiRequest()) {
if ($this->getRequest()->isGet()) {
$this->getResponse()->setHttpResponseCode(422);
throw new InvalidPropertyException(
'Cannot load object, missing parameters'
);
}
}
$this->view->undeployedChanges = $this->countUndeployedChanges();
$this->view->totalUndeployedChanges = $this->db()
->countActivitiesSinceLastDeployedConfig();
}
return $this->object;
}
protected function hasFields()
{
if (! ($object = $this->object)) {
return false;
}
return $object->hasBeenLoadedFromDb()
&& $object->supportsFields()
&& ($object->isTemplate() || $this->getType() === 'command');
}
protected function handleApiRequest()
{
$request = $this->getRequest();
$db = $this->db();
switch ($request->getMethod()) {
case 'DELETE':
$this->requireObject();
$name = $this->object->object_name;
$obj = $this->object->toPlainObject(false, true);
$form = $this->loadForm(
'icingaDeleteObject'
)->setObject($this->object)->setRequest($request)->onSuccess();
return $this->sendJson($obj);
case 'POST':
case 'PUT':
$type = $this->getType();
$data = json_decode($request->getRawBody());
if ($data === null) {
$this->getResponse()->setHttpResponseCode(400);
throw new IcingaException(
'Invalid JSON: %s' . $request->getRawBody(),
$this->getLastJsonError()
);
} else {
$data = (array) $data;
}
if ($object = $this->object) {
if ($request->getMethod() === 'POST') {
$object->setProperties($data);
} else {
$data = array_merge(
array(
'object_type' => $object->object_type,
'object_name' => $object->object_name
),
$data
);
$object->replaceWith(
IcingaObject::createByType($type, $data, $db)
);
}
} else {
$object = IcingaObject::createByType($type, $data, $db);
}
$response = $this->getResponse();
if ($object->hasBeenModified()) {
$status = $object->hasBeenLoadedFromDb() ? 200 : 201;
$object->store();
$response->setHttpResponseCode($status);
} else {
$response->setHttpResponseCode(304);
}
return $this->sendJson($object->toPlainObject(false, true));
case 'GET':
$this->requireObject();
return $this->sendJson(
$this->object->toPlainObject(
$this->params->shift('resolved'),
! $this->params->shift('withNull'),
$this->params->shift('properties')
)
);
default:
$request->getResponse()->setHttpResponseCode(400);
throw new Exception('Unsupported method ' . $request->getMethod());
}
}
protected function countUndeployedChanges()
{
if ($this->object === null) {
return 0;
}
return $this->db()->countActivitiesSinceLastDeployedConfig($this->object);
}
protected function requireObject()
{
if (! $this->object) {
$this->getResponse()->setHttpResponseCode(404);
if (! $this->params->get('name')) {
throw new NotFoundError('You need to pass a "name" parameter to access a specific object');
} else {
throw new NotFoundError('No such object available');
}
}
}
protected function gracefullyActivateTab($name)
{
$tabs = $this->getTabs();
if ($tabs->has($name)) {
return $tabs->activate($name);
}
$req = $this->getRequest();
$this->redirectNow(
$req->getUrl()->setPath('director/' . $req->getControllerName())
);
}
protected function beforeTabs()
{
}
}