(function () { 'use strict'; var refreshToken = false; var app = angular.module('dataCollectorApp', ['chart.js']); app.controller('dataCollectorCtrl', ['$scope', '$http', '$timeout', '$interval', '$sce', function($scope, $http, $timeout, $interval, $sce) { let tmpTimeout; $scope.data = {}; $scope.data.refresh = {}; $scope.data.refresh.districts = []; $scope.api_url = "https://cc-api-qa.metasolutions.net/"; $scope.reports = []; $scope.debug = false; /* Verify Authorization */ // let auth = getCookie("access_token"); // console.log("auth", auth) // if (!auth) location.href = $scope.logoff(); // $http.get(`${$scope.api_url}verify`).then(function(response) { // console.log("GET success response", response); // }, function(response){ // console.log("GET verify error", response); // if (response.data.message == "Token expired") { //console.log("old access token", getCookie("access_token")); refreshToken = true; $http.post(`${$scope.api_url}refresh`).then(function(response) { refreshToken = false; //if ($scope.debug) console.log("Set new tokens!", response); setCookie("access_token", response.data.access_token); setCookie("refresh_token", response.data.refresh_token); //if ($scope.debug) console.log("new access token", getCookie("access_token")); $scope.init(); // auth = response.data.access_token; }, function(response){ $scope.logoff(); }); //} else { // $scope.logoff(); //} //}); /* Set up defaults */ $scope.data.selectedMenu = "cd"; $scope.data.username = getCookie("username"); $scope.data.selected = {}; $scope.data.display_name = getCookie("display_name"); if (!$scope.data.display_name) $scope.data.display_name = $scope.data.username; // need to verify that this works similarly to display_name $scope.data.initials = getCookie("initials"); if (!$scope.data.initials) $scope.data.initials = $scope.data.username; // $scope.data.welcomeMessage = "Please select a report from the menu to continue."; $scope.data.menu = []; $scope.data.adminAccess = false; if ( getCookie("crosscheck") == 1 ) $scope.data.adminAccess = true; $scope.data.importing = false; $scope.data.beta_users = ["coreyhilliard", "ccadmin-ekubiak"]; $scope.data.betauser = true;//$scope.data.beta_users.includes($scope.data.username); $scope.data.sync = {"msg":"Waiting to initiate Synchronization..."}; $scope.data.timeout = 0; // Year selection for reports will grow by 1 each year $scope.data.years = [{"year" : "2021"},{"year" : "2022"},{"year" : "2023"}, {"year": "2024"}, {"year:": "2025"}, {"year": "2026"}]; // set default year to current year - will need to be updated each year $scope.data.selectedYear = {"year" : "2025"}; var syncPromise; /* set blurStudentData */ let b = getCookie("blur"); $scope.data.blur = b==1?true:false; // set scope for district names (used during blur) $scope.hideDistrictName = false; $scope.init = function() { $http.get(`${$scope.api_url}cc/access`).then(function(response) { $scope.data.connections = response.data; if (response.data.orgs.length==1) $scope.data.selected.org = response.data.orgs[0]; if ($scope.data.selected?.org?.datacollectors.length==1) $scope.data.selected.dc = $scope.data.selected.org.datacollectors[0]; if ($scope.data.selected?.dc?.districts.length==1) { $scope.data.selected.dist = $scope.data.selected.dc.districts[0]; $scope.selectDistrict($scope.data.selected.dist); } //if ($scope.debug) console.log("data.connections", $scope.data.connections); /* Preload Org */ if (!$scope.data.selected.org && getCookie("setOrg")) $scope.data.selected.org = response.data.orgs.find(function(value) { if (value.name == getCookie("setOrg")) return true; }); if (!$scope.data.selected.dc && getCookie("setDC")) $scope.data.selected.dc = $scope.data.selected.org.datacollectors.find(function(value) { if (value.name == getCookie("setDC")) return true; }); if (!$scope.data.selected.dist && getCookie("setDist")) { $scope.data.selected.dist = $scope.data.selected.dc.districts.find(function(value) { if (value.irn == getCookie("setDist")) return true; }); $scope.selectDistrict($scope.data.selected.dist); } }); $scope.loadData(); } /* Manually created Welcome Back Modal */ // if (!$scope.data.year && $scope.data.selectedDistrict) { // jQuery("#welcomeBackModal").modal({backdrop: 'static', keyboard: false}); // } $scope.reSync = function() { //if ($scope.debug) console.log("reSync()"); $scope.data.selectedMenu = "m1"; $scope.data.sync.results = {}; $scope.data.sync.hasRan = false; $scope.autoSync() || $scope.adminSync(); } /* Auto Sync */ $scope.autoSync = function() { //if ($scope.debug) console.log("autoSync()"); $scope.feathers(); if ($scope.data.adminAccess) return; if ($scope.data.sync.hasRan) { //if ($scope.debug) console.log("Already running a sync, exiting"); return true; } // store the interval promise $scope.data.sync.msg = "Synchronizing..."; $scope.data.sync.status = true; $scope.data.sync.hasRan = true; $scope.data.sync.seconds = 0; syncPromise = $interval($scope.setSyncTimer, 1000); $http.post(`${$scope.api_url}cc/sync/${$scope.data.selected.dist.irn}`).then(function(response) { //if ($scope.debug) console.log("autoSync()", response); $scope.data.sync.msg = "Synchronization Complete"; $scope.data.sync.status = false; $interval.cancel(syncPromise); if (response.data.message) { $scope.data.sync.results = {"key":"", "table":"", "success":response.data.success, "message": response.data.message}; } else { $scope.data.sync.results = response.data.records; } if ($scope.data.sync.results.length > 0) $scope.initDistricts(); $scope.feathers(); }, function(response) { // optional //if ($scope.debug) console.log("autoSync()", "error"); $scope.data.sync.msg = "Synchronization Error"; $scope.data.sync.status = false; $interval.cancel(syncPromise); $scope.data.sync.results = {"key":"", "table":"", "success":false, "message": response}; }); } /* Admin Sync */ $scope.adminSync = function() { //if ($scope.debug) console.log("adminSync()"); $scope.feathers(); if (!$scope.data.adminAccess) return; if ($scope.data.sync.hasRan) { //if ($scope.debug) console.log("Already running a sync, exiting"); return true; } // store the interval promise $scope.data.sync.msg = "Synchronizing..."; $scope.data.sync.status = true; $scope.data.sync.hasRan = true; $scope.data.sync.seconds = 0; syncPromise = $interval($scope.setSyncTimer, 1000); $http.post(`${$scope.api_url}cc/sync/${$scope.data.selected.dist.irn}`).then(function(response) { //if ($scope.debug) console.log("autoSync()", response); $scope.data.sync.msg = "Sync Complete: CrossCheckAdmin users must run a manual sync for each new district"; $scope.data.sync.status = false; $interval.cancel(syncPromise); if (response.data.message) { $scope.data.sync.results = {"key":"", "table":"", "success":response.data.success, "message": response.data.message}; } else { $scope.data.sync.results = response.data.records; } if ($scope.data.sync.results.length > 0) $scope.initDistricts(); $scope.feathers(); }, function(response) { // optional //if ($scope.debug) console.log("autoSync()", "error"); $scope.data.sync.msg = "Synchronization Error"; $scope.data.sync.status = false; $interval.cancel(syncPromise); $scope.data.sync.results = {"key":"", "table":"", "success":false, "message": response}; }); } /* Check if user has been logged off due to inactivity */ $scope.updateTime = function() { $scope.data.timeout++; if ($scope.data.timeout >= 18) { let auth = getCookie("access_token"); refreshToken = true; $http.post(`${$scope.api_url}refresh`).then(function(response) { refreshToken = false; setCookie("access_token", response.data.access_token); setCookie("refresh_token", response.data.refresh_token); //if ($scope.debug) console.log("new access token", getCookie("access_token")); auth = response.data.access_token; $scope.data.timeout = 0; }, function(response){ $scope.logoff(); alert("session expired, troubleshooting auth tokens. Please use /login to Login to CrossCheck QA") }); } } /* Setup 1 minute interval */ var checkMinute; checkMinute = $interval($scope.updateTime, 60000); $scope.updateTime(); /*$scope.loadData = function(setWelcome = true) { if (setWelcome) $scope.data.selectedMenu = "m1"; /* Get Menu and Reports List */ //let admin = $scope.data?.selected?.org?.itc_admin; //let all = admin ? "/all" : "/all"; /* $http.get(`${$scope.api_url}cc/menu`).then(function(response) { $scope.data.menu = response.data; /* When refreshing, enable the loading indiator for each specific report $scope.data.menu.forEach(function(menu){ if ($scope.data.selectedMenu && `m${menu.menu_id}` == $scope.data.selectedMenu) { $scope.data.selectedMenu2 = menu; } if (menu.reports) { menu.active = true; for (var r=0;r -1) err = err.substring(1,sql_location); // $scope.import_error += `${property} - ${ data[property].error}
`; // if (err) $scope.import_error += `Details: ${err}`; // //$scope.import_error += ": " + jQuery('#fileToUpload').val().split('\\').pop() + "
"; // } else { // $scope.import_success += `${property} - ${data[property].message}
`; $scope.getLog(); // } //} }, error: function(data) { if (data.responseText) { $scope.import_error = data.responseText; } else { $scope.import_error = "Upload Failed"; } $scope.import_success = ""; $scope.data.importing = false; $scope.$apply(); } }).done(function() { $scope.data.importing = false; $scope.$apply(); angular.element('#dataCollectorCtrl').scope().loadData(false); jQuery("#fileToUpload").val(''); }); } $scope.runReport = function(report, select) { let dist = $scope.data.selected.dist; $http.post(`${$scope.api_url}cc/run/${dist.irn}/report/${report.report_id}/year/${$scope.data.selectedYear.year}`).then(function(response) { $scope.reports[response.data.report.report_id] = response.data; report.loading = false; $scope.reports[response.data.report.report_id].sort1 = 'reviewed.initreview'; $scope.reports[report.report_id].pk = []; if (response.data.data) response.data?.data.forEach(function(row) { if (row.reviewed) { if (row.reviewed.reviewed) { row.reviewed.initreview = true; } else { row.reviewed.initreview = false; } } }) if (response.data.report && response.data.report.columns) response.data?.report?.columns.forEach(function(col) { if (col.is_pk > 0) $scope.reports[report.report_id].pk.push(col); }) if (select) { $scope.tableData = $scope.reports[report.report_id]; $scope.feathers(); } }, function(response) { report.loading = false; $scope.reports[response.data.report_id] = response.data; }); } $scope.initDistricts = function() { //console.log($scope.data.selectedYear); /* Loop through each menu, running each report to load the latest results */ let dist = $scope.data.selected.dist; //if ($scope.debug) console.log("selectedDistrict", dist) if (!dist) return false; $http.get(`${$scope.api_url}cc/dataset/district/${$scope.data.selected.dist.irn}`).then(function(response) { $scope.data.sources = response.data; $scope.feathers(); }); $http.get(`${$scope.api_url}cc/check_role/${$scope.data.selected.dist.irn}`).then(function(response) { $scope.data.user_role = response.data; }); $http.get(`${$scope.api_url}cc/users/${$scope.data.selected.dist.irn}`).then(function(response) { //if ($scope.debug) console.log("users", response.data); $scope.data.users = response.data; if (!$scope.data.users.ad) { let expirationDate = new Date($scope.data.users.users[0].password_expiration); if (expirationDate < new Date()) { $scope.data.expiration = true; $scope.displayUpdatePasswordModal(); } else { $scope.populateReports(); } } else { $scope.populateReports(); } $scope.feathers(); }); } $scope.populateReports = function() { $scope.reports = []; $scope.data.menu.forEach(function(menu){ if (menu.reports) menu.reports.forEach(function(report){ $scope.runReport(report); $scope.feathers(); }); }); $scope.feathers(); $timeout(function() { $scope.autoSync(); }); } /* feathers() - Replace the icon tags with tags, CAH - Does feathers has an angularJS method to use instead? */ $scope.feathers = function() { $timeout(function() { try { feather.replace(); } catch (error) { console.error(error); } let sidebarWidth = jQuery("nav.sidebar").width(); jQuery("main").attr("style",`margin-left:${sidebarWidth}px; width:calc(100% - ${sidebarWidth}px)`); jQuery("nav a.navbar-brand").attr("style",`max-width:inherit; flex:0 0 ${sidebarWidth-7}px`); }); }; $scope.getInfo = function(report) { let moreInfo = report.more_info; return moreInfo; } $scope.addReportTooltips = function() { $timeout.cancel(tmpTimeout); tmpTimeout = $timeout( function(){ jQuery('[data-toggle="tooltip"]').tooltip() }, 1000); } $scope.selectUser = function(user) { /* Make a copy of the selected user */ $scope.data.selected.user = JSON.parse(JSON.stringify(user)); /* Add menu reports to the selected user */ $scope.data.selected.user.reportList = JSON.parse(JSON.stringify($scope.data.menu)); /* Reset variables */ $scope.data.username_available = true; /* Loop through each menu, indicate which reports are available to the selected user */ $scope.data.selected.user.reportList.forEach(function(category) { category.reports.forEach(function(report) { let foundReport = $scope.data.selected.user.reports.find(element => element.report_id == report.report_id); if (foundReport) { report.selected = foundReport.access; if (report.child_report) { let foundChild = category.reports.find(element => element.report_id == report.child_report.report_id); if (foundChild) { report.child_report = foundChild; } } } }); }); /* Add tooltips to the reports */ $scope.addReportTooltips(); } $scope.addUser = function() { if (!$scope.data.user_role.exists) return; $scope.userForm.$setUntouched(); $scope.data.selected.user = { "new":true }; $scope.data.selected.user.reportList = JSON.parse(JSON.stringify($scope.data.menu)); $scope.data.selected.user.reportList.forEach(function(category) { category.reports.forEach(function(report) { //let foundReport = $scope.data.selected.user.reports.find(element => element.report_id == report.report_id); //if (foundReport) { //report.selected = foundReport.access; if (report.child_report) { let foundChild = category.reports.find(element => element.report_id == report.child_report.report_id); if (foundChild) { report.child_report = foundChild; } } // } }); }); $scope.data.username_available = true; $scope.addReportTooltips(); $timeout(function() { var myEl = document.getElementById('userFirstName'); var angularEl = angular.element(myEl); angularEl.focus(); }); } $scope.totalSelected = function(menu) { let tot = 0; menu.reports.forEach(function(report){ if (report.selected) tot++ }); return tot; } $scope.toggleAll = function(menu) { //if ($scope.debug) console.log("toggleAll", menu); let sel = 0, tot = 0; menu.reports.forEach(function(report){ tot++; if (report.selected) sel++ }); //if ($scope.debug) console.log("sel", sel, "tot", tot); //if ($scope.debug) console.log("unselecting all"); menu.reports.forEach(function(report){ report.selected = (sel == tot)?false:true; if (report.child_report) report.child_report.selected = (sel == tot)?false:true; }); } /* runExport() */ $scope.runExport = function() { //if ($scope.debug) console.log("runExport()", $scope.tableData); $scope.buildExport = true; var rtn = "", cr = String.fromCharCode(13) + String.fromCharCode(10); let dist = $scope.data.selected.dist, report = $scope.tableData.report; $http.post(`${$scope.api_url}cc/export/${dist.irn}/report/${report.report_id}/year/${$scope.data.selectedYear.year}`) .then(function(response) { //if ($scope.debug) console.log("response", response); rtn += response.data.headers + cr; response.data.data.forEach(function(row) { rtn += row.row + cr; }); //if ($scope.debug) console.log("rtn", rtn); var today = new Date(), y = today.getFullYear(), m = today.getMonth() + 1, d = today.getDate(), h = today.getHours(), mi = today.getMinutes(), dateTime = y + "-" + m + "-" + d + "-" + h + "-" + mi; let txtFile = makeTextFile(rtn); let target = document.createElement('a'); let title = $scope.data.selectedReport.menu_title || $scope.data.selectedReport.title; target.setAttribute("href", txtFile); target.setAttribute("download", `${title}_${$scope.data.selected.dist.name}_${dateTime}.csv`); document.body.appendChild(target); target.click(); jQuery(target).remove(); $scope.buildExport = false; }, function(response) { alert (`There was an error while creating the Export: Error: ${response.data.error}`); //if ($scope.debug) console.debug("Doh!", response); $scope.buildExport = false; }) ; } /* mainMenuClick() - Toggle the "active" property of the menu. Used to expand/collapse or highlight entries */ $scope.mainMenuClick = function( menu ) { //if ($scope.debug) console.log("mainMenuClick", menu); if (menu.angular_function) { $scope.feathers(); return true; } menu.active = !menu.active; if (typeof menu.reports === 'undefined' || ['card','dashboard'].includes(menu.menu_type)) { //if (menu.menu_type==='dashboard' && menu.dashboard_columns) jQuery("#loadingModal").modal({backdrop: 'static', keyboard: false}); $timeout(function() { $scope.data.editUsers = false; $scope.data.selectedMenu = 'm' + menu.menu_id; $scope.data.selectedMenu2 = menu; }); } $scope.feathers(); } /* selectReport() - Copy the selected report to the working/display array "tableData" */ $scope.selectReport = function( report, menu ) { //if ($scope.debug) console.log("selectReport()", report, menu); if (report.loading) return false; if (menu.menu_id) { $scope.data.selectedMenu2 = menu; } else { $scope.data.selectedMenu = menu; } $scope.data.selectedReport = report; $scope.data.editUsers = false; //if (menu.menu_type == 'reports' ) { // jQuery("#loadingModal").modal({backdrop: 'static', keyboard: false}); //} else { $scope.buildExport = false; $scope.displayReport(); $scope.feathers(); //} } $scope.colBlur = function(key) { let colsToBlur = ["statestaffid_270","ssid","statestdntid_050","employeeid_050","statestudentid_110","studentlastname_350","studentfirstname_330","statestdntid_050","statestudentid_050","employeename_060","statestudentid","statestdntid","lastname","firstname","employeename","employeeid","statestaffid","lastname_310","firstname_290","stateid_050"]; return colsToBlur.includes(key.toLowerCase()); } $scope.colHide = function(idx) { if (!$scope.data.selectedReport.report_id || !$scope.reports || !$scope.reports[$scope.data.selectedReport.report_id]) return true; let col = $scope.reports[$scope.data.selectedReport.report_id]?.report?.columns.find(function(value) { if (value.sort_by == (idx+1)) return true; //if (value.data_col == idx) return true; //Use this console.log to find the column number for the column you want to blur //console.log("colHide", value, idx); }); return col?.export_only==1; } $scope.colFmt = function(idx, report_id = $scope.data.selectedReport?.report_id) { //if (!report_id) return true; let col = $scope.reports[report_id].report.columns.find(function(value) { if (value.sort_by == (idx+1)) return true; //if (value.data_col == idx) return true; }); //if ($scope.debug) console.log("col", col); if (col) { //if ($scope.debug) console.log("return", col.data_type); return col.data_type; } else { //if ($scope.debug) console.log("return", "nothing"); return ""; } } $scope.advSearchClick = function() { $scope.data.showAdvanced=!$scope.data.showAdvanced; if ($scope.data.showAdvanced) $timeout(function() { document.getElementById("inputAdvSearch").focus(); }) } /* displayReport() - Set the menu & report based on the user selection CAH - Can this be part of routing instead */ $scope.displayReport = function() { //if ($scope.debug) console.log("displayReport()"); let menu = $scope.data.selectedMenu2; let report = $scope.data.selectedReport; //if ($scope.debug) console.log("menu", menu); //if ($scope.debug) console.log("report", report); $scope.data.selectedMenu = 'r' + report.report_id; //if ($scope.debug) console.log("selectedMenu", $scope.data.selectedMenu); // Change to a GET $scope.tableData = $scope.reports[report.report_id]; //if ($scope.debug) console.log("tableData", $scope.tableData); /* Log that the report has been used for this district + reset users session time */ //$http.get(`data/log.php?type=report&report_id=${report.report_id}`); //Fix copy+paste MS Unicode Characters from the moreInfo field: if ($scope.tableData) { if ($scope.tableData.more_info) { $scope.tableData.more_info = $scope.tableData.more_info.replace(/[\u2018]/g, "‘") .replace(/[\u2019]/g, '’') .replace(/[\u201C]/g, '“') .replace(/[\u201D]/g, '”') } } else { $scope.tableData = report; jQuery("#loadingModal").modal('hide'); } $scope.feathers(); } /* calcHeight */ $scope.calcHeight = function(row_height, row_span, add_extra) { let new_row_height = row_height, new_row_span = "", new_span = [], add_extra_space = "0px"; if(row_span !== null && typeof row_span === 'string'){ new_row_span = row_span.toLowerCase(); new_span = new_row_span.split("span "); } if (add_extra) add_extra_space = "20px"; if (new_span[1]) new_row_height = `calc((${row_height} + ${add_extra_space}) * ${new_span[1]})`; return new_row_height; } /* sortColumn() - Calculate the orderBy used for the tableData display */ $scope.sortColumn = function ( tableData, col, index ) { //if ($scope.debug) console.log("sortColumn()", tableData, col, index); if (index > -1) { if ( tableData.sortBy == `fields.${col.data_col_name}` ) { tableData.sortRev = !tableData.sortRev; } else { tableData.sortBy = `fields.${col.data_col_name}`; tableData.sortRev = false; } } if (index == -1) { tableData.sortReviewRev = !tableData.sortReviewRev; if (tableData.data) tableData?.data.forEach(function(row) { if (row.reviewed) { if (row.reviewed.reviewed) { row.reviewed.initreview = true; } else { row.reviewed.initreview = false; } } }) } var rUp = "", rDown = "-"; if (tableData.sortReviewRev) {rUp = "-"; rDown = ""; } if (tableData.sortRev) tableData.sort1 = rDown + 'reviewed.initreview'; if (!tableData.sortRev) tableData.sort1 = rUp + 'reviewed.initreview'; // if (tableData.sortRev) tableData.sort1 = rDown + 'reviewed.reviewed'; // if (!tableData.sortRev) tableData.sort1 = rUp + 'reviewed.reviewed'; $scope.feathers(); } /* activeDistricts() filter used to identify which districts to display */ $scope.activeDistricts = function(district) { if(district.status == "Register") return false; return true; }; /* toReview() - Calculates the total number of records to review for the menu */ $scope.toReview = function ( test ) { if (!test) return -1; try { if (!test.found_pk) return test.count; return test.data.filter(v => {return !v.reviewed.reviewed; }).length; } catch { return 0; } } /* treeToReview() - Calculated the total number of records of all reports on a menu branch to review */ $scope.treeToReview = function ( menu ) { if ($scope.reports.length==0) return null; let totalReports = 0, err = false; if (menu.reports) for (var reportIdx = 0; reportIdx < menu.reports.length; reportIdx++) { try { if ($scope.reports[menu.reports[reportIdx].report_id]) { if ($scope.reports[menu.reports[reportIdx].report_id].error) err = true; if ($scope.reports[menu.reports[reportIdx].report_id].found_pk) { let test = $scope.reports[menu.reports[reportIdx].report_id].data; totalReports += test.filter(v => {return !v.reviewed.reviewed; }).length; } } } catch { return null; } } if (totalReports > 500) totalReports = "500+"; if (err) { if (totalReports == 0) return "err"; totalReports += " & err"; } return totalReports; } $scope.btnBlurData = function() { if ($scope.data.blur) { $scope.data.blur = false; setCookie("blur", 0); $scope.hideDistrictName = false; // Show the district name } else { $scope.data.blur = true; setCookie("blur", 1); $scope.hideDistrictName = true; // Hide the district name } }; // Function allow user to click checkbox to blur specific row data $scope.checkBoxBlur = function() { let arr = []; if ($scope.data.blur) { arr.push("blur"); } if (arr.length > 0) { $scope.data.blur = true; setCookie("blur",1); } else { $scope.data.blur = false; setCookie("blur",0); } } /* hasReview() - Calculates the reviewed number of records in the menu */ $scope.hasReview = function ( test ) { if (!test) return false; try { return test.data.filter(v => { return v.reviewed.reviewed; }).length; } catch { return 0; } } /* refreshDC - Call the python script to refresh the selected data collector */ $scope.refreshDC = function() { let username = $scope.data.user.username; let password = $scope.data.user.password; if (!$scope.data.refreshing) { $scope.data.refreshing = true; $http.post(`${$scope.api_url}cc/scrape/${$scope.data.selected.dc.name}`, JSON.stringify({ "username" : username, "password" : password })) .then(function(results) { $scope.data.refreshing = false; $scope.data.refresh.districts = results.data.records; $scope.init(); }, function(error) { $scope.data.refreshing = false; $scope.data.refresh.districts = []; $scope.data.refresh.error = error.data; }); } } /* Display MoreInfo Modal */ $scope.displayMoreInfo = function() { jQuery("#moreInfoModal").modal({backdrop: false}); jQuery("#moreInfoModal").css('left', (jQuery( window ).width())/2 - (jQuery("#moreInfoModal").width()/2)); } /* Display MoreInfo Modal for Dashboard Overiew */ $scope.displayMenuMoreInfo = function() { jQuery("#moreInfoMenuModal").modal({backdrop: false}); jQuery("#moreInfoMenuModal").css('left', (jQuery( window ).width())/2 - (jQuery("#moreInfoMenuModal").width()/2)); } /* Display MoreInfo Modal for Dashboards */ $scope.displayMoreInfoDash = function(report) { $scope.data.dashReport = report; jQuery("#moreInfoDashModal").modal({backdrop: false}); jQuery("#moreInfoDashModal").css('left', (jQuery( window ).width())/2 - (jQuery("#moreInfoDashModal").width()/2)); } /* Display refreshDc Modal */ $scope.displayRefreshDcModal = function(report) { $scope.data.refresh.districts = []; $scope.data.dashReport = report; $scope.data.refresh.error = ""; jQuery("#refreshDcModal").modal({backdrop: false}); jQuery("#refreshDcModal").css('left', (jQuery( window ).width())/2 - (jQuery("#refreshDcModal").width()/2)); } /* Display updatePassWord Modal */ $scope.displayUpdatePasswordModal = function() { $scope.data.user.newpassword = ""; if ($scope.data.expiration) { jQuery("#updatePasswordModal").modal({keyboard: false, focus: true, backdrop: 'static'}); } else { jQuery("#updatePasswordModal").modal({focus: true}); } jQuery("#updatePasswordModal").css('left', (jQuery( window ).width())/2 - (jQuery("#updatePasswordModal").width()/2)); } /* selectOrg() */ $scope.selectOrg = function(org) { $scope.data.selected.org = org; $scope.data.selected.dc=''; $scope.data.selected.dist=''; setCookie("setOrg",org.name); } /* selectDC() */ $scope.selectDC = function(dc) { $scope.data.selected.dc = dc; $scope.data.selected.dist=''; setCookie("setDC",dc.name); } /* selectDistrict() - Select new district */ $scope.selectDistrict = function(dist) { if (!dist) return true; $scope.data.sync.results = {}; $scope.data.selected.dist = dist; setCookie("setDist", dist.irn); $scope.data.selectedMenu = 'm1'; $scope.data.selectedMenu2 = ""; $scope.data.sync.hasRan = false; $scope.data.editUsers = false; $scope.cancelUser(); $scope.loadData(); $scope.feathers(); // var found = false; // $scope.data.connections.forEach(function(connection) { // if (connection.db == $scope.data.selectedDistrict) { // found = true; // $http.post('data/set.php?db='+$scope.data.selectedDistrict+"&n="+connection.connection).then(function(response) { // //location.reload(); // jQuery("#reload").submit(); // }); // } // }); // if (!found) { // $http.post('data/set.php?d='+$scope.data.selectedDistrict).then(function(response) { // //location.reload(); // jQuery("#reload").submit(); // }); // } } /* reviewRecord() - function to mark the selected record as reviewed */ $scope.reviewRecord = function(data, clk) { //if ($scope.debug) console.log("reviewRec()", data, clk); //$scope.buildExport = true; data.loading = true; var reviewRec = { "district_irn" : $scope.data.selected.dist.irn, "report_id" : $scope.data.selectedReport.report_id, "pk_value" : data.reviewed.pk_value, "note" : data.reviewed.note, "year" : 2024, "deleted" : 0 }; if (data.reviewed.review_id) reviewRec.review_id = data.reviewed.review_id; if (clk) { if (data.reviewed.reviewed) { reviewRec.status = 0; } else { reviewRec.status = 1; } } else { if (data.reviewed.reviewed) { reviewRec.status = 1; } else { reviewRec.status = 0; } } //if ($scope.debug) console.log("reviewRec", reviewRec); //return true; $http.post(`${$scope.api_url}cc/review`, JSON.stringify(reviewRec)).then(function(response) { //$http.get(`data/log.php?type=${rectype}&report_id=${$scope.tableData.report_id}&review_id=${response.data.review_id}`); //if ($scope.debug) console.log("response.data", response.data); //if ($scope.debug) console.log("old data", JSON.parse(JSON.stringify(data))); data.reviewed.review_id = response.data.review_id; if (response.data.status==1) { data.reviewed.reviewed = true; } else { data.reviewed.reviewed = false; } //$scope.runReport($scope.data.selectedReport, true); data.loading = false; //if ($scope.debug) console.log("new data", data); }); } $scope.displayError = function(error) { if (error.indexOf("Incorrect syntax near") > -1) { let sot = error.indexOf(" '$"), eot = error.indexOf("'", sot + 3), tableName = error.substring(sot+3, eot); if (sot > -1) return `No prepared ${tableName} file exists for the ${$scope.data.year} collection. Please collect and prepare to view this check.`; } return error; } $scope.toggleChart = function(report) { report.flip = !report.flip; } $scope.dashboard_columns_calc = function(menu) { if (!menu) return; let cols = "" + (Math.floor(98/menu.dashboard_columns)) + "% "; return cols.repeat(menu.dashboard_columns); } /* trustAsHTML() - Use Strict Contextual Escaping to render trusted HTML */ $scope.trustAsHtml = function(html) { return $sce.trustAsHtml(html); } /* stayLoggedIn() - Reset the LAST_ACTION_TIMESTAMP timer */ $scope.stayLoggedIn = function() { $http.get("data/log.php?type=ts"); jQuery("#inactivityModal").modal('hide'); } /* closeWelcome() - Close the Welcome Back dialog */ $scope.closeWelcome = function() { jQuery("#welcomeBackModal").modal('hide'); } jQuery('#loadingModal').on('shown.bs.modal', function () { $timeout(function() { if ($scope.data.selectedMenu2.menu_type==='card' || !$scope.data.selectedMenu2.menu_type) { jQuery("#loadingModal").modal('hide'); } else { $scope.displayReport() } }); }) $scope.checkUsername = function() { let username = $scope.data.selected.user.username; if (username) { $http.post(`${$scope.api_url}cc/check_username`, JSON.stringify({"username" : username})).then(function(response) { //if ($scope.debug) console.log("checkUsername", response.data); if (response.data.status==1) { $scope.data.username_available = true; } else { let user_id = $scope.data.selected.user.user_id; if (user_id == response.data.user_id) { $scope.data.username_available = true; } else { $scope.data.username_available = false; } } }); } else { $scope.data.username_available = false; } } $scope.updateUser = function() { //if ($scope.debug) console.log("updateUser()", $scope.data.selected.user); if (!$scope.data.userFormValid) return true; if ($scope.data.selected.user.reportList) $scope.data.selected.user.reportList.forEach(function(category) { if (category.reports) category.reports.forEach(function(report) { if (!$scope.data.selected.user.reports) $scope.data.selected.user.reports = []; let foundReport = $scope.data.selected.user.reports.find(element => element.report_id == report.report_id); console.log("foundReport", foundReport); if (foundReport) { //foundReport = report.report_id foundReport.access = report.selected; //report.user_id = $scope.data.selected.user.user_id } else { $scope.data.selected.user.reports.push( { "report_id" : report.report_id, "access" : report.selected?true:false, "user_id" : $scope.data.selected.user.user_id } ); } }); }) let user = JSON.parse(JSON.stringify($scope.data.selected.user)); if (user.newpassword) { user.password = user.newpassword; } else { delete user.password; } if ($scope.data.users.ad) { delete user.new; delete user.newpassword; delete user.last_login; delete user.$$hashKey; delete user.reportList; delete user.active; delete user.ad_account; delete user.district_id; if(user.username != user.email) user.username = user.email; } else { if (!user.password) { $scope.cancelUser(); return true; } user = { "username" : user.username, "user_id" : user.user_id, "password" : user.password }; } $http.post(`${$scope.api_url}cc/users/${$scope.data.selected.dist.irn}`, JSON.stringify(user)).then(function(response) { $scope.data.users = response.data; $scope.cancelUser(); }, function(response) { $scope.data.selected.user.errormessage = response.data; } ); } /* deleteUser($scope.data.selected.user.user_id, $scope.data.selected.dist.irn);*/ $scope.deleteUser = function() { $http.delete(`${$scope.api_url}cc/users/${$scope.data.selected.dist.irn}`, {data: JSON.stringify({"user_id" : $scope.data.selected.user.user_id})}).then(function(response) { $scope.data.users = response.data; $scope.cancelUser(); $scope.data.deleteUser = false; }); } $scope.resetPassword = function() { if ($scope.data.user.newpassword) { $scope.data.user.password = $scope.data.user.newpassword; } if (!$scope.data.user.password) { $scope.cancelUser(); return true; } $http.post(`${$scope.api_url}cc/users/${$scope.data.selected.dist.irn}`, JSON.stringify({"username" : $scope.data.user.username, "user_id" : $scope.data.users.users[0].user_id, "password" : $scope.data.user.password})).then(function(response) { $scope.data.users = response.data;; $scope.logoff(null, true); jQuery("#updatePasswordModal").modal('hide'); }, function(response) { $scope.data.user.errormessage = response.data; } ); } // Print the page $scope.printPage = function() { window.print(); return false; } // Print an individual dashboard on the page $scope.printDash = function(report) { var printContents = document.getElementById(`dashPrint${report.report_id}`).innerHTML; var popupWin = window.open('', '_blank', 'width=800,height=1000, location=no, toolbar=no, menubar=no, scrollbars=yes'); popupWin.document.open(); popupWin.document.write(`
${ report.title }
`); if (report.more_info) popupWin.document.write(`
${ report.more_info }
`); popupWin.document.write(`
${ printContents }

Printing dashboard window, please close when finished

`); popupWin.document.close(); } // Print all dashboards on the page $scope.printAllDashboards = function() { var allDashPrintContents = document.querySelectorAll('.dashboard-container'); var popupWin = window.open('', '_blank', 'width=800,height=1000, location=no, toolbar=no, menubar=no, scrollbars=yes'); popupWin.document.open(); popupWin.document.write(` `); allDashPrintContents.forEach(function(printContent) { popupWin.document.write(`
${ printContent.innerHTML }
`); }); popupWin.document.write(`

Printing all dashboards, please close when finished

`); popupWin.document.close(); } $scope.isReadOnly = function() { if ($scope.data?.selected?.user?.user_id) { return true; } return false; } /* logoff() - Navigate the user to the logout page */ $scope.logoff = function(myvar, changedpw=false) { var cookies = document.cookie.split(";"); for (var i = 0; i < cookies.length; i++) { var cookie = cookies[i]; var eqPos = cookie.indexOf("="); var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie; document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT"; } $http.get("data/log.php?type=logoff"); if (changedpw) { window.location.replace('login?changedpw'); } else { window.location.replace('login'); } } $scope.setSyncTimer = function() { $scope.data.sync.seconds = $scope.data.sync.seconds +1; } $scope.cancelUser = function() { delete $scope.data.selected.user; $scope.userForm.$setUntouched(); } $scope.cleanUpTitle = function(title) { title = title.replace(" Checks", ""); title = title.replace("/", " / "); title = title.replace("Graduation", "Grad"); return title; } $scope.canAddUser = function(override = false) { if (!$scope.data.users) return false; let ad = $scope.data.users.ad; if (override || (ad && ( // If the roles array contains a partial string "submitter", then the user has the ability to add users $scope.data.users.roles.find(element => element.toLowerCase().indexOf("submitter")>-1) || // If the roles array contains a patrial string "submit", then the user has the ability to add users $scope.data.users.roles.find(element => element.toLowerCase().indexOf("submit")>-1) || // If CrossCheckAdmin exists in the roles array, then we can add users $scope.data.users.roles.find(element => element.toLowerCase() == "crosscheckadmin") || // Create a special case for springfield $scope.data.users.roles.find(element => element.toLoweCase() == "null.000000.crosscheck") ) ) ) { return true; } else { return false; } } // If the user has a role in the database, show true $scope.hasRole = function(role) { if (!$scope.data.users) return false; if ($scope.data.users.roles.find(element => element.toLowerCase() == role.toLowerCase())) { return true; } else { return false; } } // Hide menu items if report.length == 0 $scope.showMenu = function(menu) { if (!['dashboard','reports'].includes(menu.menu_type)) return true; if (menu.reports.filter(report => { return !report.parent_report_id }).length == 0) return false; return true; } // Generate a users initials based off the first letters of both their first and last names $scope.getInitials = function(user) { if (user.first_name && user.last_name) { return (user.first_name.charAt(0) + user.last_name.charAt(0)).toUpperCase(); } else { return user.username.charAt(0).toUpperCase(); } } $scope.categoryStatusByUser = function(category, user) { if (!user.reports) return true; if (user.ad_account) return "full"; let userReports = 0; category.reports.forEach(function(catReport) { user.reports.forEach(function(userReport) { if (catReport.report_id == userReport.report_id && userReport.access) { userReports++; } }); }); if (userReports == 0) { return "none"; } else if (userReports == category.reports.length) { return "full"; } else { return "partial"; } } /* toggleMenu() - Toggle/Expand toggle Menu Tree */ $scope.toggleMenu = function(menu) { let def = !menu.active; for (var menuIdx=0; menuIdx<$scope.data.menu.length;menuIdx++) { let m = $scope.data.menu[menuIdx]; if (m.menu_type=="reports" && m.reports.length>0) m.active = def; } menu.active = def; if (def) { jQuery("li > a:not(.dashboard)[data-toggle].nav-link").removeClass("collapsed").next("div").addClass("show"); } else { jQuery("li > a:not(.dashboard)[data-toggle].nav-link").addClass("collapsed").next("div").removeClass("show"); } } $scope.selectedDC = function(name) { if (!name) return false; if (name == $scope.data?.selectedDataCollector?.name) return `${name} (selected)`; return name; } }]) .directive("editUser", function() { return { restrict: "A", templateUrl : `templates/editUser.html?v=${Math.random()}` }; }).directive("districtUsers", function() { return { restrict: "A", templateUrl : `templates/districtUsers.html?v=${Math.random()}` }; }).directive("leftNav", function() { return { restrict: "A", templateUrl : `templates/leftNav.html?v=${Math.random()}` }; }).directive("welcome", function() { return { restrict: "A", templateUrl : `templates/welcome.html?v=${Math.random()}` }; }).directive("dashboard", function() { return { restrict: "A", templateUrl : `templates/dashboard.html?v=${Math.random()}` }; }).directive("importData", function() { return { restrict: "A", templateUrl : `templates/importData.html?v=${Math.random()}` }; }).directive("reportContainer", function() { return { restrict: "A", templateUrl : `templates/reportContainer.html?v=${Math.random()}` }; }).directive("breadcrumbs", function() { return { restrict: "A", templateUrl : `templates/breadcrumbs.html?v=${Math.random()}` }; }).directive("navigationMenu", function() { return { restrict: "A", templateUrl : `templates/navigationMenu.html?v=${Math.random()}` }; }).directive("modalMoreInfo", function() { return { restrict: "A", templateUrl : `templates/modalMoreInfo.html?v=${Math.random()}` }; }).directive("help", function() { return { restrict: "A", templateUrl : `templates/help.html?v=${Math.random()}` }; }); /* secondsToTime filter - convert integer to M:SS */ app.filter('secondsToTime', function() { return function(seconds) { let m = Math.floor(seconds/60), s = "0" + (seconds - m*60); return "" + m + ":" + s.substr(s.length-2); }; }) /* fmt filter - formats table data using the filter set in the Admin UI for the data */ app.filter('fmt', function($filter) { return function(value, filterSpec) { if (!filterSpec) return value; var args = filterSpec.split(':'); var filter = $filter(args.shift()); args.unshift(value); return filter.apply(null, args); }; }); app.factory('httpRequestInterceptor', function () { return { request: function (config) { if (refreshToken) { //if ($scope.debug) console.log("refreshToken"); config.headers['Authorization'] = `Bearer ${getCookie("refresh_token")}`; } else { //if ($scope.debug) console.log("!refreshToken", getCookie("access_token")) config.headers['Authorization'] = `Bearer ${getCookie("access_token")}`; } return config; } }; }); app.config(function ($httpProvider) { $httpProvider.interceptors.push('httpRequestInterceptor'); }); /* makeTextFile() - helper function to create the export file */ function makeTextFile(raw) { var data = new Blob([raw], { type: 'text/plain' }); if (textFile !== null) { window.URL.revokeObjectURL(textFile); } var textFile = window.URL.createObjectURL(data); return textFile; }; function getRandomColor() { var letters = '0123456789ABCDEF'.split(''); var color = '#'; for (var i = 0; i < 6; i++ ) { color += letters[Math.floor(Math.random() * 16)]; } return color; } function setCookie(cname, cvalue, exdays = 1) { //if ($scope.debug) console.log("cvalue", encodeURIComponent(cvalue)); const d = new Date(); d.setTime(d.getTime() + (exdays*24*60*60*1000)); let expires = "expires="+ d.toUTCString(); document.cookie = cname + "=" + encodeURIComponent(cvalue) + ";" + expires + ";path=/"; } function getCookie(cname) { let name = cname + "="; let decodedCookie = decodeURIComponent(document.cookie); let ca = decodedCookie.split(';'); for(let i = 0; i