Merge pull request #1203 from SteveGilvarry/feature-h264-videostorage

Merge master to feature-h264-videostorage
This commit is contained in:
Steve Gilvarry 2015-12-28 14:40:49 +11:00
commit 97bac3b150
15 changed files with 295 additions and 71 deletions

View File

@ -1,5 +1,5 @@
usr/bin
usr/lib/cgi-bin
usr/lib/zoneminder/cgi-bin
usr/share/man
usr/share/perl5/ZoneMinder
usr/share/perl5/ZoneMinder.pm

View File

@ -1,4 +1,3 @@
var/cache/zoneminder/events usr/share/zoneminder/events
var/cache/zoneminder/images usr/share/zoneminder/images
var/cache/zoneminder/temp usr/share/zoneminder/temp
usr/lib/cgi-bin usr/share/zoneminder/cgi-bin

View File

@ -17,9 +17,9 @@ override_dh_auto_configure:
-DZM_SOCKDIR=/var/run/zm \
-DZM_TMPDIR=/var/tmp/zm \
-DZM_LOGDIR=/var/log/zm \
-DZM_WEBDIR=/usr/share/zoneminder \
-DZM_WEBDIR=/usr/share/zoneminder/www \
-DZM_CONTENTDIR=/var/cache/zoneminder \
-DZM_CGIDIR=/usr/lib/cgi-bin \
-DZM_CGIDIR=/usr/lib/zoneminder/cgi-bin \
-DZM_WEB_USER=www-data \
-DZM_WEB_GROUP=www-data \
-DCMAKE_INSTALL_SYSCONFDIR=etc/zm

View File

@ -1,9 +1,21 @@
Alias /zm /usr/share/zoneminder/www
<Directory /usr/share/zoneminder/www>
php_flag register_globals off
Options Indexes FollowSymLinks
<IfModule mod_dir.c>
DirectoryIndex index.php
</IfModule>
</Directory>
<IfModule mod_fcgid.c>
<Directory /usr/share/zoneminder/www>
Options +ExecCGI
AllowOverride All
AddHandler fcgid-script .php
FCGIWrapper /usr/bin/php5-cgi
Order allow,deny
Allow from all
</Directory>
</IfModule>
<IfModule mod_php5.c>
<Directory /usr/share/zoneminder/www>
php_flag register_globals off
Options Indexes FollowSymLinks
<IfModule mod_dir.c>
DirectoryIndex index.php
</IfModule>
</Directory>
</IfModule>

View File

@ -2,6 +2,8 @@
set -e
. /etc/zm/zm.conf
if [ "$1" = "configure" ]; then
chown www-data:root /var/log/zm
chown www-data:www-data /var/lib/zm
@ -15,9 +17,13 @@ if [ "$1" = "configure" ]; then
# Ensure zoneminder is stopped
deb-systemd-invoke stop zoneminder.service || exit $?
echo 'grant lock tables, create, index, alter on zm.* to 'zmuser'@localhost identified by "zmpass";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql
# Run the ZoneMinder update tool
zmupdate.pl --nointeractive
if [ "$ZM_DB_HOST" = "localhost" ]; then
echo 'grant lock tables, create, index, alter on zm.* to 'zmuser'@localhost identified by "zmpass";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql
# Run the ZoneMinder update tool
zmupdate.pl --nointeractive
else
echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)"
fi;
fi

View File

@ -101,8 +101,8 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#html_theme = 'default'
html_theme = 'sphinx_rtd_theme'
html_theme = 'default'
#html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the

View File

@ -3,16 +3,17 @@ Mobile Devices
Here are some options for using ZoneMinder on Mobile devices:
Using the existing web console
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* You can directly use the ZoneMinder interface by launching a browser and going to the ZoneMinder server just like you do on the Desktop
* ZoneMinder also has a "mobile skin" that offers limited functionality (not all views are present in this skin). You can point your mobile browser to ``http://yourzoneminderip/zm/index.php?skin=mobile`` and bookmark it
Third party mobile clients
^^^^^^^^^^^^^^^^^^^^^^^^^^^
* zmNinja (`source code <https://github.com/pliablepixels/zmNinja>`__, needs APIs to be installed to work)
* Currently in free beta testing for iOS and Android. Will be in app/play store as soon as ZM 1.29 is launched
* zmView (limited, free) and zmView Pro (more features, paid) - `website <http://html5-clouds.com/?q=node/55>`__
* Available in App Store and Play Store - `website <http://pliablepixels.github.io/zmNinja/>`__
* zmView (limited, free) and zmView Pro (more features, paid)
* Available in App Store and Play Store, relies on ZM skins `website <http://html5-clouds.com/?q=node/55>`__
Using the existing web console
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* You can directly use the ZoneMinder interface by launching a browser and going to the ZoneMinder server just like you do on the Desktop
* ZoneMinder also has a "mobile skin" that offers limited functionality (not all views are present in this skin). You can point your mobile browser to ``http://yourzoneminderip/zm/index.php?skin=mobile`` and bookmark it. **Note however that 1.29 is the last release that will support the mobile skin. It's use is deprecated**
Discontinued clients
^^^^^^^^^^^^^^^^^^^^

View File

@ -357,7 +357,23 @@ our @options =
type => $types{boolean},
category => "system",
},
# PP - Google reCaptcha settings
{
name => "ZM_OPT_USE_API",
default => "yes",
description => "Enable ZoneMinder APIs",
help => qqq("
ZoneMinder now features a new API using which 3rd party
applications can interact with ZoneMinder data. It is
STRONGLY recommended that you enable authentication along
with APIs. Note that the APIs return sensitive data like
Monitor access details which are configured as JSON objects.
Which is why we recommend you enabling authentication, especially
if you are exposing your ZM instance on the Internet.
"),
type => $types{boolean},
category => "system",
},
# PP - Google reCaptcha settings
{
name => "ZM_OPT_USE_GOOG_RECAPTCHA",
default => "no",
@ -410,6 +426,7 @@ our @options =
type => $types {string},
category => "system",
},
{
name => "ZM_DIR_EVENTS",

View File

@ -34,7 +34,7 @@ class AppController extends Controller {
use CrudControllerTrait;
public $components = [
'Session', // PP - We are going to use SessionHelper to check PHP session vars
'Session', // We are going to use SessionHelper to check PHP session vars
'RequestHandler',
'Crud.Crud' => [
'actions' => [
@ -49,7 +49,7 @@ class AppController extends Controller {
]
];
//PP - Global beforeFilter function
// Global beforeFilter function
//Zoneminder sets the username session variable
// to the logged in user. If this variable is set
// then you are logged in
@ -58,14 +58,62 @@ class AppController extends Controller {
// Also checking to do this only if ZM_OPT_USE_AUTH is on
public function beforeFilter() {
$this->loadModel('Config');
$options = array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_OPT_USE_API'));
$config = $this->Config->find('first', $options);
$zmOptApi = $config['Config']['Value'];
if ($zmOptApi !='1')
{
throw new UnauthorizedException(__('API Disabled'));
return;
}
$options = array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_OPT_USE_AUTH'));
$config = $this->Config->find('first', $options);
$zmOptAuth = $config['Config']['Value'];
if (!$this->Session->Read('user.Username') && ($zmOptAuth=='1'))
{
throw new NotFoundException(__('Not Authenticated'));
throw new UnauthorizedException(__('Not Authenticated'));
return;
}
else
{
$this->loadModel('User');
$loggedinUser = $this->Session->Read('user.Username');
$isEnabled = $this->Session->Read('user.Enabled');
// this will likely never happen as if its
// not enabled, login will fail and Not Auth will be returned
// however, keeping this here for now
if ($isEnabled != "1" && $zmOptAuth=="1")
{
throw new UnauthorizedException(__('User is not enabled'));
return;
}
if ($zmOptAuth=='1')
{
$options = array ('conditions' => array ('User.Username' => $loggedinUser));
$userMonitors = $this->User->find('first', $options);
$this->Session->Write('allowedMonitors',$userMonitors['User']['MonitorIds']);
$this->Session->Write('streamPermission',$userMonitors['User']['Stream']);
$this->Session->Write('eventPermission',$userMonitors['User']['Events']);
$this->Session->Write('controlPermission',$userMonitors['User']['Control']);
$this->Session->Write('systemPermission',$userMonitors['User']['System']);
$this->Session->Write('monitorPermission',$userMonitors['User']['Monitors']);
}
else // if auth is not on, you can do everything
{
//$userMonitors = $this->User->find('first', $options);
$this->Session->Write('allowedMonitors','');
$this->Session->Write('streamPermission','View');
$this->Session->Write('eventPermission','Edit');
$this->Session->Write('controlPermission','Edit');
$this->Session->Write('systemPermission','Edit');
$this->Session->Write('monitorPermission','Edit');
}
}
}

View File

@ -48,7 +48,7 @@ class ImageComponent extends Component {
$imageFile = $config['ZM_DIR_EVENTS']."/".$imagePath;
//$thumbFile = ZM_DIR_EVENTS."/".$thumbPath;
$thumbFile = $thumbPath;
// PP: This segment of code results in errors when trying to get Events API
// This segment of code results in errors when trying to get Events API
// This actually seems to be generating images for the angular UI web view
// and should not be a part of the API anyway
// I've commented it so events APIs continue to work

View File

@ -15,7 +15,7 @@ class ConfigsController extends AppController {
public $components = array('RequestHandler');
/**
* PP - resolves the issue of not returning all config parameters
* resolves the issue of not returning all config parameters
* refer https://github.com/ZoneMinder/ZoneMinder/issues/953
* index method
*

View File

@ -14,6 +14,17 @@ class EventsController extends AppController {
*/
public $components = array('RequestHandler', 'Scaler', 'Image', 'Paginator');
public function beforeFilter() {
parent::beforeFilter();
$canView = $this->Session->Read('eventPermission');
if ($canView =='None')
{
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
}
/**
* index method
*
@ -22,6 +33,18 @@ class EventsController extends AppController {
*/
public function index() {
$this->Event->recursive = -1;
$allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY);
if (!empty($allowedMonitors))
{
$mon_options = array('Event.MonitorId' => $allowedMonitors);
}
else
{
$mon_options='';
}
if ($this->request->params['named']) {
$this->FilterComponent = $this->Components->load('Filter');
@ -39,7 +62,7 @@ class EventsController extends AppController {
$this->Paginator->settings = array(
// https://github.com/ZoneMinder/ZoneMinder/issues/995
// 'limit' => $limit['ZM_WEB_EVENTS_PER_PAGE'],
// PP - 25 events per page which is what the above
// 25 events per page which is what the above
// default is, is way too low for an API
// changing this to 100 so we don't kill ZM
// with many event APIs. In future, we can
@ -49,14 +72,14 @@ class EventsController extends AppController {
'limit' => '100',
'order' => array('StartTime', 'MaxScore'),
'paramType' => 'querystring',
'conditions' => $conditions
'conditions' => array (array($conditions, $mon_options))
);
$events = $this->Paginator->paginate('Event');
// For each event, get its thumbnail data (path, width, height)
foreach ($events as $key => $value) {
// PP - $thumbData = $this->createThumbnail($value['Event']['Id']);
$thumbData ="";
//$thumbData = $this->createThumbnail($value['Event']['Id']);
$thumbData = "";
$events[$key]['thumbData'] = $thumbData;
}
@ -71,41 +94,55 @@ class EventsController extends AppController {
* @param string $id
* @return void
*/
public function view($id = null) {
$this->loadModel('Config');
$configs = $this->Config->find('list', array(
'fields' => array('Name', 'Value'),
'conditions' => array('Name' => array('ZM_DIR_EVENTS'))
));
public function view($id = null)
{
$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);
$this->Event->recursive = 1;
if (!$this->Event->exists($id)) {
throw new NotFoundException(__('Invalid event'));
}
$path = $configs['ZM_DIR_EVENTS'].'/'.$this->Image->getEventPath($event).'/';
$event['Event']['BasePath'] = $path;
$allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY);
# Get the previous and next events for any monitor
$this->Event->id = $id;
if (!empty($allowedMonitors))
{
$mon_options = array('Event.MonitorId' => $allowedMonitors);
}
else
{
$mon_options='';
}
$options = array('conditions' => array(array('Event.' . $this->Event->primaryKey => $id), $mon_options));
$event = $this->Event->find('first', $options);
$path = $configs['ZM_DIR_EVENTS'].'/'.$this->Image->getEventPath($event).'/';
$event['Event']['BasePath'] = $path;
# Get the previous and next events for any monitor
$this->Event->id = $id;
$event_neighbors = $this->Event->find('neighbors');
$event['Event']['Next'] = $event_neighbors['next']['Event']['Id'];
$event['Event']['Prev'] = $event_neighbors['prev']['Event']['Id'];
$event['Event']['Next'] = $event_neighbors['next']['Event']['Id'];
$event['Event']['Prev'] = $event_neighbors['prev']['Event']['Id'];
# Also get the previous and next events for the same monitor
$event_monitor_neighbors = $this->Event->find('neighbors', array(
# Also get the previous and next events for the same monitor
$event_monitor_neighbors = $this->Event->find('neighbors', array(
'conditions'=>array('Event.MonitorId'=>$event['Event']['MonitorId'])
));
$event['Event']['NextOfMonitor'] = $event_monitor_neighbors['next']['Event']['Id'];
$event['Event']['PrevOfMonitor'] = $event_monitor_neighbors['prev']['Event']['Id'];
));
$event['Event']['NextOfMonitor'] = $event_monitor_neighbors['next']['Event']['Id'];
$event['Event']['PrevOfMonitor'] = $event_monitor_neighbors['prev']['Event']['Id'];
$this->set(array(
'event' => $event,
'_serialize' => array('event')
));
}
$this->set(array(
'event' => $event,
'_serialize' => array('event')
));
}
/**
* add method
@ -113,6 +150,13 @@ class EventsController extends AppController {
* @return void
*/
public function add() {
if ($this->Session->Read('eventPermission') != 'Edit')
{
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
if ($this->request->is('post')) {
$this->Event->create();
if ($this->Event->save($this->request->data)) {
@ -131,6 +175,13 @@ class EventsController extends AppController {
* @return void
*/
public function edit($id = null) {
if ($this->Session->Read('eventPermission') != 'Edit')
{
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
$this->Event->id = $id;
if (!$this->Event->exists($id)) {
@ -157,15 +208,19 @@ class EventsController extends AppController {
* @return void
*/
public function delete($id = null) {
if ($this->Session->Read('eventPermission') != 'Edit')
{
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
$this->Event->id = $id;
if (!$this->Event->exists()) {
throw new NotFoundException(__('Invalid event'));
}
$this->request->allowMethod('post', 'delete');
if ($this->Event->delete()) {
// PP - lets make sure the frame table entry is removed too
$this->loadModel('Frame');
$this->Frame->delete();
//$this->loadModel('Frame');
//$this->Event->Frame->delete();
return $this->flash(__('The event has been deleted.'), array('action' => 'index'));
} else {
return $this->flash(__('The event could not be deleted. Please, try again.'), array('action' => 'index'));

View File

@ -101,7 +101,10 @@ class HostController extends AppController {
function getVersion() {
$version = Configure::read('ZM_VERSION');
$apiversion = Configure::read('ZM_API_VERSION');
// not going to use the ZM_API_VERSION
// requires recompilation and dependency on ZM upgrade
//$apiversion = Configure::read('ZM_API_VERSION');
$apiversion = '1.0';
$this->set(array(
'version' => $version,

View File

@ -16,6 +16,19 @@ class MonitorsController extends AppController {
*/
public $components = array('Paginator', 'RequestHandler');
public function beforeFilter() {
parent::beforeFilter();
$canView = $this->Session->Read('monitorPermission');
if ($canView =='None')
{
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
}
/**
* index method
*
@ -23,7 +36,17 @@ class MonitorsController extends AppController {
*/
public function index() {
$this->Monitor->recursive = 0;
$monitors = $this->Monitor->find('all');
$allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY);
if (!empty($allowedMonitors))
{
$options = array('conditions'=>array('Monitor.Id'=> $allowedMonitors));
}
else
{
$options='';
}
$monitors = $this->Monitor->find('all',$options);
$this->set(array(
'monitors' => $monitors,
'_serialize' => array('monitors')
@ -42,7 +65,21 @@ class MonitorsController extends AppController {
if (!$this->Monitor->exists($id)) {
throw new NotFoundException(__('Invalid monitor'));
}
$options = array('conditions' => array('Monitor.' . $this->Monitor->primaryKey => $id));
$allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY);
if (!empty($allowedMonitors))
{
$restricted = array('Monitor.' . $this->Monitor->primaryKey => $allowedMonitors);
}
else
{
$restricted = '';
}
$options = array('conditions' => array(
array('Monitor.' . $this->Monitor->primaryKey => $id),
$restricted
)
);
$monitor = $this->Monitor->find('first', $options);
$this->set(array(
'monitor' => $monitor,
@ -57,6 +94,13 @@ class MonitorsController extends AppController {
*/
public function add() {
if ($this->request->is('post')) {
if ($this->Session->Read('systemPermission') != 'Edit')
{
throw new UnauthotizedException(__('Insufficient privileges'));
return;
}
$this->Monitor->create();
if ($this->Monitor->save($this->request->data)) {
$this->daemonControl($this->Monitor->id, 'start', $this->request->data);
@ -78,7 +122,11 @@ class MonitorsController extends AppController {
if (!$this->Monitor->exists($id)) {
throw new NotFoundException(__('Invalid monitor'));
}
if ($this->Session->Read('systemPermission') != 'Edit')
{
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
if ($this->Monitor->save($this->request->data)) {
$message = 'Saved';
} else {
@ -89,9 +137,8 @@ class MonitorsController extends AppController {
'message' => $message,
'_serialize' => array('message')
));
// PP - restart this monitor after change
$this->daemonControl($this->Monitor->id, 'restart', $this->request->data);
// - restart this monitor after change
$this->daemonControl($this->Monitor->id, 'restart', $this->request->data);
}
/**
@ -106,6 +153,11 @@ class MonitorsController extends AppController {
if (!$this->Monitor->exists()) {
throw new NotFoundException(__('Invalid monitor'));
}
if ($this->Session->Read('systemPermission') != 'Edit')
{
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
$this->request->allowMethod('post', 'delete');
$this->daemonControl($this->Monitor->id, 'stop');

View File

@ -0,0 +1,31 @@
<?php
App::uses('AppModel', 'Model');
/**
* User Model
*
*/
class User extends AppModel {
/**
* Use table
*
* @var mixed False or table name
*/
public $useTable = 'Users';
/**
* Primary key field
*
* @var string
*/
public $primaryKey = 'Id';
/**
* Display field
*
* @var string
*/
public $displayField = 'Name';
}