diff --git a/.eslintignore b/.eslintignore index 4682851df..91b0fd196 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,7 +4,7 @@ web/api/lib web/includes/csrf/ web/js/videojs.zoomrotate.js -web/skins/classic/js/bootstrap.js +web/skins/classic/js/bootstrap-4.5.0.js web/skins/classic/js/chosen web/skins/classic/js/dateTimePicker web/skins/classic/js/jquery-*.js diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 442033c50..d52f606a6 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -323,32 +323,32 @@ void Event::updateNotes(const StringSetMap &newNoteSetMap) { bool update = false; //Info( "Checking notes, %d <> %d", noteSetMap.size(), newNoteSetMap.size() ); - if ( newNoteSetMap.size() > 0 ) { - if ( noteSetMap.size() == 0 ) { + if (newNoteSetMap.size() > 0) { + if (noteSetMap.size() == 0) { noteSetMap = newNoteSetMap; update = true; } else { - for ( StringSetMap::const_iterator newNoteSetMapIter = newNoteSetMap.begin(); + for (StringSetMap::const_iterator newNoteSetMapIter = newNoteSetMap.begin(); newNoteSetMapIter != newNoteSetMap.end(); - ++newNoteSetMapIter ) { + ++newNoteSetMapIter) { const std::string &newNoteGroup = newNoteSetMapIter->first; const StringSet &newNoteSet = newNoteSetMapIter->second; //Info( "Got %d new strings", newNoteSet.size() ); - if ( newNoteSet.size() > 0 ) { + if (newNoteSet.size() > 0) { StringSetMap::iterator noteSetMapIter = noteSetMap.find(newNoteGroup); - if ( noteSetMapIter == noteSetMap.end() ) { - //Info( "Can't find note group %s, copying %d strings", newNoteGroup.c_str(), newNoteSet.size() ); + if (noteSetMapIter == noteSetMap.end()) { + //Debug(3, "Can't find note group %s, copying %d strings", newNoteGroup.c_str(), newNoteSet.size()); noteSetMap.insert(StringSetMap::value_type(newNoteGroup, newNoteSet)); update = true; } else { StringSet ¬eSet = noteSetMapIter->second; - //Info( "Found note group %s, got %d strings", newNoteGroup.c_str(), newNoteSet.size() ); - for ( StringSet::const_iterator newNoteSetIter = newNoteSet.begin(); + //Debug(3, "Found note group %s, got %d strings", newNoteGroup.c_str(), newNoteSet.size()); + for (StringSet::const_iterator newNoteSetIter = newNoteSet.begin(); newNoteSetIter != newNoteSet.end(); - ++newNoteSetIter ) { + ++newNoteSetIter) { const std::string &newNote = *newNoteSetIter; StringSet::iterator noteSetIter = noteSet.find(newNote); - if ( noteSetIter == noteSet.end() ) { + if (noteSetIter == noteSet.end()) { noteSet.insert(newNote); update = true; } diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 5e1ad605d..af9dd8639 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -141,7 +141,7 @@ bool EventStream::loadEventData(uint64_t event_id) { event_data->storage_id = dbrow[1] ? atoi(dbrow[1]) : 0; event_data->frame_count = dbrow[2] == nullptr ? 0 : atoi(dbrow[2]); event_data->start_time = SystemTimePoint(Seconds(atoi(dbrow[3]))); - event_data->end_time = dbrow[4] ? SystemTimePoint(Seconds(atoi(dbrow[4]))) : SystemTimePoint(); + event_data->end_time = dbrow[4] ? SystemTimePoint(Seconds(atoi(dbrow[4]))) : std::chrono::system_clock::now(); event_data->duration = std::chrono::duration_cast(event_data->end_time - event_data->start_time); event_data->frames_duration = std::chrono::duration_cast(dbrow[5] ? FPSeconds(atof(dbrow[5])) : FPSeconds(0.0)); diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 679ea27b7..81eacc956 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1862,8 +1862,6 @@ bool Monitor::Analyse() { Debug(3, "signal and active and modect"); Event::StringSet zoneSet; - int motion_score = last_motion_score; - if (analysis_fps_limit) { double capture_fps = get_capture_fps(); motion_frame_skip = capture_fps / analysis_fps_limit; @@ -1880,7 +1878,7 @@ bool Monitor::Analyse() { } else { Debug(1, "Detecting motion on image %d, image %p", snap->image_index, snap->image); // Get new score. - motion_score = DetectMotion(*(snap->image), zoneSet); + int motion_score = DetectMotion(*(snap->image), zoneSet); snap->zone_stats.reserve(zones.size()); for (const Zone &zone : zones) { @@ -1892,21 +1890,20 @@ bool Monitor::Analyse() { Debug(3, "After motion detection, score:%d last_motion_score(%d), new motion score(%d)", score, last_motion_score, motion_score); motion_frame_count += 1; - // Why are we updating the last_motion_score too? last_motion_score = motion_score; + if (motion_score) { + if (cause.length()) cause += ", "; + cause += MOTION_CAUSE; + noteSetMap[MOTION_CAUSE] = zoneSet; + } // end if motion_score } } else { Debug(1, "no image so skipping motion detection"); } // end if has image } else { - Debug(1, "Skipped motion detection last motion score was %d", motion_score); + Debug(1, "Skipped motion detection last motion score was %d", last_motion_score); } - if (motion_score) { - score += motion_score; - if (cause.length()) cause += ", "; - cause += MOTION_CAUSE; - noteSetMap[MOTION_CAUSE] = zoneSet; - } // end if motion_score + score += last_motion_score; } else { Debug(1, "Not Active(%d) enabled %d active %d doing motion detection: %d", Active(), enabled, shared_data->active, @@ -2007,7 +2004,7 @@ bool Monitor::Analyse() { } // end if ! event } // end if RECORDING - if (score and (function == MODECT or function == NODECT)) { + if (score and (function != MONITOR)) { if ((state == IDLE) || (state == TAPE) || (state == PREALARM)) { // If we should end then previous continuous event and start a new non-continuous event if (event && event->Frames() @@ -2142,7 +2139,8 @@ bool Monitor::Analyse() { shared_data->state = state = ((function != MOCORD) ? IDLE : TAPE); } else { Debug(1, - "State %s because image_count(%d)-last_alarm_count(%d) > post_event_count(%d) and timestamp.tv_sec(%" PRIi64 ") - recording.tv_src(%" PRIi64 ") >= min_section_length(%" PRIi64 ")", + "State %d %s because analysis_image_count(%d)-last_alarm_count(%d) > post_event_count(%d) and timestamp.tv_sec(%" PRIi64 ") - recording.tv_src(%" PRIi64 ") >= min_section_length(%" PRIi64 ")", + state, State_Strings[state].c_str(), analysis_image_count, last_alarm_count, @@ -2161,12 +2159,10 @@ bool Monitor::Analyse() { // Generate analysis images if necessary if ((savejpegs > 1) and snap->image) { for (const Zone &zone : zones) { - if (zone.Alarmed()) { - if (zone.AlarmImage()) { + if (zone.Alarmed() and zone.AlarmImage()) { if (!snap->analysis_image) snap->analysis_image = new Image(*(snap->image)); snap->analysis_image->Overlay(*(zone.AlarmImage())); - } } // end if zone is alarmed } // end foreach zone } // end if savejpegs diff --git a/web/ajax/events.php b/web/ajax/events.php index 4e364242a..090fe476e 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -67,20 +67,19 @@ if (isset($_REQUEST['sort'])) { // Offset specifies the starting row to return, used for pagination $offset = 0; -if ( isset($_REQUEST['offset']) ) { - if ( ( !is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']) ) ) { +if (isset($_REQUEST['offset'])) { + if ((!is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']))) { ZM\Error('Invalid value for offset: ' . $_REQUEST['offset']); } else { $offset = $_REQUEST['offset']; } } - // Limit specifies the number of rows to return // Set the default to 0 for events view, to prevent an issue with ALL pagination $limit = 0; -if ( isset($_REQUEST['limit']) ) { - if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) { +if (isset($_REQUEST['limit'])) { + if ((!is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']))) { ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']); } else { $limit = $_REQUEST['limit']; @@ -91,25 +90,24 @@ if ( isset($_REQUEST['limit']) ) { // MAIN LOOP // -switch ( $task ) { +switch ($task) { case 'archive' : - foreach ( $eids as $eid ) archiveRequest($task, $eid); + foreach ($eids as $eid) archiveRequest($task, $eid); break; case 'unarchive' : # The idea is that anyone can archive, but only people with Event Edit permission can unarchive.. - if ( !canEdit('Events') ) { + if (!canEdit('Events')) { ajaxError('Insufficient permissions for user '.$user['Username']); return; } - foreach ( $eids as $eid ) archiveRequest($task, $eid); + foreach ($eids as $eid) archiveRequest($task, $eid); break; case 'delete' : - if ( !canEdit('Events') ) { + if (!canEdit('Events')) { ajaxError('Insufficient permissions for user '.$user['Username']); return; } - - foreach ( $eids as $eid ) $data[] = deleteRequest($eid); + foreach ($eids as $eid) $data[] = deleteRequest($eid); break; case 'query' : $data = queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $limit); @@ -139,6 +137,8 @@ function deleteRequest($eid) { $message[] = array($eid=>'Event not found.'); } else if ( $event->Archived() ) { $message[] = array($eid=>'Event is archived, cannot delete it.'); + } else if (!$event->canEdit()) { + $message[] = array($eid=>'You do not have permission to delete event '.$event->Id()); } else { $event->delete(); } @@ -147,7 +147,6 @@ function deleteRequest($eid) { } function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $limit) { - $data = array( 'total' => 0, 'totalNotFiltered' => 0, @@ -156,7 +155,7 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim ); $failed = !$filter->test_pre_sql_conditions(); - if ( $failed ) { + if ($failed) { ZM\Debug('Pre conditions failed, not doing sql'); return $data; } @@ -171,7 +170,7 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim // The names of columns shown in the event view that are NOT dB columns in the database $col_alt = array('Monitor', 'Storage'); - if ( !in_array($sort, array_merge($columns, $col_alt)) ) { + if (!in_array($sort, array_merge($columns, $col_alt))) { ZM\Error('Invalid sort field: ' . $sort); $sort = 'Id'; } @@ -186,7 +185,7 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $storage_areas = ZM\Storage::find(); $StorageById = array(); - foreach ( $storage_areas as $S ) { + foreach ($storage_areas as $S) { $StorageById[$S->Id()] = $S; } @@ -195,41 +194,43 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim ZM\Debug('Calling the following sql query: ' .$sql); $query = dbQuery($sql, $values); - if ( $query ) { - while ( $row = dbFetchNext($query) ) { - $event = new ZM\Event($row); - $event->remove_from_cache(); - if ( !$filter->test_post_sql_conditions($event) ) { - continue; - } - $event_ids[] = $event->Id(); - $unfiltered_rows[] = $row; - } # end foreach row + if (!$query) { + ajaxError(dbError($sql)); + return; } + while ($row = dbFetchNext($query)) { + $event = new ZM\Event($row); + $event->remove_from_cache(); + if (!$filter->test_post_sql_conditions($event)) { + continue; + } + $event_ids[] = $event->Id(); + $unfiltered_rows[] = $row; + } # end foreach row ZM\Debug('Have ' . count($unfiltered_rows) . ' events matching base filter.'); $filtered_rows = null; - if ( count($advsearch) or $search != '' ) { + if (count($advsearch) or $search != '') { $search_filter = new ZM\Filter(); $search_filter = $search_filter->addTerm(array('cnj'=>'and', 'attr'=>'Id', 'op'=>'IN', 'val'=>$event_ids)); // There are two search bars in the log view, normal and advanced // Making an exuctive decision to ignore the normal search, when advanced search is in use // Alternatively we could try to do both - if ( count($advsearch) ) { + if (count($advsearch)) { $terms = array(); - foreach ( $advsearch as $col=>$text ) { + foreach ($advsearch as $col=>$text) { $terms[] = array('cnj'=>'and', 'attr'=>$col, 'op'=>'LIKE', 'val'=>$text); } # end foreach col in advsearch $terms[0]['obr'] = 1; $terms[count($terms)-1]['cbr'] = 1; $search_filter->addTerms($terms); - } else if ( $search != '' ) { + } else if ($search != '') { $search = '%' .$search. '%'; $terms = array(); - foreach ( $columns as $col ) { + foreach ($columns as $col) { $terms[] = array('cnj'=>'or', 'attr'=>$col, 'op'=>'LIKE', 'val'=>$search); } $terms[0]['obr'] = 1; diff --git a/web/ajax/modals/settings.php b/web/ajax/modals/settings.php index de42d6c87..e0bdf679c 100644 --- a/web/ajax/modals/settings.php +++ b/web/ajax/modals/settings.php @@ -38,7 +38,7 @@ if ($zmuOutput) { $ctls = shell_exec('v4l2-ctl -d '.$monitor->Device().' --list-ctrls'); if (!$ctls) { -ZM\Warning("Guessing v4l ctrls. We need v4l2-ctl please install it"); +ZM\Warning('Guessing v4l ctrls. We need v4l2-ctl please install it'); $ctls = ' brightness 0x00980900 (int) : min=-10 max=10 step=1 default=0 value=8 contrast 0x00980901 (int) : min=0 max=20 step=1 default=10 value=12 @@ -83,10 +83,15 @@ foreach ($ctls as $line) { } } + $label = translate($setting_uc); + if ($label == $setting_uc) { + $label = ucwords(str_replace('_', ' ', $label)); + } + if ($setting == 'brightness' or $setting == 'colour' or $setting == 'contrast' or $setting == 'hue') { echo ' - '.translate($setting_uc).' + '.$label.' '.$min.''.$max.' '; @@ -94,7 +99,7 @@ foreach ($ctls as $line) { if ($type == '(bool)') { echo ' - '.translate($setting_uc).' + '.$label.' '.html_radio('new'.$setting_uc, array('0'=>translate('True'), '1', translate('False')), $value, array('disabled'=>'disabled')).' @@ -102,14 +107,14 @@ foreach ($ctls as $line) { } else if ($type == '(int)') { echo ' - '.translate($setting_uc).' + '.$label.' '; } else { echo ' - '.translate($setting_uc).' + '.$label.' '.$value.' '; diff --git a/web/includes/database.php b/web/includes/database.php index 34ea384fa..01926a26e 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -112,7 +112,7 @@ function dbLog($sql, $update=false) { function dbError($sql) { global $dbConn; $error = $dbConn->errorInfo(); - if ( !$error[0] ) + if (!$error[0]) return ''; $message = "SQL-ERR '".implode("\n", $dbConn->errorInfo())."', statement was '".$sql."'"; @@ -130,17 +130,17 @@ function dbEscape( $string ) { function dbQuery($sql, $params=NULL, $debug = false) { global $dbConn; - if ( dbLog($sql, true) ) + if (dbLog($sql, true)) return; $result = NULL; try { - if ( isset($params) ) { - if ( ! $result = $dbConn->prepare($sql) ) { + if (isset($params)) { + if (!$result = $dbConn->prepare($sql)) { ZM\Error("SQL: Error preparing $sql: " . $pdo->errorInfo); return NULL; } - if ( ! $result->execute($params) ) { + if (!$result->execute($params)) { ZM\Error("SQL: Error executing $sql: " . print_r($result->errorInfo(), true)); return NULL; } diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index 9f6d34f75..6139ba3e4 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -35,12 +35,16 @@ var params = // Called by bootstrap-table to retrieve zm event data function ajaxRequest(params) { - if ( params.data && params.data.filter ) { + if (params.data && params.data.filter) { params.data.advsearch = params.data.filter; delete params.data.filter; } $j.getJSON(thisUrl + '?view=request&request=events&task=query'+filterQuery, params.data) .done(function(data) { + if (data.result == 'Error') { + alert(data.message); + return; + } var rows = processRows(data.rows); // rearrange the result into what bootstrap-table expects params.success({total: data.total, totalNotFiltered: data.totalNotFiltered, rows: rows}); diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 68ce50397..e4b2754ab 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -461,9 +461,12 @@ switch ( $name ) {
-10 Available Ids: - - + +