Merge ../ZoneMinder.master into storageareas
This commit is contained in:
commit
b4c13d56d6
|
@ -31,9 +31,7 @@ install:
|
|||
|
||||
env:
|
||||
global:
|
||||
- DEB_BUILD_OPTIONS="parallel=4"
|
||||
- DEBUILD_LINTIAN="no"
|
||||
- SMPFLAGS="-j4"
|
||||
- SMPFLAGS=-j4
|
||||
matrix:
|
||||
- OS=el DIST=6
|
||||
- OS=el DIST=6 ARCH=i386 DOCKER_REPO=knnniggett/packpack
|
||||
|
|
|
@ -83,6 +83,10 @@ BuildRequires: libcurl-devel
|
|||
BuildRequires: libv4l-devel
|
||||
BuildRequires: ffmpeg-devel
|
||||
|
||||
# Required for mp4 container support
|
||||
BuildRequires: libmp4v2-devel
|
||||
BuildRequires: x264-devel
|
||||
|
||||
%{?with_nginx:Requires: nginx}
|
||||
%{?with_nginx:Requires: fcgiwrap}
|
||||
%{?with_nginx:Requires: php-fpm}
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
zoneminder (1.31.4-vivid1) vivid; urgency=medium
|
||||
|
||||
* Release 1.31.4
|
||||
|
||||
-- Isaac Connor <iconnor@tesla.com> Thu, 21 Sep 2017 09:55:31 -0700
|
||||
|
||||
|
||||
zoneminder (1.31.39~20180223.27-stretch-1) unstable; urgency=low
|
||||
*
|
||||
-- Isaac Connor <iconnor@connortechnology.com> Fri, 23 Feb 2018 14:15:59 -0500
|
||||
|
|
58
docs/api.rst
58
docs/api.rst
|
@ -98,15 +98,15 @@ This command will add a new http monitor.
|
|||
|
||||
::
|
||||
|
||||
curl -XPOST http://server/zm/api/monitors.json -d "Monitor[Name]=Cliff-Burton \
|
||||
&Monitor[Function]=Modect \
|
||||
&Monitor[Protocol]=http \
|
||||
&Monitor[Method]=simple \
|
||||
&Monitor[Host]=usr:pass@192.168.11.20 \
|
||||
&Monitor[Port]=80 \
|
||||
&Monitor[Path]=/mjpg/video.mjpg \
|
||||
&Monitor[Width]=704 \
|
||||
&Monitor[Height]=480 \
|
||||
curl -XPOST http://server/zm/api/monitors.json -d "Monitor[Name]=Cliff-Burton\
|
||||
&Monitor[Function]=Modect\
|
||||
&Monitor[Protocol]=http\
|
||||
&Monitor[Method]=simple\
|
||||
&Monitor[Host]=usr:pass@192.168.11.20\
|
||||
&Monitor[Port]=80\
|
||||
&Monitor[Path]=/mjpg/video.mjpg\
|
||||
&Monitor[Width]=704\
|
||||
&Monitor[Height]=480\
|
||||
&Monitor[Colours]=4"
|
||||
|
||||
Edit monitor 1
|
||||
|
@ -304,26 +304,26 @@ Create a Zone
|
|||
|
||||
::
|
||||
|
||||
curl -XPOST http://server/zm/api/zones.json -d "Zone[Name]=Jason-Newsted \
|
||||
&Zone[MonitorId]=3 \
|
||||
&Zone[Type]=Active \
|
||||
&Zone[Units]=Percent \
|
||||
&Zone[NumCoords]=4 \
|
||||
&Zone[Coords]=0,0 639,0 639,479 0,479 \
|
||||
&Zone[AlarmRGB]=16711680 \
|
||||
&Zone[CheckMethod]=Blobs \
|
||||
&Zone[MinPixelThreshold]=25 \
|
||||
&Zone[MaxPixelThreshold]= \
|
||||
&Zone[MinAlarmPixels]=9216 \
|
||||
&Zone[MaxAlarmPixels]= \
|
||||
&Zone[FilterX]=3 \
|
||||
&Zone[FilterY]=3 \
|
||||
&Zone[MinFilterPixels]=9216 \
|
||||
&Zone[MaxFilterPixels]=230400 \
|
||||
&Zone[MinBlobPixels]=6144 \
|
||||
&Zone[MaxBlobPixels]= \
|
||||
&Zone[MinBlobs]=1 \
|
||||
&Zone[MaxBlobs]= \
|
||||
curl -XPOST http://server/zm/api/zones.json -d "Zone[Name]=Jason-Newsted\
|
||||
&Zone[MonitorId]=3\
|
||||
&Zone[Type]=Active\
|
||||
&Zone[Units]=Percent\
|
||||
&Zone[NumCoords]=4\
|
||||
&Zone[Coords]=0,0 639,0 639,479 0,479\
|
||||
&Zone[AlarmRGB]=16711680\
|
||||
&Zone[CheckMethod]=Blobs\
|
||||
&Zone[MinPixelThreshold]=25\
|
||||
&Zone[MaxPixelThreshold]=\
|
||||
&Zone[MinAlarmPixels]=9216\
|
||||
&Zone[MaxAlarmPixels]=\
|
||||
&Zone[FilterX]=3\
|
||||
&Zone[FilterY]=3\
|
||||
&Zone[MinFilterPixels]=9216\
|
||||
&Zone[MaxFilterPixels]=230400\
|
||||
&Zone[MinBlobPixels]=6144\
|
||||
&Zone[MaxBlobPixels]=\
|
||||
&Zone[MinBlobs]=1\
|
||||
&Zone[MaxBlobs]=\
|
||||
&Zone[OverloadFrames]=0"
|
||||
|
||||
PTZ Control APIs
|
||||
|
|
33
docs/faq.rst
33
docs/faq.rst
|
@ -71,22 +71,22 @@ The 1.2 at the start is basically adding 20% on top of the calculation to accoun
|
|||
|
||||
The math breakdown for 4 cameras running at 1280x960 capture, 50 frame buffer, 24 bit color space:
|
||||
::
|
||||
1280*960 = 1,228,800 (bits)
|
||||
1,228,800 * 24 = 2,359,296,000 (bits)
|
||||
2,359,296,000 * 50 = 5,898,240,000 (bits)
|
||||
5,898,240,000 * 4 = 7,077,888,000 (bits)
|
||||
7,077,888,000 / 8 = 884,736,000 (bytes)
|
||||
884,736,000 / 1000 = 884,736 (Kilobytes)
|
||||
884,736 / 1000 = 864 (Megabytes)
|
||||
864 / 1000 = 0.9 (Gigabyte)
|
||||
1280*960 = 1,228,800 (bytes)
|
||||
1,228,800 * (3 bytes for 24 bit) = 3,686,400 (bytes)
|
||||
3,686,400 * 50 = 184,320,000 (bytes)
|
||||
184,320,000 * 4 = 737,280,000 (bytes)
|
||||
737,280,000 / 1024 = 720,000 (Kilobytes)
|
||||
720,000 / 1024 = 703.125 (Megabytes)
|
||||
703.125 / 1024 = 0.686 (Gigabytes)
|
||||
|
||||
Around 900MB of memory.
|
||||
Around 700MB of memory.
|
||||
|
||||
So if you have 2GB of memory, you should be all set. Right? **Not, really**:
|
||||
|
||||
* This is just the base memory required to capture the streams. Remember ZM is always capturing streams irrespective of whether you are actually recording or not - to make sure its image ring buffer is there with pre images when an alarm kicks in.
|
||||
* You also need to account for other processes not related to ZM running in your box
|
||||
* You also need to account for other ZM processes - for example, I noticed the audit daemon takes up a good amount of memory when it runs, DB updates also take up memory
|
||||
* If you are using H264 encoding, that buffers a lot of frames in memory as well.
|
||||
|
||||
So a good rule of thumb is to make sure you have twice the memory as the calculation above (and if you are using the ZM server for other purposes, please factor in those memory requirements as well)
|
||||
|
||||
|
@ -128,15 +128,14 @@ So, for example:
|
|||
::
|
||||
|
||||
384x288 capture resolution, that makes: 110 592 pixels
|
||||
in 24 bit color that's x24 = 2 654 208 bits per frame
|
||||
by 80 frames ring buffer x80 = 212 336 640 bits per camera
|
||||
by 4 cameras x4 = 849 346 560 bits.
|
||||
Plus 10% overhead = 934 281 216 bits
|
||||
That's 116 785 152 bytes, and
|
||||
= 114 048 kB, respectively 111.38 MB.
|
||||
If my shared memory is set to 134 217 728, which is exactly 128MB,
|
||||
in 24 bit color that's x 3 = 331,776 bytes per frame
|
||||
by 80 frames ring buffer x80 = 26,542,080 bytes per camera
|
||||
by 4 cameras x4 = 106,168,320 bytes.
|
||||
Plus 10% overhead = 116,785,152 bytes
|
||||
Thats 114,048 kB, respectively 111.38 MB.
|
||||
If my shared memory is set to 134,217,728, which is exactly 128MB,
|
||||
that means I shouldn't have any problem.
|
||||
(Note that 1 byte = 8 bits and 1kbyte = 1024bytes, 1MB = 1024 kB)
|
||||
(Note that 1kbyte = 1024bytes, 1MB = 1024 kB)
|
||||
|
||||
If for instance you were using 24bit 640x480 then this would come to about 92Mb if you are using the default buffer size of 100. If this is too large then you can either reduce the image or buffer sizes or increase the maximum amount of shared memory available. If you are using RedHat then you can get details on how to change these settings `here <http://www.redhat.com/docs/manuals/database/RHDB-2.1-Manual/admin_user/kernel-resources.html>`__
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
All Distros - A Simpler Way to Build ZoneMinder
|
||||
All Distros - A Docker Way to Build ZoneMinder
|
||||
===============================================
|
||||
|
||||
.. contents::
|
||||
|
@ -27,6 +27,8 @@ Procedure
|
|||
|
||||
- If the desired distro does not appear in either list, then unfortuantely you cannot use the procedure described here.
|
||||
|
||||
- If the desired distro architecture is arm, refer to `Appendix A - Enable Qemu On the Host`_ to enable qemu emulation on your amd64 host machine.
|
||||
|
||||
**Step 2:** Install Docker.
|
||||
|
||||
You need to have a working installation of Docker so head over to the `Docker site <https://docs.docker.com/engine/installation/>`_ and get it working. Before continuing to the next step, verify you can run the Docker "Hello World" container as a normal user. To run a Docker container as a normal user, issue the following:
|
||||
|
@ -99,7 +101,27 @@ For advanced users who really want to go out into uncharted waters, it is theore
|
|||
|
||||
Building arm packages in this manner has not been tested by us, however.
|
||||
|
||||
Appendix A - Enable Qemu On the Host
|
||||
------------------------------------
|
||||
|
||||
If you intend to build ZoneMinder packages for arm on an amd64 host, then Debian users can following these steps to enable transparent Qemu emulation:
|
||||
|
||||
::
|
||||
|
||||
sudo apt-get install binfmt-support qemu qemu-user-static
|
||||
|
||||
Verify arm emulation is enabled by issuing:
|
||||
|
||||
::
|
||||
|
||||
sudo update-binfmts --enable qemu-arm
|
||||
|
||||
You may get a message stating emulation for this processor is already enabled.
|
||||
|
||||
More testing needs to be done for Redhat distros but it appears Fedora users can just run:
|
||||
|
||||
::
|
||||
|
||||
sudo systemctl start systemd-binfmt
|
||||
|
||||
TO-DO: Verify the details behind enabling qemu emulation on redhat distros. Pull requests are welcome.
|
||||
|
|
|
@ -88,12 +88,12 @@ bool StreamBase::checkCommandQueue() {
|
|||
//Error( "Partial message received, expected %d bytes, got %d", sizeof(msg), nbytes );
|
||||
//}
|
||||
else {
|
||||
Debug(2, "Message length is (%d)", nbytes );
|
||||
Debug(2, "Message length is (%d)", nbytes );
|
||||
processCommand( &msg );
|
||||
return( true );
|
||||
}
|
||||
} else {
|
||||
Error("sd is < 0");
|
||||
Warning("No sd in checkCommandQueue, comms not open?");
|
||||
}
|
||||
return( false );
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
From 634281a4204467b9a3c8a1a5febcc8dd9828e0f6 Mon Sep 17 00:00:00 2001
|
||||
From: Andy Bauer <knnniggett@hotmail.com>
|
||||
Date: Thu, 22 Feb 2018 08:53:50 -0600
|
||||
Subject: [PATCH] don't run lintian checks to speed up build
|
||||
|
||||
---
|
||||
pack/deb.mk | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/pack/deb.mk b/pack/deb.mk
|
||||
index de4a0b7..bddf9df 100644
|
||||
--- a/packpack/pack/deb.mk
|
||||
+++ b/packpack/pack/deb.mk
|
||||
@@ -130,7 +130,7 @@ $(BUILDDIR)/$(DPKG_CHANGES): $(BUILDDIR)/$(PRODUCT)-$(VERSION)/debian \
|
||||
@echo "Building Debian packages"
|
||||
@echo "-------------------------------------------------------------------"
|
||||
cd $(BUILDDIR)/$(PRODUCT)-$(VERSION) && \
|
||||
- debuild --preserve-envvar CCACHE_DIR --prepend-path=/usr/lib/ccache \
|
||||
+ debuild --no-lintian --preserve-envvar CCACHE_DIR --prepend-path=/usr/lib/ccache \
|
||||
-Z$(TARBALL_COMPRESSOR) -uc -us $(SMPFLAGS)
|
||||
rm -rf $(BUILDDIR)/$(PRODUCT)-$(VERSION)/
|
||||
@echo "------------------------------------------------------------------"
|
|
@ -0,0 +1,57 @@
|
|||
From 62a98b36fd62d328956503bc9427ae128bb811af Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Bauer <zonexpertconsulting@outlook.com>
|
||||
Date: Mon, 26 Feb 2018 10:05:02 -0600
|
||||
Subject: [PATCH] fix 32bit rpm builds
|
||||
|
||||
---
|
||||
pack/rpm.mk | 2 +-
|
||||
packpack | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/packpack/pack/rpm.mk b/packpack/pack/rpm.mk
|
||||
index c74e942..9a6b016 100644
|
||||
--- a/packpack/pack/rpm.mk
|
||||
+++ b/packpack/pack/rpm.mk
|
||||
@@ -124,7 +124,7 @@ package: $(BUILDDIR)/$(RPMSRC)
|
||||
@echo "-------------------------------------------------------------------"
|
||||
@echo "Building RPM packages"
|
||||
@echo "-------------------------------------------------------------------"
|
||||
- rpmbuild \
|
||||
+ setarch $(ARCH) rpmbuild \
|
||||
--define '_topdir $(BUILDDIR)' \
|
||||
--define '_sourcedir $(BUILDDIR)' \
|
||||
--define '_specdir $(BUILDDIR)' \
|
||||
diff --git a/packpack/packpack b/packpack/packpack
|
||||
index 6f4c80f..c329399 100755
|
||||
--- a/packpack/packpack
|
||||
+++ b/packpack/packpack
|
||||
@@ -125,7 +125,7 @@ chmod a+x ${BUILDDIR}/userwrapper.sh
|
||||
#
|
||||
# Save defined configuration variables to ./env file
|
||||
#
|
||||
-env | grep -E "^PRODUCT=|^VERSION=|^RELEASE=|^ABBREV=|^TARBALL_|^CHANGELOG_|^CCACHE_|^PACKAGECLOUD_|^SMPFLAGS=|^OS=|^DIST=" \
|
||||
+env | grep -E "^PRODUCT=|^VERSION=|^RELEASE=|^ABBREV=|^TARBALL_|^CHANGELOG_|^CCACHE_|^PACKAGECLOUD_|^SMPFLAGS=|^OS=|^DIST=|^ARCH=" \
|
||||
> ${BUILDDIR}/env
|
||||
|
||||
#
|
||||
diff --git a/packpack/packpack b/packpack/packpack
|
||||
index c329399..6ffaa9c 100755
|
||||
--- a/packpack/packpack
|
||||
+++ b/packpack/packpack
|
||||
@@ -19,11 +19,11 @@ DOCKER_REPO=${DOCKER_REPO:-packpack/packpack}
|
||||
if [ -z "${ARCH}" ]; then
|
||||
# Use uname -m instead of HOSTTYPE
|
||||
case "$(uname -m)" in
|
||||
- i*86) ARCH="i386" ;;
|
||||
- arm*) ARCH="armhf" ;;
|
||||
- x86_64) ARCH="x86_64"; ;;
|
||||
- aarch64) ARCH="aarch64" ;;
|
||||
- *) ARCH="${HOSTTYPE}" ;;
|
||||
+ i*86) export ARCH="i386" ;;
|
||||
+ arm*) export ARCH="armhf" ;;
|
||||
+ x86_64) export ARCH="x86_64"; ;;
|
||||
+ aarch64) export ARCH="aarch64" ;;
|
||||
+ *) export ARCH="${HOSTTYPE}" ;;
|
||||
esac
|
||||
fi
|
||||
|
|
@ -108,6 +108,18 @@ commonprep () {
|
|||
patch -p1 < utils/packpack/packpack-rpm.patch
|
||||
fi
|
||||
|
||||
# Skip deb lintian checks to speed up the build
|
||||
patch --dry-run --silent -f -p1 < utils/packpack/nolintian.patch
|
||||
if [ $? -eq 0 ]; then
|
||||
patch -p1 < utils/packpack/nolintian.patch
|
||||
fi
|
||||
|
||||
# fix 32bit rpm builds
|
||||
patch --dry-run --silent -f -p1 < utils/packpack/setarch.patch
|
||||
if [ $? -eq 0 ]; then
|
||||
patch -p1 < utils/packpack/setarch.patch
|
||||
fi
|
||||
|
||||
# The rpm specfile requires we download the tarball and manually move it into place
|
||||
# Might as well do this for Debian as well, rather than git submodule init
|
||||
CRUDVER="3.0.10"
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
/* Add new API to retrieve camera controls - for PTZ */
|
||||
/* refer to https://github.com/ZoneMinder/ZoneMinder/issues/799#issuecomment-105233112 */
|
||||
Router::mapResources('controls');
|
||||
Router::mapResources('groups');
|
||||
Router::parseExtensions();
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,15 +4,24 @@ App::uses('AppController', 'Controller');
|
|||
* Groups Controller
|
||||
*
|
||||
* @property Group $Group
|
||||
* @property PaginatorComponent $Paginator
|
||||
*/
|
||||
class GroupsController extends AppController {
|
||||
|
||||
/**
|
||||
* Components
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $components = array('RequestHandler');
|
||||
public $components = array('Paginator', 'RequestHandler');
|
||||
|
||||
public function beforeFilter() {
|
||||
parent::beforeFilter();
|
||||
$canView = $this->Session->Read('groupsPermission');
|
||||
if ( $canView == 'None' ) {
|
||||
throw new UnauthorizedException(__('Insufficient Privileges'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* index method
|
||||
|
@ -55,6 +64,12 @@ class GroupsController extends AppController {
|
|||
*/
|
||||
public function add() {
|
||||
if ($this->request->is('post')) {
|
||||
|
||||
if ($this->Session->Read('groupPermission') != 'Edit') {
|
||||
throw new UnauthorizedException(__('Insufficient privileges'));
|
||||
return;
|
||||
}
|
||||
|
||||
$this->Group->create();
|
||||
if ($this->Group->save($this->request->data)) {
|
||||
return $this->flash(__('The group has been saved.'), array('action' => 'index'));
|
||||
|
@ -75,16 +90,26 @@ class GroupsController extends AppController {
|
|||
if (!$this->Group->exists($id)) {
|
||||
throw new NotFoundException(__('Invalid group'));
|
||||
}
|
||||
if ($this->request->is(array('post', 'put'))) {
|
||||
if ( $this->request->is(array('post', 'put'))) {
|
||||
if ( $this->Session->Read('groupPermission') != 'Edit' ) {
|
||||
throw new UnauthorizedException(__('Insufficient privileges'));
|
||||
return;
|
||||
}
|
||||
if ($this->Group->save($this->request->data)) {
|
||||
return $this->flash(__('The group has been saved.'), array('action' => 'index'));
|
||||
} else {
|
||||
$message = 'Error';
|
||||
}
|
||||
} else {
|
||||
$options = array('conditions' => array('Group.' . $this->Group->primaryKey => $id));
|
||||
$this->request->data = $this->Group->find('first', $options);
|
||||
}
|
||||
$monitors = $this->Group->Monitor->find('list');
|
||||
$this->set(compact('monitors'));
|
||||
$this->set(array(
|
||||
'message' => $message,
|
||||
'monitors'=> $monitors,
|
||||
'_serialize' => array('message',)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -100,9 +125,15 @@ class GroupsController extends AppController {
|
|||
throw new NotFoundException(__('Invalid group'));
|
||||
}
|
||||
$this->request->allowMethod('post', 'delete');
|
||||
if ( $this->Session->Read('groupPermission') != 'Edit' ) {
|
||||
throw new UnauthorizedException(__('Insufficient privileges'));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->Group->delete()) {
|
||||
return $this->flash(__('The group has been deleted.'), array('action' => 'index'));
|
||||
} else {
|
||||
return $this->flash(__('The group could not be deleted. Please, try again.'), array('action' => 'index'));
|
||||
}
|
||||
}}
|
||||
} // end function delete
|
||||
} // end class GroupController
|
||||
|
|
|
@ -4,6 +4,7 @@ App::uses('AppModel', 'Model');
|
|||
* Group Model
|
||||
*
|
||||
* @property Event $Event
|
||||
* @property Zone $Zone
|
||||
*/
|
||||
class Group extends AppModel {
|
||||
|
||||
|
@ -21,6 +22,15 @@ class Group extends AppModel {
|
|||
*/
|
||||
public $primaryKey = 'Id';
|
||||
|
||||
/**
|
||||
* Display field
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $displayField = 'Name';
|
||||
|
||||
public $recursive = -1;
|
||||
|
||||
/**
|
||||
* Validation rules
|
||||
*
|
||||
|
@ -30,6 +40,9 @@ class Group extends AppModel {
|
|||
'Name' => array(
|
||||
'notEmpty' => array(
|
||||
'rule' => array('notEmpty'),
|
||||
'Id' => array(
|
||||
'numeric' => array(
|
||||
'rule' => array('numeric'),
|
||||
//'message' => 'Your custom message here',
|
||||
//'allowEmpty' => false,
|
||||
//'required' => false,
|
||||
|
@ -39,7 +52,6 @@ class Group extends AppModel {
|
|||
),
|
||||
);
|
||||
|
||||
public $recursive = -1;
|
||||
//The Associations below have been created with all possible keys, those that are not needed can be removed
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
echo json_encode($message);
|
||||
echo json_encode($group);
|
|
@ -0,0 +1 @@
|
|||
echo json_encode($groups);
|
|
@ -0,0 +1 @@
|
|||
echo json_encode($group);
|
|
@ -0,0 +1,2 @@
|
|||
$xml = Xml::fromArray(array('response' => $message));
|
||||
echo $xml->asXML();
|
|
@ -0,0 +1,2 @@
|
|||
$xml = Xml::fromArray(array('response' => $groups));
|
||||
echo $xml->asXML();
|
|
@ -0,0 +1,2 @@
|
|||
$xml = Xml::fromArray(array('response' => $group));
|
||||
echo $xml->asXML();
|
|
@ -0,0 +1,230 @@
|
|||
<?php
|
||||
require_once( 'database.php' );
|
||||
require_once( 'Server.php' );
|
||||
|
||||
class Control {
|
||||
|
||||
private $defaults = array(
|
||||
'CanMove' => 0,
|
||||
'CanMoveDiag' => 0,
|
||||
'CanMoveMap' => 0,
|
||||
'CanMoveAbs' => 0,
|
||||
'CanMoveRel' => 0,
|
||||
'CanMoveCon' => 0,
|
||||
'CanPan' => 0,
|
||||
'MinPanRange' => NULL,
|
||||
'MaxPanRange' => NULL,
|
||||
'MinPanStep' => NULL,
|
||||
'MaxPanStep' => NULL,
|
||||
'HasPanSpeed' => 0,
|
||||
'MinPanSpeed' => NULL,
|
||||
'MaxPanSpeed' => NULL,
|
||||
'HasTurboPan' => 0,
|
||||
'TurboPanSpeed' => NULL,
|
||||
'CanTilt' => 0,
|
||||
'MinTiltRange' => NULL,
|
||||
'MaxTiltRange' => NULL,
|
||||
'MinTiltStep' => NULL,
|
||||
'MaxTiltStep' => NULL,
|
||||
'HasTiltSpeed' => 0,
|
||||
'MinTiltSpeed' => NULL,
|
||||
'MaxTiltSpeed' => NULL,
|
||||
'HasTurboTilt' => 0,
|
||||
'TurboTiltSpeed' => NULL,
|
||||
'CanZoom' => 0,
|
||||
'CanZoomAbs' => 0,
|
||||
'CanZoomRel' => 0,
|
||||
'CanZoomCon' => 0,
|
||||
'MinZoomRange' => NULL,
|
||||
'MaxZoomRange' => NULL,
|
||||
'MinZoomStep' => NULL,
|
||||
'MaxZoomStep' => NULL,
|
||||
'HasZoomSpeed' => 0,
|
||||
'MinZoomSpeed' => NULL,
|
||||
'MaxZoomSpeed' => NULL,
|
||||
'CanFocus' => 0,
|
||||
'CanAutoFocus' => 0,
|
||||
'CanFocusAbs' => 0,
|
||||
'CanFocusRel' => 0,
|
||||
'CanFocusCon' => 0,
|
||||
'MinFocusRange' => NULL,
|
||||
'MaxFocusRange' => NULL,
|
||||
'MinFocusStep' => NULL,
|
||||
'MaxFocusStep' => NULL,
|
||||
'HasFocusSpeed' => 0,
|
||||
'MinFocusSpeed' => NULL,
|
||||
'MaxFocusSpeed' => NULL,
|
||||
'CanIris' => 0,
|
||||
'CanAutoIris' => 0,
|
||||
'CanIrisAbs' => 0,
|
||||
'CanIrisRel' => 0,
|
||||
'CanIrisCon' => 0,
|
||||
'MinIrisRange' => NULL,
|
||||
'MaxIrisRange' => NULL,
|
||||
'MinIrisStep' => NULL,
|
||||
'MaxIrisStep' => NULL,
|
||||
'HasIrisSpeed' => 0,
|
||||
'MinIrisSpeed' => NULL,
|
||||
'MaxIrisSpeed' => NULL,
|
||||
'CanGain' => 0,
|
||||
'CanAutoGain' => 0,
|
||||
'CanGainAbs' => 0,
|
||||
'CanGainRel' => 0,
|
||||
'CanGainCon' => 0,
|
||||
'MinGainRange' => NULL,
|
||||
'MaxGainRange' => NULL,
|
||||
'MinGainStep' => NULL,
|
||||
'MaxGainStep' => NULL,
|
||||
'HasGainSpeed' => 0,
|
||||
'MinGainSpeed' => NULL,
|
||||
'MaxGainSpeed' => NULL,
|
||||
'CanWhite' => 0,
|
||||
'CanAutoWhite' => 0,
|
||||
'CanWhiteAbs' => 0,
|
||||
'CanWhiteRel' => 0,
|
||||
'CanWhiteCon' => 0,
|
||||
'MinWhiteRange' => NULL,
|
||||
'MaxWhiteRange' => NULL,
|
||||
'MinWhiteStep' => NULL,
|
||||
'MaxWhiteStep' => NULL,
|
||||
'HasWhiteSpeed' => 0,
|
||||
'MinWhiteSpeed' => NULL,
|
||||
'MaxWhiteSpeed' => NULL,
|
||||
'HasPresets' => 0,
|
||||
'NumPresets' => 0,
|
||||
'HasHomePreset' => 0,
|
||||
'CanSetPresets' => 0,
|
||||
'Name' => 'New',
|
||||
'Type' => 'Local',
|
||||
'Protocol' => NULL
|
||||
);
|
||||
|
||||
public function __construct( $IdOrRow = NULL ) {
|
||||
if ( $IdOrRow ) {
|
||||
$row = NULL;
|
||||
if ( is_integer( $IdOrRow ) or is_numeric( $IdOrRow ) ) {
|
||||
$row = dbFetchOne( 'SELECT * FROM Control WHERE Id=?', NULL, array( $IdOrRow ) );
|
||||
if ( ! $row ) {
|
||||
Error("Unable to load Control record for Id=" . $IdOrRow );
|
||||
}
|
||||
} elseif ( is_array( $IdOrRow ) ) {
|
||||
$row = $IdOrRow;
|
||||
} else {
|
||||
Error("Unknown argument passed to Control Constructor ($IdOrRow)");
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $row ) {
|
||||
foreach ($row as $k => $v) {
|
||||
$this->{$k} = $v;
|
||||
}
|
||||
} else {
|
||||
Error('No row for Control ' . $IdOrRow );
|
||||
}
|
||||
} # end if isset($IdOrRow)
|
||||
} // end function __construct
|
||||
|
||||
public function __call($fn, array $args){
|
||||
if ( count($args) ) {
|
||||
$this->{$fn} = $args[0];
|
||||
}
|
||||
if ( array_key_exists($fn, $this) ) {
|
||||
return $this->{$fn};
|
||||
#array_unshift($args, $this);
|
||||
#call_user_func_array( $this->{$fn}, $args);
|
||||
} else {
|
||||
if ( array_key_exists($fn, $this->control_fields) ) {
|
||||
return $this->control_fields{$fn};
|
||||
} else if ( array_key_exists( $fn, $this->defaults ) ) {
|
||||
return $this->defaults{$fn};
|
||||
} else {
|
||||
$backTrace = debug_backtrace();
|
||||
$file = $backTrace[1]['file'];
|
||||
$line = $backTrace[1]['line'];
|
||||
Warning( "Unknown function call Control->$fn from $file:$line" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function set( $data ) {
|
||||
foreach ($data as $k => $v) {
|
||||
if ( is_array( $v ) ) {
|
||||
# perhaps should turn into a comma-separated string
|
||||
$this->{$k} = implode(',',$v);
|
||||
} else if ( is_string( $v ) ) {
|
||||
$this->{$k} = trim( $v );
|
||||
} else if ( is_integer( $v ) ) {
|
||||
$this->{$k} = $v;
|
||||
} else if ( is_bool( $v ) ) {
|
||||
$this->{$k} = $v;
|
||||
} else {
|
||||
Error( "Unknown type $k => $v of var " . gettype( $v ) );
|
||||
$this->{$k} = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
public static function find_all( $parameters = null, $options = null ) {
|
||||
$filters = array();
|
||||
$sql = 'SELECT * FROM Controls ';
|
||||
$values = array();
|
||||
|
||||
if ( $parameters ) {
|
||||
$fields = array();
|
||||
$sql .= 'WHERE ';
|
||||
foreach ( $parameters as $field => $value ) {
|
||||
if ( $value == null ) {
|
||||
$fields[] = $field.' IS NULL';
|
||||
} else if ( is_array( $value ) ) {
|
||||
$func = function(){return '?';};
|
||||
$fields[] = $field.' IN ('.implode(',', array_map( $func, $value ) ). ')';
|
||||
$values += $value;
|
||||
|
||||
} else {
|
||||
$fields[] = $field.'=?';
|
||||
$values[] = $value;
|
||||
}
|
||||
}
|
||||
$sql .= implode(' AND ', $fields );
|
||||
}
|
||||
if ( $options and isset($options['order']) ) {
|
||||
$sql .= ' ORDER BY ' . $options['order'];
|
||||
}
|
||||
$result = dbQuery($sql, $values);
|
||||
$results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Control');
|
||||
foreach ( $results as $row => $obj ) {
|
||||
$filters[] = $obj;
|
||||
}
|
||||
return $filters;
|
||||
}
|
||||
|
||||
public function save( $new_values = null ) {
|
||||
|
||||
if ( $new_values ) {
|
||||
foreach ( $new_values as $k=>$v ) {
|
||||
$this->{$k} = $v;
|
||||
}
|
||||
}
|
||||
// Set default values
|
||||
foreach ( $this->defaults as $k=>$v ) {
|
||||
if ( ( ! array_key_exists( $k, $this ) ) or ( $this->{$k} == '' ) ) {
|
||||
$this->{$k} = $v;
|
||||
}
|
||||
}
|
||||
|
||||
$fields = array_keys( $this->defaults );
|
||||
|
||||
if ( array_key_exists( 'Id', $this ) ) {
|
||||
$sql = 'UPDATE Controls SET '.implode(', ', array_map( function($field) {return $field.'=?';}, $fields ) ) . ' WHERE Id=?';
|
||||
$values = array_map( function($field){return $this->{$field};}, $fields );
|
||||
$values[] = $this->{'Id'};
|
||||
dbQuery( $sql, $values );
|
||||
} else {
|
||||
$sql = 'INSERT INTO Controls SET '.implode(', ', array_map( function($field) {return $field.'=?';}, $fields ) ) . '';
|
||||
$values = array_map( function($field){return $this->{$field};}, $fields );
|
||||
dbQuery( $sql, $values );
|
||||
$this->{'Id'} = dbInsertId();
|
||||
}
|
||||
} // end function save
|
||||
|
||||
} // end class Control
|
||||
?>
|
|
@ -273,34 +273,12 @@ if ( !empty($_REQUEST['mid']) && canView( 'Control', $_REQUEST['mid'] ) ) {
|
|||
// Control capability actions, require control edit permissions
|
||||
if ( canEdit( 'Control' ) ) {
|
||||
if ( $action == 'controlcap' ) {
|
||||
if ( !empty($_REQUEST['cid']) ) {
|
||||
$control = dbFetchOne( 'SELECT * FROM Controls WHERE Id = ?', NULL, array($_REQUEST['cid']) );
|
||||
} else {
|
||||
$control = array();
|
||||
}
|
||||
require_once( 'Control.php' );
|
||||
$Control = new Control( !empty($_REQUEST['cid']) ? $_REQUEST['cid'] : null );
|
||||
|
||||
// Define a field type for anything that's not simple text equivalent
|
||||
$types = array(
|
||||
// Empty
|
||||
);
|
||||
|
||||
$columns = getTableColumns( 'Controls' );
|
||||
foreach ( $columns as $name=>$type ) {
|
||||
if ( preg_match( '/^(Can|Has)/', $name ) ) {
|
||||
$types[$name] = 'toggle';
|
||||
}
|
||||
}
|
||||
$changes = getFormChanges( $control, $_REQUEST['newControl'], $types, $columns );
|
||||
|
||||
if ( count( $changes ) ) {
|
||||
if ( !empty($_REQUEST['cid']) ) {
|
||||
dbQuery( 'update Controls set '.implode( ', ', $changes ).' where Id = ?', array($_REQUEST['cid']) );
|
||||
} else {
|
||||
dbQuery( 'insert into Controls set '.implode( ', ', $changes ) );
|
||||
//$_REQUEST['cid'] = dbInsertId();
|
||||
}
|
||||
$refreshParent = true;
|
||||
}
|
||||
//$changes = getFormChanges( $control, $_REQUEST['newControl'], $types, $columns );
|
||||
$Control->save( $_REQUEST['newControl'] );
|
||||
$refreshParent = true;
|
||||
$view = 'none';
|
||||
} elseif ( $action == 'delete' ) {
|
||||
if ( isset($_REQUEST['markCids']) ) {
|
||||
|
|
|
@ -633,6 +633,7 @@ function getFormChanges( $values, $newValues, $types=false, $columns=false ) {
|
|||
|
||||
if ( !isset($types[$key]) )
|
||||
$types[$key] = false;
|
||||
|
||||
switch( $types[$key] ) {
|
||||
case 'set' :
|
||||
{
|
||||
|
@ -694,6 +695,16 @@ function getFormChanges( $values, $newValues, $types=false, $columns=false ) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case 'toggle' :
|
||||
if ( (!isset($values[$key])) or $values[$key] != $value ) {
|
||||
if ( empty($value) ) {
|
||||
$changes[$key] = "$key = 0";
|
||||
} else {
|
||||
$changes[$key] = "$key = 0";
|
||||
//$changes[$key] = $key . ' = '.dbEscape(trim($value));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default :
|
||||
{
|
||||
if ( !isset($values[$key]) || ($values[$key] != $value) ) {
|
||||
|
|
|
@ -287,7 +287,7 @@ sortReverse: true
|
|||
warningPrefix: "",
|
||||
errorPrefix: ""
|
||||
});
|
||||
new Asset.css( "/css/spinner.css" );
|
||||
new Asset.css( "css/spinner.css" );
|
||||
fetchNextLogs();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue