Merge ../ZoneMinder.master into storageareas

This commit is contained in:
Isaac Connor 2018-03-06 12:29:59 -05:00
commit b4c13d56d6
23 changed files with 477 additions and 94 deletions

View File

@ -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

View File

@ -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}

View File

@ -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

View File

@ -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

View File

@ -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>`__

View File

@ -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.

View File

@ -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 );
}

View File

@ -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 "------------------------------------------------------------------"

View File

@ -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

View File

@ -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"

View File

@ -35,7 +35,8 @@
/* 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('controls');
Router::mapResources('groups');
Router::parseExtensions();
/**

View File

@ -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

View File

@ -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
/**

View File

@ -0,0 +1,2 @@
echo json_encode($message);
echo json_encode($group);

View File

@ -0,0 +1 @@
echo json_encode($groups);

View File

@ -0,0 +1 @@
echo json_encode($group);

View File

@ -0,0 +1,2 @@
$xml = Xml::fromArray(array('response' => $message));
echo $xml->asXML();

View File

@ -0,0 +1,2 @@
$xml = Xml::fromArray(array('response' => $groups));
echo $xml->asXML();

View File

@ -0,0 +1,2 @@
$xml = Xml::fromArray(array('response' => $group));
echo $xml->asXML();

230
web/includes/Control.php Normal file
View File

@ -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
?>

View File

@ -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']) ) {

View File

@ -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) ) {

View File

@ -287,7 +287,7 @@ sortReverse: true
warningPrefix: "",
errorPrefix: ""
});
new Asset.css( "/css/spinner.css" );
new Asset.css( "css/spinner.css" );
fetchNextLogs();
}