diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 000000000..3899c241c
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "web/api/app/Plugin/Crud"]
+ path = web/api/app/Plugin/Crud
+ url = https://github.com/FriendsOfCake/crud.git
diff --git a/web/api/CMakeFiles/CMakeDirectoryInformation.cmake b/web/api/CMakeFiles/CMakeDirectoryInformation.cmake
new file mode 100644
index 000000000..3d1e4eadd
--- /dev/null
+++ b/web/api/CMakeFiles/CMakeDirectoryInformation.cmake
@@ -0,0 +1,16 @@
+# CMAKE generated file: DO NOT EDIT!
+# Generated by "Unix Makefiles" Generator, CMake Version 2.8
+
+# Relative path conversion top directories.
+SET(CMAKE_RELATIVE_PATH_TOP_SOURCE "/home/ubuntu/zm/ZoneMinder")
+SET(CMAKE_RELATIVE_PATH_TOP_BINARY "/home/ubuntu/zm/ZoneMinder")
+
+# Force unix paths in dependencies.
+SET(CMAKE_FORCE_UNIX_PATHS 1)
+
+
+# The C and CXX include file regular expressions for this directory.
+SET(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$")
+SET(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$")
+SET(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN})
+SET(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN})
diff --git a/web/api/CMakeFiles/progress.marks b/web/api/CMakeFiles/progress.marks
new file mode 100644
index 000000000..573541ac9
--- /dev/null
+++ b/web/api/CMakeFiles/progress.marks
@@ -0,0 +1 @@
+0
diff --git a/web/api/app/Config/bootstrap.php b/web/api/app/Config/bootstrap.php
index b8932f3a6..e4102d62b 100644
--- a/web/api/app/Config/bootstrap.php
+++ b/web/api/app/Config/bootstrap.php
@@ -69,6 +69,7 @@ Cache::config('default', array('engine' => 'File'));
* CakePlugin::load('DebugKit'); //Loads a single plugin named DebugKit
*
*/
+CakePlugin::load('Crud');
/**
* You can attach event listeners to the request lifecycle as Dispatcher Filter. By default CakePHP bundles two filters:
diff --git a/web/api/app/Config/core.php b/web/api/app/Config/core.php
new file mode 100644
index 000000000..1e1b11bc7
--- /dev/null
+++ b/web/api/app/Config/core.php
@@ -0,0 +1,387 @@
+ 0
+ * and log errors with CakeLog when debug = 0.
+ *
+ * Options:
+ *
+ * - `handler` - callback - The callback to handle errors. You can set this to any callable type,
+ * including anonymous functions.
+ * Make sure you add App::uses('MyHandler', 'Error'); when using a custom handler class
+ * - `level` - integer - The level of errors you are interested in capturing.
+ * - `trace` - boolean - Include stack traces for errors in log files.
+ *
+ * @see ErrorHandler for more information on error handling and configuration.
+ */
+ Configure::write('Error', array(
+ 'handler' => 'ErrorHandler::handleError',
+ 'level' => E_ALL & ~E_DEPRECATED,
+ 'trace' => true
+ ));
+
+/**
+ * Configure the Exception handler used for uncaught exceptions. By default,
+ * ErrorHandler::handleException() is used. It will display a HTML page for the exception, and
+ * while debug > 0, framework errors like Missing Controller will be displayed. When debug = 0,
+ * framework errors will be coerced into generic HTTP errors.
+ *
+ * Options:
+ *
+ * - `handler` - callback - The callback to handle exceptions. You can set this to any callback type,
+ * including anonymous functions.
+ * Make sure you add App::uses('MyHandler', 'Error'); when using a custom handler class
+ * - `renderer` - string - The class responsible for rendering uncaught exceptions. If you choose a custom class you
+ * should place the file for that class in app/Lib/Error. This class needs to implement a render method.
+ * - `log` - boolean - Should Exceptions be logged?
+ * - `skipLog` - array - list of exceptions to skip for logging. Exceptions that
+ * extend one of the listed exceptions will also be skipped for logging.
+ * Example: `'skipLog' => array('NotFoundException', 'UnauthorizedException')`
+ *
+ * @see ErrorHandler for more information on exception handling and configuration.
+ */
+ Configure::write('Exception', array(
+ 'handler' => 'ErrorHandler::handleException',
+ 'renderer' => 'ExceptionRenderer',
+ 'log' => true
+ ));
+
+/**
+ * Application wide charset encoding
+ */
+ Configure::write('App.encoding', 'UTF-8');
+
+/**
+ * To configure CakePHP *not* to use mod_rewrite and to
+ * use CakePHP pretty URLs, remove these .htaccess
+ * files:
+ *
+ * /.htaccess
+ * /app/.htaccess
+ * /app/webroot/.htaccess
+ *
+ * And uncomment the App.baseUrl below. But keep in mind
+ * that plugin assets such as images, CSS and JavaScript files
+ * will not work without URL rewriting!
+ * To work around this issue you should either symlink or copy
+ * the plugin assets into you app's webroot directory. This is
+ * recommended even when you are using mod_rewrite. Handling static
+ * assets through the Dispatcher is incredibly inefficient and
+ * included primarily as a development convenience - and
+ * thus not recommended for production applications.
+ */
+ //Configure::write('App.baseUrl', env('SCRIPT_NAME'));
+
+/**
+ * To configure CakePHP to use a particular domain URL
+ * for any URL generation inside the application, set the following
+ * configuration variable to the http(s) address to your domain. This
+ * will override the automatic detection of full base URL and can be
+ * useful when generating links from the CLI (e.g. sending emails)
+ */
+ //Configure::write('App.fullBaseUrl', 'http://example.com');
+
+/**
+ * Web path to the public images directory under webroot.
+ * If not set defaults to 'img/'
+ */
+ //Configure::write('App.imageBaseUrl', 'img/');
+
+/**
+ * Web path to the CSS files directory under webroot.
+ * If not set defaults to 'css/'
+ */
+ //Configure::write('App.cssBaseUrl', 'css/');
+
+/**
+ * Web path to the js files directory under webroot.
+ * If not set defaults to 'js/'
+ */
+ //Configure::write('App.jsBaseUrl', 'js/');
+
+/**
+ * Uncomment the define below to use CakePHP prefix routes.
+ *
+ * The value of the define determines the names of the routes
+ * and their associated controller actions:
+ *
+ * Set to an array of prefixes you want to use in your application. Use for
+ * admin or other prefixed routes.
+ *
+ * Routing.prefixes = array('admin', 'manager');
+ *
+ * Enables:
+ * `admin_index()` and `/admin/controller/index`
+ * `manager_index()` and `/manager/controller/index`
+ *
+ */
+ //Configure::write('Routing.prefixes', array('admin'));
+
+/**
+ * Turn off all caching application-wide.
+ *
+ */
+ //Configure::write('Cache.disable', true);
+
+/**
+ * Enable cache checking.
+ *
+ * If set to true, for view caching you must still use the controller
+ * public $cacheAction inside your controllers to define caching settings.
+ * You can either set it controller-wide by setting public $cacheAction = true,
+ * or in each action using $this->cacheAction = true.
+ *
+ */
+ //Configure::write('Cache.check', true);
+
+/**
+ * Enable cache view prefixes.
+ *
+ * If set it will be prepended to the cache name for view file caching. This is
+ * helpful if you deploy the same application via multiple subdomains and languages,
+ * for instance. Each version can then have its own view cache namespace.
+ * Note: The final cache file name will then be `prefix_cachefilename`.
+ */
+ //Configure::write('Cache.viewPrefix', 'prefix');
+
+/**
+ * Session configuration.
+ *
+ * Contains an array of settings to use for session configuration. The defaults key is
+ * used to define a default preset to use for sessions, any settings declared here will override
+ * the settings of the default config.
+ *
+ * ## Options
+ *
+ * - `Session.cookie` - The name of the cookie to use. Defaults to 'CAKEPHP'
+ * - `Session.timeout` - The number of minutes you want sessions to live for. This timeout is handled by CakePHP
+ * - `Session.cookieTimeout` - The number of minutes you want session cookies to live for.
+ * - `Session.checkAgent` - Do you want the user agent to be checked when starting sessions? You might want to set the
+ * value to false, when dealing with older versions of IE, Chrome Frame or certain web-browsing devices and AJAX
+ * - `Session.defaults` - The default configuration set to use as a basis for your session.
+ * There are four builtins: php, cake, cache, database.
+ * - `Session.handler` - Can be used to enable a custom session handler. Expects an array of callables,
+ * that can be used with `session_save_handler`. Using this option will automatically add `session.save_handler`
+ * to the ini array.
+ * - `Session.autoRegenerate` - Enabling this setting, turns on automatic renewal of sessions, and
+ * sessionids that change frequently. See CakeSession::$requestCountdown.
+ * - `Session.ini` - An associative array of additional ini values to set.
+ *
+ * The built in defaults are:
+ *
+ * - 'php' - Uses settings defined in your php.ini.
+ * - 'cake' - Saves session files in CakePHP's /tmp directory.
+ * - 'database' - Uses CakePHP's database sessions.
+ * - 'cache' - Use the Cache class to save sessions.
+ *
+ * To define a custom session handler, save it at /app/Model/Datasource/Session/.php.
+ * Make sure the class implements `CakeSessionHandlerInterface` and set Session.handler to
+ *
+ * To use database sessions, run the app/Config/Schema/sessions.php schema using
+ * the cake shell command: cake schema create Sessions
+ *
+ */
+ Configure::write('Session', array(
+ 'defaults' => 'php'
+ ));
+
+/**
+ * A random string used in security hashing methods.
+ */
+ Configure::write('Security.salt', 'y8s4nPwjdjrmAGRxtnbxWhOknOBX6y1etr6RD8XM');
+
+/**
+ * A random numeric string (digits only) used to encrypt/decrypt strings.
+ */
+ Configure::write('Security.cipherSeed', '28284715058574819699789789248');
+
+/**
+ * Apply timestamps with the last modified time to static assets (js, css, images).
+ * Will append a query string parameter containing the time the file was modified. This is
+ * useful for invalidating browser caches.
+ *
+ * Set to `true` to apply timestamps when debug > 0. Set to 'force' to always enable
+ * timestamping regardless of debug value.
+ */
+ //Configure::write('Asset.timestamp', true);
+
+/**
+ * Compress CSS output by removing comments, whitespace, repeating tags, etc.
+ * This requires a/var/cache directory to be writable by the web server for caching.
+ * and /vendors/csspp/csspp.php
+ *
+ * To use, prefix the CSS link URL with '/ccss/' instead of '/css/' or use HtmlHelper::css().
+ */
+ //Configure::write('Asset.filter.css', 'css.php');
+
+/**
+ * Plug in your own custom JavaScript compressor by dropping a script in your webroot to handle the
+ * output, and setting the config below to the name of the script.
+ *
+ * To use, prefix your JavaScript link URLs with '/cjs/' instead of '/js/' or use JsHelper::link().
+ */
+ //Configure::write('Asset.filter.js', 'custom_javascript_output_filter.php');
+
+/**
+ * The class name and database used in CakePHP's
+ * access control lists.
+ */
+ Configure::write('Acl.classname', 'DbAcl');
+ Configure::write('Acl.database', 'default');
+
+/**
+ * Uncomment this line and correct your server timezone to fix
+ * any date & time related errors.
+ */
+ //date_default_timezone_set('UTC');
+
+/**
+ * `Config.timezone` is available in which you can set users' timezone string.
+ * If a method of CakeTime class is called with $timezone parameter as null and `Config.timezone` is set,
+ * then the value of `Config.timezone` will be used. This feature allows you to set users' timezone just
+ * once instead of passing it each time in function calls.
+ */
+ //Configure::write('Config.timezone', 'Europe/Paris');
+
+/**
+ *
+ * Cache Engine Configuration
+ * Default settings provided below
+ *
+ * File storage engine.
+ *
+ * Cache::config('default', array(
+ * 'engine' => 'File', //[required]
+ * 'duration' => 3600, //[optional]
+ * 'probability' => 100, //[optional]
+ * 'path' => CACHE, //[optional] use system tmp directory - remember to use absolute path
+ * 'prefix' => 'cake_', //[optional] prefix every cache file with this string
+ * 'lock' => false, //[optional] use file locking
+ * 'serialize' => true, //[optional]
+ * 'mask' => 0664, //[optional]
+ * ));
+ *
+ * APC (http://pecl.php.net/package/APC)
+ *
+ * Cache::config('default', array(
+ * 'engine' => 'Apc', //[required]
+ * 'duration' => 3600, //[optional]
+ * 'probability' => 100, //[optional]
+ * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string
+ * ));
+ *
+ * Xcache (http://xcache.lighttpd.net/)
+ *
+ * Cache::config('default', array(
+ * 'engine' => 'Xcache', //[required]
+ * 'duration' => 3600, //[optional]
+ * 'probability' => 100, //[optional]
+ * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string
+ * 'user' => 'user', //user from xcache.admin.user settings
+ * 'password' => 'password', //plaintext password (xcache.admin.pass)
+ * ));
+ *
+ * Memcached (http://www.danga.com/memcached/)
+ *
+ * Uses the memcached extension. See http://php.net/memcached
+ *
+ * Cache::config('default', array(
+ * 'engine' => 'Memcached', //[required]
+ * 'duration' => 3600, //[optional]
+ * 'probability' => 100, //[optional]
+ * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string
+ * 'servers' => array(
+ * '127.0.0.1:11211' // localhost, default port 11211
+ * ), //[optional]
+ * 'persistent' => 'my_connection', // [optional] The name of the persistent connection.
+ * 'compress' => false, // [optional] compress data in Memcached (slower, but uses less memory)
+ * ));
+ *
+ * Wincache (http://php.net/wincache)
+ *
+ * Cache::config('default', array(
+ * 'engine' => 'Wincache', //[required]
+ * 'duration' => 3600, //[optional]
+ * 'probability' => 100, //[optional]
+ * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string
+ * ));
+ */
+
+/**
+ * Configure the cache handlers that CakePHP will use for internal
+ * metadata like class maps, and model schema.
+ *
+ * By default File is used, but for improved performance you should use APC.
+ *
+ * Note: 'default' and other application caches should be configured in app/Config/bootstrap.php.
+ * Please check the comments in bootstrap.php for more info on the cache engines available
+ * and their settings.
+ */
+$engine = 'File';
+
+// In development mode, caches should expire quickly.
+$duration = '+999 days';
+if (Configure::read('debug') > 0) {
+ $duration = '+10 seconds';
+}
+
+// Prefix each application on the same server with a different string, to avoid Memcache and APC conflicts.
+$prefix = 'myapp_';
+
+/**
+ * Configure the cache used for general framework caching. Path information,
+ * object listings, and translation cache files are stored with this configuration.
+ */
+Cache::config('_cake_core_', array(
+ 'engine' => $engine,
+ 'prefix' => $prefix . 'cake_core_',
+ 'path' => CACHE . 'persistent' . DS,
+ 'serialize' => ($engine === 'File'),
+ 'duration' => $duration
+));
+
+/**
+ * Configure the cache for model and datasource caches. This cache configuration
+ * is used to store schema descriptions, and table listings in connections.
+ */
+Cache::config('_cake_model_', array(
+ 'engine' => $engine,
+ 'prefix' => $prefix . 'cake_model_',
+ 'path' => CACHE . 'models' . DS,
+ 'serialize' => ($engine === 'File'),
+ 'duration' => $duration
+));
diff --git a/web/api/app/Config/routes.php b/web/api/app/Config/routes.php
index ed2d1f2ca..0f9343644 100644
--- a/web/api/app/Config/routes.php
+++ b/web/api/app/Config/routes.php
@@ -28,6 +28,14 @@
Router::mapResources('configs');
Router::mapResources('events');
Router::mapResources('frames');
+ Router::mapResources('host');
+ Router::mapResources('logs');
+ Router::mapResources('states');
+ Router::mapResources('zonepresets');
+
+ /* Add new API to retrieve camera controls - for PTZ */
+ /* refer to https://github.com/ZoneMinder/ZoneMinder/issues/799#issuecomment-105233112 */
+ Router::mapResources('controls');
Router::parseExtensions();
/**
diff --git a/web/api/app/Controller/AppController.php b/web/api/app/Controller/AppController.php
index a827969e1..f3011e6ff 100644
--- a/web/api/app/Controller/AppController.php
+++ b/web/api/app/Controller/AppController.php
@@ -18,8 +18,8 @@
* @since CakePHP(tm) v 0.2.9
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
-
App::uses('Controller', 'Controller');
+App::uses('CrudControllerTrait', 'Crud.Lib');
/**
* Application Controller
@@ -31,4 +31,20 @@ App::uses('Controller', 'Controller');
* @link http://book.cakephp.org/2.0/en/controllers.html#the-app-controller
*/
class AppController extends Controller {
+ use CrudControllerTrait;
+
+ public $components = [
+ 'RequestHandler',
+ 'Crud.Crud' => [
+ 'actions' => [
+ 'index' => 'Crud.Index',
+ 'add' => 'Crud.Add',
+ 'edit' => 'Crud.Edit',
+ 'view' => 'Crud.View',
+ 'keyvalue' => 'Crud.List',
+ 'category' => 'Crud.Category'
+ ],
+ 'listeners' => ['Api', 'ApiTransformation']
+ ]
+ ];
}
diff --git a/web/api/app/Controller/Component/ConfigParserComponent.php b/web/api/app/Controller/Component/ConfigParserComponent.php
index 18d06fba8..56a2039a0 100644
--- a/web/api/app/Controller/Component/ConfigParserComponent.php
+++ b/web/api/app/Controller/Component/ConfigParserComponent.php
@@ -24,7 +24,7 @@ class ConfigParserComponent extends Component {
public function getInput($name, $type, $id) {
if ($type == 'checkbox') {
- $string = '';
+ $string = '';
} elseif ($type == 'text') {
$string = '';
} elseif ($type == 'textarea') {
diff --git a/web/api/app/Controller/Component/FilterComponent.php b/web/api/app/Controller/Component/FilterComponent.php
new file mode 100644
index 000000000..bf6e423f7
--- /dev/null
+++ b/web/api/app/Controller/Component/FilterComponent.php
@@ -0,0 +1,34 @@
+ $value) {
+ // If the named param contains an array, we want to turn it into an IN condition
+ // Otherwise, we add it right into the $conditions array
+ if (is_array($value)) {
+ $array = array();
+
+ foreach ($value as $term) {
+ array_push($array, $term);
+ }
+
+ $query = array($attribute => $array);
+ array_push($conditions, $query);
+ } else {
+ array_push($conditions, array($attribute => $value));
+ }
+ }
+
+ }
+
+ return $conditions;
+ }
+
+}
+?>
diff --git a/web/api/app/Controller/Component/ImageComponent.php b/web/api/app/Controller/Component/ImageComponent.php
new file mode 100644
index 000000000..147a26dd7
--- /dev/null
+++ b/web/api/app/Controller/Component/ImageComponent.php
@@ -0,0 +1,89 @@
+getEventPath($event);
+
+ $captImage = sprintf( "%0".$config['ZM_EVENT_IMAGE_DIGITS']."d-capture.jpg", $frame['Frame']['FrameId'] );
+ $captPath = $eventPath.'/'.$captImage;
+ $thumbCaptPath = $config['ZM_DIR_IMAGES'].'/'.$event['Event']['Id'].'-'.$captImage;
+
+ $analImage = sprintf( "%0".$config['ZM_EVENT_IMAGE_DIGITS']."d-analyse.jpg", $frame['Frame']['FrameId'] );
+ $analPath = $eventPath.'/'.$analImage;
+ $analFile = $config['ZM_DIR_EVENTS']."/".$analPath;
+ $thumbAnalPath = $config['ZM_DIR_IMAGES'].'/'.$event['Event']['Id'].'-'.$analImage;
+
+ $alarmFrame = $frame['Frame']['Type']=='Alarm';
+
+ $hasAnalImage = $alarmFrame && file_exists( $analFile ) && filesize( $analFile );
+ $isAnalImage = $hasAnalImage && !$captureOnly;
+
+
+ if ( !$config['ZM_WEB_SCALE_THUMBS'] || $scale >= 100 || !function_exists( 'imagecreatefromjpeg' ) ) {
+ $imagePath = $thumbPath = $isAnalImage?$analPath:$captPath;
+ $imageFile = $config['ZM_DIR_EVENTS']."/".$imagePath;
+ $thumbFile = $config['ZM_DIR_EVENTS']."/".$thumbPath;
+ } else {
+ if ( version_compare( phpversion(), "4.3.10", ">=") )
+ $fraction = sprintf( "%.3F", $scale/100 );
+ else
+ $fraction = sprintf( "%.3f", $scale/100 );
+ $scale = (int)round( $scale );
+
+ $thumbCaptPath = preg_replace( "/\.jpg$/", "-$scale.jpg", $thumbCaptPath );
+ $thumbAnalPath = preg_replace( "/\.jpg$/", "-$scale.jpg", $thumbAnalPath );
+
+ if ( $isAnalImage )
+ {
+ $imagePath = $analPath;
+ $thumbPath = $thumbAnalPath;
+ }
+ else
+ {
+ $imagePath = $captPath;
+ $thumbPath = $thumbCaptPath;
+ }
+
+ $imageFile = $config['ZM_DIR_EVENTS']."/".$imagePath;
+ //$thumbFile = ZM_DIR_EVENTS."/".$thumbPath;
+ $thumbFile = $thumbPath;
+ if ( $overwrite || !file_exists( $thumbFile ) || !filesize( $thumbFile ) )
+ {
+ // Get new dimensions
+ list( $imageWidth, $imageHeight ) = getimagesize( $imageFile );
+ $thumbWidth = $imageWidth * $fraction;
+ $thumbHeight = $imageHeight * $fraction;
+
+ // Resample
+ $thumbImage = imagecreatetruecolor( $thumbWidth, $thumbHeight );
+ $image = imagecreatefromjpeg( $imageFile );
+ imagecopyresampled( $thumbImage, $image, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $imageWidth, $imageHeight );
+
+ if ( !imagejpeg( $thumbImage, $thumbFile ) )
+ Error( "Can't create thumbnail '$thumbPath'" );
+ }
+ }
+
+ $imageData = array(
+ 'eventPath' => $eventPath,
+ 'imagePath' => $imagePath,
+ 'thumbPath' => $thumbPath,
+ 'imageFile' => $imageFile,
+ 'thumbFile' => $thumbFile,
+ 'imageClass' => $alarmFrame?"alarm":"normal",
+ 'isAnalImage' => $isAnalImage,
+ 'hasAnalImage' => $hasAnalImage,
+ );
+
+ return( $imageData );
+
+ }
+
+ // Take the StartTime of an Event and return
+ // the path to its location on the filesystem
+ public function getEventPath( $event ) {
+ return $event['Event']['MonitorId'].'/'.strftime( "%y/%m/%d/%H/%M/%S", strtotime($event['Event']['StartTime']) );
+ }
+}
+?>
diff --git a/web/api/app/Controller/Component/ScalerComponent.php b/web/api/app/Controller/Component/ScalerComponent.php
new file mode 100644
index 000000000..30678dad6
--- /dev/null
+++ b/web/api/app/Controller/Component/ScalerComponent.php
@@ -0,0 +1,27 @@
+
diff --git a/web/api/app/Controller/ConfigsController.php b/web/api/app/Controller/ConfigsController.php
index 3198ae58e..651f5724e 100644
--- a/web/api/app/Controller/ConfigsController.php
+++ b/web/api/app/Controller/ConfigsController.php
@@ -14,20 +14,6 @@ class ConfigsController extends AppController {
*/
public $components = array('RequestHandler');
-/**
- * index method
- *
- * @return void
- */
- public function index() {
- $this->Config->recursive = 0;
- $configs = $this->Config->find('all');
- $this->set(array(
- 'configs' => $configs,
- '_serialize' => array('configs')
- ));
- }
-
/**
* view method
*
@@ -47,6 +33,19 @@ class ConfigsController extends AppController {
));
}
+ public function viewByName($name = null) {
+ $config = $this->Config->findByName($name, array('fields' => 'Value'));
+
+ if (!$config) {
+ throw new NotFoundException(__('Invalid config'));
+ }
+
+ $this->set(array(
+ 'config' => $config['Config'],
+ '_serialize' => array('config')
+ ));
+ }
+
/**
* edit method
*
@@ -93,45 +92,19 @@ class ConfigsController extends AppController {
/**
* categories method
*
- * Either return a list of distinct categories
- * Or all configs under a certain category
+ * return a list of distinct categories
*/
public function categories($category = null) {
- if ($category != null) {
- if (!$this->Config->find('first', array( 'conditions' => array('Config.Category' => $category)))) {
- throw new NotFoundException(__('Invalid Config Category'));
- }
-
- $config = $this->Config->find('all', array(
- 'conditions' => array('Config.Category' => $category),
- 'recursive' => 0
- ));
- $this->set(array(
- 'config' => $config,
- '_serialize' => array('config')
- ));
- } else {
- $categories = $this->Config->find('all', array(
- 'fields' => array('DISTINCT Config.Category'),
- 'conditions' => array('Config.Category !=' => 'hidden'),
- 'recursive' => 0
- ));
- $this->set(array(
- 'categories' => $categories,
- '_serialize' => array('categories')
- ));
- }
-
- }
-
- public function keyValue() {
- $keyValues = $this->Config->find('list', array(
- 'fields' => array('Config.Name', 'Config.Value')
+ $categories = $this->Config->find('all', array(
+ 'fields' => array('DISTINCT Config.Category'),
+ 'conditions' => array('Config.Category !=' => 'hidden'),
+ 'recursive' => 0
));
$this->set(array(
- 'keyValues' => $keyValues,
- '_serialize' => array('keyValues')
+ 'categories' => $categories,
+ '_serialize' => array('categories')
));
}
}
+
diff --git a/web/api/app/Controller/ControlsController.php b/web/api/app/Controller/ControlsController.php
new file mode 100644
index 000000000..879142f75
--- /dev/null
+++ b/web/api/app/Controller/ControlsController.php
@@ -0,0 +1,59 @@
+Control->recursive = 0;
+ $controls = $this->Control->find('all');
+ $this->set(array(
+ 'controls' => $controls,
+ '_serialize' => array('controls')
+ ));
+ }
+
+/**
+ * view method
+ *
+ * @throws NotFoundException
+ * @param string $id
+ * @return void
+ */
+ public function view($id = null) {
+ if (!$this->Control->exists($id)) {
+ throw new NotFoundException(__('Invalid control'));
+ }
+ $options = array('conditions' => array('Control.' . $this->Control->primaryKey => $id));
+ $control = $this->Control->find('first', $options);
+ $this->set(array(
+ 'control' => $control,
+ '_serialize' => array('control')
+ ));
+ }
+}
+
diff --git a/web/api/app/Controller/EventsController.php b/web/api/app/Controller/EventsController.php
index 394e61caf..05a280be3 100644
--- a/web/api/app/Controller/EventsController.php
+++ b/web/api/app/Controller/EventsController.php
@@ -12,20 +12,46 @@ class EventsController extends AppController {
*
* @var array
*/
- public $components = array('RequestHandler');
+ public $components = array('RequestHandler', 'Scaler', 'Image', 'Paginator');
/**
* index method
*
* @return void
+ * This also creates a thumbnail for each event.
*/
public function index() {
$this->Event->recursive = -1;
- $events = $this->Event->find('all');
- $this->set(array(
- 'events' => $events,
- '_serialize' => array('events')
+
+ if ($this->request->params['named']) {
+ $this->FilterComponent = $this->Components->load('Filter');
+ $conditions = $this->FilterComponent->buildFilter($this->request->params['named']);
+ } else {
+ $conditions = array();
+ }
+
+ // How many events to return
+ $this->loadModel('Config');
+ $limit = $this->Config->find('list', array(
+ 'conditions' => array('Name' => 'ZM_WEB_EVENTS_PER_PAGE'),
+ 'fields' => array('Name', 'Value')
));
+ $this->Paginator->settings = array(
+ 'limit' => $limit['ZM_WEB_EVENTS_PER_PAGE'],
+ 'order' => array('StartTime', 'MaxScore'),
+ 'paramType' => 'querystring',
+ 'conditions' => $conditions
+ );
+ $events = $this->Paginator->paginate('Event');
+
+ // For each event, get its thumbnail data (path, width, height)
+ foreach ($events as $key => $value) {
+ $thumbData = $this->createThumbnail($value['Event']['Id']);
+ $events[$key]['thumbData'] = $thumbData;
+
+ }
+
+ $this->set(compact('events'));
}
/**
@@ -36,12 +62,23 @@ class EventsController extends AppController {
* @return void
*/
public function view($id = null) {
- $this->Event->recursive = -1;
+ $this->loadModel('Config');
+ $configs = $this->Config->find('list', array(
+ 'fields' => array('Name', 'Value'),
+ 'conditions' => array('Name' => array('ZM_DIR_EVENTS'))
+ ));
+
+ $this->Event->recursive = 1;
if (!$this->Event->exists($id)) {
throw new NotFoundException(__('Invalid event'));
}
$options = array('conditions' => array('Event.' . $this->Event->primaryKey => $id));
$event = $this->Event->find('first', $options);
+
+ $path = $configs['ZM_DIR_EVENTS'].'/'.$this->Image->getEventPath($event).'/';
+
+ $event['Event']['BasePath'] = $path;
+
$this->set(array(
'event' => $event,
'_serialize' => array('event')
@@ -108,4 +145,142 @@ class EventsController extends AppController {
} else {
return $this->flash(__('The event could not be deleted. Please, try again.'), array('action' => 'index'));
}
- }}
+ }
+
+ public function search() {
+ $this->Event->recursive = -1;
+ $conditions = array();
+
+ foreach ($this->params['named'] as $param_name => $value) {
+ // Transform params into mysql
+ if (preg_match("/interval/i", $value, $matches)) {
+ $condition = array("$param_name >= (date_sub(now(), $value))");
+ } else {
+ $condition = array($param_name => $value);
+ }
+ array_push($conditions, $condition);
+ }
+
+ $results = $this->Event->find('all', array(
+ 'conditions' => $conditions
+ ));
+
+ $this->set(array(
+ 'results' => $results,
+ '_serialize' => array('results')
+ ));
+
+
+ }
+
+ public function consoleEvents($interval = null) {
+ $this->Event->recursive = -1;
+ $results = array();
+
+ $query = $this->Event->query("select MonitorId, COUNT(*) AS Count from Events WHERE StartTime >= (DATE_SUB(NOW(), interval $interval)) GROUP BY MonitorId;");
+
+ foreach ($query as $result) {
+ $results[$result['Events']['MonitorId']] = $result[0]['Count'];
+ }
+
+ $this->set(array(
+ 'results' => $results,
+ '_serialize' => array('results')
+ ));
+ }
+
+ // Create a thumbnail and return the thumbnail's data for a given event id.
+ public function createThumbnail($id = null) {
+ $this->Event->recursive = -1;
+
+ if (!$this->Event->exists($id)) {
+ throw new NotFoundException(__('Invalid event'));
+ }
+
+ $event = $this->Event->find('first', array(
+ 'conditions' => array('Id' => $id)
+ ));
+
+ // Find the max Frame for this Event. Error out otherwise.
+ $this->loadModel('Frame');
+ if (! $frame = $this->Frame->find('first', array(
+ 'conditions' => array(
+ 'EventId' => $event['Event']['Id'],
+ 'Score' => $event['Event']['MaxScore']
+ )
+ ))) {
+ throw new NotFoundException(__("Can not find Frame for Event " . $event['Event']['Id']));
+ }
+
+ $this->loadModel('Config');
+
+ // Get the config options required for reScale and getImageSrc
+ // The $bw, $thumbs and unset() code is a workaround / temporary
+ // until I have a better way of handing per-bandwidth config options
+ $bw = (isset($_COOKIE['zmBandwidth']) ? strtoupper(substr($_COOKIE['zmBandwidth'], 0, 1)) : 'L');
+ $thumbs = "ZM_WEB_${bw}_SCALE_THUMBS";
+
+ $config = $this->Config->find('list', array(
+ 'conditions' => array('OR' => array(
+ 'Name' => array('ZM_WEB_LIST_THUMB_WIDTH',
+ 'ZM_WEB_LIST_THUMB_HEIGHT',
+ 'ZM_EVENT_IMAGE_DIGITS',
+ 'ZM_DIR_IMAGES',
+ "$thumbs",
+ 'ZM_DIR_EVENTS'
+ )
+ )),
+ 'fields' => array('Name', 'Value')
+ ));
+ $config['ZM_WEB_SCALE_THUMBS'] = $config[$thumbs];
+ unset($config[$thumbs]);
+
+ // reScale based on either the width, or the hight, of the event.
+ if ( $config['ZM_WEB_LIST_THUMB_WIDTH'] ) {
+ $thumbWidth = $config['ZM_WEB_LIST_THUMB_WIDTH'];
+ $scale = (100 * $thumbWidth) / $event['Event']['Width'];
+ $thumbHeight = $this->Scaler->reScale( $event['Event']['Height'], $scale );
+ }
+ elseif ( $config['ZM_WEB_LIST_THUMB_HEIGHT'] ) {
+ $thumbHeight = $config['ZM_WEB_LIST_THUMB_HEIGHT'];
+ $scale = (100*$thumbHeight)/$event['Event']['Height'];
+ $thumbWidth = $this->Scaler->reScale( $event['Event']['Width'], $scale );
+ }
+ else {
+ throw new NotFoundException(__('No thumbnail width or height specified, please check in Options->Web'));
+ }
+
+ $imageData = $this->Image->getImageSrc( $event, $frame, $scale, $config );
+ $thumbData['Path'] = $imageData['thumbPath'];
+ $thumbData['Width'] = (int)$thumbWidth;
+ $thumbData['Height'] = (int)$thumbHeight;
+
+ return( $thumbData );
+
+ }
+
+ public function archive($id = null) {
+ $this->Event->recursive = -1;
+ if (!$this->Event->exists($id)) {
+ throw new NotFoundException(__('Invalid event'));
+ }
+
+ // Get the current value of Archive
+ $archived = $this->Event->find('first', array(
+ 'fields' => array('Event.Archived'),
+ 'conditions' => array('Event.Id' => $id)
+ ));
+ // If 0, 1, if 1, 0
+ $archiveVal = (($archived['Event']['Archived'] == 0) ? 1 : 0);
+
+ // Save the new value
+ $this->Event->id = $id;
+ $this->Event->saveField('Archived', $archiveVal);
+
+ $this->set(array(
+ 'archived' => $archiveVal,
+ '_serialize' => array('archived')
+ ));
+ }
+
+}
diff --git a/web/api/app/Controller/HostController.php b/web/api/app/Controller/HostController.php
new file mode 100644
index 000000000..973caf286
--- /dev/null
+++ b/web/api/app/Controller/HostController.php
@@ -0,0 +1,110 @@
+set(array(
+ 'result' => $result,
+ '_serialize' => array('result')
+ ));
+ }
+
+ function getLoad() {
+ $load = sys_getloadavg();
+
+ $this->set(array(
+ 'load' => $load,
+ '_serialize' => array('load')
+ ));
+ }
+
+ // If $mid is set, only return disk usage for that monitor
+ // Else, return an array of total disk usage, and per-monitor
+ // usage.
+ function getDiskPercent($mid = null) {
+ $this->loadModel('Config');
+ $this->loadModel('Monitor');
+
+ // If $mid is passed, see if it is valid
+ if ($mid) {
+ if (!$this->Monitor->exists($mid)) {
+ throw new NotFoundException(__('Invalid monitor'));
+ }
+ }
+
+ $zm_dir_events = $this->Config->find('list', array(
+ 'conditions' => array('Name' => 'ZM_DIR_EVENTS'),
+ 'fields' => array('Name', 'Value')
+ ));
+ $zm_dir_events = $zm_dir_events['ZM_DIR_EVENTS' ];
+
+ // Test to see if $zm_dir_events is relative or absolute
+ if ('/' === "" || strrpos($zm_dir_events, '/', -strlen($zm_dir_events)) !== TRUE) {
+ // relative - so add the full path
+ $zm_dir_events = Configure::read('ZM_PATH_WEB') . '/' . $zm_dir_events;
+ }
+
+ if ($mid) {
+ // Get disk usage for $mid
+ $usage = shell_exec ("du -sh0 $zm_dir_events/$mid | awk '{print $1}'");
+ } else {
+ $monitors = $this->Monitor->find('all', array(
+ 'fields' => array('Id', 'Name', 'WebColour')
+ ));
+ $usage = array();
+
+ // Add each monitor's usage to array
+ foreach ($monitors as $key => $value) {
+ $id = $value['Monitor']['Id'];
+ $name = $value['Monitor']['Name'];
+ $color = $value['Monitor']['WebColour'];
+
+ $space = shell_exec ("du -s0 $zm_dir_events/$id | awk '{print $1}'");
+ if ($space == null) {
+ $space = 0;
+ }
+ $space = $space/1024/1024;
+
+ $usage[$name] = array(
+ 'space' => rtrim($space),
+ 'color' => $color
+ );
+ }
+
+ // Add total usage to array
+ $space = shell_exec( "df $zm_dir_events |tail -n1 | awk '{print $3 }'");
+ $space = $space/1024/1024;
+ $usage['Total'] = array(
+ 'space' => rtrim($space),
+ 'color' => '#F7464A'
+ );
+ }
+
+ $this->set(array(
+ 'usage' => $usage,
+ '_serialize' => array('usage')
+ ));
+ }
+
+ function getVersion() {
+ $version = Configure::read('ZM_VERSION');
+
+ $this->set(array(
+ 'version' => $version,
+ '_serialize' => array('version')
+ ));
+ }
+}
diff --git a/web/api/app/Controller/LogsController.php b/web/api/app/Controller/LogsController.php
index 908c635e2..bb8f47b80 100644
--- a/web/api/app/Controller/LogsController.php
+++ b/web/api/app/Controller/LogsController.php
@@ -13,7 +13,12 @@ class LogsController extends AppController {
*
* @var array
*/
- public $components = array('Paginator');
+ public $components = array('Paginator', 'RequestHandler');
+ public $paginate = array(
+ 'limit' => 100,
+ 'order' => array( 'Log.TimeKey' => 'asc' ),
+ 'paramType' => 'querystring'
+ );
/**
* index method
@@ -21,8 +26,11 @@ class LogsController extends AppController {
* @return void
*/
public function index() {
- $this->Log->recursive = 0;
- $this->set('logs', $this->Paginator->paginate());
+ $this->Log->recursive = -1;
+ $this->Paginator->settings = $this->paginate;
+
+ $logs = $this->Paginator->paginate('Log');
+ $this->set(compact('logs'));
}
/**
diff --git a/web/api/app/Controller/MonitorsController.php b/web/api/app/Controller/MonitorsController.php
index da4339e8e..0588a8cc2 100644
--- a/web/api/app/Controller/MonitorsController.php
+++ b/web/api/app/Controller/MonitorsController.php
@@ -59,6 +59,7 @@ class MonitorsController extends AppController {
if ($this->request->is('post')) {
$this->Monitor->create();
if ($this->Monitor->save($this->request->data)) {
+ $this->daemonControl($this->Monitor->id, 'start', $this->request->data);
return $this->flash(__('The monitor has been saved.'), array('action' => 'index'));
}
}
@@ -103,6 +104,9 @@ class MonitorsController extends AppController {
throw new NotFoundException(__('Invalid monitor'));
}
$this->request->allowMethod('post', 'delete');
+
+ $this->daemonControl($this->Monitor->id, 'stop');
+
if ($this->Monitor->delete()) {
return $this->flash(__('The monitor has been deleted.'), array('action' => 'index'));
} else {
@@ -124,5 +128,81 @@ class MonitorsController extends AppController {
));
}
+ // Check if a daemon is running for the monitor id
+ public function daemonStatus() {
+ $id = $this->request->params['named']['id'];
+ $daemon = $this->request->params['named']['daemon'];
+
+ if (!$this->Monitor->exists($id)) {
+ throw new NotFoundException(__('Invalid monitor'));
+ }
+
+ $monitor = $this->Monitor->find('first', array(
+ 'fields' => array('Id', 'Type', 'Device'),
+ 'conditions' => array('Id' => $id)
+ ));
+
+ // Clean up the returned array
+ $monitor = Set::extract('/Monitor/.', $monitor);
+
+ // Pass -d for local, otherwise -m
+ if ($monitor[0]['Type'] == 'Local') {
+ $args = "-d ". $monitor[0]['Device'];
+ } else {
+ $args = "-m ". $monitor[0]['Id'];
+ }
+
+ // Build the command, and execute it
+ $zm_path_bin = Configure::read('ZM_PATH_BIN');
+ $command = escapeshellcmd("$zm_path_bin/zmdc.pl status $daemon $args");
+ $status = exec( $command );
+
+ // If 'not' is present, the daemon is not running, so return false
+ // https://github.com/ZoneMinder/ZoneMinder/issues/799#issuecomment-108996075
+ // Also sending back the status text so we can check if the monitor is in pending
+ // state which means there may be an error
+ $statustext = $status;
+ $status = (strpos($status, 'not')) ? false : true;
+
+ $this->set(array(
+ 'status' => $status,
+ 'statustext' => $statustext,
+ '_serialize' => array('status','statustext'),
+ ));
+ }
+
+ public function daemonControl($id, $command, $monitor=null, $daemon=null) {
+ $args = '';
+ $daemons = array();
+
+ if (!$monitor) {
+ // Need to see if it is local or remote
+ $monitor = $this->Monitor->find('first', array(
+ 'fields' => array('Type', 'Function'),
+ 'conditions' => array('Id' => $id)
+ ));
+ $monitor = $monitor['Monitor'];
+ }
+
+ if ($monitor['Type'] == 'Local') {
+ $args = "-d " . $monitor['Device'];
+ } else {
+ $args = "-m " . $id;
+ }
+
+ if ($monitor['Function'] == 'Monitor') {
+ array_push($daemons, 'zmc');
+ } else {
+ array_push($daemons, 'zmc', 'zma');
+ }
+
+ $zm_path_bin = Configure::read('ZM_PATH_BIN');
+
+ foreach ($daemons as $daemon) {
+ $shellcmd = escapeshellcmd("$zm_path_bin/zmdc.pl $command $daemon $args");
+ $status = exec( $shellcmd );
+ }
+ }
+
}
diff --git a/web/api/app/Controller/StatesController.php b/web/api/app/Controller/StatesController.php
new file mode 100644
index 000000000..2b007f08f
--- /dev/null
+++ b/web/api/app/Controller/StatesController.php
@@ -0,0 +1,117 @@
+State->recursive = 0;
+ $states = $this->State->find('all');
+ $this->set(array(
+ 'states' => $states,
+ '_serialize' => array('states')
+ ));
+ }
+
+/**
+ * view method
+ *
+ * @throws NotFoundException
+ * @param string $id
+ * @return void
+ */
+ public function view($id = null) {
+ if (!$this->State->exists($id)) {
+ throw new NotFoundException(__('Invalid state'));
+ }
+ $options = array('conditions' => array('State.' . $this->State->primaryKey => $id));
+ $this->set('state', $this->State->find('first', $options));
+ }
+
+/**
+ * add method
+ *
+ * @return void
+ */
+ public function add() {
+ if ($this->request->is('post')) {
+ $this->State->create();
+ if ($this->State->save($this->request->data)) {
+ return $this->flash(__('The state has been saved.'), array('action' => 'index'));
+ }
+ }
+ }
+
+/**
+ * edit method
+ *
+ * @throws NotFoundException
+ * @param string $id
+ * @return void
+ */
+ public function edit($id = null) {
+ if (!$this->State->exists($id)) {
+ throw new NotFoundException(__('Invalid state'));
+ }
+ if ($this->request->is(array('post', 'put'))) {
+ if ($this->State->save($this->request->data)) {
+ return $this->flash(__('The state has been saved.'), array('action' => 'index'));
+ }
+ } else {
+ $options = array('conditions' => array('State.' . $this->State->primaryKey => $id));
+ $this->request->data = $this->State->find('first', $options);
+ }
+ }
+
+/**
+ * delete method
+ *
+ * @throws NotFoundException
+ * @param string $id
+ * @return void
+ */
+ public function delete($id = null) {
+ $this->State->id = $id;
+ if (!$this->State->exists()) {
+ throw new NotFoundException(__('Invalid state'));
+ }
+ $this->request->allowMethod('post', 'delete');
+ if ($this->State->delete()) {
+ return $this->flash(__('The state has been deleted.'), array('action' => 'index'));
+ } else {
+ return $this->flash(__('The state could not be deleted. Please, try again.'), array('action' => 'index'));
+ }
+ }
+
+ public function change() {
+ $newState = $this->request->params['pass'][0];
+ $blah = $this->packageControl($newState);
+
+ $this->set(array(
+ 'blah' => $blah,
+ '_serialize' => array('blah')
+ ));
+ }
+
+ public function packageControl( $command ) {
+ $zm_path_bin = Configure::read('ZM_PATH_BIN');
+ $string = $zm_path_bin.'/zmpkg.pl '.escapeshellarg( $command );
+ $status = exec( $string );
+
+ return $status;
+ }
+
+
+}
diff --git a/web/api/app/Controller/ZonePresetsController.php b/web/api/app/Controller/ZonePresetsController.php
new file mode 100644
index 000000000..b89a6c75d
--- /dev/null
+++ b/web/api/app/Controller/ZonePresetsController.php
@@ -0,0 +1,99 @@
+ZonePreset->find('all');
+ $this->set(array(
+ 'zonePresets' => $zonePresets,
+ '_serialize' => array('zonePresets')
+ ));
+ }
+
+/**
+ * view method
+ *
+ * @throws NotFoundException
+ * @param string $id
+ * @return void
+ */
+ public function view($id = null) {
+ if (!$this->ZonePreset->exists($id)) {
+ throw new NotFoundException(__('Invalid zone preset'));
+ }
+ $options = array('conditions' => array('ZonePreset.' . $this->ZonePreset->primaryKey => $id));
+ $this->set('zonePreset', $this->ZonePreset->find('first', $options));
+ }
+
+/**
+ * add method
+ *
+ * @return void
+ */
+ public function add() {
+ if ($this->request->is('post')) {
+ $this->ZonePreset->create();
+ if ($this->ZonePreset->save($this->request->data)) {
+ return $this->flash(__('The zone preset has been saved.'), array('action' => 'index'));
+ }
+ }
+ }
+
+/**
+ * edit method
+ *
+ * @throws NotFoundException
+ * @param string $id
+ * @return void
+ */
+ public function edit($id = null) {
+ if (!$this->ZonePreset->exists($id)) {
+ throw new NotFoundException(__('Invalid zone preset'));
+ }
+ if ($this->request->is(array('post', 'put'))) {
+ if ($this->ZonePreset->save($this->request->data)) {
+ return $this->flash(__('The zone preset has been saved.'), array('action' => 'index'));
+ }
+ } else {
+ $options = array('conditions' => array('ZonePreset.' . $this->ZonePreset->primaryKey => $id));
+ $this->request->data = $this->ZonePreset->find('first', $options);
+ }
+ }
+
+/**
+ * delete method
+ *
+ * @throws NotFoundException
+ * @param string $id
+ * @return void
+ */
+ public function delete($id = null) {
+ $this->ZonePreset->id = $id;
+ if (!$this->ZonePreset->exists()) {
+ throw new NotFoundException(__('Invalid zone preset'));
+ }
+ $this->request->allowMethod('post', 'delete');
+ if ($this->ZonePreset->delete()) {
+ return $this->flash(__('The zone preset has been deleted.'), array('action' => 'index'));
+ } else {
+ return $this->flash(__('The zone preset could not be deleted. Please, try again.'), array('action' => 'index'));
+ }
+ }}
diff --git a/web/api/app/Controller/ZonesController.php b/web/api/app/Controller/ZonesController.php
index dc30a382a..be80c57fc 100644
--- a/web/api/app/Controller/ZonesController.php
+++ b/web/api/app/Controller/ZonesController.php
@@ -4,51 +4,26 @@ App::uses('AppController', 'Controller');
* Zones Controller
*
* @property Zone $Zone
- * @property PaginatorComponent $Paginator
*/
class ZonesController extends AppController {
-/**
- * Components
- *
- * @var array
- */
- public $components = array('Paginator', 'RequestHandler');
-
-/**
- * index method
- *
- * @return void
- */
- public function index() {
- $this->Zone->recursive = -1;
- $zones = $this->Zone->find('all');
- $this->set(array(
- 'zones' => $zones,
- '_serialize' => array('zones')
- ));
- }
-
-/**
- * view method
- *
- * @throws NotFoundException
- * @param string $id
- * @return void
- */
- public function view($id = null) {
- $this->Zone->recursive = -1;
- if (!$this->Zone->exists($id)) {
- throw new NotFoundException(__('Invalid zone'));
+// Find all zones which belong to a MonitorId
+ public function forMonitor($id = null) {
+ $this->loadModel('Monitor');
+ if (!$this->Monitor->exists($id)) {
+ throw new NotFoundException(__('Invalid monitor'));
}
- $options = array('conditions' => array('Zone.' . $this->Zone->primaryKey => $id));
- $zone = $this->Zone->find('first', $options);
+
+ $this->Zone->recursive = -1;
+
+ $zones = $this->Zone->find('all', array(
+ 'conditions' => array('MonitorId' => $id)
+ ));
$this->set(array(
- 'zone' => $zone,
- '_serialize' => array('zone')
+ 'zones' => $zones,
+ '_serialize' => array('zones')
));
}
-
/**
* add method
*
@@ -108,4 +83,38 @@ class ZonesController extends AppController {
} else {
return $this->flash(__('The zone could not be deleted. Please, try again.'), array('action' => 'index'));
}
- }}
+ }
+
+
+
+ public function createZoneImage( $id = null ) {
+ $this->loadModel('Monitor');
+ $this->Monitor->id = $id;
+ if (!$this->Monitor->exists()) {
+ throw new NotFoundException(__('Invalid zone'));
+ }
+
+
+ $this->loadModel('Config');
+ $zm_dir_images = $this->Config->find('list', array(
+ 'conditions' => array('Name' => 'ZM_DIR_IMAGES'),
+ 'fields' => array('Name', 'Value')
+ ));
+
+ $zm_dir_images = $zm_dir_images['ZM_DIR_IMAGES'];
+ $zm_path_web = Configure::read('ZM_PATH_WEB');
+ $zm_path_bin = Configure::read('ZM_PATH_BIN');
+ $images_path = "$zm_path_web/$zm_dir_images";
+
+ chdir($images_path);
+
+ $command = escapeshellcmd("$zm_path_bin/zmu -z -m $id");
+ system( $command, $status );
+
+ $this->set(array(
+ 'status' => $status,
+ '_serialize' => array('status')
+ ));
+
+ }
+}
diff --git a/web/api/app/Model/Config.php b/web/api/app/Model/Config.php
index 2ada8258d..d83728c76 100644
--- a/web/api/app/Model/Config.php
+++ b/web/api/app/Model/Config.php
@@ -18,13 +18,25 @@ class Config extends AppModel {
*
* @var string
*/
- public $primaryKey = 'Id';
+ public $primaryKey = 'Name';
/**
* Display field
*
* @var string
*/
- public $displayField = 'Name';
+ public $displayField = 'Value';
+
+
+ // Add a find method for returning a hash of the Config table.
+ // This is used for the Options view.
+ public $findMethods = array('hash' => true);
+ protected function _findHash($state, $query, $results = array()) {
+ if ($state === 'before') {
+ return $query;
+ }
+ $results = Set::combine($results, '{n}.Config.Name', '{n}.Config');
+ return $results;
+ }
}
diff --git a/web/api/app/Model/Control.php b/web/api/app/Model/Control.php
new file mode 100644
index 000000000..d5716cc66
--- /dev/null
+++ b/web/api/app/Model/Control.php
@@ -0,0 +1,54 @@
+ array(
+ 'numeric' => array(
+ 'rule' => array('numeric'),
+ //'message' => 'Your custom message here',
+ //'allowEmpty' => false,
+ //'required' => false,
+ //'last' => false, // Stop validation after this rule
+ //'on' => 'create', // Limit validation to 'create' or 'update' operations
+ ),
+ ),
+ );
+
+}
diff --git a/web/api/app/Model/Frame.php b/web/api/app/Model/Frame.php
index 48b880304..96c5fdc50 100644
--- a/web/api/app/Model/Frame.php
+++ b/web/api/app/Model/Frame.php
@@ -121,4 +121,6 @@ class Frame extends AppModel {
'order' => ''
)
);
+
+ public $recursive = -1;
}
diff --git a/web/api/app/Model/Host.php b/web/api/app/Model/Host.php
new file mode 100644
index 000000000..5c24c7531
--- /dev/null
+++ b/web/api/app/Model/Host.php
@@ -0,0 +1,9 @@
+
+Paginator->params();
+ echo json_encode($array);
+?>
diff --git a/web/api/app/View/Logs/json/index.ctp b/web/api/app/View/Logs/json/index.ctp
new file mode 100644
index 000000000..32cbd51f8
--- /dev/null
+++ b/web/api/app/View/Logs/json/index.ctp
@@ -0,0 +1,5 @@
+Paginator->params();
+ echo json_encode($array);
+?>
diff --git a/web/api/app/View/View/Configs/json/edit.ctp b/web/api/app/View/View/Configs/json/edit.ctp
new file mode 100644
index 000000000..75fa758bd
--- /dev/null
+++ b/web/api/app/View/View/Configs/json/edit.ctp
@@ -0,0 +1 @@
+echo json_encode($config);
diff --git a/web/api/app/View/View/Configs/json/index.ctp b/web/api/app/View/View/Configs/json/index.ctp
new file mode 100644
index 000000000..86edf870a
--- /dev/null
+++ b/web/api/app/View/View/Configs/json/index.ctp
@@ -0,0 +1 @@
+echo json_encode($configs);
diff --git a/web/api/app/View/View/Configs/json/view.ctp b/web/api/app/View/View/Configs/json/view.ctp
new file mode 100644
index 000000000..75fa758bd
--- /dev/null
+++ b/web/api/app/View/View/Configs/json/view.ctp
@@ -0,0 +1 @@
+echo json_encode($config);
diff --git a/web/api/app/View/View/Configs/xml/index.ctp b/web/api/app/View/View/Configs/xml/index.ctp
new file mode 100644
index 000000000..b13a76093
--- /dev/null
+++ b/web/api/app/View/View/Configs/xml/index.ctp
@@ -0,0 +1,2 @@
+$xml = Xml::fromArray(array('response' => $configs));
+echo $xml->asXML();
diff --git a/web/api/app/View/View/Configs/xml/view.ctp b/web/api/app/View/View/Configs/xml/view.ctp
new file mode 100644
index 000000000..7987d32e7
--- /dev/null
+++ b/web/api/app/View/View/Configs/xml/view.ctp
@@ -0,0 +1,2 @@
+$xml = Xml::fromArray(array('response' => $config));
+echo $xml->asXML();
diff --git a/web/api/app/View/View/Elements/empty b/web/api/app/View/View/Elements/empty
new file mode 100644
index 000000000..e69de29bb
diff --git a/web/api/app/View/View/Emails/html/default.ctp b/web/api/app/View/View/Emails/html/default.ctp
new file mode 100644
index 000000000..e2bff19c0
--- /dev/null
+++ b/web/api/app/View/View/Emails/html/default.ctp
@@ -0,0 +1,25 @@
+
+ ' . $line . "
\n";
+endforeach;
+?>
\ No newline at end of file
diff --git a/web/api/app/View/View/Emails/text/default.ctp b/web/api/app/View/View/Emails/text/default.ctp
new file mode 100644
index 000000000..090b5c403
--- /dev/null
+++ b/web/api/app/View/View/Emails/text/default.ctp
@@ -0,0 +1,19 @@
+
+
\ No newline at end of file
diff --git a/web/api/app/View/View/Errors/error400.ctp b/web/api/app/View/View/Errors/error400.ctp
new file mode 100644
index 000000000..4c3850b28
--- /dev/null
+++ b/web/api/app/View/View/Errors/error400.ctp
@@ -0,0 +1,31 @@
+
+
+
+=')):
+ echo '';
+ echo __d('cake_dev', 'Your version of PHP is 5.2.8 or higher.');
+ echo '';
+ else:
+ echo '';
+ echo __d('cake_dev', 'Your version of PHP is too low. You need PHP 5.2.8 or higher to use CakePHP.');
+ echo '';
+ endif;
+?>
+
+ ';
+ echo __d('cake_dev', 'The %s is being used for core caching. To change the config edit %s', ''. $settings['engine'] . 'Engine', 'APP/Config/core.php');
+ echo '';
+ else:
+ echo '';
+ echo __d('cake_dev', 'Your cache is NOT working. Please check the settings in %s', 'APP/Config/core.php');
+ echo '';
+ endif;
+ ?>
+
+ isConnected()):
+ echo '';
+ echo __d('cake_dev', 'CakePHP is able to connect to the database.');
+ echo '';
+ else:
+ echo '';
+ echo __d('cake_dev', 'CakePHP is NOT able to connect to the database.');
+ echo '
';
+ echo $errorMsg;
+ echo '';
+ endif;
+ ?>
+
+
+';
+ echo __d('cake_dev', 'PCRE has not been compiled with Unicode support.');
+ echo ' ';
+ echo __d('cake_dev', 'Recompile PCRE with Unicode support by adding --enable-unicode-properties when configuring');
+ echo '';
+ endif;
+?>
+
+
+ ';
+ echo __d('cake_dev', 'DebugKit plugin is present');
+ echo '';
+ else:
+ echo '';
+ echo __d('cake_dev', 'DebugKit is not installed. It will help you inspect and debug different aspects of your application.');
+ echo ' ';
+ echo __d('cake_dev', 'You can install it from %s', $this->Html->link('GitHub', 'https://github.com/cakephp/debug_kit'));
+ echo '';
+ endif;
+ ?>
+
+
+
+
+
+To change its layout, edit: %s.
+You can also add some CSS styles for your pages at: %s.',
+ 'APP/View/Pages/home.ctp', 'APP/View/Layouts/default.ctp', 'APP/webroot/css');
+?>
+