From 32f62a1d86942bea81b14a6f9bd42a674941bd28 Mon Sep 17 00:00:00 2001 From: Roelof Date: Mon, 7 May 2018 09:03:51 +0200 Subject: [PATCH 01/10] Edit gitignore --- .gitignore | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index a819620..46fd2be 100644 --- a/.gitignore +++ b/.gitignore @@ -8,11 +8,5 @@ src/statusjob/import_into_db.php *.log *.sql -test/index.php test/* - -.idea/Mdb.iml -.idea/vcs.xml -.idea/modules.xml -.idea/workspace.xml - +.idea/* From 48665725f9996aef98f1a6aed73c70dec998a055 Mon Sep 17 00:00:00 2001 From: Roelof Date: Mon, 7 May 2018 15:30:09 +0200 Subject: [PATCH 02/10] Minor edits - Updated nl language file - Updated en language file - Updated tickets views to accept values based on language files - Added topnav location searchbar - Changed logging to show different log files onclick - Added ticket external party table to database --- env.example.ini | 11 +- js/main.js | 17 +- src/.htaccess | 2 +- src/classes/class.ticket.php | 25 +- src/config/error_handler.php | 21 +- src/lang/en.json | 516 +++++++++++++++++++++++++++ src/lang/nl.json | 107 ++++-- src/logs/{ => 2018}/Errors/empty.php | 0 view/index.php | 11 +- view/layout/topnav.layout.php | 6 +- view/logging.view.php | 45 ++- view/logging/log.php | 26 +- view/settings.view.php | 14 +- view/ticket.view.php | 18 +- view/ticket/ticket_new.view.php | 164 ++++----- view/ticket/ticket_view.view.php | 72 ++-- view/user.view.php | 6 +- view/users.view.php | 12 +- 18 files changed, 850 insertions(+), 223 deletions(-) create mode 100644 src/lang/en.json rename src/logs/{ => 2018}/Errors/empty.php (100%) diff --git a/env.example.ini b/env.example.ini index 7821822..c974953 100644 --- a/env.example.ini +++ b/env.example.ini @@ -7,15 +7,20 @@ URL_ROOT_IMG = ROOT_PATH = SES_NAME = db_user ENV = CORE -VER = v1.3.1 +VER = 1.4.0 GOOGLE_API = -DEBUG = true +DEBUG = false [EVENTS] ENABLE_AUDIO = true ENABLE_GROUPED_EVENTS = true GROUPED_EVENTS = 5 GROUPED_EVENTS_WARNING = 10 GROUPED_EVENTS_DANGER = 20 +[MAPS] +ENABLE_GROUPED_LOCATIONS = true +GROUPED_LOCATIONS = 5 +GROUPED_LOCATIONS_WARNING = 15 +GROUPED_LOCATIONS_DANGER = 20 [SMTP] SMTP_HOST = SMTP_PORT = 25 @@ -24,12 +29,12 @@ HOST = USER = PASS = NAME = +LOGS = [SCS_DB] HOST = USER = PASS = NAME = -LOGS = [PORT_MONITOR] HOST = USER = diff --git a/js/main.js b/js/main.js index a77ed1f..cad07c9 100644 --- a/js/main.js +++ b/js/main.js @@ -5,12 +5,7 @@ */ $(document).ready(function () { - - $(".select2").select2({ - placeholder: 'Select...', - allowClear: true - }); - + var url = window.location; // Will only work if string in href matches with location $('ul.nav a[href="'+ url +'"]').parent().addClass('active'); @@ -30,9 +25,15 @@ $(document).ready(function () { lng: lang_code }, function (t){ $('#i18container').i18n(); - $('[data-toggle="tooltip"]').tooltip(); + $('[data-toggle="tooltip"]').tooltip(); + + // Init select2 dropdown with autocomplete and i18n support + $(".select2").select2({ + placeholder: i18n.t('placeholders.select'), + allowClear: true + }); }); - + // Add body-small class if window less than 768px if ($(this).width() < 769) { $('body').addClass('body-small'), diff --git a/src/.htaccess b/src/.htaccess index 0c17b3e..b627360 100644 --- a/src/.htaccess +++ b/src/.htaccess @@ -11,7 +11,7 @@ Allow from 127.0.0.1 ## RewriteRule ^(.+)$ index.php ## Only allow controller files and language files - + Order Deny,Allow Allow from all \ No newline at end of file diff --git a/src/classes/class.ticket.php b/src/classes/class.ticket.php index 6c80874..0cd52a8 100644 --- a/src/classes/class.ticket.php +++ b/src/classes/class.ticket.php @@ -70,11 +70,11 @@ public function ticketSaveUpdate($post_val) 'ticket_closed' => $gesloten, 'ticket_external_ticket_nr' => empty($post_val['ticketnr']) ? $row_wb['ticket_external_ticket_nr'] : $post_val['ticketnr'], 'ticket_extra_comment' => strip_tags($post_val['extra_comment_update']) , - 'ticket_status' => $this->setStatus($post_val, $row_wb) , + 'ticket_status' => $this->setStatus($post_val) , 'ticket_updates' => 1 ); - // Indien status Doorzetten + // Indien status Geannuleerd if ($post_val['status_update'] == "Geannuleerd") { $query_data['ticket_sub_status'] = $post_val['reden_geannuleerd']; @@ -86,12 +86,14 @@ public function ticketSaveUpdate($post_val) // Indien status Doorzetten if ($post_val['status_update'] == "Doorzetten") { - $query_data['ticket_extern'] = $post_val['doorzetten_naar']; + $door_naar = $conn->getOne("SELECT external_name FROM app_customer_tickets_external WHERE external_id = ?s",$post_val['doorzetten_naar']); + + $query_data['ticket_extern'] = $door_naar; $query_data['ticket_put_through'] = 1; - $query_data['ticket_put_through_too'] = $post_val['doorzetten_naar']; + $query_data['ticket_put_through_too'] = $door_naar; $msg_type = 'success'; $msg_title = 'Succes'; - $this->succesMessage .= "Werkbon doorgezet naar: " . $post_val['doorzetten_naar'] . "
"; + $this->succesMessage .= "Werkbon doorgezet naar: " . $door_naar . "
"; } // Indien status on hold @@ -187,7 +189,7 @@ public function ticketCreateNew($post_val) 'ticket_customer_scs' => substr(($post_val['OMS']) , -6) , 'ticket_customer_scsnr' => $post_val['OMS'], 'ticket_created_by' => $this->auth_user, - 'ticket_extern' => $post_val['extern'], + 'ticket_extern' => $conn->getOne("SELECT external_name FROM app_customer_tickets_external WHERE external_id = ?i",$post_val['extern']), 'ticket_service' => ucfirst($post_val['dienst']) , 'ticket_customer_region' => $post_val['regio'], 'ticket_created_date' => date("Y-m-d H:i:s") , @@ -558,7 +560,7 @@ protected function setStatusText($post_val, $row_wb = '') return $status_text; } - protected function setStatus($post_val, $row_wb = '') + protected function setStatus($post_val) { if ($post_val['status_update'] == "Geannuleerd") { @@ -595,6 +597,15 @@ protected function setStatus($post_val, $row_wb = '') return $status; } + protected function getStatusText($status_id) + { + $conn = $this->db_conn; + + $status_text = $conn->getOne("SELECT ticket_status_name FROM app_customer_tickets_status WHERE ticket_status_id = ?i", $$status_id); + + return $status_text; + } + protected function getTicketRow($db_conn, $post_id) { return $db_conn->getRow("SELECT * FROM app_customer_tickets WHERE ticket_id = ?i", $post_id); diff --git a/src/config/error_handler.php b/src/config/error_handler.php index 71dc63f..7e7a524 100644 --- a/src/config/error_handler.php +++ b/src/config/error_handler.php @@ -2,23 +2,22 @@ /* ========================================================================================================== - Name: Paperless Office custom error handler - Functie: - - Schrijft errors weg naar error.log indien debug in config.php uit staat. - - Geeft een user friendly Fatal error weer. - - Logged Fatal error in error.log file. + Functie: + - Writes errors too error.log if debug is FALSE in env.ini + - Shows user friendly error message if debug is TRUE in env.ini + - Log Fatal error too error.log file. - Version: 1.1.1 + Version: 1.2.0 Author: Roelof Jan van Golen - ========================================================================================================== */ error_reporting(E_ALL); - // Modify parse errors uit php.ini dmv APP_DEBUG - // indien APP_DEBUG = TRUE worden de errors in de applicatie weergegeven + // Modify parse errors from php.ini through APP_DEBUG + // if APP_DEBUG = TRUE errors are shown in application ini_set("display_errors", (APP_DEBUG === 1) ? 'on' : 'off'); - define('ERROR_LOG_FILE', ROOT_PATH.'/Src/Logs/Errors/'.date("Y-m-d").'_error.log'); + define('ERROR_LOG_FILE', ROOT_PATH.'/Src/Logs/'.date("Y").'/Errors/'.date("Y-m-d").'_error.log'); /** * Custom error handler @@ -151,8 +150,8 @@ function shutdown() { } } - if ($isError && APP_DEBUG !== 1){ - // Indien er een ajax call wordt uitgevoerd + if ($isError && APP_DEBUG !== 1){ + // If an ajax call is being proccesed if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') { $return = array(); $return['title'] = "Fatal error"; diff --git a/src/lang/en.json b/src/lang/en.json new file mode 100644 index 0000000..b79dcf9 --- /dev/null +++ b/src/lang/en.json @@ -0,0 +1,516 @@ +{ + "placeholders":{ + "select":"Select...", + "input":"Fill..." + }, + "layout":{ + "topnav":{ + "placeholder":"Search for location", + "logout":"Log out" + }, + "sidebar":{ + "title":{ + "1":"Home", + "2":"Tickets", + "3":"Tools", + "4":"User", + "5":"Users", + "6":"Logging", + "7":"Settings" + } + } + }, + "swal":{ + "confirm":{ + "title":"Are you sure?", + "confirmbutton":"Yes, i am sure", + "cancelbutton":"Cancel" + } + }, + "connection":{ + "conn": "Connected", + "diss": "Disconnected", + "back": "Backup connected", + "nopath": "No pathstatus", + "oos": "In service till", + "main_err": "Mainboard failure", + "batt_err": "Battery failure", + "230_err": "230v failure", + "multi_err": "Multiple failures" + }, + "error_page":{ + "return_btn":"Go back", + "403":{ + "label":"Access denied", + "msg":"Admin rights are mandatory for access. Contact the admins" + }, + "404":{ + "label":"Page not found", + "msg":"Sorry, but the page you are looking for can not be found. Check the URL for errors, refresh the page" + }, + "500":{ + "label":"Internal server error", + "msg":"The server encountered something unexpected that prevented the request from being completed. We apologise. You can return to the main page:" + }, + "denied":{ + "label":"Access denied", + "msg":"Admin rights are mandatory for access. Contact the admins" + }, + "maintenance":{ + "label":"Maintenance busy", + "msg":"Please have patience or ask for a status update with the admins" + } + }, + "error_msg":{ + "die":{ + "label":"Something definitely went wrong", + "msg":"Check the log files!" + }, + "csrf":{ + "label":"CSRF token is not valid", + "msg":"Check the browser URL and refresh the page!" + } + }, + "installscreen":{ + "welcome": "Welcome to", + "text": "This is your first time.", + "subtext": "Take the time to fill in the information below.", + "login": "Install", + "phpversion":{ + "err":"PHP version too low", + "msg":"Version 7.0.0 is a minimum requirement." + }, + "admin":{ + "txt": "Administrator setting", + "email": "Enter admin email address", + "pass": "Enter admin password", + "local": "Select location", + "lang": "Select the default language", + "msg":{ + "user": "Admin username", + "pass": "One-time password", + "store": "Write down the above password in a safe place" + } + }, + "app":{ + "txt": "Application setting", + "root": "URL root", + "docu": "Root folder", + "api": "Google API key" + }, + "scs":{ + "txt": "SCS connection", + "user": "Username", + "pass": "Password" + }, + "rms":{ + "txt": "RMS connection" + }, + "msg":{ + "fail": "Installation unsuccessful", + "try": "Try again", + "suc": "Installation successful" + } + }, + "loginscreen":{ + "welcome": "Welcome to", + "text": "An improved experience for the management of RMS and SCS.", + "subtext": "Please login to see it in action.", + "login": "Log in", + "placeholder": { + "email":"email", + "password":"password" + }, + "request": "Request", + "forget": "Forgot password" + }, + "tokenmsg":{ + "welcome": "Recover password", + "text": "Click the recover button", + "button": "Recover" + }, + "loginmsg":{ + "lck":{ + "label":"Account blocked", + "msg":"For 2 hours." + }, + "id":{ + "label":"Verification failed", + "msg":"Check your initials or password." + }, + "dev":{ + "label":"Error", + "msg":"No DEV account." + }, + "blc":{ + "label":"Error", + "msg":"User account is blocked. Contact the administrator." + }, + "uknw":{ + "label":"Error", + "msg":"User does not exist." + }, + "tok":{ + "suc":{ + "label":"Succesvol", + "msg":"Reset token requested." + }, + "err":{ + "label":"Reset token request failed", + "msg":"Mail not sent correctly
Request a new token or report this to an admin." + }, + "inv":{ + "label":"Token is invalid", + "msg":"Request a new one or report it to an admin." + }, + "uknw":{ + "label":"Token not found", + "msg":"Request a new one or report it to an admin." + }, + "exp":{ + "label":"Token expired", + "msg":"This is no longer usable. Request a new token." + } + }, + "res":{ + "suc": "Check your initials or password.", + "err": "Check your initials or password." + } + }, + "home":{ + "events":{ + "h5":"Events", + "day":{ + "label":"24h", + "small_label":"Since a day" + }, + "week":{ + "label":"Weekly", + "small_label":"Since a week" + }, + "month":{ + "label":"Monthly", + "small_label":"Since a month" + } + }, + "filters": "Filters", + "actions": { + "selectdefault": "Default", + "text": "Actions", + "mapzoom": "Set zoom level of map:", + "clusterzoom": "Cluster zoom level:", + "clustersize": "Cluster zoom size:", + "mapcontrols": "Map controls", + "buttons": { + "clear": "Clear clusters", + "refresh": "Refresh", + "center": "Center" + } + }, + "locations": { + "active": { + "label":"Active locations", + "table": { + "th1": "Connection", + "th2": "ID", + "th3": "Location", + "th4": "Last signal" + } + }, + "problem": { + "label":"Problem locations", + "table": { + "th1": "Connection", + "th2": "ID", + "th3": "Location", + "th4": "Last signal" + } + }, + "notactive": { + "label":"No pathstatus", + "table": { + "th1": "Connection", + "th2": "ID", + "th3": "Location", + "th4": "Last signal" + } + }, + "device": { + "label":"230v / ACCU storing", + "table": { + "th1": "Connection", + "th2": "ID", + "th3": "Location", + "th4": "Last signal" + } + } + } + }, + "location":{ + "connection": "Connection", + "status": "Status", + "address": "Address", + "zipcode": "Zipcode", + "city": "City", + "first": "First signal", + "last": "Last recieved signal", + "path": "Path status", + "mac": "MAC address", + "udid": "UDID nr", + "serie": "Serial nr", + "sim": "Simcard nr", + "serviceid": "ServiceID nr", + "lijn": "Line denomination", + "components":{ + "txt":"Location components", + "values":"Location values" + }, + "values":{ + "table": { + "txt":"Location values", + "th1": "Name", + "th2": "Values" + } + }, + "components":{ + "table": { + "txt":"Location components", + "th1": "Component", + "th2": "Count", + "th3": "Serial#", + "th4": "Installation date", + "th5": "Expiration date" + } + }, + "events":{ + "week":"Week", + "label":"Events this week", + "count":"Total events count" + }, + "tab":{ + "location":"Location", + "update":"Last updated", + "tab1":{ + "text":"Connection status", + "h3":"Path status", + "path_conn":"Connection", + "path_name":"Path", + "power":"230 volt", + "battery":"Battery" + }, + "tab2":{ + "text":"Poll delay", + "h3":"Poll delay count" + }, + "tab3":{ + "text":"Component status", + "h3":"Component status" + } + } + }, + "admin":{ + "h1":"Welcome admin", + "small":"Please wait" + }, + "user":{ + "title":"User", + "edit":{ + "title":"Edit user", + "button":"Update", + "input":{ + "1":"User name", + "2":"User last name", + "3":"User email" + } + }, + "acc_update":{ + "msg":{ + "update":{ + "label": "Success", + "text": "successfully updated" + }, + "err_email":{ + "label": "Something went wrong", + "text": "This is not a correct email address" + }, + "err_email_in_use":{ + "label": "Something went wrong", + "text": "This email address is already in use" + }, + "suc":{ + "label": "Success", + "text": "User account has been updated" + }, + "err":{ + "label": "Something went wrong", + "text": "Try again or contact the administrator" + } + } + } + }, + "users":{ + "title":"Users", + "edit":{ + "title":"Edit users", + "button":"Update", + "input":{ + "1":"Users name", + "2":"User lastname", + "3":"User email", + "4":"Users role", + "5":"Users status" + }, + "msg":{ + "del":{ + "label": "Success", + "text": "Successfully removed" + }, + "suc":{ + "label": "Success", + "text": "User account has been updated" + }, + "err":{ + "label": "Something went wrong", + "text": "Try again or contact the administrator" + } + } + }, + "new":{ + "title":"New user", + "button":"Create", + "msg":{ + "login_email":{ + "label": "Success", + "text": "Login email sent to", + "err": "Login email not sent" + }, + "suc":{ + "label": "Success", + "text": "User account has been updated" + }, + "err":{ + "label": "Something went wrong", + "text": "Try again or contact the administrator" + } + } + }, + "status":{ + "active":"Active", + "inactive":"Inactive" + }, + "actions":{ + "edit":"Edit", + "delete":"Delete" + }, + "table":{ + "th1":"Username", + "th2":"Email address", + "th3":"Last seen", + "th4":"User role", + "th5":"Status", + "th6":"ACtion" + }, + "swal":{ + "confirm":{ + "text":"The user: __placeholder__ will be permanently deleted!" + } + } + }, + "tickets":{ + "label":"Ticket", + "select":{ + "label":{ + "current":"Current status", + "on_hold":"On hold till", + "sent_to":"Sent too", + "external":"External parties", + "canceled":"Reason canceled", + "options":"Ticket options", + "actions":"Ticket actions" + } + }, + "status":{ + "aangevraagd":"Requested", + "open":"Open", + "on_hold":"On hold", + "totaal_uitval":"Totaal failure", + "gesloten":"Closed", + "geannuleerd":"Canceled", + "opnieuw_geopend":"Re-opened", + "opnieuw_verzenden":"Re-sent", + "doorzetten":"Push through", + "storing_hersteld":"Fault restored", + "ticket_onnodig":"Ticket unnecessary", + "ticket_foutief":"Incorrect ticket" + }, + "create":{ + "label":"Create a ticket", + "txt":{ + "scs":"SCS number", + "service":"Service", + "location":"Location", + "address":"Address", + "zipcode":"Zipcode", + "city":"City", + "for":"For", + "storing":"Malfunction", + "action":"Action", + "cp":"Contact", + "cptel":"Contact phone number", + "comment":"Extra comment" + }, + "malfunction":{ + "anders":"Different", + "1":"No linesync", + "2":"GPRS failure", + "3":"RAM failure", + "4":"Battery failure", + "5":"230v failure", + "6":"Router failure", + "7":"NVR comm failure", + "8":"Total failure" + } + }, + "update":{ + "submitted_by":"Created by", + "checked_by":"Checked by", + "status":"Status", + "updates":"Updates", + "ticket_for":"Ticket for", + "create":{ + "label":"Update ticket", + "external":"External ticket number", + "up_comm":"Update comment", + "up_status":"Update status" + } + }, + "filters":{ + "service":"Service (ALL)", + "external":"External (ALL)", + "status":"Status (ALL)" + }, + "table": { + "th1": "Ticket#", + "th2": "Location ID", + "th3": "Location name", + "th4": "Last update", + "th5": "Service", + "th6": "External party", + "th7": "Malfunction", + "th8": "Ticket number", + "th9": "Created on", + "th10": "Status" + }, + "buttons":{ + "new":"New", + "send":"Send", + "re_send":"Re-send", + "send_fast":"Send immediately", + "send_too":"Send too", + "update":"Update" + } + }, + "footer":{ + "copyright": "Copyright" + } +} \ No newline at end of file diff --git a/src/lang/nl.json b/src/lang/nl.json index f86e848..d100a2a 100644 --- a/src/lang/nl.json +++ b/src/lang/nl.json @@ -1,6 +1,11 @@ { + "placeholders":{ + "select":"Selecteer...", + "input":"Vul in..." + }, "layout":{ "topnav":{ + "placeholder":"Zoek naar locatie", "logout":"Uitloggen" }, "sidebar":{ @@ -37,7 +42,7 @@ "return_btn":"Ga terug", "403":{ "label":"Toegang geweigerd", - "msg":"Admin rechten zijn verplicht voor toegang. Neem contact op met de admins. Doeidoei!" + "msg":"Admin rechten zijn verplicht voor toegang. Neem contact op met de admins" }, "404":{ "label":"Pagina niet gevonden", @@ -49,7 +54,7 @@ }, "denied":{ "label":"Toegang geweigerd", - "msg":"Admin rechten zijn verplicht voor toegang. Neem contact op met de admins. Doeidoei!" + "msg":"Admin rechten zijn verplicht voor toegang. Neem contact op met de admins" }, "maintenance":{ "label":"Maintenance bezig", @@ -413,31 +418,62 @@ }, "tickets":{ "label":"Ticket", - "state":{ - "pending":"In afwachting", - "closed":"Gesloten" + "select":{ + "label":{ + "current":"Huidige status", + "on_hold":"On hold tot", + "sent_to":"Doorsturen naar", + "external":"Externe partij", + "canceled":"Reden geannuleerd", + "options":"Ticket opties", + "actions":"Ticket acties" + } + }, + "status":{ + "aangevraagd":"Aangevraagd", + "open":"Open", + "on_hold":"On hold", + "totaal_uitval":"Totaal uitval", + "gesloten":"Gesloten", + "geannuleerd":"Geannuleerd", + "opnieuw_geopend":"Opnieuw openen", + "opnieuw_verzenden":"Opnieuw verzenden", + "doorzetten":"Doorzetten", + "storing_hersteld":"Storing hersteld", + "ticket_onnodig":"Ticket onnodig", + "ticket_foutief":"Foutief ticket" }, "create":{ - "label":"Maak een ticket", - "placeholder":"Vul in...", - "dropdown":"Selecteer...", - "txt_scs":"SCS nummer", - "txt_service":"Service", - "txt_location":"Locatie", - "txt_address":"Adres", - "txt_zipcode":"Postcode", - "txt_city":"Stad", - "txt_for":"Voor", - "txt_storing":"Storing", - "txt_action":"Actie", - "txt_cp":"Contactpersoon", - "txt_cptel":"Contactpersoon tel nummer", - "txt_comment":"Extra commentaar" + "label":"Nieuw ticket", + "txt":{ + "scs":"SCS nummer", + "service":"Service", + "location":"Locatie", + "address":"Adres", + "zipcode":"Postcode", + "city":"Stad", + "for":"Voor", + "storing":"Storing", + "action":"ACtie", + "cp":"Contact", + "cptel":"Contact telefoon nummer", + "comment":"Extra commentaar" + }, + "malfunction":{ + "anders":"Anders", + "1":"Geen lijnsync", + "2":"GPRS uitval", + "3":"RAM uitval", + "4":"ACCU uitval", + "5":"230v uitval", + "6":"Router uitval", + "7":"NVR comm uitval", + "8":"Totaal uitval" + } }, - "update":{ - "placeholder":"Vul in...", + "update":{ "submitted_by":"Aangemaakt door", - "checked_by":"Gecontroleerd door", + "checked_by":"Gecontrolleerd door", "status":"Status", "updates":"Updates", "ticket_for":"Ticket voor", @@ -446,19 +482,32 @@ "external":"Extern ticket nummer", "up_comm":"Update commentaar", "up_status":"Update status" - } + } }, + "filters":{ + "service":"Service (ALL)", + "external":"Extern (ALL)", + "status":"Status (ALL)" + }, "table": { "th1": "Ticket#", "th2": "Locatie ID", - "th3": "Service", - "th4": "Laatste update", - "th5": "SLA", - "th6": "Status" + "th3": "Locatie naam", + "th4": "Laatst geupdatet", + "th5": "Dienst", + "th6": "Externe partij", + "th7": "Storing", + "th8": "Ticket nummer", + "th9": "Aangemaakt op", + "th10": "Status" }, "buttons":{ + "new":"Nieuw", "send":"Verzenden", - "update":"Updaten" + "re_send":"Opnieuw verzenden", + "send_fast":"Onmiddelijk verzenden", + "send_too":"Doorzetten naar", + "update":"Update" } }, "footer":{ diff --git a/src/logs/Errors/empty.php b/src/logs/2018/Errors/empty.php similarity index 100% rename from src/logs/Errors/empty.php rename to src/logs/2018/Errors/empty.php diff --git a/view/index.php b/view/index.php index 1b781b5..6268074 100644 --- a/view/index.php +++ b/view/index.php @@ -137,7 +137,16 @@ \ No newline at end of file diff --git a/view/logging/log.php b/view/logging/log.php index 27d844f..a6d747e 100644 --- a/view/logging/log.php +++ b/view/logging/log.php @@ -1,11 +1,27 @@ '; foreach($file as $text) { echo $text; diff --git a/view/settings.view.php b/view/settings.view.php index 277a3b6..0e9f58a 100644 --- a/view/settings.view.php +++ b/view/settings.view.php @@ -13,43 +13,43 @@
- +
- +
- +
- +
- +
- +
- +
diff --git a/view/ticket.view.php b/view/ticket.view.php index c29f0ba..1178d2f 100644 --- a/view/ticket.view.php +++ b/view/ticket.view.php @@ -12,7 +12,7 @@
- - - - - + + getAll("SELECT external_id, external_name FROM app_customer_tickets_external"); + foreach($externals as $external){ + echo ''; + } + ?>
diff --git a/view/ticket/ticket_new.view.php b/view/ticket/ticket_new.view.php index 15424ba..7d32c55 100644 --- a/view/ticket/ticket_new.view.php +++ b/view/ticket/ticket_new.view.php @@ -16,40 +16,40 @@
- - " data-inputmask="'mask': '99-99-999999'" maxlength="12" data-i18n="[placeholder]tickets.create.placeholder" > + + " data-inputmask="'mask': '99-99-999999'" maxlength="12" data-i18n="[placeholder]placeholders.input" >
- - + +
- - + +
- - + +
- - + +
- - + +
@@ -58,13 +58,15 @@
- - - - - - + getAll("SELECT external_id, external_name FROM app_customer_tickets_external"); + foreach($externals as $external){ + echo ''; + } + ?>
@@ -72,47 +74,45 @@
- +
- + + getAll("SELECT malfunctions_id, malfunctions_name FROM app_customer_tickets_malfunctions"); + foreach($ticket_mals as $ticket_mal){ + echo ''; + } + ?> +
- - + +
-
- +
+
- - + +
- - + +
-
- + +
- - + +
@@ -148,40 +148,17 @@ ?> \ No newline at end of file + + function Storing(val){ + var div_send_totaaluitval = document.getElementById('div_send_totaaluitval'), + div_send_button = document.getElementById('div_send_button'), + searchclear = document.getElementById('searchclear'); + + if(val=='Totale uitval') + $('#totaal_uitval').val(1), + div_send_totaaluitval.style.display='block', + div_send_button.style.display='none', + $('#header').removeClass('modal-header-info'), + $('#header').addClass('modal-header-warning'); + else if (val=='anders') + document.getElementById('storing_wijzigen').innerHTML = '', + searchclear.style.display='block', + div_send_totaaluitval.style.display='none', + div_send_button.style.display='block', + $('#header').removeClass('modal-header-warning'), + $('#header').addClass('modal-header-info'); + else + div_send_totaaluitval.style.display='none', + div_send_button.style.display='block', + $('#header').removeClass('modal-header-warning'), + $('#header').addClass('modal-header-info'); + } + \ No newline at end of file diff --git a/view/ticket/ticket_view.view.php b/view/ticket/ticket_view.view.php index baaf1d2..7650272 100644 --- a/view/ticket/ticket_view.view.php +++ b/view/ticket/ticket_view.view.php @@ -37,7 +37,7 @@
Submitted by door: Checked by: -

Ticket

+

Ticket

@@ -70,47 +70,47 @@
- +
- +
- +
- +
- +
@@ -143,9 +144,9 @@ - - - + + + @@ -203,7 +204,8 @@ } }); $('select[name="doorzetten_naar"]').on('change', function() { - $("#btn_externe_partij").html('Doorsturen naar: '+ this.value); + var text = i18n.t('tickets.select.label.sent_to'); + $("#btn_externe_partij").html(''+text + ' ' + this.value); }); function loadInfo(){ @@ -289,49 +291,49 @@ function getUrlParameter(sParam) { actie: { validators: { notEmpty: { - message: 'Vul het actie commentaar in' + } } }, extra_comment: { validators: { notEmpty: { - message: 'Vul het controle commentaar in' + } } }, status: { validators: { notEmpty: { - message: 'Wijzig de status' + } } }, extra_comment_update: { validators: { notEmpty: { - message: 'Vul update commentaar in' + } } }, status_update: { validators: { notEmpty: { - message: 'Wijzig de status' + } } }, reden_geannuleerd: { validators: { notEmpty: { - message: 'Vul de reden in' + } } }, doorzetten_naar: { validators: { notEmpty: { - message: 'Selecteer de externe partij' + } } } diff --git a/view/user.view.php b/view/user.view.php index 5da3f86..d33eaca 100644 --- a/view/user.view.php +++ b/view/user.view.php @@ -19,20 +19,20 @@
- +
- +
- +
diff --git a/view/users.view.php b/view/users.view.php index d27d2a2..5f1ecf7 100644 --- a/view/users.view.php +++ b/view/users.view.php @@ -43,19 +43,19 @@
- +
- +
- +
@@ -117,19 +117,19 @@
- +
- +
- +
From 57bb8b61a7536281d286ee141757d7f29f811f0c Mon Sep 17 00:00:00 2001 From: Roelof Date: Tue, 8 May 2018 14:17:22 +0200 Subject: [PATCH 03/10] Cleaned up request urls - Added router.php - Add main url request 'law' - Removed empty view folders --- .htaccess | 9 +- src/classes/class.login.php | 4 +- src/classes/class.ticket.php | 2 +- src/classes/class.user.php | 2 +- src/config/common.php | 52 ++--- src/{ => config}/file_package.php | 2 +- src/config/router.php | 89 ++++++++ src/{ => helpers}/functions.php | 17 +- src/{ => helpers}/scs_naw_get.json.php | 0 src/{ => helpers}/scs_naw_get_wb.json.php | 0 src/{ => helpers}/scs_naw_hint.json.php | 0 view/admin/empty.php | 2 - view/errors.view.php | 15 -- view/errors/page_403.php | 4 +- view/errors/page_404.php | 5 +- view/errors/page_500.php | 4 +- view/errors/page_denied.php | 4 +- view/errors/page_maintenance.php | 4 +- view/home/empty.php | 2 - view/home/google.js | 147 ------------- view/index.php | 207 +++--------------- view/layout/sidenav.layout.php | 14 +- view/location/empty.php | 2 - view/logging.view.php | 2 +- view/logging/empty.php | 2 - view/settings.view.php | 2 +- view/settings/empty.php | 2 - view/ticket.view.php | 2 +- .../{ticket_new.view.php => new.view.php} | 4 +- view/ticket/template.view.php | 69 ++++++ view/ticket/ticket_new/index.php.lnk | Bin 874 -> 0 bytes view/ticket/ticket_view/index.php.lnk | Bin 874 -> 0 bytes .../{ticket_view.view.php => view.view.php} | 6 +- .../ticket_view => }/ticket_info.view.php | 0 .../ticket_view => }/ticket_updates.view.php | 0 view/tools.view.php | 10 +- view/tools/events/index.php | 56 ----- view/tools/events_group/index.php | 56 ----- view/tools/graphs/index.php | 60 ----- view/tools/maps.view.php | 3 +- view/tools/maps/index.php | 79 ------- view/tools/port/index.php | 56 ----- view/tools/template.view.php | 84 +++++++ view/user.view.php | 1 - view/user/empty.php | 2 - view/user_model.view.php | 185 ++++++++++++++++ view/users.view.php | 3 +- view/users/empty.php | 2 - 48 files changed, 533 insertions(+), 740 deletions(-) rename src/{ => config}/file_package.php (98%) create mode 100644 src/config/router.php rename src/{ => helpers}/functions.php (95%) rename src/{ => helpers}/scs_naw_get.json.php (100%) rename src/{ => helpers}/scs_naw_get_wb.json.php (100%) rename src/{ => helpers}/scs_naw_hint.json.php (100%) delete mode 100644 view/admin/empty.php delete mode 100644 view/errors.view.php delete mode 100644 view/home/empty.php delete mode 100644 view/home/google.js delete mode 100644 view/location/empty.php delete mode 100644 view/logging/empty.php delete mode 100644 view/settings/empty.php rename view/ticket/{ticket_new.view.php => new.view.php} (99%) create mode 100644 view/ticket/template.view.php delete mode 100644 view/ticket/ticket_new/index.php.lnk delete mode 100644 view/ticket/ticket_view/index.php.lnk rename view/ticket/{ticket_view.view.php => view.view.php} (96%) rename view/{ticket/ticket_view => }/ticket_info.view.php (100%) rename view/{ticket/ticket_view => }/ticket_updates.view.php (100%) delete mode 100644 view/tools/events/index.php delete mode 100644 view/tools/events_group/index.php delete mode 100644 view/tools/graphs/index.php delete mode 100644 view/tools/maps/index.php delete mode 100644 view/tools/port/index.php create mode 100644 view/tools/template.view.php delete mode 100644 view/user/empty.php create mode 100644 view/user_model.view.php delete mode 100644 view/users/empty.php diff --git a/.htaccess b/.htaccess index 5df4a6e..397cae5 100644 --- a/.htaccess +++ b/.htaccess @@ -12,6 +12,13 @@ ErrorDocument 403 /mdb/View/Errors/page_403.php ErrorDocument 404 /mdb/View/Errors/page_404.php ErrorDocument 500 /mdb/View/Errors/page_500.php +RewriteEngine On + +RewriteCond %{REQUEST_FILENAME} !-d +RewriteCond %{REQUEST_FILENAME} !-f + +RewriteRule ^(.+)$ view/index.php/$1 [L] + ## order allow,deny @@ -33,5 +40,5 @@ DirectoryIndex index.php /mdb/View/ Order allow,deny Deny from all - + RedirectMatch 403 ^/src/.*$ diff --git a/src/classes/class.login.php b/src/classes/class.login.php index d460b99..476d9fc 100644 --- a/src/classes/class.login.php +++ b/src/classes/class.login.php @@ -696,11 +696,11 @@ public function redirectLogin() } elseif ($user_role == 1 && $connected) { - header("location: " . URL_ROOT . "/view/home/"); + header("location: " . URL_ROOT . "/home/"); } elseif ($user_role == 2 && $connected) { - header("location: " . URL_ROOT . "/view/home/"); + header("location: " . URL_ROOT . "/home/"); } else { diff --git a/src/classes/class.ticket.php b/src/classes/class.ticket.php index 0cd52a8..852b857 100644 --- a/src/classes/class.ticket.php +++ b/src/classes/class.ticket.php @@ -21,7 +21,7 @@ class Ticket function __construct($db_conn) { $this->db_conn = $db_conn; - $this->wb_link = URL_ROOT . "/view/ticket/ticket_view/?id="; + $this->wb_link = URL_ROOT."/ticket/view/?id="; $this->auth_user = htmlentities($_SESSION[SES_NAME]['user_email'], ENT_QUOTES, 'UTF-8'); // create new TCPDF document //$this->pdf = new MYPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); diff --git a/src/classes/class.user.php b/src/classes/class.user.php index faea375..19b44cb 100644 --- a/src/classes/class.user.php +++ b/src/classes/class.user.php @@ -421,7 +421,7 @@ public function getTable() 'dt' => 5, 'formatter' => function ($d, $row) { - $edit = "" . LANG['users']['actions']['edit'] . ""; + $edit = "" . LANG['users']['actions']['edit'] . ""; $dele = "" . LANG['users']['actions']['delete'] . ""; return $edit . ' ' . $dele; } diff --git a/src/config/common.php b/src/config/common.php index 4bd0ee8..2857d9d 100644 --- a/src/config/common.php +++ b/src/config/common.php @@ -33,10 +33,10 @@ { die("Failed to connect to the database: " . $ex->getMessage()); } - + $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - $db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); - + $db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); + define('LOGO_NAME', $env['APP']['LOGO_NAME']); define('FAVICON_NAME', $env['APP']['FAVICON_NAME']); define('URL_ROOT', $env['APP']['URL_ROOT']); @@ -94,10 +94,10 @@ // Make language file available as variable $lang = json_decode(file_get_contents(URL_ROOT.'/Src/lang/'.APP_LANG.'.json'), true); define('LANG',$lang); - + // Include file router - require ROOT_PATH.'/Src/file_package.php'; - + require ROOT_PATH.'/Src/config/file_package.php'; + // Function files foreach(ROOT_FILE['FUNC'] as $func){ require ROOT_PATH.$func; @@ -112,8 +112,9 @@ foreach(ROOT_FILE['CLASS'] as $class){ require ROOT_PATH.$class; } - - // Define function to get settings + + + // Define function to get settings from settings table function getSetting($db_conn, $setting_name){ $stmt = $db_conn->prepare("SELECT * FROM app_settings LIMIT 1"); $stmt->execute(); @@ -122,7 +123,7 @@ function getSetting($db_conn, $setting_name){ return $row[strtolower($setting_name)]; } - + // Function to allow dynamic include of class files function getClasses($path) { $class_arr = array(); @@ -166,40 +167,21 @@ function undo_magic_quotes_gpc(&$array) // Set header content header('Content-Type: text/html; charset=UTF-8'); - + // Start session - session_start(); + session_start(); - // DB connection with wrapper + // DB connection with SQL wrapper $db_conn = new SafeMySQL(); - // Set package const as variable + // Set CSS an JS package const as variable $arr_css = ROOT_CSS; $arr_js = ROOT_JS; + // Define router + require ROOT_PATH.'/Src/config/router.php'; //$user_db = new SafeMySQL(); //$user_ini = @htmlentities($_SESSION[SES_NAME]['user_id'], ENT_QUOTES, 'UTF-8'); //$user_cols = $user_db->getRow("SELECT * FROM app_users WHERE user_status = 'Active' AND user_id = ?i",$user_ini); - - // Get url and set view relative to view folder - $url_arr = parse_url($_SERVER['REQUEST_URI']); - - // Prevent access to errors and layout folders - if($url_arr['path'] == '/view/errors/' || $url_arr['path'] == '/view/layout/'){ - http_response_code(404); - include ROOT_PATH.'/view/errors/page_404.php'; - die(); - } else { - $urlarr = explode('/',$url_arr['path']); - if(count($urlarr) > 2){ - //array_shift($urlarr); - unset($urlarr[1]); - $view_url = implode('/',$urlarr); - //var_dump($view_url); - } - $view_content = preg_replace('{/$}', '.view.php', $view_url); - $view_basename = basename($view_url, '.view.php'); - } - - \ No newline at end of file + diff --git a/src/file_package.php b/src/config/file_package.php similarity index 98% rename from src/file_package.php rename to src/config/file_package.php index 972fe67..c425419 100644 --- a/src/file_package.php +++ b/src/config/file_package.php @@ -31,7 +31,7 @@ // Helper functions 'FUNC' => array ( 'error_handler' => '/Src/Config/error_handler.php', - 'functions' => '/Src/functions.php', + 'functions' => '/Src/helpers/functions.php', ), // Classes diff --git a/src/config/router.php b/src/config/router.php new file mode 100644 index 0000000..a0caa7c --- /dev/null +++ b/src/config/router.php @@ -0,0 +1,89 @@ + 4){ + //array_shift($urlarr); + unset($urlarr[1]); + $view_url = implode('/',$urlarr); + //var_dump($view_url); + } else { + $view_url = implode('/',$urlarr); + } + + // Prevent access to errors and layout folders + if($url_arr['path'] == '/view/errors/' || $url_arr['path'] == '/view/layout/') { + http_response_code(404); + include ROOT_PATH . '/view/errors/page_404.php'; + die(); + } elseif(in_array($view_url,$admin_only) && htmlentities($_SESSION[SES_NAME]['user_role'], ENT_QUOTES, 'UTF-8') != 1){ + // prevent access to defined admin views + http_response_code(403); + include ROOT_PATH . '/view/errors/page_403.php'; + die(); + } else { + // view variable + $view_content = preg_replace('{/$}', '.view.php', $view_url); + // variable to allow dynamic basename in views + $view_basename = basename($view_url, '.view.php'); + } + */ + + // Define admin only views + $admin_only = array( + 'admin', + 'logging', + 'users', + 'settings' + ); + // Main routing law + $url = isset($_SERVER['PATH_INFO']) ? explode('/', ltrim($_SERVER['PATH_INFO'],'/')) : '/'; + + if ($url == '/') + { + // This is the home page + // Initiate the home controller + // and render the home view + } else { + + // This is not home page + // Initiate the appropriate controller + // and render the required view + + //The first element should be a controller + $requestedController = $url[0]; + + // If a second part is added in the URI, + // it should be a method + $requestedAction = isset($url[1]) ? $url[1] : ''; + + // The remain parts are considered as + // arguments of the method + $requestedParams = array_slice($url, 2); + + // Check if controller exists. NB: + // You have to do that for the model and the view too + $ctrlPath = ROOT_PATH . '/view/' . $requestedController . '.view.php'; + + if(checkUserIsAdmin() && in_array($requestedController, $admin_only)) { + + http_response_code(403); + include ROOT_PATH . '/view/errors/page_403.php'; + die(); + + } elseif (file_exists($ctrlPath)) { + + $view_content = '/view/' . $requestedController . '.view.php'; + $view_basename = $requestedController; + + } else { + + http_response_code(404); + include ROOT_PATH . '/view/errors/page_404.php'; + die(); + //require the 404 controller and initiate it + //Display its view + } + } \ No newline at end of file diff --git a/src/functions.php b/src/helpers/functions.php similarity index 95% rename from src/functions.php rename to src/helpers/functions.php index 7014c77..11b6e4d 100644 --- a/src/functions.php +++ b/src/helpers/functions.php @@ -22,7 +22,22 @@ ========================================================================================================== */ - function setEmailTemplate($arr_val, $template_name){ + function checkUserIsAdmin() + { + $user_db = new SafeMySQL(); + + $user_id = htmlentities($_SESSION[SES_NAME]['user_id'], ENT_QUOTES, 'UTF-8'); + + if($user_db->getRow("SELECT user_id FROM app_users WHERE user_status = 'Active' AND user_id = ?s",$user_id)){ + return true; + } else { + return false; + } + + } + + function setEmailTemplate($arr_val, $template_name) + { $template = file_get_contents(URL_ROOT.'/view/email_temp/'.$template_name); foreach($arr_val as $key => $value){ diff --git a/src/scs_naw_get.json.php b/src/helpers/scs_naw_get.json.php similarity index 100% rename from src/scs_naw_get.json.php rename to src/helpers/scs_naw_get.json.php diff --git a/src/scs_naw_get_wb.json.php b/src/helpers/scs_naw_get_wb.json.php similarity index 100% rename from src/scs_naw_get_wb.json.php rename to src/helpers/scs_naw_get_wb.json.php diff --git a/src/scs_naw_hint.json.php b/src/helpers/scs_naw_hint.json.php similarity index 100% rename from src/scs_naw_hint.json.php rename to src/helpers/scs_naw_hint.json.php diff --git a/view/admin/empty.php b/view/admin/empty.php deleted file mode 100644 index 86ad6de..0000000 --- a/view/admin/empty.php +++ /dev/null @@ -1,2 +0,0 @@ - -
-
-
-

- Welcome in INSPINIA Static SeedProject -

- - It is an application skeleton for a typical web app. You can use it to quickly bootstrap your webapp projects and dev environment for these projects. - -
-
-
-
\ No newline at end of file diff --git a/view/errors/page_403.php b/view/errors/page_403.php index 0f2c3ec..2d3b881 100644 --- a/view/errors/page_403.php +++ b/view/errors/page_403.php @@ -12,7 +12,7 @@ '; } ?> @@ -36,7 +36,7 @@ '; } ?> diff --git a/view/errors/page_404.php b/view/errors/page_404.php index 9b9a111..39fa3fa 100644 --- a/view/errors/page_404.php +++ b/view/errors/page_404.php @@ -12,9 +12,10 @@ '; } + ?> @@ -36,7 +37,7 @@ '; } ?> diff --git a/view/errors/page_500.php b/view/errors/page_500.php index ea4753a..cc52348 100644 --- a/view/errors/page_500.php +++ b/view/errors/page_500.php @@ -12,7 +12,7 @@ '; } ?> @@ -37,7 +37,7 @@ '; } ?> diff --git a/view/errors/page_denied.php b/view/errors/page_denied.php index f729087..134a31a 100644 --- a/view/errors/page_denied.php +++ b/view/errors/page_denied.php @@ -13,7 +13,7 @@ '; } ?> @@ -36,7 +36,7 @@ '; } ?> diff --git a/view/errors/page_maintenance.php b/view/errors/page_maintenance.php index 4bc810f..c3c349c 100644 --- a/view/errors/page_maintenance.php +++ b/view/errors/page_maintenance.php @@ -12,7 +12,7 @@ '; } ?> @@ -48,7 +48,7 @@ function getRandomArr($ar){ '; } ?> diff --git a/view/home/empty.php b/view/home/empty.php deleted file mode 100644 index 86ad6de..0000000 --- a/view/home/empty.php +++ /dev/null @@ -1,2 +0,0 @@ -<' + '/script>'); - } - - var modules = google.maps.modules = {}; - google.maps.__gjsload__ = function(name, text) { - modules[name] = text; - }; - - google.maps.Load = function(apiLoad) { - delete google.maps.Load; - apiLoad([0.009999999776482582,[null,[["https://khms0.googleapis.com/kh?v=781\u0026hl=nl-NL\u0026","https://khms1.googleapis.com/kh?v=781\u0026hl=nl-NL\u0026"],null,null,null,1,"781",["https://khms0.google.com/kh?v=781\u0026hl=nl-NL\u0026","https://khms1.google.com/kh?v=781\u0026hl=nl-NL\u0026"]],null,null,null,null,[["https://cbks0.googleapis.com/cbk?","https://cbks1.googleapis.com/cbk?"]],[["https://khms0.googleapis.com/kh?v=113\u0026hl=nl-NL\u0026","https://khms1.googleapis.com/kh?v=113\u0026hl=nl-NL\u0026"],null,null,null,null,"113",["https://khms0.google.com/kh?v=113\u0026hl=nl-NL\u0026","https://khms1.google.com/kh?v=113\u0026hl=nl-NL\u0026"]],[["https://mts0.googleapis.com/mapslt?hl=nl-NL\u0026","https://mts1.googleapis.com/mapslt?hl=nl-NL\u0026"]],null,null,null,[["https://mts0.googleapis.com/mapslt?hl=nl-NL\u0026","https://mts1.googleapis.com/mapslt?hl=nl-NL\u0026"]]],["nl-NL","US",null,0,null,null,"https://maps.gstatic.com/mapfiles/","https://csi.gstatic.com","https://maps.googleapis.com","https://maps.googleapis.com",null,"https://maps.google.com","https://gg.google.com","https://maps.gstatic.com/maps-api-v3/api/images/","https://www.google.com/maps",0,"https://www.google.com"],["https://maps.googleapis.com/maps-api-v3/api/js/32/4a/intl/nl_ALL","3.32.4a"],[3405116937],1,null,null,null,null,null,"",null,null,1,"https://khms.googleapis.com/mz?v=781\u0026","AIzaSyC2ST2bk9ulQdZqwC3nM73G0aFaJJGtJNI","https://earthbuilder.googleapis.com","https://earthbuilder.googleapis.com",null,"https://mts.googleapis.com/maps/vt/icon",[["https://maps.googleapis.com/maps/vt"],["https://maps.googleapis.com/maps/vt"],null,null,null,null,null,null,null,null,null,null,["https://www.google.com/maps/vt"],"/maps/vt",413000000,413],2,500,[null,null,null,null,"https://www.google.com/maps/preview/log204","","https://static.panoramio.com.storage.googleapis.com/photos/",["https://geo0.ggpht.com/cbk","https://geo1.ggpht.com/cbk","https://geo2.ggpht.com/cbk","https://geo3.ggpht.com/cbk"],"https://maps.googleapis.com/maps/api/js/GeoPhotoService.GetMetadata","https://maps.googleapis.com/maps/api/js/GeoPhotoService.SingleImageSearch",["https://lh3.ggpht.com/","https://lh4.ggpht.com/","https://lh5.ggpht.com/","https://lh6.ggpht.com/"]],null,null,null,null,"/maps/api/js/ApplicationService.GetEntityDetails",0,null,null,[null,null,null,null,null,null,null,null,null,[0,0]],null,[],["32.4a"]], loadScriptTime); - }; - var loadScriptTime = (new Date).getTime(); -})(); -// inlined -(function(_){var ta,xa,za,Ba,Ca,Oa,Pa,bb,hb,ib,kb,pb,ob,qb,rb,Ib,Lb,Pb,Xb,Zb,ac,kc,oc,sc,Fc,Gc,Hc,Ic,Kc,Qc,Tc,Wc,Sc,Xc,$c,ed,md,od,qd,ud,vd,Dd,Fd,Ed,Pd,Rd,Td,Wd,Xd,Zd,ae,ce,Yd,$d,ee,ge,me,ne,Ce,De,Ee,Ge,He,Je,Ke,Oe,Pe,Te,Ue,Xe,Ze,$e,jf,kf,lf,mf,nf,of,pf,rf,sf,vf,Af,Ff,Hf,Of,Pf,Qf,Xf,$f,ag,bg,cg,dg,eg,fg,Fg,Gg,Ig,Kg,Lg,Mg,Sg,Qg,Tg,Ug,Wg,Zg,ah,$g,ch,gh,ih,th,uh,xh,yh,zh,Ah,Bh,Dh,wa,va,La,Ma;_.aa="ERROR";_.ba="INVALID_REQUEST";_.ca="MAX_DIMENSIONS_EXCEEDED";_.da="MAX_ELEMENTS_EXCEEDED";_.ea="MAX_WAYPOINTS_EXCEEDED"; -_.fa="NOT_FOUND";_.ha="OK";_.ia="OVER_QUERY_LIMIT";_.ja="REQUEST_DENIED";_.ka="UNKNOWN_ERROR";_.la="ZERO_RESULTS";_.ma=function(){return function(a){return a}};_.l=function(){return function(){}};_.na=function(a){return function(b){this[a]=b}};_.pa=function(a){return function(){return this[a]}};_.qa=function(a){return function(){return a}};_.sa=function(a){return function(){return _.ra[a].apply(this,arguments)}};ta=function(){ta=_.l();_.ua.Symbol||(_.ua.Symbol=va)}; -_.ya=function(){ta();var a=_.ua.Symbol.iterator;a||(a=_.ua.Symbol.iterator=_.ua.Symbol("iterator"));"function"!=typeof Array.prototype[a]&&wa(Array.prototype,a,{configurable:!0,writable:!0,value:function(){return xa(this)}});_.ya=_.l()};xa=function(a){var b=0;return za(function(){return bc?Math.max(0,a.length+c):c;if(_.Da(a))return _.Da(b)&&1==b.length?a.indexOf(b,c):-1;for(;c=arguments.length?Array.prototype.slice.call(a,b):Array.prototype.slice.call(a,b,c)};_.Xa=function(){return-1!=_.Wa.toLowerCase().indexOf("webkit")}; -_.Ya=function(a){return-1!=_.Wa.indexOf(a)};_.Za=function(a,b,c){for(var d in a)b.call(c,a[d],d,a)};_.ab=function(){return _.Ya("Trident")||_.Ya("MSIE")};_.cb=function(){return _.Ya("Safari")&&!(bb()||_.Ya("Coast")||_.Ya("Opera")||_.Ya("Edge")||_.Ya("Silk")||_.Ya("Android"))};bb=function(){return(_.Ya("Chrome")||_.Ya("CriOS"))&&!_.Ya("Edge")};_.db=function(){return _.Ya("Android")&&!(bb()||_.Ya("Firefox")||_.Ya("Opera")||_.Ya("Silk"))};_.eb=function(){return _.Ya("iPhone")&&!_.Ya("iPod")&&!_.Ya("iPad")}; -_.fb=function(a){_.fb[" "](a);return a};hb=function(){var a=_.gb.document;return a?a.documentMode:void 0};ib=function(a,b){this.j=a;this.l=b;this.f=0;this.b=null};_.jb=_.ma();kb=function(a){_.gb.setTimeout(function(){throw a;},0)};pb=function(){var a=_.lb.f;a=mb(a);!_.Ja(_.gb.setImmediate)||_.gb.Window&&_.gb.Window.prototype&&!_.Ya("Edge")&&_.gb.Window.prototype.setImmediate==_.gb.setImmediate?(nb||(nb=ob()),nb(a)):_.gb.setImmediate(a)}; -ob=function(){var a=_.gb.MessageChannel;"undefined"===typeof a&&"undefined"!==typeof window&&window.postMessage&&window.addEventListener&&!_.Ya("Presto")&&(a=function(){var a=window.document.createElement("IFRAME");a.style.display="none";a.src="";window.document.documentElement.appendChild(a);var b=a.contentWindow;a=b.document;a.open();a.write("");a.close();var c="callImmediate"+Math.random(),d="file:"==b.location.protocol?"*":b.location.protocol+"//"+b.location.host;a=(0,_.t)(function(a){if(("*"== -d||a.origin==d)&&a.data==c)this.port1.onmessage()},this);b.addEventListener("message",a,!1);this.port1={};this.port2={postMessage:function(){b.postMessage(c,d)}}});if("undefined"!==typeof a&&!_.ab()){var b=new a,c={},d=c;b.port1.onmessage=function(){if(_.p(c.next)){c=c.next;var a=c.hh;c.hh=null;a()}};return function(a){d.next={hh:a};d=d.next;b.port2.postMessage(0)}}return"undefined"!==typeof window.document&&"onreadystatechange"in window.document.createElement("SCRIPT")?function(a){var b=window.document.createElement("SCRIPT"); -b.onreadystatechange=function(){b.onreadystatechange=null;b.parentNode.removeChild(b);b=null;a();a=null};window.document.documentElement.appendChild(b)}:function(a){_.gb.setTimeout(a,0)}};qb=function(){this.f=this.b=null};rb=function(){this.next=this.b=this.Wc=null};_.lb=function(a,b){_.lb.b||_.lb.m();_.lb.j||(_.lb.b(),_.lb.j=!0);_.lb.l.add(a,b)};_.sb=function(a){return a*Math.PI/180};_.tb=function(a){return 180*a/Math.PI};_.x=function(a){return a?a.length:0}; -_.vb=function(a,b){_.ub(b,function(c){a[c]=b[c]})};_.wb=function(a,b,c){null!=b&&(a=Math.max(a,b));null!=c&&(a=Math.min(a,c));return a};_.xb=function(a,b,c){c-=b;return((a-b)%c+c)%c+b};_.yb=function(a,b,c){return Math.abs(a-b)<=(c||1E-9)};_.zb=function(a,b){for(var c=[],d=_.x(a),e=0;ea.f};_.mc=function(a,b){var c=b-a;return 0<=c?c:b+180-(a-180)}; -_.nc=function(a){return a.isEmpty()?0:_.lc(a)?360-(a.b-a.f):a.f-a.b};oc=function(a,b){this.b=a;this.f=b};_.E=function(a,b,c){if(a&&(void 0!==a.lat||void 0!==a.lng))try{pc(a),b=a.lng,a=a.lat,c=!1}catch(d){_.Nb(d)}a-=0;b-=0;c||(a=_.wb(a,-90,90),180!=b&&(b=_.xb(b,-180,180)));this.lat=function(){return a};this.lng=function(){return b}};_.qc=function(a){return _.sb(a.lat())};_.rc=function(a){return _.sb(a.lng())};sc=function(a,b){b=Math.pow(10,b);return Math.round(a*b)/b}; -_.tc=function(a){try{if(a instanceof _.E)return a;a=pc(a);return new _.E(a.lat,a.lng)}catch(b){throw _.Mb("not a LatLng or LatLngLiteral",b);}};_.uc=function(a,b){a=a&&_.tc(a);b=b&&_.tc(b);if(a){b=b||a;var c=_.wb(a.lat(),-90,90),d=_.wb(b.lat(),-90,90);this.f=new oc(c,d);a=a.lng();b=b.lng();360<=b-a?this.b=new kc(-180,180):(a=_.xb(a,-180,180),b=_.xb(b,-180,180),this.b=new kc(a,b))}else this.f=new oc(1,-1),this.b=new kc(180,-180)};_.vc=function(a,b,c,d){return new _.uc(new _.E(a,b,!0),new _.E(c,d,!0))}; -_.xc=function(a){if(a instanceof _.uc)return a;try{return a=wc(a),_.vc(a.south,a.west,a.north,a.east)}catch(b){throw _.Mb("not a LatLngBounds or LatLngBoundsLiteral",b);}};_.Dc=function(a){a=a||window.event;_.Bc(a);_.Cc(a)};_.Bc=function(a){a.cancelBubble=!0;a.stopPropagation&&a.stopPropagation()};_.Cc=function(a){a.preventDefault&&_.p(a.defaultPrevented)?a.preventDefault():a.returnValue=!1};_.Ec=function(a){a.handled=!0;void 0===a.bubbles&&(a.returnValue="handled")}; -Fc=function(a,b){a.__e3_||(a.__e3_={});a=a.__e3_;a[b]||(a[b]={});return a[b]};Gc=function(a,b){var c=a.__e3_||{};if(b)a=c[b]||{};else for(b in a={},c)_.vb(a,c[b]);return a};Hc=function(a,b){return function(c){return b.call(a,c,this)}};Ic=function(a,b,c){return function(d){var e=[b,a];_.Bb(e,arguments);_.G.trigger.apply(this,e);c&&_.Ec.apply(null,arguments)}};Kc=function(a,b,c,d){this.f=a;this.j=b;this.b=c;this.l=d;this.id=++Jc;Fc(a,b)[this.id]=this}; -Qc=function(a){return function(b){b||(b=window.event);if(b&&!b.target)try{b.target=b.srcElement}catch(d){}var c=a.b.apply(a.f,[b]);return b&&"click"==b.type&&(b=b.srcElement)&&"A"==b.tagName&&"javascript:void(0)"==b.href?!1:c}};_.Rc=function(a){return""+(_.Ka(a)?_.Na(a):a)};_.J=_.l();Tc=function(a,b){var c=b+"_changed";if(a[c])a[c]();else a.changed(b);c=Sc(a,b);for(var d in c){var e=c[d];Tc(e.dd,e.zb)}_.G.trigger(a,b.toLowerCase()+"_changed")}; -_.Vc=function(a){return Uc[a]||(Uc[a]=a.substr(0,1).toUpperCase()+a.substr(1))};Wc=function(a){a.gm_accessors_||(a.gm_accessors_={});return a.gm_accessors_};Sc=function(a,b){a.gm_bindings_||(a.gm_bindings_={});a.gm_bindings_.hasOwnProperty(b)||(a.gm_bindings_[b]={});return a.gm_bindings_[b]};Xc=function(a){this.R=[];this.b=a&&a.Ld||_.Fa;this.f=a&&a.Md||_.Fa}; -_.Zc=function(a,b,c,d){function e(){_.w(f,function(a){b.call(c||null,function(b){if(a.once){if(a.once.eh)return;a.once.eh=!0;_.Ua(g.R,a);g.R.length||g.b()}a.Wc.call(a.context,b)})})}var f=a.R.slice(0),g=a;d&&d.sync?e():Yc(e)};$c=function(a,b){return function(c){return c.Wc==a&&c.context==(b||null)}};_.ad=function(){this.R=new Xc({Ld:(0,_.t)(this.Ld,this),Md:(0,_.t)(this.Md,this)})};_.bd=function(a){return function(){return this.get(a)}}; -_.cd=function(a,b){return b?function(c){try{this.set(a,b(c))}catch(d){_.Nb(_.Mb("set"+_.Vc(a),d))}}:function(b){this.set(a,b)}};_.dd=function(a,b){_.ub(b,function(b,d){var c=_.bd(b);a["get"+_.Vc(b)]=c;d&&(d=_.cd(b,d),a["set"+_.Vc(b)]=d)})};_.fd=function(a){this.b=a||[];ed(this)};ed=function(a){a.set("length",a.b.length)};_.gd=function(){this.f={};this.j=0};_.hd=function(a,b){var c=a.f,d=_.Rc(b);c[d]||(c[d]=b,++a.j,_.G.trigger(a,"insert",b),a.b&&a.b(b))};_.id=_.na("b"); -_.jd=function(a,b,c){this.heading=a;this.pitch=_.wb(b,-90,90);this.zoom=Math.max(0,c)};_.kd=function(){this.__gm=new _.J;this.l=null};_.ld=function(a){_.ad.call(this);this.m=!!a};_.nd=function(a){return new md(a,void 0)};md=function(a,b){_.ld.call(this,b);this.b=a};od=_.l();_.pd=function(a,b){a[b]||(a[b]=[]);return a[b]}; -_.rd=function(a,b){if(null==a||null==b)return null==a==(null==b);if(a.constructor!=Array&&a.constructor!=Object)throw Error("Invalid object type passed into jsproto.areObjectsEqual()");if(a===b)return!0;if(a.constructor!=b.constructor)return!1;for(var c in a)if(!(c in b&&qd(a[c],b[c])))return!1;for(var d in b)if(!(d in a))return!1;return!0}; -qd=function(a,b){if(a===b||!(!0!==a&&1!==a||!0!==b&&1!==b)||!(!1!==a&&0!==a||!1!==b&&0!==b))return!0;if(a instanceof Object&&b instanceof Object){if(!_.rd(a,b))return!1}else return!1;return!0};ud=function(a,b,c,d){this.type=a;this.label=b;this.Rk=c;this.Tc=d};vd=function(a){switch(a){case "d":case "f":case "i":case "j":case "u":case "v":case "x":case "y":case "g":case "h":case "n":case "o":case "e":return 0;case "s":case "z":case "B":return"";case "b":return!1;default:return null}}; -_.wd=function(a,b,c){return new ud(a,1,_.p(b)?b:vd(a),c)};_.xd=function(a,b,c){return new ud(a,2,_.p(b)?b:vd(a),c)};_.yd=function(a){return _.wd("i",a)};_.zd=function(a){return _.wd("v",a)};_.Ad=function(a){return _.wd("b",a)};_.Bd=function(a){return _.wd("e",a)};_.K=function(a,b){return _.wd("m",a,b)};_.Cd=function(a){return new ud("m",3,void 0,a)};Dd=_.l(); -Fd=function(a,b,c){for(var d=1;dd&&(d=-90);b=Math.sin(b);var e=Math.cos(_.sb(a.lat()));if(90==c||-90==d||1E-6>e)return new _.uc(new _.E(d,-180),new _.E(c,180));b=_.tb(Math.asin(b/e));return new _.uc(new _.E(d,a.lng()-b),new _.E(c,a.lng()+b))}; -Of=function(a,b){_.kd.call(this);_.Ne(a);this.__gm=new _.J;this.f=null;b&&b.client&&(this.f=_.Mf[b.client]||null);var c=this.controls=[];_.ub(_.Nf,function(a,b){c[b]=new _.fd});this.j=!0;this.b=a;this.m=!1;this.__gm.$b=b&&b.$b||new _.gd;this.set("standAlone",!0);this.setPov(new _.jd(0,0,1));b&&b.Ie&&(a=b.Ie,_.Cb(a.zoom)||(a.zoom=_.Ea(b.zoom)?b.zoom:1));this.setValues(b);void 0==this.getVisible()&&this.setVisible(!0);_.G.addListenerOnce(this,"pano_changed",_.Hb(function(){_.Q("marker",(0,_.t)(function(a){a.b(this.__gm.$b, -this)},this))}))};Pf=function(){this.l=[];this.j=this.b=this.f=null};Qf=function(a,b,c,d,e){this.X=b;this.b=e;this.f=_.nd(new _.id([]));this.G=new _.gd;new _.fd;this.l=new _.gd;this.B=new _.gd;this.m=new _.gd;var f=this.$b=new _.gd;f.b=function(){delete f.b;_.Q("marker",_.Hb(function(b){b.b(f,a)}))};this.C=new Of(c,{visible:!1,enableCloseButton:!0,$b:f});this.C.bindTo("reportErrorControl",a);this.C.j=!1;this.j=new Pf;this.overlayLayer=null};_.Rf=function(){this.R=new Xc}; -_.Sf=function(a){this.pk=a||0;_.G.bind(this,"forceredraw",this,this.C)};_.Tf=function(a,b){a=a.style;a.width=b.width+b.f;a.height=b.height+b.b};_.Uf=function(a){return new _.D(a.offsetWidth,a.offsetHeight)};_.Wf=function(){var a=[],b=_.gb.google&&_.gb.google.maps&&_.gb.google.maps.fisfetsz;b&&Array.isArray(b)&&_.Vf[15]&&b.forEach(function(b){_.Cb(b)&&a.push(b)});0==a.length&&(_.Vf[35]?a.push(4111425):_.Vf[43]||a.push(1301875));return a};Xf=function(a){this.data=a||[]}; -$f=function(){Yf||(Yf={b:-1,A:[,_.Zf,_.Zf,_.Zf,_.Zf]});return Yf};ag=function(a){this.data=a||[]};bg=function(a){this.data=a||[]};cg=function(a){this.data=a||[]};dg=function(a){this.data=a||[]};eg=function(a){this.data=a||[]};fg=function(a){this.data=a||[]}; -Fg=function(a){if(!gg){var b=gg={b:-1,A:[]},c=new dg([]);hg||(hg={b:-1,A:[,_.S,_.S]});c=_.K(c,hg);var d=new eg([]);ig||(ig={b:-1,A:[]},ig.A=[,_.T,_.T,_.Bd(1)]);d=_.K(d,ig);var e=new cg([]);if(!jg){var f=[];jg={b:-1,A:f};f[1]=_.U;f[2]=_.V;f[3]=_.V;f[5]=_.W;f[6]=_.W;kg||(kg={b:-1,A:[]},kg.A=[,_.U,_.Bd(1),_.xg,_.K(new Xf([]),$f()),_.V,_.xg,_.xg,_.U,_.K(new Xf([]),$f()),_.xg]);f[8]=_.Cd(kg);var g=new bg([]);yg||(yg={b:-1,A:[,_.zg,_.V]});f[9]=_.K(g,yg);f[10]=_.V;f[11]=_.V;f[12]=_.V;f[13]=_.zg;f[14]=_.Ag; -f[15]=_.V;f[100]=_.V}e=_.K(e,jg);f=new mf([]);if(!Bg){g=Bg={b:-1,A:[]};var h=new of([]);Cg||(Cg={b:-1,A:[,_.V,_.V]});h=_.K(h,Cg);var k=new nf([]);Dg||(Dg={b:-1,A:[,_.V]});g.A=[,,,,,,,,,,h,,_.K(k,Dg)]}b.A=[,c,_.U,_.T,d,e,_.K(f,Bg)]}return _.Eg.b(a.data,gg)};Gg=function(a,b,c,d,e){_.Sf.call(this);this.H=b;this.G=new _.Jf;this.V=c+"/maps/api/js/StaticMapService.GetMapImage";this.f=this.b=null;this.B=d;this.j=e?new md(null,void 0):null;this.l=null;this.m=!1;this.set("div",a);this.set("loading",!0)}; -Ig=function(a){var b=a.get("tilt")||_.x(a.get("styles"));a=a.get("mapTypeId");return b?null:Hg[a]};_.Jg=function(a){a.parentNode&&a.parentNode.removeChild(a)};Kg=function(a,b){var c=a.f;c.onload=null;c.onerror=null;var d=a.get("size");d&&(b&&(c.parentNode||a.b.appendChild(c),a.j||_.Tf(c,d),_.G.trigger(a,"staticmaploaded"),a.B.set(_.Qa())),a.set("loading",!1))}; -Lg=function(a,b,c,d,e){var f=new fg,g=new dg(_.P(f,0));g.data[0]=b.I;g.data[1]=b.K;f.data[1]=e;f.setZoom(c);c=new eg(_.P(f,3));c.data[0]=b.N-b.I;c.data[1]=b.S-b.K;var h=new cg(_.P(f,4));h.data[0]=d;h.data[4]=_.wf(_.zf(_.R));h.data[5]=_.xf(_.zf(_.R)).toLowerCase();h.data[9]=!0;_.Wf().forEach(function(a){0>_.Id(h,13).indexOf(a)&&_.Jd(h,13,a)});h.data[11]=!0;_.Vf[13]&&(b=new ag(_.Nd(h,7)),b.data[0]=33,b.data[1]=3,b.data[7]=1);f=a.V+(0,window.unescape)("%3F")+Fg(f);return a.H(f)}; -Mg=function(a,b){var c=a.f;b!=c.src?(a.j||_.Jg(c),c.onload=function(){Kg(a,!0)},c.onerror=function(){Kg(a,!1)},c.src=b):!c.parentNode&&b&&a.b.appendChild(c)};_.Og=function(a){for(var b;b=a.firstChild;)_.Ng(b),a.removeChild(b)};_.Ng=function(a){a=new lf(a);try{for(;;){var b=a.next();b&&_.G.clearInstanceListeners(b)}}catch(c){if(c!==Pg)throw c;}}; -Sg=function(a,b){var c=_.Qa();Gf&&Hf();var d=new _.Rf,e=b||{};e.noClear||_.Og(a);var f="undefined"==typeof window.document?null:window.document.createElement("div");f&&a.appendChild&&(a.appendChild(f),f.style.width=f.style.height="100%");if(![].forEach)throw _.Q("controls",function(b){b.xg(a)}),Error("The Google Maps API does not support this browser.");var g;b=new window.Promise(function(a){g=a});_.Qd.call(this,new Qf(this,a,f,d,b));_.p(e.mapTypeId)||(e.mapTypeId="roadmap");this.setValues(e);this.ea= -_.Vf[15]&&e.noControlsOrLogging;this.mapTypes=new Pd;this.features=new _.J;_.Ne(f);this.notify("streetView");b=_.Uf(f);var h=null;Qg(e.useStaticMap,b)&&(h=new Gg(f,_.Rg,_.N(_.zf(_.R),9),new md(null,void 0),!0),_.G.forward(h,"staticmaploaded",this),h.set("size",b),h.bindTo("center",this),h.bindTo("zoom",this),h.bindTo("mapTypeId",this),h.bindTo("styles",this));this.overlayMapTypes=new _.fd;var k=this.controls=[];_.ub(_.Nf,function(a,b){k[b]=new _.fd});var n=this,q=!0;_.Q("map",function(a){n.getDiv()&& -f&&a.f(n,e,f,h,q,c,d,g)});q=!1;this.data=new Ce({map:this})};Qg=function(a,b){if(!_.R||2==_.Hd(_.R,37))return!1;if(_.p(a))return!!a;a=b.width;b=b.height;return 384E3>=a*b&&800>=a&&800>=b};Tg=function(){_.Q("maxzoom",_.Fa)};Ug=function(a,b){!a||_.Eb(a)||_.Cb(a)?(this.set("tableId",a),this.setValues(b)):this.setValues(a)};_.Vg=_.l();Wg=function(a){a=a||{};a.visible=_.Ab(a.visible,!0);return a};_.Xg=function(a){return a&&a.radius||6378137};Zg=function(a){return a instanceof _.fd?Yg(a):new _.fd((0,_.qe)(a))}; -ah=function(a){if(_.Ha(a)||a instanceof _.fd)if(0==_.x(a))var b=!0;else b=a instanceof _.fd?a.getAt(0):a[0],b=_.Ha(b)||b instanceof _.fd;else b=!1;return b?a instanceof _.fd?$g(Yg)(a):new _.fd(_.Sb(Zg)(a)):new _.fd([Zg(a)])};$g=function(a){return function(b){if(!(b instanceof _.fd))throw _.Mb("not an MVCArray");b.forEach(function(b,d){try{a(b)}catch(e){throw _.Mb("at index "+d,e);}});return b}};_.bh=function(a){this.setValues(Wg(a));_.Q("poly",_.Fa)}; -ch=function(a){this.set("latLngs",new _.fd([new _.fd]));this.setValues(Wg(a));_.Q("poly",_.Fa)};_.dh=function(a){ch.call(this,a)};_.eh=function(a){ch.call(this,a)};_.fh=function(a){this.setValues(Wg(a));_.Q("poly",_.Fa)};gh=function(){this.b=null};_.hh=function(){this.b=null}; -_.jh=function(a){var b=this;this.tileSize=a.tileSize||new _.D(256,256);this.name=a.name;this.alt=a.alt;this.minZoom=a.minZoom;this.maxZoom=a.maxZoom;this.j=(0,_.t)(a.getTileUrl,a);this.b=new _.gd;this.f=null;this.set("opacity",a.opacity);_.Q("map",function(a){var c=b.f=a.b,e=b.tileSize||new _.D(256,256);b.b.forEach(function(a){var d=a.__gmimt,f=d.da,k=d.zoom,n=b.j(f,k);(d.cb=c({L:f.x,M:f.y,$:k},e,a,n,function(){return _.G.trigger(a,"load")})).setOpacity(ih(b))})})}; -ih=function(a){a=a.get("opacity");return"number"==typeof a?a:1};_.kh=function(){_.kh.kf(this,"constructor")};_.rh=function(a,b){_.rh.kf(this,"constructor");this.set("styles",a);a=b||{};this.b=a.baseMapTypeId||"roadmap";this.minZoom=a.minZoom;this.maxZoom=a.maxZoom||20;this.name=a.name;this.alt=a.alt;this.projection=null;this.tileSize=new _.D(256,256)};_.sh=function(a,b){_.Tb(Pb,"container is not a Node")(a);this.setValues(b);_.Q("controls",(0,_.t)(function(b){b.Yl(this,a)},this))};th=_.na("b"); -uh=function(a,b,c){for(var d=Array(b.length),e=0,f=b.length;e to Object.prototype. Extending Object.prototype breaks JavaScript for..in loops, which are used heavily in Google Maps API v3.")}; -Bh=function(a){(a="version"in a)&&window.console&&window.console.error("You have included the Google Maps API multiple times on this page. This may cause unexpected errors.");return a};_.ra=[];_.ua="undefined"!=typeof window&&window===this?this:"undefined"!=typeof window.global&&null!=window.global?window.global:this;_.Ch="function"==typeof Object.create?Object.create:function(a){function b(){}b.prototype=a;return new b}; -if("function"==typeof Object.setPrototypeOf)Dh=Object.setPrototypeOf;else{var Eh;a:{var Fh={nk:!0},Gh={};try{Gh.__proto__=Fh;Eh=Gh.nk;break a}catch(a){}Eh=!1}Dh=Eh?function(a,b){a.__proto__=b;if(a.__proto__!==b)throw new TypeError(a+" is not extensible");return a}:null}_.Hh=Dh;wa="function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){a!=Array.prototype&&a!=Object.prototype&&(a[b]=c.value)};va=function(){var a=0;return function(b){return"jscomp_symbol_"+(b||"")+a++}}(); -Ba("Array.prototype.findIndex",function(a){return a?a:function(a,c){a:{var b=this;b instanceof String&&(b=String(b));for(var e=b.length,f=0;fc&&(c=Math.max(0,b+c));if(null==d||d>b)d=b;d=Number(d);0>d&&(d=Math.max(0,b+d));for(c=Number(c||0);c>>0);Ma=0;a:{var Ih=_.gb.navigator;if(Ih){var Jh=Ih.userAgent;if(Jh){_.Wa=Jh;break a}}_.Wa=""};_.fb[" "]=_.Fa;var Wh;_.Kh=_.Ya("Opera");_.Lh=_.ab();_.Mh=_.Ya("Edge");_.Nh=_.Ya("Gecko")&&!(_.Xa()&&!_.Ya("Edge"))&&!(_.Ya("Trident")||_.Ya("MSIE"))&&!_.Ya("Edge");_.Oh=_.Xa()&&!_.Ya("Edge");_.Ph=_.Ya("Macintosh");_.Qh=_.Ya("Windows");_.Rh=_.Ya("Linux")||_.Ya("CrOS");_.Sh=_.Ya("Android");_.Th=_.eb();_.Uh=_.Ya("iPad");_.Vh=_.Ya("iPod"); -a:{var Xh="",Yh=function(){var a=_.Wa;if(_.Nh)return/rv:([^\);]+)(\)|;)/.exec(a);if(_.Mh)return/Edge\/([\d\.]+)/.exec(a);if(_.Lh)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if(_.Oh)return/WebKit\/(\S+)/.exec(a);if(_.Kh)return/(?:Version)[ \/]?(\S+)/.exec(a)}();Yh&&(Xh=Yh?Yh[1]:"");if(_.Lh){var Zh=hb();if(null!=Zh&&Zh>(0,window.parseFloat)(Xh)){Wh=String(Zh);break a}}Wh=Xh}_.$h=Wh;var bi=_.gb.document;_.ai=bi&&_.Lh?hb()||("CSS1Compat"==bi.compatMode?(0,window.parseInt)(_.$h,10):5):void 0;_.ci=_.Ya("Firefox");_.di=_.eb()||_.Ya("iPod");_.ei=_.Ya("iPad");_.fi=_.db();_.gi=bb();_.hi=_.cb()&&!(_.eb()||_.Ya("iPad")||_.Ya("iPod"));var ii;ii=_.Nh||_.Oh&&!_.hi||_.Kh;_.ji=ii||"function"==typeof _.gb.btoa;_.ki=ii||!_.hi&&!_.Lh&&"function"==typeof _.gb.atob;ib.prototype.get=function(){if(0b.f&&(b.f++,a.next=b.b,b.b=a)}_.lb.j=!1};_.ni={ROADMAP:"roadmap",SATELLITE:"satellite",HYBRID:"hybrid",TERRAIN:"terrain"};_.Nf={TOP_LEFT:1,TOP_CENTER:2,TOP:2,TOP_RIGHT:3,LEFT_CENTER:4,LEFT_TOP:5,LEFT:5,LEFT_BOTTOM:6,RIGHT_TOP:7,RIGHT:7,RIGHT_CENTER:8,RIGHT_BOTTOM:9,BOTTOM_LEFT:10,BOTTOM_CENTER:11,BOTTOM:11,BOTTOM_RIGHT:12,CENTER:13};_.u(Lb,Error);var oi,qi;_.Yb=_.Tb(_.Cb,"not a number");oi=_.Vb(_.Yb,function(a){if((0,window.isNaN)(a))throw _.Mb("NaN is not an accepted value");return a});_.pi=_.Tb(_.Eb,"not a string");qi=_.Tb(_.Fb,"not a boolean");_.ri=_.Wb(_.Yb);_.si=_.Wb(_.pi);_.ti=_.Wb(qi);_.ui=new _.A(0,0);_.A.prototype.toString=function(){return"("+this.x+", "+this.y+")"};_.A.prototype.aa=function(a){return a?a.x==this.x&&a.y==this.y:!1};_.A.prototype.equals=_.A.prototype.aa;_.A.prototype.round=function(){this.x=Math.round(this.x);this.y=Math.round(this.y)};_.A.prototype.Ae=_.sa(0);_.vi=new _.D(0,0);_.D.prototype.toString=function(){return"("+this.width+", "+this.height+")"};_.D.prototype.aa=function(a){return a?a.width==this.width&&a.height==this.height:!1};_.D.prototype.equals=_.D.prototype.aa;_.bc.prototype.aa=function(a){return a?this.O==a.O&&this.P==a.P:!1};_.wi=new _.dc({Ic:new _.cc(256),Jc:void 0});_.ec.prototype.aa=function(a){return a?this.m11==a.m11&&this.m12==a.m12&&this.m21==a.m21&&this.m22==a.m22:!1};_.ic.prototype.isEmpty=function(){return!(this.I=b:_.lc(a)?a.b<=c||a.f>=b:a.b<=c&&a.f>=b};_.m.contains=function(a){-180==a&&(a=180);var b=this.b,c=this.f;return _.lc(this)?(a>=b||a<=c)&&!this.isEmpty():a>=b&&a<=c};_.m.extend=function(a){this.contains(a)||(this.isEmpty()?this.b=this.f=a:_.mc(a,this.b)<_.mc(this.f,a)?this.b=a:this.f=a)}; -_.m.aa=function(a){return 1E-9>=Math.abs(a.b-this.b)%360+Math.abs(_.nc(a)-_.nc(this))};_.m.Z=function(){var a=(this.b+this.f)/2;_.lc(this)&&(a=_.xb(a+180,-180,180));return a};_.m=oc.prototype;_.m.isEmpty=function(){return this.b>this.f};_.m.intersects=function(a){var b=this.b,c=this.f;return b<=a.b?a.b<=c&&a.b<=a.f:b<=a.f&&b<=c};_.m.contains=function(a){return a>=this.b&&a<=this.f};_.m.extend=function(a){this.isEmpty()?this.f=this.b=a:athis.f&&(this.f=a)}; -_.m.aa=function(a){return this.isEmpty()?a.isEmpty():1E-9>=Math.abs(a.b-this.b)+Math.abs(this.f-a.f)};_.m.Z=function(){return(this.f+this.b)/2};var pc=_.Ob({lat:_.Yb,lng:_.Yb},!0);_.E.prototype.toString=function(){return"("+this.lat()+", "+this.lng()+")"};_.E.prototype.toJSON=function(){return{lat:this.lat(),lng:this.lng()}};_.E.prototype.aa=function(a){return a?_.yb(this.lat(),a.lat())&&_.yb(this.lng(),a.lng()):!1};_.E.prototype.equals=_.E.prototype.aa;_.E.prototype.toUrlValue=function(a){a=_.p(a)?a:6;return sc(this.lat(),a)+","+sc(this.lng(),a)};_.qe=_.Sb(_.tc);_.m=_.uc.prototype;_.m.getCenter=function(){return new _.E(this.f.Z(),this.b.Z())};_.m.toString=function(){return"("+this.getSouthWest()+", "+this.getNorthEast()+")"};_.m.toJSON=function(){return{south:this.f.b,west:this.b.b,north:this.f.f,east:this.b.f}};_.m.toUrlValue=function(a){var b=this.getSouthWest(),c=this.getNorthEast();return[b.toUrlValue(a),c.toUrlValue(a)].join()};_.m.aa=function(a){if(!a)return!1;a=_.xc(a);return this.f.aa(a.f)&&this.b.aa(a.b)};_.uc.prototype.equals=_.uc.prototype.aa; -_.m=_.uc.prototype;_.m.contains=function(a){a=_.tc(a);return this.f.contains(a.lat())&&this.b.contains(a.lng())};_.m.intersects=function(a){a=_.xc(a);return this.f.intersects(a.f)&&this.b.intersects(a.b)};_.m.extend=function(a){a=_.tc(a);this.f.extend(a.lat());this.b.extend(a.lng());return this};_.m.union=function(a){a=_.xc(a);if(!a||a.isEmpty())return this;this.extend(a.getSouthWest());this.extend(a.getNorthEast());return this};_.m.getSouthWest=function(){return new _.E(this.f.b,this.b.b,!0)}; -_.m.getNorthEast=function(){return new _.E(this.f.f,this.b.f,!0)};_.m.toSpan=function(){var a=this.f;a=a.isEmpty()?0:a.f-a.b;return new _.E(a,_.nc(this.b),!0)};_.m.isEmpty=function(){return this.f.isEmpty()||this.b.isEmpty()};var wc=_.Ob({south:_.Yb,west:_.Yb,north:_.Yb,east:_.Yb},!1);var Jc; -_.G={addListener:function(a,b,c){return new Kc(a,b,c,0)},hasListeners:function(a,b){if(!a)return!1;b=(a=a.__e3_)&&a[b];if(a=!!b){a:{for(c in b){var c=!1;break a}c=!0}a=!c}return a},removeListener:function(a){a&&a.remove()},clearListeners:function(a,b){_.ub(Gc(a,b),function(a,b){b&&b.remove()})},clearInstanceListeners:function(a){_.ub(Gc(a),function(a,c){c&&c.remove()})},trigger:function(a,b,c){if(_.G.hasListeners(a,b)){var d=_.Va(arguments,2),e=Gc(a,b),f;for(f in e){var g=e[f];g&&g.b.apply(g.f,d)}}}, -addDomListener:function(a,b,c,d){var e=d?4:1;if(!a.addEventListener&&a.attachEvent)return c=new Kc(a,b,c,2),a.attachEvent("on"+b,Qc(c)),c;a.addEventListener&&a.addEventListener(b,c,d);return new Kc(a,b,c,e)},addDomListenerOnce:function(a,b,c,d){var e=_.G.addDomListener(a,b,function(){e.remove();return c.apply(this,arguments)},d);return e},ka:function(a,b,c,d){return _.G.addDomListener(a,b,Hc(c,d))},bind:function(a,b,c,d){return _.G.addListener(a,b,(0,_.t)(d,c))},addListenerOnce:function(a,b,c){var d= -_.G.addListener(a,b,function(){d.remove();return c.apply(this,arguments)});return d},forward:function(a,b,c){return _.G.addListener(a,b,Ic(b,c))},Xc:function(a,b,c,d){_.G.addDomListener(a,b,Ic(b,c,!d))}};Jc=0;Kc.prototype.remove=function(){if(this.f){if(this.f.removeEventListener)switch(this.l){case 1:this.f.removeEventListener(this.j,this.b,!1);break;case 4:this.f.removeEventListener(this.j,this.b,!0)}delete Fc(this.f,this.j)[this.id];this.b=this.f=null}};_.m=_.J.prototype;_.m.get=function(a){var b=Wc(this);a+="";b=Ib(b,a);if(_.p(b)){if(b){a=b.zb;b=b.dd;var c="get"+_.Vc(a);return b[c]?b[c]():b.get(a)}return this[a]}};_.m.set=function(a,b){var c=Wc(this);a+="";var d=Ib(c,a);if(d)if(a=d.zb,d=d.dd,c="set"+_.Vc(a),d[c])d[c](b);else d.set(a,b);else this[a]=b,c[a]=null,Tc(this,a)};_.m.notify=function(a){var b=Wc(this);a+="";(b=Ib(b,a))?b.dd.notify(b.zb):Tc(this,a)}; -_.m.setValues=function(a){for(var b in a){var c=a[b],d="set"+_.Vc(b);if(this[d])this[d](c);else this.set(b,c)}};_.m.setOptions=_.J.prototype.setValues;_.m.changed=_.l();var Uc={};_.J.prototype.bindTo=function(a,b,c,d){a+="";c=(c||a)+"";this.unbind(a);var e={dd:this,zb:a},f={dd:b,zb:c,dh:e};Wc(this)[a]=f;Sc(b,c)[_.Rc(e)]=e;d||Tc(this,a)};_.J.prototype.unbind=function(a){var b=Wc(this),c=b[a];c&&(c.dh&&delete Sc(c.dd,c.zb)[_.Rc(c.dh)],this[a]=this.get(a),b[a]=null)}; -_.J.prototype.unbindAll=function(){var a=(0,_.t)(this.unbind,this),b=Wc(this),c;for(c in b)a(c)};_.J.prototype.addListener=function(a,b){return _.G.addListener(this,a,b)};Xc.prototype.addListener=function(a,b,c){c=c?{eh:!1}:null;var d=!this.R.length;var e=this.R;var f=_.Sa(e,$c(a,b),void 0);(e=0>f?null:_.Da(e)?e.charAt(f):e[f])?e.once=e.once&&c:this.R.push({Wc:a,context:b||null,once:c});d&&this.f();return a};Xc.prototype.addListenerOnce=function(a,b){this.addListener(a,b,!0);return a};Xc.prototype.removeListener=function(a,b){if(this.R.length){var c=this.R;a=_.Sa(c,$c(a,b),void 0);0<=a&&_.Ta(c,a);this.R.length||this.b()}};var Yc=_.lb;_.m=_.ad.prototype;_.m.Md=_.l();_.m.Ld=_.l();_.m.addListener=function(a,b){return this.R.addListener(a,b)};_.m.addListenerOnce=function(a,b){return this.R.addListenerOnce(a,b)};_.m.removeListener=function(a,b){return this.R.removeListener(a,b)};_.m.notify=function(a){_.Zc(this.R,function(a){a(this.get())},this,a)};_.u(_.fd,_.J);_.m=_.fd.prototype;_.m.getAt=function(a){return this.b[a]};_.m.indexOf=function(a){for(var b=0,c=this.b.length;b",0);_.ff("",0);_.ff("
",0);var Pg="StopIteration"in _.gb?_.gb.StopIteration:{message:"StopIteration",stack:""};jf.prototype.next=function(){throw Pg;};_.u(kf,jf);kf.prototype.setPosition=function(a,b,c){if(this.node=a)this.f=_.Ea(b)?b:1!=this.node.nodeType?0:this.b?-1:1;_.Ea(c)&&(this.depth=c)}; -kf.prototype.next=function(){if(this.j){if(!this.node||this.l&&0==this.depth)throw Pg;var a=this.node;var b=this.b?-1:1;if(this.f==b){var c=this.b?a.lastChild:a.firstChild;c?this.setPosition(c):this.setPosition(a,-1*b)}else(c=this.b?a.previousSibling:a.nextSibling)?this.setPosition(c):this.setPosition(a.parentNode,-1*b);this.depth+=this.f*(this.b?-1:1)}else this.j=!0;a=this.node;if(!this.node)throw Pg;return a};kf.prototype.aa=function(a){return a.node==this.node&&(!this.node||a.f==this.f)}; -kf.prototype.splice=function(a){var b=this.node,c=this.b?1:-1;this.f==c&&(this.f=-1*c,this.depth+=this.f*(this.b?-1:1));this.b=!this.b;kf.prototype.next.call(this);this.b=!this.b;c=_.Ia(arguments[0])?arguments[0]:arguments;for(var d=c.length-1;0<=d;d--)_.gf(c[d],b);_.hf(b)};_.u(lf,kf);lf.prototype.next=function(){do lf.Bb.next.call(this);while(-1==this.f);return this.node};var Bg;_.u(mf,_.L);var Dg;_.u(nf,_.L);var Cg;_.u(of,_.L);_.u(pf,_.L);_.u(_.qf,_.L);_.u(rf,_.L);_.u(sf,_.L);_.u(vf,_.L);_.Vf={};var Gf;_.If.prototype.aa=function(a){return this==a||a instanceof _.If&&this.size.aa(a.size)&&this.heading==a.heading&&this.fa==a.fa};_.kj=new _.If(new _.bc(256,256),0,0);_.lj=!!(_.gb.requestAnimationFrame&&_.gb.performance&&_.gb.performance.now);_.Jf.prototype.fromLatLngToPoint=function(a,b){b=b||new _.A(0,0);var c=this.b;b.x=c.x+a.lng()*this.j;a=_.wb(Math.sin(_.sb(a.lat())),-(1-1E-15),1-1E-15);b.y=c.y+.5*Math.log((1+a)/(1-a))*-this.l;return b};_.Jf.prototype.fromPointToLatLng=function(a,b){var c=this.b;return new _.E(_.tb(2*Math.atan(Math.exp((a.y-c.y)/-this.l))-Math.PI/2),(a.x-c.x)/this.j,b)};_.Mf={japan_prequake:20,japan_postquake2010:24};_.mj={NEAREST:"nearest",BEST:"best"};_.nj={DEFAULT:"default",OUTDOOR:"outdoor"};_.u(Of,_.kd);Of.prototype.visible_changed=function(){var a=this;!a.m&&a.getVisible()&&(a.m=!0,_.Q("streetview",function(b){if(a.f)var c=a.f;b.Nm(a,c)}))};_.dd(Of.prototype,{visible:_.ti,pano:_.si,position:_.Wb(_.tc),pov:_.Wb(yi),motionTracking:qi,photographerPov:null,location:null,links:_.Sb(_.Tb(_.Db)),status:null,zoom:_.ri,enableCloseButton:_.ti});Of.prototype.registerPanoProvider=function(a,b){this.set("panoProvider",{li:a,options:b||{}})};_.u(Qf,od);_.Rf.prototype.addListener=function(a,b){this.R.addListener(a,b)};_.Rf.prototype.addListenerOnce=function(a,b){this.R.addListenerOnce(a,b)};_.Rf.prototype.removeListener=function(a,b){this.R.removeListener(a,b)};_.Rf.prototype.b=_.sa(7);_.u(_.Sf,_.J);_.Sf.prototype.T=function(){var a=this;a.ja||(a.ja=_.gb.setTimeout(function(){a.ja=void 0;a.oa()},a.pk))};_.Sf.prototype.C=function(){this.ja&&_.gb.clearTimeout(this.ja);this.ja=void 0;this.oa()};var Yf;_.u(Xf,_.L);var kg;_.u(ag,_.L);var yg;_.u(bg,_.L);var jg;_.u(cg,_.L);var hg;_.u(dg,_.L);var ig;_.u(eg,_.L);var gg;_.u(fg,_.L);fg.prototype.getZoom=function(){return _.M(this,2)};fg.prototype.setZoom=function(a){this.data[2]=a};_.u(Gg,_.Sf);var Hg={roadmap:0,satellite:2,hybrid:3,terrain:4},oj={0:1,2:2,3:2,4:2};_.m=Gg.prototype;_.m.Gh=_.bd("center");_.m.Sg=_.bd("zoom");_.m.changed=function(){var a=this.Gh(),b=this.Sg(),c=Ig(this);if(a&&!a.aa(this.D)||this.ia!=b||this.Na!=c)this.j||_.Jg(this.f),this.T(),this.ia=b,this.Na=c;this.D=a}; -_.m.oa=function(){var a=Ig(this);if(this.j&&this.m)this.l!=a&&_.Jg(this.f);else{var b="",c=this.Gh(),d=this.Sg(),e=this.get("size");if(e){if(c&&(0,window.isFinite)(c.lat())&&(0,window.isFinite)(c.lng())&&1(b||0)?"best":"nearest"},c)};_.hh.prototype.getPanoramaById=function(a,b){this.getPanorama({pano:a},b)};_.u(_.jh,_.J);_.m=_.jh.prototype;_.m.getTile=function(a,b,c){if(!a||!c)return null;var d=c.createElement("div");c={da:a,zoom:b,cb:null};d.__gmimt=c;_.hd(this.b,d);if(this.f){var e=this.tileSize||new _.D(256,256),f=this.j(a,b);(c.cb=this.f({L:a.x,M:a.y,$:b},e,d,f,function(){_.G.trigger(d,"load")})).setOpacity(ih(this))}return d};_.m.releaseTile=function(a){a&&this.b.contains(a)&&(this.b.remove(a),(a=a.__gmimt.cb)&&a.release())};_.m.zf=_.sa(8);_.m.opacity_changed=function(){var a=ih(this);this.b.forEach(function(b){b.__gmimt.cb.setOpacity(a)})}; -_.m.triggersTileLoadEvent=!0;_.dd(_.jh.prototype,{opacity:_.ri});_.u(_.kh,_.J);_.kh.prototype.getTile=li;_.kh.prototype.tileSize=new _.D(256,256);_.kh.prototype.triggersTileLoadEvent=!0;_.u(_.rh,_.kh);_.u(_.sh,_.J);_.dd(_.sh.prototype,{attribution:_.Wb(Yi),place:_.Wb(Zi)});var pj={Animation:{BOUNCE:1,DROP:2,Ao:3,vo:4},Circle:_.bh,ControlPosition:_.Nf,Data:Ce,GroundOverlay:_.We,ImageMapType:_.jh,InfoWindow:_.Le,LatLng:_.E,LatLngBounds:_.uc,MVCArray:_.fd,MVCObject:_.J,Map:Sg,MapTypeControlStyle:{DEFAULT:0,HORIZONTAL_BAR:1,DROPDOWN_MENU:2,INSET:3,INSET_LARGE:4},MapTypeId:_.ni,MapTypeRegistry:Pd,Marker:_.Ie,MarkerImage:function(a,b,c,d,e){this.url=a;this.size=b||e;this.origin=c;this.anchor=d;this.scaledSize=e;this.labelOrigin=null},NavigationControlStyle:{DEFAULT:0,SMALL:1, -ANDROID:2,ZOOM_PAN:3,Bo:4,dk:5},OverlayView:_.Vg,Point:_.A,Polygon:_.dh,Polyline:_.eh,Rectangle:_.fh,ScaleControlStyle:{DEFAULT:0},Size:_.D,StreetViewPreference:_.mj,StreetViewSource:_.nj,StrokePosition:{CENTER:0,INSIDE:1,OUTSIDE:2},SymbolPath:Ni,ZoomControlStyle:{DEFAULT:0,SMALL:1,LARGE:2,dk:3},event:_.G};_.vb(Ce,{Feature:_.fe,Geometry:Rd,GeometryCollection:_.pe,LineString:_.re,LinearRing:_.se,MultiLineString:_.ue,MultiPoint:_.ve,MultiPolygon:_.ze,Point:_.Sd,Polygon:_.xe}); -_.vb(pj,{BicyclingLayer:_.Ye,DirectionsRenderer:Oe,DirectionsService:Pe,DirectionsStatus:{OK:_.ha,UNKNOWN_ERROR:_.ka,OVER_QUERY_LIMIT:_.ia,REQUEST_DENIED:_.ja,INVALID_REQUEST:_.ba,ZERO_RESULTS:_.la,MAX_WAYPOINTS_EXCEEDED:_.ea,NOT_FOUND:_.fa},DirectionsTravelMode:_.Qi,DirectionsUnitSystem:_.Pi,DistanceMatrixService:Te,DistanceMatrixStatus:{OK:_.ha,INVALID_REQUEST:_.ba,OVER_QUERY_LIMIT:_.ia,REQUEST_DENIED:_.ja,UNKNOWN_ERROR:_.ka,MAX_ELEMENTS_EXCEEDED:_.da,MAX_DIMENSIONS_EXCEEDED:_.ca},DistanceMatrixElementStatus:{OK:_.ha, -NOT_FOUND:_.fa,ZERO_RESULTS:_.la},ElevationService:Ue,ElevationStatus:{OK:_.ha,UNKNOWN_ERROR:_.ka,OVER_QUERY_LIMIT:_.ia,REQUEST_DENIED:_.ja,INVALID_REQUEST:_.ba,qo:"DATA_NOT_AVAILABLE"},FusionTablesLayer:Ug,Geocoder:_.Ve,GeocoderLocationType:{ROOFTOP:"ROOFTOP",RANGE_INTERPOLATED:"RANGE_INTERPOLATED",GEOMETRIC_CENTER:"GEOMETRIC_CENTER",APPROXIMATE:"APPROXIMATE"},GeocoderStatus:{OK:_.ha,UNKNOWN_ERROR:_.ka,OVER_QUERY_LIMIT:_.ia,REQUEST_DENIED:_.ja,INVALID_REQUEST:_.ba,ZERO_RESULTS:_.la,ERROR:_.aa},KmlLayer:Xe, -KmlLayerStatus:_.cj,MaxZoomService:Tg,MaxZoomStatus:{OK:_.ha,ERROR:_.aa},SaveWidget:_.sh,StreetViewCoverageLayer:gh,StreetViewPanorama:Of,StreetViewService:_.hh,StreetViewStatus:{OK:_.ha,UNKNOWN_ERROR:_.ka,ZERO_RESULTS:_.la},StyledMapType:_.rh,TrafficLayer:Ze,TrafficModel:_.Ri,TransitLayer:$e,TransitMode:_.Si,TransitRoutePreference:_.Ti,TravelMode:_.Qi,UnitSystem:_.Pi});_.de("main",{});var vh=/'/g,wh;var Fe=arguments[0]; -window.google.maps.Load(function(a,b){var c=window.google.maps;Ah();var d=Bh(c);_.R=new sf(a);_.qj=Math.random()<_.M(_.R,0,1);_.rj=Math.round(1E15*Math.random()).toString(36);_.Rg=xh();_.bj=yh();_.dj=new _.fd;_.Ef=b;for(a=0;a<_.Od(_.R,8);++a)_.Vf[_.Md(_.R,8,a)]=!0;a=new _.qf(_.R.data[3]);Ge(_.N(a,0));_.ub(pj,function(a,b){c[a]=b});c.version=_.N(a,1);window.setTimeout(function(){ee(["util","stats"],function(a,b){a.f.b();a.j();d&&b.b.b({ev:"api_alreadyloaded",client:_.N(_.R,6),key:_.yf()})})},5E3); -Gf=new Ff;(a=_.N(_.R,11))&&ee(_.Id(_.R,12),zh(a),!0)});}).call(this,{}); diff --git a/view/index.php b/view/index.php index 6268074..837d483 100644 --- a/view/index.php +++ b/view/index.php @@ -8,8 +8,9 @@ // Die statement is essentieel. Zonder dit kunnen users de // privé content zien zonder ingelogd te zijn. die("Redirecting to ".URL_ROOT."index.php"); - } + } + if($requestedAction == '' ){ ?> @@ -21,7 +22,7 @@ - <?= APP_TITLE; ?> | Home + <?= APP_TITLE; ?> | <?= $requestedController; ?> - + '; + } + ?> - - $('#myModal').modal('show');"; } ?> + \ No newline at end of file diff --git a/view/layout/sidenav.layout.php b/view/layout/sidenav.layout.php index c78271d..688a823 100644 --- a/view/layout/sidenav.layout.php +++ b/view/layout/sidenav.layout.php @@ -14,17 +14,17 @@
-
  • -
  • -
  • -
  • +
  • +
  • +
  • +

  • -
  • -
  • -
  • +
  • +
  • +
  • diff --git a/view/location/empty.php b/view/location/empty.php deleted file mode 100644 index 86ad6de..0000000 --- a/view/location/empty.php +++ /dev/null @@ -1,2 +0,0 @@ - +'/view/logging/log.php?file='+file, function(){}); } diff --git a/view/logging/empty.php b/view/logging/empty.php deleted file mode 100644 index 86ad6de..0000000 --- a/view/logging/empty.php +++ /dev/null @@ -1,2 +0,0 @@ - +
    diff --git a/view/settings/empty.php b/view/settings/empty.php deleted file mode 100644 index 86ad6de..0000000 --- a/view/settings/empty.php +++ /dev/null @@ -1,2 +0,0 @@ -
    diff --git a/view/ticket/ticket_new.view.php b/view/ticket/new.view.php similarity index 99% rename from view/ticket/ticket_new.view.php rename to view/ticket/new.view.php index 7d32c55..dd4fc41 100644 --- a/view/ticket/ticket_new.view.php +++ b/view/ticket/new.view.php @@ -333,7 +333,7 @@ // ========================================================================================================== $(document).ready(function() { $('#autocomplete-custom-append').autocomplete({ - serviceUrl: +'/src/scs_naw_hint.json.php', + serviceUrl: +'/src/helpers/scs_naw_hint.json.php', max: 10, onSearchComplete: function (query, suggestions) { if(!suggestions.length) { @@ -356,7 +356,7 @@ function fillForm(){ $.ajax({ type: 'POST', data: ({p : inpval}), - url: +'/src/scs_naw_get.json.php', + url: +'/src/helpers/scs_naw_get.json.php', success: function(data) { var object = $.parseJSON(data); diff --git a/view/ticket/template.view.php b/view/ticket/template.view.php new file mode 100644 index 0000000..fd4f7a6 --- /dev/null +++ b/view/ticket/template.view.php @@ -0,0 +1,69 @@ + + + + + + + + + + + + <?= APP_TITLE; ?> | <?= $requestedController; ?> + + + '; + } + ?> + + + + + +
    + + + +
    + + + + +
    + +
    + + + + + + diff --git a/view/ticket/ticket_new/index.php.lnk b/view/ticket/ticket_new/index.php.lnk deleted file mode 100644 index 130171946e3f8a0f41bcd7d9dc354ae9287cf43a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 874 zcmaiy&r2IY6vw|wRRUGIkth}mE`>s=M6GC%P=jL0K_=|BgsLz?)ud#RBukU(LQ%oH zCwr<5Ej^fv6i=n}5c($+L=X?+rBK>~NDua6>wB}Ctj)z)-g~n%Z$9&Wi~tab1W5y5 zl}2IGSr~Nj0hiNzVn@GC}E09uIl#oUN3!r1@#1oHah`XyAlIeLPHE!ae z$1}wC3hyxQ*DGe-Q50V#i8c=dDU4HWOiXyhl;~emL=4qww^wt$t@Djgl&|B$23Wp6MzTuUjT2dgjCm|^uzo8QUx1;tiQ7gzZiiE;?&mrs=M6GC%P=jL0K_=|BgsLz?)ud#RBukU(LQ%oH zCwr<5Ej^fv6i=n}5c($+L=X?+rBK>~NDua6>wB}Ctj)z)-g~n%Z$9&Wi~tab1W5y5 zl}2IGSr~Nj0hiNzVn@GC}E09uIl#oUN3!r1@#1oHah`XyAlIeLPHE!ae z$1}wC3hyxQ*DGe-Q50V#i8c=dDU4HWOiXyhl;~emL=4qww^wt$t@Djgl&|B$23Wp6MzTuUjT2dgjCm|^uzo8QUx1;tiQ7gzZiiE;?&mr Submitted by door: Checked by: -

    Ticket

    +

    Ticket

    @@ -209,7 +209,7 @@ }); function loadInfo(){ - $('.chat-discussion').load('ticket_updates.view.php?id='+getUrlParameter('id'), function(){ + $('.chat-discussion').load( +'/view/ticket_updates.view.php?id='+getUrlParameter('id'), function(){ $.i18n.init({ resGetPath: +'/src/lang/__lng__.json', load: 'unspecific', @@ -221,7 +221,7 @@ function loadInfo(){ }); } function loadUpdates(){ - $('#ticket_info').load('ticket_info.view.php?id='+getUrlParameter('id'), function(){ + $('#ticket_info').load( +'/view/ticket_info.view.php?id='+getUrlParameter('id'), function(){ $.i18n.init({ resGetPath: +'/src/lang/__lng__.json', load: 'unspecific', diff --git a/view/ticket/ticket_view/ticket_info.view.php b/view/ticket_info.view.php similarity index 100% rename from view/ticket/ticket_view/ticket_info.view.php rename to view/ticket_info.view.php diff --git a/view/ticket/ticket_view/ticket_updates.view.php b/view/ticket_updates.view.php similarity index 100% rename from view/ticket/ticket_view/ticket_updates.view.php rename to view/ticket_updates.view.php diff --git a/view/tools.view.php b/view/tools.view.php index a9f0d63..58225e6 100644 --- a/view/tools.view.php +++ b/view/tools.view.php @@ -6,8 +6,8 @@
    Tools
    - - + +
    @@ -18,8 +18,8 @@
    Events
    - - + +
    @@ -31,7 +31,7 @@
    Maps
    - +
    diff --git a/view/tools/events/index.php b/view/tools/events/index.php deleted file mode 100644 index 9e6f316..0000000 --- a/view/tools/events/index.php +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - <?= APP_TITLE; ?> | Pending events - - - - '; - } - ?> - - - - - -
    - -
    - - - - -
    - -
    - - - - - - diff --git a/view/tools/events_group/index.php b/view/tools/events_group/index.php deleted file mode 100644 index 499fb7f..0000000 --- a/view/tools/events_group/index.php +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - <?= APP_TITLE; ?> | Grouped events - - - - '; - } - ?> - - - - - -
    - -
    - - - - -
    - -
    - - - - - - diff --git a/view/tools/graphs/index.php b/view/tools/graphs/index.php deleted file mode 100644 index cdd5fb3..0000000 --- a/view/tools/graphs/index.php +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - <?= APP_TITLE; ?> | Graphs - - - - '; - } - ?> - - - - - -
    - -
    - - - - -
    - -
    - - - - - - diff --git a/view/tools/maps.view.php b/view/tools/maps.view.php index 7a0b510..a902274 100644 --- a/view/tools/maps.view.php +++ b/view/tools/maps.view.php @@ -1,4 +1,5 @@ -
    + +
    diff --git a/view/tools/maps/index.php b/view/tools/maps/index.php deleted file mode 100644 index 0996fe6..0000000 --- a/view/tools/maps/index.php +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - - <?= APP_TITLE; ?> | Maps - - - - '; - } - ?> - - - - - -
    - - - -
    - - - - diff --git a/view/tools/port/index.php b/view/tools/port/index.php deleted file mode 100644 index 35b6396..0000000 --- a/view/tools/port/index.php +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - <?= APP_TITLE; ?> | Port monitor - - - - '; - } - ?> - - - - - -
    - -
    - - - - -
    - -
    - - - - - - diff --git a/view/tools/template.view.php b/view/tools/template.view.php new file mode 100644 index 0000000..1dfe49f --- /dev/null +++ b/view/tools/template.view.php @@ -0,0 +1,84 @@ + + + + + + + + + + + + <?= APP_TITLE; ?> | <?= $requestedAction;?> + + + + '; + } + ?> + + + + + +
    + + + +
    + + + + diff --git a/view/user.view.php b/view/user.view.php index d33eaca..42c5f5c 100644 --- a/view/user.view.php +++ b/view/user.view.php @@ -142,7 +142,6 @@ text: data.body, type: data.type }); - table_active.ajax.reload( null, false ); }, error: function(xhr, status, error){ var json = $.parseJSON(xhr.responseText); diff --git a/view/user/empty.php b/view/user/empty.php deleted file mode 100644 index 86ad6de..0000000 --- a/view/user/empty.php +++ /dev/null @@ -1,2 +0,0 @@ - + +
    + + + \ No newline at end of file diff --git a/view/users.view.php b/view/users.view.php index 5f1ecf7..2e32f25 100644 --- a/view/users.view.php +++ b/view/users.view.php @@ -147,7 +147,8 @@ ?>
    - + +
    diff --git a/view/users/empty.php b/view/users/empty.php deleted file mode 100644 index 86ad6de..0000000 --- a/view/users/empty.php +++ /dev/null @@ -1,2 +0,0 @@ - Date: Mon, 14 May 2018 10:30:40 +0200 Subject: [PATCH 04/10] Edited location url --- src/classes/class.home.php | 7 +++---- src/config/router.php | 4 ++-- view/email_temp/email.header.php | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/classes/class.home.php b/src/classes/class.home.php index 36914a3..62344c3 100644 --- a/src/classes/class.home.php +++ b/src/classes/class.home.php @@ -146,7 +146,7 @@ public function getMarkers($getall = false, $updatetime = '') $is_letter = (ctype_alpha(substr(getCategory($row['SCS_Account_Nmbr']) , 0, 1)) == true) ? strtoupper(substr(getCategory($row['SCS_Account_Nmbr']) , 0, 1)) : strtoupper('A'); $locs[$row['SCS_Account_Nmbr']] = array( - 'info' => '
    ' . $row['SCS_Account_Address_Name'] . '
    ' . $row['SCS_Account_Address_Address'] . '
    #' . $row['SCS_Account_Nmbr'] . '
    ' . $conn_status . '' . $device_status . '
    ', + 'info' => '
    ' . $row['SCS_Account_Address_Name'] . '
    ' . $row['SCS_Account_Address_Address'] . '
    #' . $row['SCS_Account_Nmbr'] . '
    ' . $conn_status . '' . $device_status . '
    ', 'path_status' => $path_status, 'first_char' => $is_letter, 'lat' => $row['Latitude'], @@ -253,8 +253,7 @@ public function getList($state) $conn_class = 'text-navy'; } - //return ''.$d.''; - return '' . $d . ''; + return '' . $d . ''; } ) , array( @@ -384,7 +383,7 @@ public function getListRms() $conn = new SafeMySQL(SCS_DB_CONN); $account_code = $conn->getOne("SELECT SCS_Account_Nmbr FROM scs_account_info WHERE scs_account_info.SCS_Account_CallerID_1 LIKE ?s", '%'.$d.'%'); //return $location_name - return '' . $account_code . ''; + return '' . $account_code . ''; } ) , array( diff --git a/src/config/router.php b/src/config/router.php index a0caa7c..5abac09 100644 --- a/src/config/router.php +++ b/src/config/router.php @@ -66,7 +66,7 @@ // Check if controller exists. NB: // You have to do that for the model and the view too $ctrlPath = ROOT_PATH . '/view/' . $requestedController . '.view.php'; - + if(checkUserIsAdmin() && in_array($requestedController, $admin_only)) { http_response_code(403); @@ -81,7 +81,7 @@ } else { http_response_code(404); - include ROOT_PATH . '/view/errors/page_404.php'; + //include ROOT_PATH . '/view/errors/page_404.php'; die(); //require the 404 controller and initiate it //Display its view diff --git a/view/email_temp/email.header.php b/view/email_temp/email.header.php index ab94c40..7bcc930 100644 --- a/view/email_temp/email.header.php +++ b/view/email_temp/email.header.php @@ -1,5 +1,5 @@ -> + Email Template From 1e03c9b106025df85d97259b4c8f30b8de20eef7 Mon Sep 17 00:00:00 2001 From: MillieOfzo Date: Mon, 4 Jun 2018 08:49:51 +0200 Subject: [PATCH 05/10] Added tel queue dashboard --- css/style.css | 16 ++ src/classes/class.ticket.php | 2 +- src/classes/class.tools.php | 297 ++++++++++++++++++++++++++- src/config/common.php | 6 + src/config/router.php | 2 +- src/controllers/tools.controller.php | 11 +- view/tools.view.php | 1 + view/tools/tel_queue.view.php | 154 ++++++++++++++ 8 files changed, 484 insertions(+), 5 deletions(-) create mode 100644 view/tools/tel_queue.view.php diff --git a/css/style.css b/css/style.css index 723f3c2..3157707 100644 --- a/css/style.css +++ b/css/style.css @@ -4044,6 +4044,21 @@ table.table-mail tr td { right: 0; } /* BACKGROUNDS */ +.c-gray { + color: #949ba2; +} +.light-bg, +.bg-muted { + background-color: #f3f3f4; +} +.dark-gray-bg, +.bg-muted{ + background-color: #404040; + color: #ffffff; +} +.dark-gray-bg > span { + color: #949ba2; +} .gray-bg, .bg-muted { background-color: #f3f3f4; @@ -4078,6 +4093,7 @@ table.table-mail tr td { } .black-bg { background-color: #262626; + color: #ffffff; } .panel-primary { border-color: #1ab394; diff --git a/src/classes/class.ticket.php b/src/classes/class.ticket.php index 852b857..c207372 100644 --- a/src/classes/class.ticket.php +++ b/src/classes/class.ticket.php @@ -601,7 +601,7 @@ protected function getStatusText($status_id) { $conn = $this->db_conn; - $status_text = $conn->getOne("SELECT ticket_status_name FROM app_customer_tickets_status WHERE ticket_status_id = ?i", $$status_id); + $status_text = $conn->getOne("SELECT ticket_status_name FROM app_customer_tickets_status WHERE ticket_status_id = ?i", $status_id); return $status_text; } diff --git a/src/classes/class.tools.php b/src/classes/class.tools.php index 9f8bd68..ab123c8 100644 --- a/src/classes/class.tools.php +++ b/src/classes/class.tools.php @@ -24,6 +24,12 @@ */ class Tools { + private $queue_array = array(); + private $queue_total_in_count = 0; + private $queue_total_out_count = 0; + private $queue_missed_count = 0; + private $queue_agent_status; + /* * Constants values defined in env.ini */ @@ -43,7 +49,294 @@ function __construct($db_conn) { $this->db_conn = $db_conn; } - /** + + private function connectSqlSrv() + { + $serverName = QUEUE_HOST; + $connectionInfo = array( "Database"=>QUEUE_NAME, "UID"=>QUEUE_USER, "PWD"=>QUEUE_PASS); + $conn = sqlsrv_connect( $serverName, $connectionInfo ); + if( $conn === false ) { + die( print_r( sqlsrv_errors(), true)); + } + return $conn; + } + + public function getQueueRow() + { + $conn = $this->connectSqlSrv(); + + $stmt = sqlsrv_query( $conn, "SELECT Queue, Name, SLA1, SLA2 FROM autodeliver" ); + if( $stmt === false) { + die( print_r( sqlsrv_errors(), true) ); + } + $row_count = sqlsrv_num_rows( $stmt ); + + $rows ='
    '; + + $i = 1; + while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC ) ) { + + $queue = $this->checkQueueCount($row['Queue'], $row['SLA2']); + + $this->queue_array[] = $row['Queue']; + $this->queue_total_in_count += $queue['q_calls_total_in']; + $this->queue_total_out_count = $queue['q_calls_total_out']; + $this->queue_missed_count += $queue['q_calls_missed']; + $total_calls = $queue['q_calls_total_in'] + $queue['q_calls_missed']; + + $percent_class = ''; + if($total_calls > 0){ + $percent = round((100 / $total_calls) * $queue['q_sla_count']); + + if($percent == 0 || $percent < 50) + { + $percent_class = 'danger'; + } + elseif($percent >= 50 && $percent <= 90) + { + $percent_class = 'warning'; + } + else + { + $percent_class = 'navy'; + } + $percent = $percent.'%'; + $avg_wait = ($queue['q_avg_wait_time'] / $total_calls > 1) ? gmdate("H:i:s", $queue['q_avg_wait_time'] / $total_calls) : ''; + } else { + $percent = ''; + $avg_wait = ''; + } + + if($queue['q_calls_count'] > 2) + { + $class='red'; + $span_class=''; + } + elseif($queue['q_calls_count'] > 0) + { + $class='yellow'; + $span_class=''; + } + else + { + $class='dark-gray'; + $span_class='c-gray'; + } + + $count = ($queue['q_calls_count'] > 0) ? '

    '. $queue['q_calls_count'].'

    ' : ''; + $count_total = ($queue['q_calls_total_in'] > 0) ? $queue['q_calls_total_in'] : ''; + $count_total_missed = ($queue['q_calls_missed'] > 0) ? $queue['q_calls_missed'] : ''; + $total_wait = ($queue['q_avg_wait_time'] > 1) ? gmdate("H:i:s",$queue['q_avg_wait_time']) : ''; + + $rows .= '
    +
    +
    + '.$count.' +
    +

    + '.$row['Name'].' +

    +
    +
    +
    + + + +
    Calls
    Totaal '.$count_total.'
    Gemist '.$count_total_missed.'
    + +
    + + + + + +
    Wachttijd
    Gem'.$avg_wait.'
    Totaal'.$total_wait.'
    SLA'.$percent.'
    +
    + + + '; + if($i % 6 == 0) + { + $rows .= '
    '; + } + if($i == $row_count) + { + $rows .= '
    '; + } + + $i++; + } + + $res = array( + 'status' => 1, + 'row' => $rows, + 'total_in' => $this->queue_total_in_count, + 'total_out' => $this->queue_total_out_count, + 'total_missed' => $this->queue_missed_count + ); + jsonArr($res); + } + + public function getQueueAgents() + { + $conn = $this->connectSqlSrv(); + + $stmt = sqlsrv_query( $conn, "SELECT * FROM AvailableAgents WHERE CONVERT (date, LastCall) = CONVERT (date, GETDATE()) ORDER BY Name ASC" ); // AND SortedLines like '%2%' + if( $stmt === false) { + die( print_r( sqlsrv_errors(), true) ); + } + + $rows = ''; + + $class_out = ''; + $class_missed = ''; + $highest_in = 0; + $highest_out = 0; + $highest_missed = 0; + $firstLoop = true; + while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) ) { + $this->getQueueAgentsStatus($row['StateDiscription']); + $agent_stat = $this->getQueueAgentsCallStats($row['Extension']); + + $count_in = ($agent_stat['q_agent_call_count_in'] > 0) ? $agent_stat['q_agent_call_count_in'] : ''; + $count_out = ($agent_stat['q_agent_call_count_out'] > 0) ? $agent_stat['q_agent_call_count_out'] : ''; + $count_missed = ($agent_stat['q_agent_call_missed_count'] > 0) ? $agent_stat['q_agent_call_missed_count'] : ''; + $count_wait_time = ($agent_stat['q_agent_call_wait_time'] > 0) ? gmdate('H:i:s',$agent_stat['q_agent_call_wait_time'] / $count_in) : ''; + + if ($firstLoop) { + $firstLoop = false; + $highest_in = $count_in; + $maxPrice = $count_out; + } + else { + $highest_in = max($highest_in, $count_in); + $maxPrice = max($maxPrice, $count_out); + } + + if ($count_in === $highest_in){ + $class_in= 'class="text-navy"'; + } + if ($count_missed > $highest_missed){ + $highest_missed = $count_missed; + $class_missed= 'class="text-navy"'; + } + $rows .= ' + '.$row['Extension'].' + '.$row['Name'].' + '.$this->queue_agent_status.' + '. $count_in .' + '. $count_out .' + '. $count_missed .' + '. $count_wait_time .' + '; + } + + $res = array( + 'status' => 1, + 'rows' => $rows, + 'maxId' => $highest_in + ); + jsonArr($res); + } + + private function getQueueAgentsCallStats($agent_id) + { + // Total calls + // Calls in + // Calls out + // Missed calls + // Total Wait time + // Total Speak time + $conn = $this->connectSqlSrv(); + + $params = array( $agent_id); + + $q_array = array( + "q_agent_call_count_in" => "SELECT count(distinct CallID) FROM AgentADR WHERE CONVERT (date, ChangeDate) = CONVERT (date, GETDATE()) And StateTime != 0 AND Discription = 'Busy-In' and Extension = ?", + "q_agent_call_count_out" => "SELECT count(distinct CallID) FROM AgentADR WHERE CONVERT (date, ChangeDate) = CONVERT (date, GETDATE()) And StateTime != 0 AND Discription = 'Busy-Out' and Extension = ?", + "q_agent_call_missed_count" => "SELECT count(distinct CallID) FROM MissedCalls WHERE CONVERT (date, MissedTime) = CONVERT (date, GETDATE()) AND Extension = ?", + "q_agent_call_wait_time" => "SELECT sum(WaitTime) FROM Distrihistri WHERE CONVERT (date, Startcall) = CONVERT (date, GETDATE()) and DeliveredTo = ?", + ); + + $res = array(); + + foreach($q_array as $key => $val) + { + $stmt = sqlsrv_prepare( $conn, $val, $params); + sqlsrv_execute( $stmt); + if( $stmt === false) { + die( print_r( sqlsrv_errors(), true) ); + } + + while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC) ) { + $res[$key] = $row[0]; + } + + } + + return $res; + } + + private function getQueueAgentsStatus($status) + { + switch($status) + { + case 'Busy-Out': + $this->queue_agent_status = ' '; + break; + case 'Busy-In': + $this->queue_agent_status = ' '; + break; + case 'Dialing': + $this->queue_agent_status = ' dialing...'; + break; + case 'Offline': + $this->queue_agent_status = 'Offline'; + break; + case 'Idle': + $this->queue_agent_status = 'Idle...'; + break; + default: + $this->queue_agent_status = $status .'...'; + } + } + + private function checkQueueCount($queue_id, $sla = '') + { + $conn = $this->connectSqlSrv(); + + $params = array( $queue_id); + + $q_array = array( + "q_calls_count" => "SELECT COUNT(QueueID) FROM queue WHERE QueueID = ?", + "q_queue_active" => "SELECT Active FROM UserTrack WHERE QueueID = ?", + "q_calls_total_in" => "SELECT count(CallID) FROM Distrihistri WHERE CONVERT (date, Startcall) = CONVERT (date, GETDATE()) AND QueueID = ? ", + "q_calls_total_out" => "SELECT count(distinct CallID) FROM AgentADR WHERE CONVERT (date, ChangeDate) = CONVERT (date, GETDATE()) And StateTime != 0 AND Discription = 'Busy-Out'", + "q_calls_missed" => "SELECT count(distinct CallID) FROM MissedCalls WHERE CONVERT (date, MissedTime) = CONVERT (date, GETDATE()) AND QueueID = ?", + "q_avg_wait_time" => "SELECT sum(WaitTime) FROM Distrihistri WHERE CONVERT (date, Startcall) = CONVERT (date, GETDATE()) AND QueueID = ?", + "q_sla_count" => "SELECT count(CallID) FROM Distrihistri WHERE CONVERT (date, Startcall) = CONVERT (date, GETDATE()) AND QueueID = ? AND WaitTime <= ". $sla, + ); + + $res = array(); + + foreach($q_array as $key => $val) + { + $stmt = sqlsrv_prepare( $conn, $val, $params); + sqlsrv_execute( $stmt); + if( $stmt === false) { + die( print_r( sqlsrv_errors(), true) ); + } + + while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC) ) { + $res[$key] = $row[0]; + } + + } + + return $res; + } + + /** * Get operator treshold as pie graph. * * @param resource $post_val - $_POST values @@ -1388,7 +1681,7 @@ protected function setPriority($prio_nr, $event_operator = null) ); } /** - * Get signal load weekly avarage + * Get signal load trend analyse * * @param integer $x - specify x axis value * @param integer $y - specify y axis value diff --git a/src/config/common.php b/src/config/common.php index 2857d9d..950c17d 100644 --- a/src/config/common.php +++ b/src/config/common.php @@ -78,6 +78,12 @@ define('PORT_MONITOR_USER', $env['PORT_MONITOR']['USER']); define('PORT_MONITOR_PASS', $env['PORT_MONITOR']['PASS']); define('PORT_MONITOR_NAME', $env['PORT_MONITOR']['NAME']); + + // Define Phone queue DB conn + define('QUEUE_HOST', $env['QUEUE_DB']['HOST']); + define('QUEUE_USER', $env['QUEUE_DB']['USER']); + define('QUEUE_PASS', $env['QUEUE_DB']['PASS']); + define('QUEUE_NAME', $env['QUEUE_DB']['NAME']); // Define SCS conn define('SCS_DB_HOST', $env['SCS_DB']['HOST']); diff --git a/src/config/router.php b/src/config/router.php index 5abac09..648f5d6 100644 --- a/src/config/router.php +++ b/src/config/router.php @@ -67,7 +67,7 @@ // You have to do that for the model and the view too $ctrlPath = ROOT_PATH . '/view/' . $requestedController . '.view.php'; - if(checkUserIsAdmin() && in_array($requestedController, $admin_only)) { + if(!checkUserIsAdmin() && in_array($requestedController, $admin_only)) { http_response_code(403); include ROOT_PATH . '/view/errors/page_403.php'; diff --git a/src/controllers/tools.controller.php b/src/controllers/tools.controller.php index 083e9b3..21b3c86 100644 --- a/src/controllers/tools.controller.php +++ b/src/controllers/tools.controller.php @@ -44,6 +44,15 @@ if(isset($_GET['aoip'])){ $obj->getPortMonitorAoip('AOIP gateway'); } - } + } + + if($_GET['get'] == 'queue'){ + if(isset($_GET['row'])){ + $obj->getQueueRow(); + } + if(isset($_GET['agents'])){ + $obj->getQueueAgents(); + } + } } diff --git a/view/tools.view.php b/view/tools.view.php index 58225e6..45b3538 100644 --- a/view/tools.view.php +++ b/view/tools.view.php @@ -8,6 +8,7 @@
    +
    diff --git a/view/tools/tel_queue.view.php b/view/tools/tel_queue.view.php new file mode 100644 index 0000000..ed3c06d --- /dev/null +++ b/view/tools/tel_queue.view.php @@ -0,0 +1,154 @@ +
    +
    +
    +

    Telefoon queues

    +
    + +
    +
    +
    +
    +

    +
    +
    +

    +
    +
    +
    +
    +
    +
    +
    +
    +

    +
    +
    +

    +
    +
    +
    +
    +
    +
    +
    +
    +

    +
    +
    +

    +
    +
    +
    +
    +
    + +
    + +
    +
    +

    Queue agents

    +
    + + + + + + + + + + + + + + +
    #AgentStatus Gem wachttijd
    +
    +
    +
    +
    + + + + + + + '; + } + ?> + + \ No newline at end of file From 8f652da9a2da728c40d0cb75a347353e8f02e00c Mon Sep 17 00:00:00 2001 From: MillieOfzo Date: Wed, 6 Jun 2018 08:42:49 +0200 Subject: [PATCH 06/10] Tel queue update --- src/classes/class.tools.php | 18 ++++++++---- view/tools/tel_queue.view.php | 53 +++++++++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/src/classes/class.tools.php b/src/classes/class.tools.php index ab123c8..b2897b5 100644 --- a/src/classes/class.tools.php +++ b/src/classes/class.tools.php @@ -28,6 +28,8 @@ class Tools private $queue_total_in_count = 0; private $queue_total_out_count = 0; private $queue_missed_count = 0; + private $queue_in_sla_count = 0; + private $queue_out_sla_count = 0; private $queue_agent_status; /* @@ -82,6 +84,7 @@ public function getQueueRow() $this->queue_total_in_count += $queue['q_calls_total_in']; $this->queue_total_out_count = $queue['q_calls_total_out']; $this->queue_missed_count += $queue['q_calls_missed']; + $this->queue_in_sla_count += $queue['q_sla_count']; $total_calls = $queue['q_calls_total_in'] + $queue['q_calls_missed']; $percent_class = ''; @@ -101,7 +104,7 @@ public function getQueueRow() $percent_class = 'navy'; } $percent = $percent.'%'; - $avg_wait = ($queue['q_avg_wait_time'] / $total_calls > 1) ? gmdate("H:i:s", $queue['q_avg_wait_time'] / $total_calls) : ''; + $avg_wait = (($queue['q_avg_wait_time'] / $total_calls) > 1) ? gmdate("H:i:s", $queue['q_avg_wait_time'] / $total_calls) : ''; } else { $percent = ''; $avg_wait = ''; @@ -123,7 +126,7 @@ public function getQueueRow() $span_class='c-gray'; } - $count = ($queue['q_calls_count'] > 0) ? '

    '. $queue['q_calls_count'].'

    ' : ''; + $count = ($queue['q_calls_count'] > 0) ? '

    '. $queue['q_calls_count'].'

    ' : ''; $count_total = ($queue['q_calls_total_in'] > 0) ? $queue['q_calls_total_in'] : ''; $count_total_missed = ($queue['q_calls_missed'] > 0) ? $queue['q_calls_missed'] : ''; $total_wait = ($queue['q_avg_wait_time'] > 1) ? gmdate("H:i:s",$queue['q_avg_wait_time']) : ''; @@ -172,7 +175,9 @@ public function getQueueRow() 'row' => $rows, 'total_in' => $this->queue_total_in_count, 'total_out' => $this->queue_total_out_count, - 'total_missed' => $this->queue_missed_count + 'total_missed' => $this->queue_missed_count, + 'total_in_sla' => round((100 / $this->queue_total_in_count) * $this->queue_in_sla_count), + 'total_out_sla' => round((100 / $this->queue_total_in_count) * ($this->queue_total_in_count - $this->queue_in_sla_count)), ); jsonArr($res); } @@ -181,7 +186,7 @@ public function getQueueAgents() { $conn = $this->connectSqlSrv(); - $stmt = sqlsrv_query( $conn, "SELECT * FROM AvailableAgents WHERE CONVERT (date, LastCall) = CONVERT (date, GETDATE()) ORDER BY Name ASC" ); // AND SortedLines like '%2%' + $stmt = sqlsrv_query( $conn, "SELECT * FROM AvailableAgents WHERE Hosts != '' OR CONVERT (date, LastCall) = CONVERT (date, GETDATE()) ORDER BY Name ASC" ); // AND SortedLines like '%2%' if( $stmt === false) { die( print_r( sqlsrv_errors(), true) ); } @@ -202,6 +207,7 @@ public function getQueueAgents() $count_out = ($agent_stat['q_agent_call_count_out'] > 0) ? $agent_stat['q_agent_call_count_out'] : ''; $count_missed = ($agent_stat['q_agent_call_missed_count'] > 0) ? $agent_stat['q_agent_call_missed_count'] : ''; $count_wait_time = ($agent_stat['q_agent_call_wait_time'] > 0) ? gmdate('H:i:s',$agent_stat['q_agent_call_wait_time'] / $count_in) : ''; + $count_speak_time = ($agent_stat['q_agent_call_speak_time'] > 0) ? gmdate('H:i:s',$agent_stat['q_agent_call_speak_time'] / $count_in) : ''; if ($firstLoop) { $firstLoop = false; @@ -228,6 +234,7 @@ public function getQueueAgents() '. $count_out .' '. $count_missed .' '. $count_wait_time .' + '. $count_speak_time .' '; } @@ -254,8 +261,9 @@ private function getQueueAgentsCallStats($agent_id) $q_array = array( "q_agent_call_count_in" => "SELECT count(distinct CallID) FROM AgentADR WHERE CONVERT (date, ChangeDate) = CONVERT (date, GETDATE()) And StateTime != 0 AND Discription = 'Busy-In' and Extension = ?", "q_agent_call_count_out" => "SELECT count(distinct CallID) FROM AgentADR WHERE CONVERT (date, ChangeDate) = CONVERT (date, GETDATE()) And StateTime != 0 AND Discription = 'Busy-Out' and Extension = ?", - "q_agent_call_missed_count" => "SELECT count(distinct CallID) FROM MissedCalls WHERE CONVERT (date, MissedTime) = CONVERT (date, GETDATE()) AND Extension = ?", + "q_agent_call_missed_count" => "SELECT count( distinct CallID) FROM MissedCalls WHERE CONVERT (date, MissedTime) = CONVERT (date, GETDATE()) AND Extension = ?", "q_agent_call_wait_time" => "SELECT sum(WaitTime) FROM Distrihistri WHERE CONVERT (date, Startcall) = CONVERT (date, GETDATE()) and DeliveredTo = ?", + "q_agent_call_speak_time" => "SELECT sum(Speaktime) FROM Distrihistri WHERE CONVERT (date, Startcall) = CONVERT (date, GETDATE()) and DeliveredTo = ?", ); $res = array(); diff --git a/view/tools/tel_queue.view.php b/view/tools/tel_queue.view.php index ed3c06d..6165fde 100644 --- a/view/tools/tel_queue.view.php +++ b/view/tools/tel_queue.view.php @@ -1,9 +1,8 @@
    -

    Telefoon queues

    +

    Totaal statistiek

    -
    @@ -13,6 +12,9 @@

    +
    + Totaal inkomende calls +
    @@ -25,6 +27,9 @@

    +
    + Totaal uitgaande calls +
    @@ -33,14 +38,53 @@

    +

    +
    + Totaal gemiste calls +
    +
    + + +
    +
    +
    +
    +

    SLA

    +
    +
    +

    %

    +
    +
    + Percentage inkomende calls binnen SLA +
    +
    +
    +
    +
    +
    +
    +
    +

    SLA

    +
    +
    +

    %

    +
    +
    + Percentage inkomende calls buiten SLA +
    +
    +
    +

    Telefoon queues

    +
    +
    @@ -58,6 +102,7 @@ Gem wachttijd + Gem spreektijd @@ -126,11 +171,15 @@ function getQueues(){ $('#total_in').html(data.total_in); $('#total_out').html(data.total_out); $('#missed').html(data.total_missed); + $('#total_in_sla').html(data.total_in_sla); + $('#total_out_sla').html(data.total_out_sla); } else { $('#queue').html(''); $('#total_in').html(''); $('#total_out').html(''); $('#missed').html(''); + $('#total_in_sla').html(''); + $('#total_out_sla').html(''); } } }); From deccae50965d5cb424041d2be1c3d203b6223fe9 Mon Sep 17 00:00:00 2001 From: MillieOfzo Date: Wed, 6 Jun 2018 15:25:15 +0200 Subject: [PATCH 07/10] Update license --- LICENSE | 144 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 123 insertions(+), 21 deletions(-) diff --git a/LICENSE b/LICENSE index 4c9efd6..a98667a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,123 @@ -MIT License - -Copyright (c) 2018 Roelof - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +  +** END USER LICENSE AGREEMENT +------------------------------------------------------------ + +This End-User License Agreement (the “EULA”) is a LEGAL AGREEMENT between the individual or legal entity that intents to download and/or actually downloads and uses the Software and ASB Monitoring BV (the “Company”), the author +of the software (the “Software”), which may include associated media, printed materials, and “online” or electronic documentation. + +By installing, accessing, copying or (otherwise) using the Software, Licensee is BOUND BY THE TERMS AND CONDITIONS SET FORTH IN THIS EULA. If Licensee does not agree to and/or comply with the terms and conditions set forth in +this EULA, then Licensee must not download, install, or (continue to) use the Software. + +This EULA expresses and describes Dutch legal concepts in English and not in their original Dutch terms. Consequently, this EULA is made on the express condition that all words, terms and expressions used herein shall be +construed and interpreted in accordance with the laws of the Netherlands. + +The Company is allowed to change the terms and conditions of this EULA at any time. + +1. DEFINITIONS. + +* “Company” shall refer to the licensor, the private company with limited liability ASB Security BV, located at Boschdijk 720, 5624CL, Eindhoven, The Netherlands, registered at the Dutch Chamber of Commerce under number +17042775. +* "End User" shall mean an employee, contractor or agent of Licensee and its affiliates authorized by Licensee to use the Software as per the terms of this EULA. +* “Licensee” shall mean the individual or legal entity that intents to download and/or actually downloads and uses the Software. +* “Software” shall mean the deliverables provided pursuant to this EULA, namely: titanium remote service portal. + +2. GRANT OF LICENSE. + +* SOFTWARE PRODUCT LICENSE. The Software is licensed, not sold. Subject to the terms of this EULA, Company hereby grants to Licensee a royalty-free, non-exclusive, non-sublicensable and non-transferable license to possess +and to use a copy of the Software only for Licensee's own internal use and limited to the number of End Users for which Licensee has paid the applicable license fee. Licensee shall maintain accurate records necessary to +verify the number of End Users. Upon Company's written request, Licensee shall provide Company with such records within ten (10) days. If Licensee has more End Users than Licensee has paid for, Licensee shall immediately pay +Company an additional license fee in addition to any costs incurred by Company associated with reviewing such records. +* LICENSEE'S RESPONSIBILITY FOR END USERS. Licensee shall be responsible for any act or omission of all End Users and for their compliance with all of the terms of this EULA. Any action or breach by any of Licensee's +employees, contractors, agents or affiliates shall be deemed an action or breach by Licensee of this EULA and Licensee hereby indemnifies and holds Company harmless from any and all such breaches of this EULA. Licensee +waives all of those defenses that Licensee may have in law or otherwise which may be raised to avoid liability should Licensee not be liable for its employees', contractors’, agents’ or affiliates’ acts, omissions and +non-compliance with the terms of this EULA. +* INSTALLATION AND USE. Licensee shall install the Software on its premises. The Software may be installed on one computer or device ("Licensed Hardware System") for use by one person at a time only. Licensee may not allow +multiple users, computers or devices to access or use the Software (indirectly) through the Licensed Hardware System. If Licensee wishes to use the Software on more than hardware system, it must obtain separate copies and +separate licenses to go with each copy. +* REPRODUCTION AND COPIES. Licensee is allowed to reproduce the Software and this reproduction may serve as a back-up copy, insofar as this is necessary for the intended use of the Software only. The back-up copy may not be +distributed and may only be used to reinstall the Software. + +3. DESCRIPTION OF LIMITATIONS. + +* LIMITATIONS. Licensee may not - irrespective of whether for commercial purposes or not - reverse engineer, decompile, disassemble, publish, copy, rent, lease, rend or encumber the Software or attempt to circumvent +technical protection measures, except and only to the extent that such activity is expressly permitted in this EULA or by applicable law. +* SEPARATION OF COMPONENTS. Software is licensed as a single product. Its components may not be separated or virtualized for use on more than one computer. +* SOFTWARE TRANSFER. Licensee cannot transfer any rights under the EULA. This limitation affects both the law of obligations and property rights. + +4. INTELLECTUAL PROPERTY. + +All intellectual property rights, including titles, interests and copyrights in and to the Software, including but not limited to all images, photographs, animations, video, audio, music, text, data, computer code, algorithms, +and information, are owned by and shall (regardless of Licensee's involvement in its (further) development) continue to be property of Company and/or its licensors. To the extent that with regard to the Software intellectual +property rights would arise on the part of Licensee, Licensee hereby declares it shall (without charge) fully cooperate to assigning these rights to the Company. The Software is protected by all applicable copyright laws and +international treaties. Therefore, Licensee is required to treat Software like any other copyrighted material, except as otherwise provided for in this EULA. + +5. NON-SUPPORT. + +Company is under no obligation to support the Software, or to continue providing or updating any of the Software. + +6. DURATION AND TERMINATION. + +* This EULA is effective for an indefinite period. +* If Licensee fails to comply with any of the terms and conditions set forth in this EULA, it shall automatically be in default and the Company shall be entitled to terminate (in Dutch: "ontbinden") it. +* Notwithstanding the foregoing, this EULA may be terminated (in Dutch: "opzeggen" or "ontbinden") by Company in accordance with its (other) rights following from this EULA and/or applicable law and/or case law. “Opzegging” +means any termination which under the applicable law leads, to the extent permitted, desired and communicated, to the end of the obligations of the parties beyond the date of such termination, without prejudice to the +obligations accrued prior to the date of such termination. “Ontbinding” means any termination which under the applicable law creates the obligation for the parties to undo, to the extent permitted, desired and communicated, +any performance rendered prior to the date of such termination. +* Company may terminate (in Dutch: "opzeggen") this EULA upon written notice, including e-mail, to Licensee, with or without cause, provided that it takes into account a notice period of one month. Licensee affirms that this +is a reasonable notice period. +* If the EULA is ended by the Company in accordance with this article, it shall not be liability for any compensation. + +7. INTEGRATION. + +Both parties agree that this EULA is the complete and exclusive statement of the mutual understanding of the parties and supersedes and cancels all previous written and oral agreements and communications relating to the subject +matter of this EULA. + +8. JURISDICTION. + +This EULA shall be deemed to have been made in, and shall be construed pursuant to and governed exclusively by the laws of the Netherlands, without regard to conflicts of laws provisions thereof. Any legal action or proceeding +resulting from or relating to this EULA shall - insofar as Dutch imperative law allows it - be brought exclusively to the competent judge of the judicial district of Oost-Brabant, the Netherlands, and each party consents to the +jurisdiction thereof. If the Company is the prevailing party in any action to enforce this EULA it shall be entitled to recover all accompanying costs and expenses including, without limitation, attorneys’ fees. + +9. NON-TRANSFERABLE. + +This EULA is not assignable or transferable (neither under civil law nor property law) by Licensee without the prior written consent of Company; any attempt to do so shall be void. + +10. NOTICES. + +Any notice, report, approval or consent required or permitted hereunder shall be in writing and will be deemed to have been duly given if delivered personally or mailed by first-class, registered or certified mail, postage +prepaid to the respective addresses of the parties and/or the email address a party has indicated and/or proven in the past to be accessible on. + +11. SEVERABILITY. + + SEVERABILITY. No failure to exercise, and no delay in exercising, on the part of Company, any privilege, any power or any rights hereunder will operate as a waiver thereof, nor will any single or partial exercise of any right +or power hereunder preclude further exercise of any other right hereunder. If any provision of this EULA shall be adjudged by any court of competent jurisdiction to be unenforceable or invalid, that provision shall be limited +or eliminated to the minimum extent necessary so that this EULA shall otherwise remain in full force and effect and enforceable. + +12. WARRANTY DISCLAIMER. + + WARRANTY DISCLAIMER. Company hereby expressly disclaims any representation and/or warranty for the Software. Software and any related documentation is provided “as is” without representation and/or warranty of any kind, either +express or implied, including, without limitation, the implied warranties of merchantability, fitness for a particular purpose, or non-infringement. Licensee accepts any and all risk arising out of or in connection with use or +performance of the Software. + +13. LIMITED LIABILITY. + +With the exception of deliberate intent (in Dutch: "opzet") or deliberate recklessness (in Dutch: "bewuste roekeloosheid") of Company and/or its managerial subordinates, Company excludes its entire liability towards Licensee +and/or third parties for damages arising out of or in connection with this EULA and/or the use or performance of the Software, all in the broadest sense (breach of contract, tort or any other legal basis). + +In the event that the above exemption from liability does not uphold, the Company’s aggregate liability to Licensee and/or any third party (claiming through Licensee) shall never exceed the financial amount actually paid by +Licensee to Company for the Software. Furthermore, Company shall in no event be liable towards Licensee and/or any third party (claiming through Licensee) for any indirect damages, including but not limited to loss of profits, +income, savings, or any other consequential, incidental, special, punitive damage, whether arising in contract, tort, warranty, or otherwise. + +14. INFRINGEMENT. + +During any term of this EULA, if any portion of the Software is held by a court of competent jurisdiction to infringe any third party intellectual property rights and Licensee incurs a liability or expense as a result of such +holding, then the Licensee's sole remedy shall be, and Company will, at its option: (i) obtain the right for Licensee to continue to use the Software consistent with this EULA; (ii) modify the Software so that it is +non-infringing; or (iii) replace the infringing component with a non-infringing component, or (iv) refund all money paid in the then-current calendar quarter under this EULA and all of Licensee's rights and licenses under this +EULA shall automatically terminate. + +15. ENTIRE AGREEMENT. + +This EULA constitutes the entire agreement between Company and Licensee and supersedes all prior understandings of Company and Licensee, including any prior representation, statement, condition, or warranty, unless to the extent +that such prior understanding supports interpretation of this EULA. + +Version 2017103EN From a04be5c37d32c39149794756640ea8019ff55d75 Mon Sep 17 00:00:00 2001 From: MillieOfzo Date: Fri, 13 Jul 2018 15:41:44 +0200 Subject: [PATCH 08/10] Updated maps to show IP disconnects --- js/google_style_dark.js | 3 +- src/classes/class.home.php | 84 +++-- src/classes/class.safemysql.php | 2 +- src/helpers/functions.php | 21 +- src/lang/nl.json | 3 +- src/lang/pt.json | 523 ++++++++++++++++++++++++++++++++ view/home.view.php | 9 +- view/tools/maps.view.php | 50 ++- 8 files changed, 651 insertions(+), 44 deletions(-) create mode 100644 src/lang/pt.json diff --git a/js/google_style_dark.js b/js/google_style_dark.js index bbe011e..4d649a5 100644 --- a/js/google_style_dark.js +++ b/js/google_style_dark.js @@ -196,7 +196,8 @@ var google_styles = [ "elementType": "geometry.fill", "stylers": [ { - "color": "#539a4b" + // #539a4b + "color": "#282828" }, { "saturation": -100 diff --git a/src/classes/class.home.php b/src/classes/class.home.php index 62344c3..707c5e5 100644 --- a/src/classes/class.home.php +++ b/src/classes/class.home.php @@ -22,10 +22,11 @@ class Home * $path_arr possible values used to show locations and grouped locations * 0 = disconnected * 1 = connected - * 2 = connected by backup - * 3 = no path defined + * 2 = backup disconnected + * 3 = primair disconnected + * 4 = no path defined */ - protected $path_arr = array(0,2); + protected $path_arr = array(0,2,3); /* * Constants values defined in env.ini */ @@ -38,7 +39,8 @@ function __construct($db_conn) { $this->db_conn = $db_conn; } - /** + + /** * Get marker set based on locations in SCS who got latitude and longitude defined * * @param boolean $getall - get complete dataset of get changed dataset since $updatetime @@ -112,7 +114,7 @@ public function getMarkers($getall = false, $updatetime = '') if ($path_status == 3) { $conn_status = $this->getPathStatusTranslation(3); - $err_class = 'text-default'; + $err_class = 'text-warning'; } elseif ($path_status == 0) { @@ -123,6 +125,11 @@ public function getMarkers($getall = false, $updatetime = '') { $conn_status = $this->getPathStatusTranslation(2); $err_class = 'text-warning'; + } + elseif ($path_status == 4) + { + $conn_status = $this->getPathStatusTranslation(4); + $err_class = 'text-default'; } else { @@ -161,6 +168,7 @@ public function getMarkers($getall = false, $updatetime = '') jsonArr($locs); } + /** * Get server side list of SCS location status to be used in client side DataTable * @@ -210,7 +218,7 @@ public function getList($state) $path_status = getPathStatus($d); if ($path_status == 3) { - $conn_status = ' ' . LANG['connection']['nopath']; + $conn_status = ' ' . LANG['connection']['prim']; } elseif ($path_status == 0) { @@ -219,6 +227,10 @@ public function getList($state) elseif ($path_status == 2) { $conn_status = ' ' . LANG['connection']['back']; + } + elseif ($path_status == 4) + { + $conn_status = ' ' . LANG['connection']['nopath']; } else { @@ -239,6 +251,10 @@ public function getList($state) if ($path_status == 3) { $conn_class = 'text-default'; + } + elseif ($path_status == 4) + { + $conn_class = 'text-warning'; } elseif ($path_status == 0) { @@ -314,6 +330,7 @@ public function getList($state) jsonArr(SSP::complex($_GET, $db, 'scs_account_status', 'scs_account_nmbr', $columns, $whereResult = null, $whereAll = $where)); } + /** * Get server side list of RMS devices from local database to be used in client side DataTable * @@ -432,7 +449,8 @@ public function getListRms() jsonArr(SSP::complex($_GET, $db, 'rms_status_db', 'Diag_scan_id', $columns, $whereResult = null, $whereAll = $where)); } - /** + + /** * Get SCS events counts from current week for 24h and current week * * @return array|JSON @@ -509,7 +527,8 @@ function percent($nieuweWaarde, $oudeWaarde) jsonArr($response_array); } - /** + + /** * Get all divs used to display in maps tools dashboard. Makes calls to multiple set methods * * @param boolean $getall - get complete dataset of get changed dataset since $updatetime @@ -532,6 +551,7 @@ public function getMarkersDiv() $locs['count'] = array( 'conn' => ' ' . $location_count['connected'] . '', 'diss' => ' ' . $location_count['disconnected'] . '', + 'prim' => ' ' . $location_count['primair'] . '', 'back' => ' ' . $location_count['backup'] . '', 'nopath' => ' ' . $location_count['nopath'] . '' ); @@ -548,7 +568,8 @@ public function getMarkersDiv() jsonArr($locs); } - /** + + /** * Get multidimensional array containing all locations from sql result with path status, group name and SCS nr * * @return multidimensional array|locations=>array|path,group,id @@ -594,7 +615,7 @@ protected function setMarkersStatusArray() if ($path_status == 3) { - // No path defined + // IP disconnected $locs['locations'][] = array( 'path' => 3, 'group' => $row['SCS_Account_Group'], @@ -609,10 +630,19 @@ protected function setMarkersStatusArray() 'group' => $row['SCS_Account_Group'], 'id' => $row['SCS_Account_Nmbr'] ); + } + elseif ($path_status == 4) + { + // No path status + $locs['locations'][] = array( + 'path' => 4, + 'group' => $row['SCS_Account_Group'], + 'id' => $row['SCS_Account_Nmbr'] + ); } elseif ($path_status == 2) { - // Backup + // Backup disconnected $locs['locations'][] = array( 'path' => 2, 'group' => $row['SCS_Account_Group'], @@ -637,7 +667,8 @@ protected function setMarkersStatusArray() return $locs; } - /** + + /** * Get multidimensional array containing all locations where path is defined in $path_arr * and the group name does not appear in the array from method setMarkersGrouped() * @@ -670,7 +701,10 @@ protected function setMarkersDivLocations() $conn_status = ' ' . $this->getPathStatusTranslation(2); break; case 3: - $conn_status = ' ' . $this->getPathStatusTranslation(3); + $conn_status = ' ' . $this->getPathStatusTranslation(3); + break; + case 4: + $conn_status = ' ' . $this->getPathStatusTranslation(4); break; default: $conn_status = ''; @@ -689,6 +723,7 @@ protected function setMarkersDivLocations() return $locs; } + /** * Get multidimensional array containing all locations grouped * based on the defined $path_arr and if the belong to the same group @@ -782,7 +817,8 @@ protected function setMarkersGrouped() ); } - /** + + /** * Get total count value based on locations in setMarkersStatusArray() method * * @return array=>connected, disconnected, backup, nopath @@ -794,6 +830,7 @@ protected function setMarkersDivCount() $stat_nopath = 0; $stat_diss = 0; + $stat_prim = 0; $stat_back = 0; $stat_conn = 0; @@ -815,6 +852,10 @@ protected function setMarkersDivCount() break; case 3: $conn_status = $this->getPathStatusTranslation(3); + $stat_prim += 1; + break; + case 4: + $conn_status = $this->getPathStatusTranslation(4); $stat_nopath += 1; break; default: @@ -826,19 +867,22 @@ protected function setMarkersDivCount() return array( 'connected' => $stat_conn, 'disconnected' => $stat_diss, + 'primair' => $stat_prim, 'backup' => $stat_back, 'nopath' => $stat_nopath ); } - /** + + /** * Get path connection translation * * @param integer $path_nr - path status integer. * Possible values: * 0 = disconnected, * 1 = connected, - * 2 = connected by backup, - * 3 = no path defined, + * 2 = backup disconnected, + * 3 = IP disconnected, + * 4 = no path defined, * @return string */ protected function getPathStatusTranslation($path_nr) @@ -855,12 +899,16 @@ protected function getPathStatusTranslation($path_nr) return LANG['connection']['back']; break; case 3: - return LANG['connection']['nopath']; + return LANG['connection']['prim']; break; + case 4: + return LANG['connection']['nopath']; + break; default: return ''; break; } } + } diff --git a/src/classes/class.safemysql.php b/src/classes/class.safemysql.php index 5e0e90b..7b1f1dc 100644 --- a/src/classes/class.safemysql.php +++ b/src/classes/class.safemysql.php @@ -1 +1 @@ - 'user', * 'pass' => 'pass', * 'db' => 'db', * 'charset' => 'latin1' * ); * $db = new SafeMySQL($opts); // with some of the default settings overwritten * * Alternatively, you can just pass an existing mysqli instance that will be used to run queries * instead of creating a new connection. * Excellent choice for migration! * * $db = new SafeMySQL(['mysqli' => $mysqli]); * * Some examples: * * $name = $db->getOne('SELECT name FROM table WHERE id = ?i',$_GET['id']); * $data = $db->getInd('id','SELECT * FROM ?n WHERE id IN ?a','table', array(1,2)); * $data = $db->getAll("SELECT * FROM ?n WHERE mod=?s LIMIT ?i",$table,$mod,$limit); * $data = $db->getRow("SELECT * FROM ?n WHERE mod=?s LIMIT ?i",$table,$mod,$limit); getRow($query,$param1,$param2, ...) - returns 1-dimensional array, a row * * $ids = $db->getCol("SELECT id FROM tags WHERE tagname = ?s",$tag); * $data = $db->getAll("SELECT * FROM table WHERE category IN (?a)",$ids); * * $data = array('offers_in' => $in, 'offers_out' => $out); * $sql = "INSERT INTO stats SET pid=?i,dt=CURDATE(),?u ON DUPLICATE KEY UPDATE ?u"; * $db->query($sql,$pid,$data,$data); * * if ($var === NULL) { * $sqlpart = "field is NULL"; * } else { * $sqlpart = $db->parse("field = ?s", $var); * } * $data = $db->getAll("SELECT * FROM table WHERE ?p", $bar, $sqlpart); * * RGO: Replaced mysqli_real_escape_string with HTMLpurifier in escapeString() */ class SafeMySQL { protected $conn; protected $stats; protected $emode; protected $exname; protected $report; protected $purifier = null; protected $defaults = array( 'host' => DB_HOST, 'user' => DB_USER, 'pass' => DB_PASS, 'db' => DB_NAME, 'port' => NULL, 'socket' => NULL, 'pconnect' => FALSE, 'charset' => 'utf8', 'errmode' => 'exception', //or 'error' 'exception' => 'Exception', //Exception class name ); const RESULT_ASSOC = MYSQLI_ASSOC; const RESULT_NUM = MYSQLI_NUM; function __construct($opt = array()) { $opt = array_merge($this->defaults,$opt); //$this->report = mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); $this->emode = $opt['errmode']; $this->exname = $opt['exception']; if (isset($opt['mysqli'])) { if ($opt['mysqli'] instanceof mysqli) { $this->conn = $opt['mysqli']; return; } else { $this->error("mysqli option must be valid instance of mysqli class"); } } if ($opt['pconnect']) { $opt['host'] = "p:".$opt['host']; } @$this->conn = mysqli_connect($opt['host'], $opt['user'], $opt['pass'], $opt['db'], $opt['port'], $opt['socket']); if ( !$this->conn ) { $this->error(mysqli_connect_errno()." ".mysqli_connect_error()); } mysqli_set_charset($this->conn, $opt['charset']) or $this->error(mysqli_error($this->conn)); unset($opt); // I am paranoid // RGO: HTMLpurifier class is included through common.php $this->purifier = new HTMLPurifier(HTMLPurifier_Config::createDefault()); } /** * Conventional function to run a query with placeholders. A mysqli_query wrapper with placeholders support * * Examples: * $db->query("DELETE FROM table WHERE id=?i", $id); * * @param string $query - an SQL query with placeholders * @param mixed $arg,... unlimited number of arguments to match placeholders in the query * @return resource|FALSE whatever mysqli_query returns */ public function query() { return $this->rawQuery($this->prepareQuery(func_get_args())); } /** * Conventional function to fetch single row. * * @param resource $result - myqli result * @param int $mode - optional fetch mode, RESULT_ASSOC|RESULT_NUM, default RESULT_ASSOC * @return array|FALSE whatever mysqli_fetch_array returns */ public function fetch($result,$mode=self::RESULT_ASSOC) { return mysqli_fetch_array($result, $mode); } /** * Conventional function to get number of affected rows. * * @return int whatever mysqli_affected_rows returns */ public function affectedRows() { return mysqli_affected_rows ($this->conn); } /** * Conventional function to get last insert id. * * @return int whatever mysqli_insert_id returns */ public function insertId() { return mysqli_insert_id($this->conn); } /** * Conventional function to get number of rows in the resultset. * * @param resource $result - myqli result * @return int whatever mysqli_num_rows returns */ public function numRows($result) { return mysqli_num_rows($result); } /** * Conventional function to free the resultset. */ public function free($result) { mysqli_free_result($result); } /** * Helper function to get scalar value right out of query and optional arguments * * Examples: * $name = $db->getOne("SELECT name FROM table WHERE id=1"); * $name = $db->getOne("SELECT name FROM table WHERE id=?i", $id); * * @param string $query - an SQL query with placeholders * @param mixed $arg,... unlimited number of arguments to match placeholders in the query * @return string|FALSE either first column of the first row of resultset or FALSE if none found */ public function getOne() { $query = $this->prepareQuery(func_get_args()); if ($res = $this->rawQuery($query)) { $row = $this->fetch($res); if (is_array($row)) { return reset($row); } $this->free($res); } return FALSE; } /** * Helper function to get single row right out of query and optional arguments * * Examples: * $data = $db->getRow("SELECT * FROM table WHERE id=1"); * $data = $db->getOne("SELECT * FROM table WHERE id=?i", $id); * * @param string $query - an SQL query with placeholders * @param mixed $arg,... unlimited number of arguments to match placeholders in the query * @return array|FALSE either associative array contains first row of resultset or FALSE if none found */ public function getRow() { $query = $this->prepareQuery(func_get_args()); if ($res = $this->rawQuery($query)) { $ret = $this->fetch($res); $this->free($res); return $ret; } return FALSE; } /** * Helper function to get single column right out of query and optional arguments * * Examples: * $ids = $db->getCol("SELECT id FROM table WHERE cat=1"); * $ids = $db->getCol("SELECT id FROM tags WHERE tagname = ?s", $tag); * * @param string $query - an SQL query with placeholders * @param mixed $arg,... unlimited number of arguments to match placeholders in the query * @return array|FALSE either enumerated array of first fields of all rows of resultset or FALSE if none found */ public function getCol() { $ret = array(); $query = $this->prepareQuery(func_get_args()); if ( $res = $this->rawQuery($query) ) { while($row = $this->fetch($res)) { $ret[] = reset($row); } $this->free($res); } return $ret; } /** * Helper function to get all the rows of resultset right out of query and optional arguments * * Examples: * $data = $db->getAll("SELECT * FROM table"); * $data = $db->getAll("SELECT * FROM table LIMIT ?i,?i", $start, $rows); * * @param string $query - an SQL query with placeholders * @param mixed $arg,... unlimited number of arguments to match placeholders in the query * @return array enumerated 2d array contains the resultset. Empty if no rows found. */ public function getAll() { $ret = array(); $query = $this->prepareQuery(func_get_args()); if ( $res = $this->rawQuery($query) ) { while($row = $this->fetch($res)) { $ret[] = $row; } $this->free($res); } return $ret; } /** * Helper function to get all the rows of resultset into indexed array right out of query and optional arguments * * Examples: * $data = $db->getInd("id", "SELECT * FROM table"); * $data = $db->getInd("id", "SELECT * FROM table LIMIT ?i,?i", $start, $rows); * * @param string $index - name of the field which value is used to index resulting array * @param string $query - an SQL query with placeholders * @param mixed $arg,... unlimited number of arguments to match placeholders in the query * @return array - associative 2d array contains the resultset. Empty if no rows found. */ public function getInd() { $args = func_get_args(); $index = array_shift($args); $query = $this->prepareQuery($args); $ret = array(); if ( $res = $this->rawQuery($query) ) { while($row = $this->fetch($res)) { $ret[$row[$index]] = $row; } $this->free($res); } return $ret; } /** * Helper function to get a dictionary-style array right out of query and optional arguments * * Examples: * $data = $db->getIndCol("name", "SELECT name, id FROM cities"); * * @param string $index - name of the field which value is used to index resulting array * @param string $query - an SQL query with placeholders * @param mixed $arg,... unlimited number of arguments to match placeholders in the query * @return array - associative array contains key=value pairs out of resultset. Empty if no rows found. */ public function getIndCol() { $args = func_get_args(); $index = array_shift($args); $query = $this->prepareQuery($args); $ret = array(); if ( $res = $this->rawQuery($query) ) { while($row = $this->fetch($res)) { $key = $row[$index]; unset($row[$index]); $ret[$key] = reset($row); } $this->free($res); } return $ret; } /** * Function to parse placeholders either in the full query or a query part * unlike native prepared statements, allows ANY query part to be parsed * * useful for debug * and EXTREMELY useful for conditional query building * like adding various query parts using loops, conditions, etc. * already parsed parts have to be added via ?p placeholder * * Examples: * $query = $db->parse("SELECT * FROM table WHERE foo=?s AND bar=?s", $foo, $bar); * echo $query; * * if ($foo) { * $qpart = $db->parse(" AND foo=?s", $foo); * } * $data = $db->getAll("SELECT * FROM table WHERE bar=?s ?p", $bar, $qpart); * * @param string $query - whatever expression contains placeholders * @param mixed $arg,... unlimited number of arguments to match placeholders in the expression * @return string - initial expression with placeholders substituted with data. */ public function parse() { return $this->prepareQuery(func_get_args()); } /** * function to implement whitelisting feature * sometimes we can't allow a non-validated user-supplied data to the query even through placeholder * especially if it comes down to SQL OPERATORS * * Example: * * $order = $db->whiteList($_GET['order'], array('name','price')); * $dir = $db->whiteList($_GET['dir'], array('ASC','DESC')); * if (!$order || !dir) { * throw new http404(); //non-expected values should cause 404 or similar response * } * $sql = "SELECT * FROM table ORDER BY ?p ?p LIMIT ?i,?i" * $data = $db->getArr($sql, $order, $dir, $start, $per_page); * * @param string $iinput - field name to test * @param array $allowed - an array with allowed variants * @param string $default - optional variable to set if no match found. Default to false. * @return string|FALSE - either sanitized value or FALSE */ public function whiteList($input,$allowed,$default=FALSE) { $found = array_search($input,$allowed); return ($found === FALSE) ? $default : $allowed[$found]; } /** * function to filter out arrays, for the whitelisting purposes * useful to pass entire superglobal to the INSERT or UPDATE query * OUGHT to be used for this purpose, * as there could be fields to which user should have no access to. * * Example: * $allowed = array('title','url','body','rating','term','type'); * $data = $db->filterArray($_POST,$allowed); * $sql = "INSERT INTO ?n SET ?u"; * $db->query($sql,$table,$data); * * @param array $input - source array * @param array $allowed - an array with allowed field names * @return array filtered out source array */ public function filterArray($input,$allowed) { foreach(array_keys($input) as $key ) { if ( !in_array($key,$allowed) ) { unset($input[$key]); } } return $input; } /** * Function to get last executed query. * * @return string|NULL either last executed query or NULL if were none */ public function lastQuery() { $last = end($this->stats); return $last['query']; } /** * Function to get all query statistics. * * @return array contains all executed queries with timings and errors */ public function getStats() { return $this->stats; } public function escape($value) { if ($value === NULL) { return 'NULL'; } return mysqli_real_escape_string($this->conn,$value); } /** * protected function which actually runs a query against Mysql server. * also logs some stats like profiling info and error message * * @param string $query - a regular SQL query * @return mysqli result resource or FALSE on error */ protected function rawQuery($query) { $start = microtime(TRUE); $res = mysqli_query($this->conn, $query); $timer = microtime(TRUE) - $start; $this->stats[] = array( 'query' => $query, 'start' => $start, 'timer' => $timer, ); if (!$res) { $error = mysqli_error($this->conn); end($this->stats); $key = key($this->stats); $this->stats[$key]['error'] = $error; $this->cutStats(); $this->error("$error. Full query: [$query]"); } $this->cutStats(); return $res; } protected function prepareQuery($args) { $query = ''; $raw = array_shift($args); $array = preg_split('~(\?[nsiuap])~u',$raw,null,PREG_SPLIT_DELIM_CAPTURE); $anum = count($args); $pnum = floor(count($array) / 2); if ( $pnum != $anum ) { $this->error("Number of args ($anum) doesn't match number of placeholders ($pnum) in [$raw]"); } foreach ($array as $i => $part) { if ( ($i % 2) == 0 ) { $query .= $part; continue; } $value = array_shift($args); switch ($part) { case '?n': $part = $this->escapeIdent($value); break; case '?s': $part = $this->escapeString($value); break; case '?i': $part = $this->escapeInt($value); break; case '?a': $part = $this->createIN($value); break; case '?u': $part = $this->createSET($value); break; case '?p': $part = $value; break; } $query .= $part; } return $query; } protected function escapeInt($value) { if ($value === NULL) { return 'NULL'; } if(!is_numeric($value)) { $this->error("Integer (?i) placeholder expects numeric value, ".gettype($value)." given"); return FALSE; } if (is_float($value)) { $value = number_format($value, 0, '.', ''); // may lose precision on big numbers } return $value; } protected function escapeString($value) { if ($value === NULL) { return 'NULL'; } //return "'".mysqli_real_escape_string($this->conn,$value)."'"; // RGO: Use HTMLpurifier, am paranoid return "'".$this->purifier->purify($value)."'"; } protected function escapeIdent($value) { if ($value) { return "`".str_replace("`","``",$value)."`"; } else { $this->error("Empty value for identifier (?n) placeholder"); } } protected function createIN($data) { if (!is_array($data)) { $this->error("Value for IN (?a) placeholder should be array"); return; } if (!$data) { return 'NULL'; } $query = $comma = ''; foreach ($data as $value) { $query .= $comma.$this->escapeString($value); $comma = ","; } return $query; } protected function createSET($data) { if (!is_array($data)) { $this->error("SET (?u) placeholder expects array, ".gettype($data)." given"); return; } if (!$data) { $this->error("Empty array for SET (?u) placeholder"); return; } $query = $comma = ''; foreach ($data as $key => $value) { $query .= $comma.$this->escapeIdent($key).'='.$this->escapeString($value); $comma = ","; } return $query; } protected function error($err) { $err = __CLASS__.": ".$err; if ( $this->emode == 'error' ) { $err .= ". Error initiated in ".$this->caller().", thrown"; trigger_error($err,E_USER_ERROR); } else { throw new $this->exname($err); } } protected function caller() { $trace = debug_backtrace(); $caller = ''; foreach ($trace as $t) { if ( isset($t['class']) && $t['class'] == __CLASS__ ) { $caller = $t['file']." on line ".$t['line']; } else { break; } } return $caller; } /** * On a long run we can eat up too much memory with mere statsistics * Let's keep it at reasonable size, leaving only last 100 entries. */ protected function cutStats() { if ( count($this->stats) > 100 ) { reset($this->stats); $first = key($this->stats); unset($this->stats[$first]); } } } \ No newline at end of file + 'user', * 'pass' => 'pass', * 'db' => 'db', * 'charset' => 'latin1' * ); * $db = new SafeMySQL($opts); // with some of the default settings overwritten * * Alternatively, you can just pass an existing mysqli instance that will be used to run queries * instead of creating a new connection. * Excellent choice for migration! * * $db = new SafeMySQL(['mysqli' => $mysqli]); * * Some examples: * * $name = $db->getOne('SELECT name FROM table WHERE id = ?i',$_GET['id']); * $data = $db->getInd('id','SELECT * FROM ?n WHERE id IN ?a','table', array(1,2)); * $data = $db->getAll("SELECT * FROM ?n WHERE mod=?s LIMIT ?i",$table,$mod,$limit); * $data = $db->getRow("SELECT * FROM ?n WHERE mod=?s LIMIT ?i",$table,$mod,$limit); getRow($query,$param1,$param2, ...) - returns 1-dimensional array, a row * * $ids = $db->getCol("SELECT id FROM tags WHERE tagname = ?s",$tag); * $data = $db->getAll("SELECT * FROM table WHERE category IN (?a)",$ids); * * $data = array('offers_in' => $in, 'offers_out' => $out); * $sql = "INSERT INTO stats SET pid=?i,dt=CURDATE(),?u ON DUPLICATE KEY UPDATE ?u"; * $db->query($sql,$pid,$data,$data); * * if ($var === NULL) { * $sqlpart = "field is NULL"; * } else { * $sqlpart = $db->parse("field = ?s", $var); * } * $data = $db->getAll("SELECT * FROM table WHERE ?p", $bar, $sqlpart); * * RGO: Replaced mysqli_real_escape_string with HTMLpurifier in escapeString() */ class SafeMySQL { protected $conn; protected $stats; protected $emode; protected $exname; protected $report; protected $purifier = null; protected $defaults = array( 'host' => DB_HOST, 'user' => DB_USER, 'pass' => DB_PASS, 'db' => DB_NAME, 'port' => NULL, 'socket' => NULL, 'pconnect' => FALSE, 'charset' => 'utf8', 'errmode' => 'exception', //or 'error' 'exception' => 'Exception', //Exception class name ); const RESULT_ASSOC = MYSQLI_ASSOC; const RESULT_NUM = MYSQLI_NUM; function __construct($opt = array()) { $opt = array_merge($this->defaults,$opt); //$this->report = mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); $this->emode = $opt['errmode']; $this->exname = $opt['exception']; if (isset($opt['mysqli'])) { if ($opt['mysqli'] instanceof mysqli) { $this->conn = $opt['mysqli']; return; } else { $this->error("mysqli option must be valid instance of mysqli class"); } } if ($opt['pconnect']) { $opt['host'] = "p:".$opt['host']; } @$this->conn = mysqli_connect($opt['host'], $opt['user'], $opt['pass'], $opt['db'], $opt['port'], $opt['socket']); if ( !$this->conn ) { $this->error(mysqli_connect_errno()." ".mysqli_connect_error()); } mysqli_set_charset($this->conn, $opt['charset']) or $this->error(mysqli_error($this->conn)); unset($opt); // I am paranoid // RGO: HTMLpurifier class is included through common.php $this->purifier = new HTMLPurifier(HTMLPurifier_Config::createDefault()); } /** * Conventional function to run a query with placeholders. A mysqli_query wrapper with placeholders support * * Examples: * $db->query("DELETE FROM table WHERE id=?i", $id); * * @param string $query - an SQL query with placeholders * @param mixed $arg,... unlimited number of arguments to match placeholders in the query * @return resource|FALSE whatever mysqli_query returns */ public function query() { return $this->rawQuery($this->prepareQuery(func_get_args())); } /** * Conventional function to fetch single row. * * @param resource $result - myqli result * @param int $mode - optional fetch mode, RESULT_ASSOC|RESULT_NUM, default RESULT_ASSOC * @return array|FALSE whatever mysqli_fetch_array returns */ public function fetch($result,$mode=self::RESULT_ASSOC) { return mysqli_fetch_array($result, $mode); } /** * Conventional function to get number of affected rows. * * @return int whatever mysqli_affected_rows returns */ public function affectedRows() { return mysqli_affected_rows ($this->conn); } /** * Conventional function to get last insert id. * * @return int whatever mysqli_insert_id returns */ public function insertId() { return mysqli_insert_id($this->conn); } /** * Conventional function to get number of rows in the resultset. * * @param resource $result - myqli result * @return int whatever mysqli_num_rows returns */ public function numRows($result) { return mysqli_num_rows($result); } /** * Conventional function to free the resultset. */ public function free($result) { mysqli_free_result($result); } /** * Helper function to get scalar value right out of query and optional arguments * * Examples: * $name = $db->getOne("SELECT name FROM table WHERE id=1"); * $name = $db->getOne("SELECT name FROM table WHERE id=?i", $id); * * @param string $query - an SQL query with placeholders * @param mixed $arg,... unlimited number of arguments to match placeholders in the query * @return string|FALSE either first column of the first row of resultset or FALSE if none found */ public function getOne() { $query = $this->prepareQuery(func_get_args()); if ($res = $this->rawQuery($query)) { $row = $this->fetch($res); if (is_array($row)) { return reset($row); } $this->free($res); } return FALSE; } /** * Helper function to get single row right out of query and optional arguments * * Examples: * $data = $db->getRow("SELECT * FROM table WHERE id=1"); * $data = $db->getOne("SELECT * FROM table WHERE id=?i", $id); * * @param string $query - an SQL query with placeholders * @param mixed $arg,... unlimited number of arguments to match placeholders in the query * @return array|FALSE either associative array contains first row of resultset or FALSE if none found */ public function getRow() { $query = $this->prepareQuery(func_get_args()); if ($res = $this->rawQuery($query)) { $ret = $this->fetch($res); $this->free($res); return $ret; } return FALSE; } /** * Helper function to get single column right out of query and optional arguments * * Examples: * $ids = $db->getCol("SELECT id FROM table WHERE cat=1"); * $ids = $db->getCol("SELECT id FROM tags WHERE tagname = ?s", $tag); * * @param string $query - an SQL query with placeholders * @param mixed $arg,... unlimited number of arguments to match placeholders in the query * @return array|FALSE either enumerated array of first fields of all rows of resultset or FALSE if none found */ public function getCol() { $ret = array(); $query = $this->prepareQuery(func_get_args()); if ( $res = $this->rawQuery($query) ) { while($row = $this->fetch($res)) { $ret[] = reset($row); } $this->free($res); } return $ret; } /** * Helper function to get all the rows of resultset right out of query and optional arguments * * Examples: * $data = $db->getAll("SELECT * FROM table"); * $data = $db->getAll("SELECT * FROM table LIMIT ?i,?i", $start, $rows); * * @param string $query - an SQL query with placeholders * @param mixed $arg,... unlimited number of arguments to match placeholders in the query * @return array enumerated 2d array contains the resultset. Empty if no rows found. */ public function getAll() { $ret = array(); $query = $this->prepareQuery(func_get_args()); if ( $res = $this->rawQuery($query) ) { while($row = $this->fetch($res)) { $ret[] = $row; } $this->free($res); } return $ret; } /** * Helper function to get all the rows of resultset into indexed array right out of query and optional arguments * * Examples: * $data = $db->getInd("id", "SELECT * FROM table"); * $data = $db->getInd("id", "SELECT * FROM table LIMIT ?i,?i", $start, $rows); * * @param string $index - name of the field which value is used to index resulting array * @param string $query - an SQL query with placeholders * @param mixed $arg,... unlimited number of arguments to match placeholders in the query * @return array - associative 2d array contains the resultset. Empty if no rows found. */ public function getInd() { $args = func_get_args(); $index = array_shift($args); $query = $this->prepareQuery($args); $ret = array(); if ( $res = $this->rawQuery($query) ) { while($row = $this->fetch($res)) { $ret[$row[$index]] = $row; } $this->free($res); } return $ret; } /** * Helper function to get a dictionary-style array right out of query and optional arguments * * Examples: * $data = $db->getIndCol("name", "SELECT name, id FROM cities"); * * @param string $index - name of the field which value is used to index resulting array * @param string $query - an SQL query with placeholders * @param mixed $arg,... unlimited number of arguments to match placeholders in the query * @return array - associative array contains key=value pairs out of resultset. Empty if no rows found. */ public function getIndCol() { $args = func_get_args(); $index = array_shift($args); $query = $this->prepareQuery($args); $ret = array(); if ( $res = $this->rawQuery($query) ) { while($row = $this->fetch($res)) { $key = $row[$index]; unset($row[$index]); $ret[$key] = reset($row); } $this->free($res); } return $ret; } /** * Function to parse placeholders either in the full query or a query part * unlike native prepared statements, allows ANY query part to be parsed * * useful for debug * and EXTREMELY useful for conditional query building * like adding various query parts using loops, conditions, etc. * already parsed parts have to be added via ?p placeholder * * Examples: * $query = $db->parse("SELECT * FROM table WHERE foo=?s AND bar=?s", $foo, $bar); * echo $query; * * if ($foo) { * $qpart = $db->parse(" AND foo=?s", $foo); * } * $data = $db->getAll("SELECT * FROM table WHERE bar=?s ?p", $bar, $qpart); * * @param string $query - whatever expression contains placeholders * @param mixed $arg,... unlimited number of arguments to match placeholders in the expression * @return string - initial expression with placeholders substituted with data. */ public function parse() { return $this->prepareQuery(func_get_args()); } /** * function to implement whitelisting feature * sometimes we can't allow a non-validated user-supplied data to the query even through placeholder * especially if it comes down to SQL OPERATORS * * Example: * * $order = $db->whiteList($_GET['order'], array('name','price')); * $dir = $db->whiteList($_GET['dir'], array('ASC','DESC')); * if (!$order || !dir) { * throw new http404(); //non-expected values should cause 404 or similar response * } * $sql = "SELECT * FROM table ORDER BY ?p ?p LIMIT ?i,?i" * $data = $db->getArr($sql, $order, $dir, $start, $per_page); * * @param string $iinput - field name to test * @param array $allowed - an array with allowed variants * @param string $default - optional variable to set if no match found. Default to false. * @return string|FALSE - either sanitized value or FALSE */ public function whiteList($input,$allowed,$default=FALSE) { $found = array_search($input,$allowed); return ($found === FALSE) ? $default : $allowed[$found]; } /** * function to filter out arrays, for the whitelisting purposes * useful to pass entire superglobal to the INSERT or UPDATE query * OUGHT to be used for this purpose, * as there could be fields to which user should have no access to. * * Example: * $allowed = array('title','url','body','rating','term','type'); * $data = $db->filterArray($_POST,$allowed); * $sql = "INSERT INTO ?n SET ?u"; * $db->query($sql,$table,$data); * * @param array $input - source array * @param array $allowed - an array with allowed field names * @return array filtered out source array */ public function filterArray($input,$allowed) { foreach(array_keys($input) as $key ) { if ( !in_array($key,$allowed) ) { unset($input[$key]); } } return $input; } /** * Function to get last executed query. * * @return string|NULL either last executed query or NULL if were none */ public function lastQuery() { $last = end($this->stats); return $last['query']; } /** * Function to get all query statistics. * * @return array contains all executed queries with timings and errors */ public function getStats() { return $this->stats; } public function escape($value) { if ($value === NULL) { return 'NULL'; } return mysqli_real_escape_string($this->conn,$value); } /** * protected function which actually runs a query against Mysql server. * also logs some stats like profiling info and error message * * @param string $query - a regular SQL query * @return mysqli result resource or FALSE on error */ protected function rawQuery($query) { $start = microtime(TRUE); $res = mysqli_query($this->conn, $query); $timer = microtime(TRUE) - $start; $this->stats[] = array( 'query' => $query, 'start' => $start, 'timer' => $timer, ); if (!$res) { $error = mysqli_error($this->conn); end($this->stats); $key = key($this->stats); $this->stats[$key]['error'] = $error; $this->cutStats(); $this->error("$error. Full query: [$query]"); } $this->cutStats(); return $res; } protected function prepareQuery($args) { $query = ''; $raw = array_shift($args); $array = preg_split('~(\?[nsiuap])~u',$raw,null,PREG_SPLIT_DELIM_CAPTURE); $anum = count($args); $pnum = floor(count($array) / 2); if ( $pnum != $anum ) { $this->error("Number of args ($anum) doesn't match number of placeholders ($pnum) in [$raw]"); } foreach ($array as $i => $part) { if ( ($i % 2) == 0 ) { $query .= $part; continue; } $value = array_shift($args); switch ($part) { case '?n': $part = $this->escapeIdent($value); break; case '?s': $part = $this->escapeString($value); break; case '?i': $part = $this->escapeInt($value); break; case '?a': $part = $this->createIN($value); break; case '?u': $part = $this->createSET($value); break; case '?p': $part = $value; break; } $query .= $part; } return $query; } protected function escapeInt($value) { if ($value === NULL) { return 'NULL'; } if(!is_numeric($value)) { $this->error("Integer (?i) placeholder expects numeric value, ".gettype($value)." given"); return FALSE; } if (is_float($value)) { $value = number_format($value, 0, '.', ''); // may lose precision on big numbers } return $value; } protected function escapeString($value) { if ($value === NULL) { return 'NULL'; } //return "'".mysqli_real_escape_string($this->conn,$value)."'"; // RGO: Use HTMLpurifier return "'".$this->purifier->purify($value)."'"; } protected function escapeIdent($value) { if ($value) { return "`".str_replace("`","``",$value)."`"; } else { $this->error("Empty value for identifier (?n) placeholder"); } } protected function createIN($data) { if (!is_array($data)) { $this->error("Value for IN (?a) placeholder should be array"); return; } if (!$data) { return 'NULL'; } $query = $comma = ''; foreach ($data as $value) { $query .= $comma.$this->escapeString($value); $comma = ","; } return $query; } protected function createSET($data) { if (!is_array($data)) { $this->error("SET (?u) placeholder expects array, ".gettype($data)." given"); return; } if (!$data) { $this->error("Empty array for SET (?u) placeholder"); return; } $query = $comma = ''; foreach ($data as $key => $value) { $query .= $comma.$this->escapeIdent($key).'='.$this->escapeString($value); $comma = ","; } return $query; } protected function error($err) { $err = __CLASS__.": ".$err; if ( $this->emode == 'error' ) { $err .= ". Error initiated in ".$this->caller().", thrown"; trigger_error($err,E_USER_ERROR); } else { throw new $this->exname($err); } } protected function caller() { $trace = debug_backtrace(); $caller = ''; foreach ($trace as $t) { if ( isset($t['class']) && $t['class'] == __CLASS__ ) { $caller = $t['file']." on line ".$t['line']; } else { break; } } return $caller; } /** * On a long run we can eat up too much memory with mere statsistics * Let's keep it at reasonable size, leaving only last 100 entries. */ protected function cutStats() { if ( count($this->stats) > 100 ) { reset($this->stats); $first = key($this->stats); unset($this->stats[$first]); } } } \ No newline at end of file diff --git a/src/helpers/functions.php b/src/helpers/functions.php index 11b6e4d..146d091 100644 --- a/src/helpers/functions.php +++ b/src/helpers/functions.php @@ -96,10 +96,10 @@ function getCategory($scsnr){ $dienst = "ING"; } elseif($oms == "010278"){ $regio = ""; - $dienst = "IPC_ADT"; + $dienst = "AOIP_ADT"; } elseif($oms == "010276"){ $regio = ""; - $dienst = "IPC_SMC"; + $dienst = "AOIP_SMC"; } elseif($oms == "010274"){ $regio = ""; $dienst = "MusDoNet"; @@ -114,10 +114,10 @@ function getCategory($scsnr){ $dienst = "S&E"; } elseif($oms == "010100"){ $regio = ""; - $dienst = "SMOKE"; + $dienst = "FOG"; } elseif($oms == "010300"){ $regio = ""; - $dienst = "BNOT"; + $dienst = "N-BNOT"; } else { $regio = ""; $dienst = ""; @@ -159,10 +159,19 @@ function getPathStatus($path_status){ if(@$path_arr[0] =='?' && @$path_arr[2] == '?' && @$path_arr[1] == '?' && @$path_arr[3] == '?'){ // No path status - $path_conn = 3; - } elseif(!in_array( '1', $primair ) && in_array( '1', $secundair )){ + $path_conn = 4; + } elseif(!in_array( '1', $primair ) && in_array( '1', $secundair ) && !in_array( '?', $secundair )){ // Backup conn + $path_conn = 3; + } elseif(!in_array( '1', $primair ) && in_array( '1', $secundair ) && in_array( '?', $secundair )){ + // Backup conn + $path_conn = 3; + } elseif(in_array( '1', $primair ) && !in_array( '1', $secundair ) && !in_array( '?', $secundair )){ + // Primair conn $path_conn = 2; + } elseif(in_array( '1', $primair ) && !in_array( '1', $secundair ) && in_array( '0', $secundair )){ + // Primair conn + $path_conn = 2; } elseif(!in_array( '1', $primair ) && !in_array( '1', $secundair )){ // Disconnected $path_conn = 0; diff --git a/src/lang/nl.json b/src/lang/nl.json index d100a2a..b1c17e8 100644 --- a/src/lang/nl.json +++ b/src/lang/nl.json @@ -30,7 +30,8 @@ "connection":{ "conn": "Verbonden", "diss": "Niet verbonden", - "back": "Verbonden met backup", + "prim": "IP uitval", + "back": "Backup uitval", "nopath": "Geen pathstatus", "oos": "In onderhoud tot", "main_err": "Mainboard uitval", diff --git a/src/lang/pt.json b/src/lang/pt.json new file mode 100644 index 0000000..55076bc --- /dev/null +++ b/src/lang/pt.json @@ -0,0 +1,523 @@ +{ + "placeholders":{ + "select":"Selecione...", + "input":"Preencher..." + }, + "layout":{ + "topnav":{ + "placeholder":"Procurar por localização", + "logout":"Sair" + }, + "sidebar":{ + "title":{ + "1":"Casa", + "2":"Bilhetes", + "3":"Ferramentas", + "4":"Usuário", + "5":"De usuário", + "6":"Logging", + "7":"Configurações" + } + } + }, + "swal":{ + "confirm":{ + "title":"Você tem certeza?", + "confirmbutton":"Sim eu tenho certeza", + "cancelbutton":"Cancelar" + } + }, + "connection":{ + "conn": "Conectado", + "diss": "Não conectado", + "back": "Conectado ao backup", + "nopath": "Geen pathstatus", + "oos": "Fora de serviço até", + "main_err": "Falha na placa-mãe", + "batt_err": "Falha da bateria", + "230_err": "Falha de 230v", + "multi_err": "Questões múltiplas" + }, + "error_page":{ + "return_btn":"Volte", + "403":{ + "label":"Acesso negado", + "msg":"Direitos de administrador são obrigatórios para acesso. Entre em contato com os administradores!" + }, + "404":{ + "label":"Página não encontrada", + "msg":"Desculpe, mas a página que você está procurando não pode ser encontrada. Verifique o URL para erros, atualize a página " + }, + "500":{ + "label":"Erro do Servidor Interno", + "msg":"O servidor encontrou algo inesperado que não pôde concluir a solicitação. Pedimos desculpas, você pode voltar para a página principal" + }, + "denied":{ + "label":"Access denied", + "msg":"Admin rights are mandatory for access. Contact the admins" + }, + "maintenance":{ + "label":"Manutenção ocupada", + "msg":"Aguarde ou confira o status com os administradores" + } + }, + "error_msg":{ + "die":{ + "label":"Algo definitivamente deu errado", + "msg":"Verifique os arquivos de log!" + }, + "csrf":{ + "label":"O token de CSRF não é válido", + "msg":"Verifique o URL do navegador e atualize a página!" + } + }, + "installscreen":{ + "welcome": "Bem-vindo ao DB +", + "text": "Esta é a sua primeira vez.", + "subtext": "Aproveite o tempo para preencher os detalhes abaixo.", + "login": "Instalar", + "phpversion": { + "err":"Versão PHP muito baixa", + "msg":"A versão 7.0.0 é um requisito mínimo." + }, + "admin":{ + "txt": "Configuração de administrador", + "email": "Digite o email do administrador", + "pass": "Digite a senha do administrador", + "local": "Insira a localização", + "lang": "Selecione o idioma padrão" + "msg":{ + "user": "Admin username", + "pass": "Senha única", + "store": "Anote a senha acima em um lugar seguro" + } + }, + "app":{ + "txt": "Configuração de aplicativo", + "root": "URL root", + "docu": "Root folder", + "api": "Google API key" + }, + "scs":{ + "txt": "Conexão SCS", + "user": "Nome de usuário", + "pass": "Senha" + }, + "rms":{ + "txt": "Conexão RMS" + }, + "msg":{ + "fail": "Installation unsuccessful", + "try": "Try again", + "suc": "Installation successful" + } + }, + "loginscreen":{ + "welcome": "Bem-vindo ao DB +", + "text": "Uma experiência aprimorada para gerenciamento de RMS e SCS.", + "subtext": "Faça o login. Para vê-lo em ação.", + "login": "Entrar", + "placeholder": { + "email":"email", + "password":"senha" + }, + "request": "Pedido", + "forget": "Esqueceu a senha?" + }, + "tokenmsg":{ + "welcome": "Recuperar senha", + "text": "Clique no botão recuperar", + "button": "Recuperar" + }, + "loginmsg":{ + "lck":{ + "label":"Autenticação falhou", + "msg":"Conta bloqueada por 2 horas." + }, + "id":{ + "label":"Autenticação falhou", + "msg":"Verifique suas iniciais ou senha." + }, + "dev":{ + "label":"Erro", + "msg":"Nenhuma conta DEV." + }, + "blc":{ + "label":"Erro", + "msg":"Conta de usuário está bloqueada. Entre em contato com o administrador." + }, + "uknw":{ + "label":"Erro", + "msg":"Usuário não existe." + }, + "tok":{ + "suc":{ + "label":"Bem sucedido", + "msg":"Redefinir token solicitado." + }, + "mul":{ + "label":"Falha na solicitação de token", + "msg":"Não é possível solicitar vários tokens. Por favor, espere até que o token atual tenha expirado" + }, + "err":{ + "label":"A solicitação de token de redefinição falhou", + "msg":"Atualize a página e tente novamente" + }, + "inv":{ + "label":"O token é inválido", + "msg":"Atualize a página e solicite um novo token" + }, + "uknw":{ + "label":"Token não encontrado", + "msg":"Atualize a página e solicite um novo token" + }, + "exp":{ + "label":"Token expirado", + "msg":"Isso não é mais utilizável. Atualize a página e solicite um novo token" + } + }, + "res":{ + "suc": "Verifique suas iniciais ou senha.", + "err": "Verifique suas iniciais ou senha." + } + }, + "home":{ + "events":{ + "h5":"Localizações", + "day":{ + "label":"Conectados", + "small_label":"Desde um dia" + }, + "week":{ + "label":"Desligada", + "small_label":"Desde uma semana" + }, + "month":{ + "label":"Por mês", + "small_label":"Desde um mes" + } + }, + "filters": "Filters", + "actions": { + "selectdefault": "Padrão", + "text": "Ações", + "map_zoom": "Definir o nível de zoom do mapa:", + "filter_status": "Status do filtro:", + "filter_location": "Localização do filtro:", + "clusterzoom": "Nível de zoom do cluster:", + "clustersize": "Tamanho do zoom de cluster:", + "map_controls": "Controles de mapa", + "cluster_controls": "Controles de cluster", + "buttons": { + "cluster": "Agrupar", + "clear": "Clusters claros", + "refresh": "Atualizar", + "center": "Centro" + } + "locations": { + "active": { + "label":"Locais on-line", + "table": { + "th1": "ID de dispositivo", + "th2": "Nome do dispositivo", + "th3": "endereço MAC", + "th4": "Status", + "th5": "Nome da localização" + } + }, + "problem": { + "label":"Localizações off-line", + "table": { + "th1": "ID de dispositivo", + "th2": "Nome do dispositivo", + "th3": "endereço MAC", + "th4": "Status" + } + }, + "notactive": { + "label":"Nenhum status de caminho", + "table": { + "th1": "Conexão", + "th2": "ID", + "th3": "Localização", + "th4": "Último sinal" + } + }, + "device": { + "label":"230v / Falha da bateria", + "table": { + "th1": "Conexão", + "th2": "ID", + "th3": "Localização", + "th4": "Último sinal" + } + } + }, + "location":{ + "connection": "Conexão", + "status": "Status", + "address": "Endereço", + "zipcode": "Código postal", + "city": "Cidade", + "first": "Primeiro sinal", + "last": "Último sinal", + "path": "Estado do caminho", + "mac": "Endereço MAC", + "udid": "UDID não", + "serie": "Série não", + "sim": "Sim cartão não", + "serviceid": "ID do serviço não", + "lijn": "Denominação de linha", + "components":{ + "txt":"Componentes de localização", + "values":"Valores de localização" + }, + "values":{ + "table": { + "txt":"Valores de localização", + "th1": "Nome", + "th2": "Valor" + } + }, + "components":{ + "table": { + "txt":"Componentes de localização", + "th1": "Componente", + "th2": "Quantidade", + "th3": "Serial#", + "th4": "Data de instalação", + "th5": "Data de validade" + } + }, + "events":{ + "week":"Semana", + "label":"Eventos desta semana", + "count":"Total de eventos" + }, + "tab":{ + "location":"Localização", + "update":"Atualizado em", + "tab1":{ + "text":"Status da conexão", + "h3":"Estado do caminho", + "path_conn":"Conexão", + "path_name":"Trajeto", + "power":"230 volt", + "battery":"Bateria" + }, + "tab2":{ + "text":"Atraso de enquete", + "h3":"Contagem de atraso de pesquisa" + }, + "tab3":{ + "text":"Nível de atraso da pesquisa", + "h3":"Status do componente" + } + } + }, + "admin":{ + "h1":"Bem-vindo administrador", + "small":"Por favor espere" + }, + "user":{ + "title":"Usuário", + "edit":{ + "title":"Editar usuário", + "button":"Atualizar", + "input":{ + "1":"Nome de usuário", + "2":"Sobrenome do usuário", + "3":"E-mail do usuário" + } + }, + "acc_update":{ + "msg":{ + "update":{ + "label": "Sucesso", + "text": "atualizado com sucesso" + }, + "err_email":{ + "label": "Algo deu errado", + "msg": "Este não é um endereço de email correto" + }, + "err_email_in_use":{ + "label": "Algo deu errado", + "msg": "Este endereço de e-mail já está em uso" + }, + "suc":{ + "label": "Sucesso", + "msg": "Conta de usuário foi atualizada" + }, + "err":{ + "label": "Algo deu errado", + "msg": "Atualize a página e tente novamente" + } + } + } + }, + "users":{ + "title":"De usuário", + "edit":{ + "title":"Editar usuários", + "button":"Atualizar", + "input":{ + "1":"Nome dos usuários", + "2":"Sobrenome do usuário", + "3":"E-mail do usuário", + "4":"Papel dos usuários", + "5":"Status dos usuários" + }, + "msg":{ + "del":{ + "label": "Sucesso", + "text": "Removido com sucesso" + }, + "suc":{ + "label": "Sucesso", + "text": "Conta de usuário foi atualizada" + }, + "err":{ + "label": "Algo deu errado", + "text": "Tente novamente ou entre em contato com o administrador" + } + } + }, + "new":{ + "title":"Novo usuário", + "button":"Crio", + "msg":{ + "login_email":{ + "label": "Sucesso", + "text": "E-mail de login enviado para", + "err": "E-mail de login não enviado" + }, + "suc":{ + "label": "Sucesso", + "text": "Conta de usuário foi criada" + }, + "err":{ + "label": "Algo deu errado", + "text": "Tente novamente ou entre em contato com o administrador" + } + } + }, + "status":{ + "active":"Ativo", + "inactive":"Inativo" + }, + "actions":{ + "edit":"Editar", + "delete":"Excluir" + }, + "table":{ + "th1":"ID do usuário", + "th2":"Nome de usuário", + "th3":"Último nome", + "th4":"Endereço de e-mail", + "th5":"Papel do usuário", + "th6":"Status", + }, + "swal":{ + "confirm":{ + "text":"O usuário: __placeholder__ será excluído permanentemente!" + } + } + }, + "tickets":{ + "label":"Bilhete", + "select":{ + "label":{ + "current":"Status atual", + "on_hold":"Em espera paral", + "sent_to":"Enviado também", + "external":"Terceiros", + "canceled":"Razão cancelada", + "options":"Opções de ingressos", + "actions":"Ações de ticket" + } + }, + "status":{ + "aangevraagd":"Requeridos", + "open":"Aberto", + "on_hold":"Em espera", + "totaal_uitval":"Falha total ", + "gesloten":"Fechadas", + "geannuleerd":"Cancelado", + "opnieuw_geopend":"Reaberto", + "opnieuw_verzenden":"Reenviado", + "doorzetten":"Forçe até o fim", + "storing_hersteld":"Falha restaurada", + "ticket_onnodig":"Bilhete desnecessário", + "ticket_foutief":"Bilhete incorreto" + }, + "create":{ + "label":"Crie um ticket", + "txt":{ + "scs":"Número SCS", + "service":"Serviço", + "location":"Localização", + "address":"Endereço", + "zipcode":"Código postal", + "city":"Cidade", + "for":"Para", + "storing":"Defeituoso", + "action":"Açao", + "cp":"Entre em contato", + "cptel":"Número de telefone do contato", + "comment":"Comentário extra" + }, + "malfunction":{ + "anders":"Diferente", + "1":"Sem linesync", + "2":"Falha GPRS", + "3":"Falha RAM", + "4":"Falha da bateria", + "5":"Falha de 230v", + "6":"Falha do roteador", + "7":"Falha de comunicação NVR", + "8":"Falha total" + } + }, + "update":{ + "submitted_by":"Enviado por", + "checked_by":"Verificado por", + "status":"Estado", + "updates":"Atualizações", + "ticket_for":"Bilhete para", + "create":{ + "label":"Atualizar bilhete", + "external":"Número do bilhete externo", + "up_comm":"Atualizar comentário", + "up_status":"Atualizar o status" + } + }, + "filters":{ + "service":"Serviço (TODOS)", + "external":"Externo (TODOS)", + "status":"Status (TODOS)" + }, + "table": { + "th1": "Bilhete#", + "th2": "ID de localização", + "th3": "Nome da localização", + "th4": "Última atualização", + "th5": "Serviço", + "th6": "Festa externa", + "th7": "Defeituoso", + "th8": "Número do bilhete", + "th9": "Criado em", + "th10": "Status" + }, + "buttons":{ + "new":"Novo", + "send":"Enviar", + "re_send":"Reenviar", + "send_fast":"Send immediately", + "send_too":"Send too", + "update":"Update" + } + }, + "footer":{ + "copyright": "Direito autoral" + } +} \ No newline at end of file diff --git a/view/home.view.php b/view/home.view.php index b2dea65..ca9c117 100644 --- a/view/home.view.php +++ b/view/home.view.php @@ -296,6 +296,7 @@ // On tab switch 2 $('a[href="#tab-2"]').on('shown.bs.tab', function (e) { + // If datatable not initialized if ( ! $.fn.DataTable.isDataTable( '.datatable_problem' ) ) { // Show loading @@ -504,7 +505,9 @@ function setMarkers(locObj) { } else if(loc.path_status == 2){ err_icon = url+'yellow_Marker'+loc.first_char+'.png'; } else if(loc.path_status == 3){ - err_icon = url+'blue_Marker'+loc.first_char+'.png'; + err_icon = url+'orange_Marker'+loc.first_char+'.png'; + } else if(loc.path_status == 4){ + err_icon = url+'blue_Marker'+loc.first_char+'.png'; } else { err_icon = url+'darkgreen_Marker'+loc.first_char+'.png'; } @@ -558,6 +561,10 @@ function setMarkers(locObj) { err_icon = url+'red_Marker'+loc.first_char+'.png'; } else if(loc.path_status == 2){ err_icon = url+'yellow_Marker'+loc.first_char+'.png'; + } else if(loc.path_status == 3){ + err_icon = url+'orange_Marker'+loc.first_char+'.png'; + } else if(loc.path_status == 4){ + err_icon = url+'blue_Marker'+loc.first_char+'.png'; } else { err_icon = url+'darkgreen_Marker'+loc.first_char+'.png'; } diff --git a/view/tools/maps.view.php b/view/tools/maps.view.php index a902274..a49892f 100644 --- a/view/tools/maps.view.php +++ b/view/tools/maps.view.php @@ -2,6 +2,7 @@
    +

    Realtime disconnects

    @@ -11,17 +12,25 @@
    - - - - - - + + + + + +
    Verbonden
    Backup uitval
    Primair uitval
    Niet verbonden
    Geen pathstatus
    +
    + + + + + + + + +
    AOIP
    BRAND
    DIGIALARM
    ING
    B-NOTIFIED
    MUSDONET
    S&E
    MISTMACHINE
    - - - +
    @@ -142,12 +151,16 @@ function setMarkers(locObj) { if(loc.path_status == 0){ err_icon = url+'red_Marker'+loc.first_char+'.png'; + } else if(loc.path_status == 1){ + err_icon = url+'darkgreen_Marker'+loc.first_char+'.png'; } else if(loc.path_status == 2){ err_icon = url+'yellow_Marker'+loc.first_char+'.png'; } else if(loc.path_status == 3){ + err_icon = url+'orange_Marker'+loc.first_char+'.png'; + } else if(loc.path_status == 4){ err_icon = url+'blue_Marker'+loc.first_char+'.png'; } else { - err_icon = url+'darkgreen_Marker'+loc.first_char+'.png'; + err_icon = url+'brown_Marker'+loc.first_char+'.png'; } //Create marker @@ -197,10 +210,16 @@ function setMarkers(locObj) { if(loc.path_status!==undefined ) { if(loc.path_status == 0){ err_icon = url+'red_Marker'+loc.first_char+'.png'; + } else if(loc.path_status == 1){ + err_icon = url+'darkgreen_Marker'+loc.first_char+'.png'; } else if(loc.path_status == 2){ err_icon = url+'yellow_Marker'+loc.first_char+'.png'; + } else if(loc.path_status == 3){ + err_icon = url+'orange_Marker'+loc.first_char+'.png'; + } else if(loc.path_status == 4){ + err_icon = url+'blue_Marker'+loc.first_char+'.png'; } else { - err_icon = url+'darkgreen_Marker'+loc.first_char+'.png'; + err_icon = url+'brown_Marker'+loc.first_char+'.png'; } locations[key].marker.setIcon(err_icon) } @@ -245,15 +264,13 @@ function setMarkers(locObj) { function getMarkerData() { ajaxObj.options.url = url_str+'?get=markers&time='+ajaxObj.updatetime; $.ajax(ajaxObj.options) - //fires when ajax returns successfully + // fires when ajax returns successfully .done(function(data){ setMarkers(data); ajaxObj.updatetime = data.updatetime; - - //console.log(ajaxObj.updatetime); }) - .fail(ajaxObj.fail) //fires when an ajax error occurs - .always(ajaxObj.get(getMarkerData, 10000)); //fires after ajax success or ajax error + .fail(ajaxObj.fail) // fires when an ajax error occurs + .always(ajaxObj.get(getMarkerData, 10000)); // fires after ajax success or ajax error } function getMarkerTable() { @@ -263,6 +280,7 @@ function getMarkerTable() { if(data.status == 1){ $('#div_alert_active').html(data.count.conn); $('#div_alert_diss').html(data.count.diss); + $('#div_alert_primair').html(data.count.prim); $('#div_alert_backup').html(data.count.back); $('#div_alert_nopath').html(data.count.nopath); From c31ab12509f17880eaf67e1172cd68d0c5dfc019 Mon Sep 17 00:00:00 2001 From: MillieOfzo Date: Fri, 13 Jul 2018 16:49:54 +0200 Subject: [PATCH 09/10] Updated maps style --- js/google_style_dark.js | 2 +- view/home.view.php | 31 +++++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/js/google_style_dark.js b/js/google_style_dark.js index 4d649a5..266630f 100644 --- a/js/google_style_dark.js +++ b/js/google_style_dark.js @@ -200,7 +200,7 @@ var google_styles = [ "color": "#282828" }, { - "saturation": -100 + "saturation": -80 } ] }, diff --git a/view/home.view.php b/view/home.view.php index ca9c117..397c585 100644 --- a/view/home.view.php +++ b/view/home.view.php @@ -169,10 +169,12 @@ Filter status:
    @@ -623,13 +625,26 @@ function refreshNow(){ function filterStatus(status) { - for (var i = 0, marker; marker = markers_arr[i]; i++) { - if (marker.path == status || status.length === 0) { - marker.setVisible(true); - } else { - marker.setVisible(false); - } + if(status == 'Trouble'){ + for (var i = 0, marker; marker = markers_arr[i]; i++) { + + if (marker.path == 2 || marker.path == 3 || marker.path == 0 || status.length === 0) { + marker.setVisible(true); + } else { + marker.setVisible(false); + } + } + } else { + for (var i = 0, marker; marker = markers_arr[i]; i++) { + + if (marker.path == status || status.length === 0) { + marker.setVisible(true); + } else { + marker.setVisible(false); + } + } } + } function filterLocation(category) { From e9b7eb682b85ae5e151a1d3e72e8d585d2d2e971 Mon Sep 17 00:00:00 2001 From: MillieOfzo Date: Fri, 13 Jul 2018 16:50:05 +0200 Subject: [PATCH 10/10] Updated maps style --- js/google_style_dark.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/google_style_dark.js b/js/google_style_dark.js index 266630f..4d649a5 100644 --- a/js/google_style_dark.js +++ b/js/google_style_dark.js @@ -200,7 +200,7 @@ var google_styles = [ "color": "#282828" }, { - "saturation": -80 + "saturation": -100 } ] },