Odyssey
secureForms.prg
1 <?php
2 /**
3  * @package secureDocuments.prg -- contains the code for the secure documents menu items
4  * This file replaces Index.prg and AdmECO.prg
5  */
6 
7 $self = "$menu_link?ft=$ft";
8 
9 $string = array("filter" => HCUFILTER_INPUT_STRING);
10 HCU_ImportVars($parameters, "a", array("operation" => $string));
11 $operation = HCU_array_key_exists("operation", $parameters["a"]) ? trim($parameters["a"]["operation"]) : "";
12 $showSQL = $SYSENV["devmode"];
13 
14 if ($operation != "") {
15  $isJson = true;
16  switch($operation) {
17  case "readForms":
18  $tz = GetCreditUnionTimezone($dbh, $Cu);
19  $tz = new DateTimeZone($tz);
20  $returnArray = readSecureForms($tz, $home_path);
21  break;
22  case "removeFiles":
23  $tz = GetCreditUnionTimezone($dbh, $Cu);
24  $tz = new DateTimeZone($tz);
25  $returnArray = removeFiles($tz, false, $home_path, $Cn);
26  break;
27  case "restoreFiles":
28  $tz = GetCreditUnionTimezone($dbh, $Cu);
29  $tz = new DateTimeZone($tz);
30  $returnArray = removeFiles($tz, true, $home_path, $Cn);
31  break;
32  case "viewFile":
33  viewFile($home_path);
34  $isJson = false;
35  break;
36  case "downloadFile":
37  viewFile($home_path, "data");
38  $isJson = false;
39  break;
40  default: $returnArray = array("sql" => array(), "error" => array("Operation not recognized: $operation."), "record" => array());
41  break;
42  }
43 
44  if ($isJson) {
45  header('Content-type: application/json');
46  if (!$showSQL) {
47  unset($returnArray["sql"]);
48  }
49  print HCU_JsonEncode($returnArray);
50  }
51 
52 } else {
53  printSecureFormPage($self);
54 }
55 
56 /**
57  * function viewFile($home_path, $type="regular")
58  * This is the main utility function for getting the data of the files and then showing it based on the file type.
59  *
60  * @param string $home_path -- this variable is from an earlier script that references the base directory of the CU.
61  * @param string $type -- this is the type of the file. It determines how the file is processed.
62  */
63 function viewFile($homePath, $type = "regular") {
64  $string = array("filter" => HCUFILTER_INPUT_STRING);
65  HCU_ImportVars($parameters, "a", array("filename" => $string));
66  $filename = HCU_array_key_exists("filename", $parameters["a"]) ? trim($parameters["a"]["filename"]) : "";
67  $file = $filename; // Prevent console error.
68 
69  try {
70  $path = "$homePath/sslforms/$filename";
71  if (!is_file($path)) {
72  throw new exception("File is not found.", 1);
73  }
74  $file = file($path);
75  if (!is_array($file)) {
76  throw new exception("File is invalid.", 2);
77  }
78 
79  switch(trim($type)) {
80  case "regular":
81  case "":
82  $fileString = implode("", $file);
83  print $fileString;
84  break;
85  case "data":
86  if (strpos($filename, ".dat") === false) {
87  throw new exception("Data file is not valid.", 4);
88  }
89 
90  $fileString = implode("", $file);
91  header("Content-length: " . strlen($fileString) );
92  header("Content-type: application/octetstream");
93  header("Content-disposition: inline; filename=\"$filename\"");
94 
95  print ($fileString);
96  break;
97  default:
98  throw new exception("Type is unrecognized.", 3);
99  break;
100  }
101  } catch(exception $e) {
102  print "The file $file was not found. It may have been deleted.";
103  }
104 }
105 
106 /**
107  * function removeFiles($restore, $home_path, $Cn)
108  * This function removes files or restores files. (The files aren't actually being removed at this step, merely the filename is changed to known if it is "deleted" or not.)
109  *
110  * @param string $tz -- the timezone of the credit union.
111  * @param boolean $restore -- if true, then the file (and any corresponding dat files) will lose the deleted by postfix. Otherwise the deleted by postfix will be added to the file.
112  * @param string $home_path -- this variable is from an earlier script that references the base directory of the CU.
113  * @param string $Cn -- this variable is from an earlier script which means the logged in user. This user will appended on to a deleted file.
114  *
115  * Imported from the request variables:
116  * "files" -- a json-encoded array of the filenames.
117  * "nextFormIndex" -- whatever the next index of the files are.
118  *
119  * @return array --
120  * array "error" -- list of errors encountered
121  * integer "code" -- zero if no errors, nonzero if errors
122  * array "formData" -- This will be the updated new form files (after rename)
123  */
124 function removeFiles($tz, $restore, $homePath, $Cn) {
125  $parameters = array("a" => array("files" => "", "nextFormIndex" => ""));
126  $string = array("filter" => HCUFILTER_INPUT_STRING);
127  HCU_ImportVars($parameters, "a", array("files" => $string, "nextFormIndex" => $string));
128  extract($parameters["a"]);
129  $files = isset($files) ? trim($files) : "";
130  $nextFormIndex = isset($nextFormIndex) ? trim($nextFormIndex) : "";
131 
132  $formData = array();
133  try {
134  if ($nextFormIndex == "") {
135  throw new exception("Next Form Index is required.", 10);
136  }
137  if (!is_numeric($nextFormIndex)) {
138  throw new exception("Next Form Index needs to be numeric.", 12);
139  }
140  $directory = "$homePath/sslforms";
141  if ($files == "") {
142  throw new exception("Filenames are required.", 1);
143  }
144  $files = HCU_JsonDecode($files);
145  if (!is_array($files)) {
146  throw new exception("Filenames are not encoded correctly.", 2);
147  }
148  $parsedFiles = array();
149  foreach($files as $fileRecord) {
150  $name = trim($fileRecord["name"]);
151  if (!isset($name)) {
152  throw new exception("Filenames are not encoded correctly.", 3);
153  }
154  $preg= '/^([a-zA-Z]+\\d+\\.html)' . ($restore ? '\\.(\\w+)' : '') . '$/';
155 
156  $pregResults = @preg_match($preg, $name, $matches);
157  if ($pregResults === false) {
158  throw new exception("Filenames are not encoded correctly.", 5);
159  }
160  if ($pregResults == 0) {
161  throw new exception("Filenames are not found.", 14);
162  }
163  $parsedFiles[] = $matches;
164  }
165 
166  $extension = bin2hex($Cn);
167  foreach($parsedFiles as $matches) {
168  $oldFilename = $matches[0];
169  $oldFile = "$directory/$oldFilename";
170  if ($restore) {
171  $newFilename = $matches[1];
172  $newFile = "$directory/$newFilename";
173  if (!file_exists($oldFile)) {
174  throw new exception("File does not exist.", 6);
175  }
176  if (!@rename($oldFile, $newFile)) { // 0 is the full regex so the file. 1 is the first parathesis which I have set to the regular file and extension.
177  throw new exception("File could not be renamed.", 7);
178  }
179 
180  $fileInfo = retrieveDateAndNames($tz, $newFilename, $directory);
181 
182  $oldDataFilename = str_replace(".html", ".dat", $oldFilename);
183  $newDataFilename = str_replace(".html", ".dat", $newFilename);
184  $oldDataFile = "$directory/$oldDataFilename";
185  $newDataFile = "$directory/$newDataFilename";
186  if (file_exists($oldDataFile)) {
187  if (!@rename($oldDataFile, $newDataFile)) {
188  throw new exception("File could not be renamed.", 10);
189  }
190  } else {
191  $newDataFilename = "";
192  }
193 
194  $formData[] = array("index" => $nextFormIndex++, "dataFile" => $newDataFilename, "type" => $fileInfo["type"],
195  "createdDate" => $fileInfo["createdDate"], "modifiedDate" => $fileInfo["modifiedDate"], "deletedBy" => $fileInfo["deletedBy"], "filename" => $newFilename);
196  } else {
197 
198  $newFilename = $matches[0] . ".$extension";
199  $newFile = "$directory/$newFilename";
200  if (file_exists($oldFile)) {
201 
202  if (!@rename($oldFile, $newFile)) {
203  throw new exception("File could not be renamed.", 8);
204  }
205  } else {
206  if (!@touch($newFile)) {
207  throw new exception("File could not be renamed.", 9);
208  }
209  }
210 
211  $fileInfo = retrieveDateAndNames($tz, $newFilename, $directory);
212 
213  $oldDataFilename = str_replace(".html", ".dat", $oldFilename);
214  $newDataFilename = str_replace(".html", ".dat", $newFilename);
215  $oldDataFile = "$directory/$oldDataFilename";
216  $newDataFile = "$directory/$newDataFilename";
217  if (is_file($oldDataFile)) {
218  if (!@rename($oldDataFile, $newDataFile)) {
219  throw new exception("File could not be renamed.", 12);
220  }
221  } else {
222  $newDataFilename= "";
223  }
224 
225  $formData[] = array("index" => $nextFormIndex++, "dataFile" => $newDataFilename, "type" => $fileInfo["type"],
226  "createdDate" => $fileInfo["createdDate"], "modifiedDate" => $fileInfo["modifiedDate"], "deletedBy" => $fileInfo["deletedBy"], "filename" => $newFilename);
227  }
228  }
229  } catch(exception $e) {
230  return array("error" => array($e->getMessage()), "code" => $e->getCode(), "formData" => array());
231  }
232  return array("error" => array(), "code" => 0, "formData" => $formData);
233 }
234 
235 /**
236  * function readSecureForms($home_path)
237  * This function gets all the *.html.* and *.fdf.* files in the sslforms subdirectory for the CU with all the file information necessary and divides those into four groups for the kendo grids.
238  * It also removes deleted files that are older than 10 days. These do not show up in the list.
239  *
240  * @param string $tz -- the timezone of the credit union.
241  * @param string $home_path -- this variable is from an earlier script that references the base directory of the CU.
242  * @return array --
243  * array "error" -- the list of errors encountered
244  * integer "code" -- nonzero if there are errors
245  * array "formData" -- data for the form table
246  * array "deletedFormData" -- data for the deleted form table
247  */
248 function readSecureForms($tz, $homePath) {
249  $formData = array();
250  $deletedFormData = array();
251  try {
252  $directory = "$homePath/sslforms";
253  if (!is_dir($directory)) {
254  throw new exception("Directory not found.", 1);
255  }
256  $dh = opendir($directory);
257  if (!$dh) {
258  throw new exception("Directory not readable.", 2);
259  }
260  $index = 1;
261 
262  $daystokeep = 10;
263  $cutoff = time() - ($daystokeep * 86400); # calculate $daystokeep purge timestamp
264 
265  while (($file = readdir($dh)) !== false) {
266  // This is true for the normal syntax of the forms: letters and then numbers before extension.
267  // Extensions are valid for forms: D.dat, .dat, and .html. Extensions valid for forms: .fdf. Any of these files can have a prefix for delete by.
268  $pregMatch = @preg_match('/^([a-zA-Z]+\\d+(D?\\.dat)|(\\.html))|(\\d+\\.fdf)(\.\\w+?)$/', $file);
269  if ($pregMatch === false) {
270  throw new exception("String match failed.", 3);
271  }
272  if ($pregMatch && filemtime("$directory/$file") < $cutoff) {
273  if (!@unlink("$directory/$file")) {
274  throw new exception("File not unlinkable.", 4);
275  }
276  continue; // In this case, the file is removed: too old so it will not show up in the resultset.
277  }
278 
279  $dateAndNames = retrieveDateAndNames($tz, $file, "$homePath/sslforms");
280 
281  if ($dateAndNames["dontProcess"]) {
282  continue;
283  }
284 
285  $dataFile = str_replace(".html", ".dat", $file);
286  $dataFile = is_file("$directory/$dataFile") ? $dataFile : "";
287 
288  $row = array("index" => $index++, "dataFile" => $dataFile, "type" => $dateAndNames["type"], "createdDate" => $dateAndNames["createdDate"],
289  "modifiedDate" => $dateAndNames["modifiedDate"], "deletedBy" => $dateAndNames["deletedBy"], "filename" => $file);
290 
291  if ($row["deletedBy"] == "") {
292  $formData[] = $row;
293  } else {
294  $deletedFormData[] = $row;
295  }
296  }
297  closedir($dh);
298  } catch(exception $e) {
299  return array("error" => array($e->getMessage()), "code" => $e->getCode(), "formData" => array(), "deletedFormData" => array());
300  }
301  return array("error" => array(), "code" => 0, "formData" => $formData, "deletedFormData" => $deletedFormData);
302 }
303 
304 /**
305  * function retrieveDateAndNames($filename, $directory, $mode="kendo")
306  * This retrieves dates and names for a file
307  *
308  * @param string $tz -- the timezone of the credit union.
309  * @param string $filename -- the filename to get information
310  * @param string $directory -- the directory that the filename is in
311  * @param string $mode -- The encoding of the dates and whatnot
312  * @return array --
313  * boolean "dontProcess" -- If true, then the directory read will not add this to the datalist. (Since the filename doesn't fit the regexes.)
314  * string "createdDate" -- The created date in the format readable by kendo.
315  * string "modifiedDate" -- The modified date in the format readable by kendo.
316  * string "deletedBy" -- Whoever deleted the file.
317  * string "type" -- The base name of the file (without the timestamp, extension, or deleted by postfix)
318  * @throws exception -- If there is a file read, preg match, or DateTime failure.
319  */
320 function retrieveDateAndNames($tz, $filename, $directory, $mode = "kendo") {
321  $modifiedDate = "";
322  $createdDate = "";
323  $deletedDate = "";
324  $type = "";
325 
326  try {
327  $pregResults = @preg_match('/^(\\d+)\\.fdf(\\.(\\w+))?$/', $filename, $matches);
328  if ($pregResults === false) {
329  throw new exception("Preg match failed.", 3);
330  }
331 
332  if ($pregResults !== 0) {
333  throw new exception("Mortgage files are phased out 9/1/2017.", -1);
334  } else {
335  $pregResults = @preg_match('/^([a-zA-Z]+)(\\d+)\\.html(\\.(\\w+))?$/', $filename, $matches);
336  if ($pregResults === false) {
337  throw new exception("Preg match failed.", 2);
338  }
339  if ($pregResults === 0) {
340  throw new exception("File doesn't match. Don't process this.", -1);
341  }
342 
343  if (!@file_exists("$directory/$filename")) {
344  throw new exception("File doesn't exist.", 1);
345  }
346 
347  $count = count($matches);
348  if ($count > 1) {
349  $type = trim($matches[1]);
350  }
351  if ($count > 2) {
352  $createdDate = trim($matches[2]);
353  }
354  if ($count > 4) {
355  $deletedBy = trim($matches[4]);
356  }
357  }
358 
359  // We KNOW that the date is UTC. As of May 23, 2019, all secure forms are being saved with a UTC timestamp.
360  $UTCtz = new DateTimeZone("UTC");
361  $createdDateUTC = isset($createdDate) ? DateTime::createFromFormat("YmdHis+", $createdDate, $UTCtz) : null;
362  $deletedBy = isset($deletedBy) ? pack('H*',$deletedBy) : "";
363  $modifiedDateUTC = DateTime::createFromFormat("U", filemtime("$directory/$filename"), $UTCtz);
364 
365  if ($createdDateUTC === false) {
366  throw new exception("Created date is not parseable from filename.", 4);
367  }
368  if ($modifiedDateUTC === false) {
369  throw new exception("Modified date is not parseable.", 5);
370  }
371 
372  // Convert to CU timezone.
373  $createdDateUTC->setTimezone($tz);
374  $modifiedDateUTC->setTimezone($tz);
375 
376  switch($mode) {
377  case "kendo": // Have Kendo parse in a date and use the kendo.toString to format whatever we want from within the grid.
378  $createdDate = isset($createdDateUTC) ? $createdDateUTC->format("Y-m-d H:i:s.u") . "Z" : null;
379  $modifiedDate = isset($modifiedDateUTC) ? $modifiedDateUTC->format("Y-m-d H:i:s.u") . "Z" : null;
380  break;
381  }
382  } catch(exception $e) {
383  if ($e->getCode() == -1) {
384  return array("dontProcess" => true);
385  }
386  throw new exception("Name retrieval failed: " . $e->getMessage(), 3);
387  }
388  return array("createdDate" => $createdDate, "modifiedDate" => $modifiedDate, "deletedBy" => $deletedBy, "type" => $type, "dontProcess" => false);
389 }
390 
391 /**
392  * function printSecureFormPage($self)
393  * Prints out the page for the secure forms.
394  *
395  * @param string $self -- the URL of this script.
396  */
397 function printSecureFormPage($self) { ?>
398  <script type="text/javascript">
399  <?php // Library javascript functions
400  getShowWaitFunctions(); ?>
401 
402  var tempData = [];
403 
404  function openDeleteConfirm(isRestore) {
405  var deleteConfirm = $("#deleteConfirm").data("kendoDialog");
406  if (deleteConfirm == null) {
407  deleteConfirm = $("<div id='deleteConfirm'></div>").appendTo("body").kendoDialog({
408  actions: [
409  {text: "No"},
410  {text: "Yes", primary: true, action: function() {
411  $("#deleteConfirm").data("kendoDialog").close();
412  deleteRestoreClick($("#deleteConfirm").data("isRestore"));
413  }}
414  ],
415  visible: false,
416  open: function() {
417  if (window.activeWindows != null) {
418  window.activeWindows.push(this);
419  }
420  },
421  close: function() {
422  if (window.activeWindows != null) {
423  window.activeWindows.pop();
424  }
425  }
426  }).data("kendoDialog");
427  }
428  deleteConfirm.title(isRestore ? "Restore Files" : "Delete Files").content(
429  "<p>You are about to " + (isRestore ? "restore" : "delete") + " these files.</p><p>Do you wish to continue?</p>").open();
430  $("#deleteConfirm").data({isRestore: isRestore});
431  }
432 
433  function openFileWindow(filename, formtype) {
434  var fileWindow = $("#fileWindow").data("kendoWindow");
435  if (fileWindow == null) {
436  var fileWindow = $("<div id='fileWindow'></div>").appendTo("body").kendoWindow({
437  visible: false,
438  actions: [ "Print", "Close" ],
439  open: function() {
440  if (window.activeWindows != null) {
441  window.activeWindows.push(this);
442  }
443  },
444  close: function() {
445  if (window.activeWindows != null) {
446  window.activeWindows.pop();
447  }
448  },
449  width: 600,
450  title: "View File",
451  modal: true
452  }).data("kendoWindow");
453 
454  $("#fileWindow").on("click", ".closeBtn", function() {
455  $("#fileWindow").data("kendoWindow").close();
456  });
457  }
458 
459 
460  var bodyWidth = $("#body-wrapper").width();
461  var bodyHeight = $("#body-wrapper").height();
462  var width = 600;
463  var height = 300;
464  if (formtype == 'loan' || formtype == 'subuser') {
465  width = 900;
466  height = 450;
467  }
468  width = Math.min(Math.floor(bodyWidth * .95), width);
469  height = Math.min(Math.floor(bodyHeight * .95), height);
470  var template = kendo.template('<div class="hcu-template"><iframe id="viewIframe" style="width: 100%;" '
471  + 'src="<?php echo $self; ?>&operation=#: operation #&filename=#: filename #"></iframe>'
472  + '<div class="hcu-edit-buttons k-state-default"><a class="closeBtn k-button k-primary" href="\\#"><i class="fa fa-check"></i>Close</a></div></div>');
473  <?php // set width first so open center will actually center ?>
474  $(fileWindow.wrapper).css({ width: width});
475  fileWindow.content(template({operation: "viewFile", filename: filename})).open().center();
476  $("#viewIframe").height(height);
477 
478  var dialog = $("#fileWindow").data('kendoWindow');
479 
480  printButton = dialog.wrapper.find(".k-i-print");
481  printButton.click(function (e) {
482  <?php // get string from iframe source ?>
483  var src = $("#viewIframe").attr('src');
484  window.open( src, "print_view" );
485  });
486 
487  homecuTooltip.reset(); <?php // set to defaults, probably unnecessary but just in case ?>
488  homecuTooltip.custom.content = "View/Print in new window";
489  printButton.kendoTooltip(homecuTooltip.custom).data("kendoTooltip");
490  }
491 
492  <?php
493  /**
494  * function init()
495  * This initializes all two grids (forms, deleted forms) and all the buttons in the grids.
496  * The definitions are created for forms. There is one difference between the active and deleted grids: extra column.
497  */
498  ?>
499  function init() {
500  var rowTemplateTemplate = kendo.template("# var downloadClass= 'dataDownload';"
501  + "var viewClass = 'formPreview'; #<tr data-uid='\\#: uid \\#'><td class='checkboxTD'><input type='checkbox' class='rowCheckbox'></td>"
502  + "<td><i class='fa fa-search #: viewClass # showClickable'></i>&nbsp; # if (gridType == 'form') { # \\# if (dataFile != '' && dataFile != null) { \\# # } #"
503  + "<i class='fa fa-download #: downloadClass # showClickable'></i># if (gridType == 'form') { # \\# } \\# # } #</td>"
504  + "# if (gridType == 'form') { #<td>\\#: kendo.toString(createdDate, 'G') \\#</td><td>\\#: type \\#</td> # } else { # <td>\\#: filename \\#</td> # } #"
505  + "# if (showsDeleted) { #<td>\\#: kendo.toString(modifiedDate, 'd') \\#</td><td>\\#: deletedBy \\#</td> # } #</tr>");
506 
507  $("#deleteSelectedFormsBtn").click(function() {
508  if (!$(this).hasClass("k-state-disabled")) {
509  openDeleteConfirm(false, false);
510  }
511  return false;
512  });
513 
514  $("#restoreSelectedFormsBtn").click(function() {
515  if (!$(this).hasClass("k-state-disabled")) {
516  openDeleteConfirm(true, false);
517  }
518  return false;
519  });
520 
521  var formDefinition = {
522  dataSource: {
523  transport: {
524  read: function (options) {
525  options.success(tempData);
526  }
527  },
528  schema: {
529  model: {
530  id: "index",
531  fields: {
532  index: {type: "number"},
533  dataFile: {type: "string"},
534  type: {type: "string"},
535  createdDate: {type: "date"},
536  modifiedDate: {type: "date"},
537  deletedBy: {type: "string"},
538  filename: {type: "string"},
539  checked: {type: "boolean"}
540  }
541  }
542  },
543  sort: {field: "createdDate", dir: "desc"}
544  },
545  sortable: true,
546  filterable: true,
547  columns: [
548  {title: "", width: "45px", headerTemplate: "<input type='checkbox' class='allCheckbox'>"},
549  {width: "90px"},
550  {field: "createdDate", title: "Created", width: "170px"},
551  {field: "type", title: "File Type"}
552  ],
553  rowTemplate: rowTemplateTemplate({gridType: "form", showsDeleted: false}),
554  noRecords: {
555  template: "<tr><td colspan='4'>No Records Found</td></tr>"
556  }
557  };
558 
559  var formGrid = $("#formGrid").kendoGrid(formDefinition).data("kendoGrid");
560 
561  formDefinition.columns.splice(4,0, {field: "modifiedDate", title: "Deleted"}, {field: "deletedBy", title: "Deleted By"});
562 
563  formDefinition.rowTemplate = rowTemplateTemplate({gridType: "form", showsDeleted: true});
564  var deletedFormGrid = $("#deletedFormGrid").kendoGrid(formDefinition).data("kendoGrid");
565 
566  <?php printCheckboxEvents("#formGrid", "#deleteSelectedFormsBtn");
567  printCheckboxEvents("#deletedFormGrid", "#restoreSelectedFormsBtn"); ?>
568 
569  $("#showDeletedBtn").click(function() {
570  $("#activeFormDiv").hide();
571  $("#deletedFormDiv").show();
572  return false;
573  });
574 
575  $("#showActiveBtn").click(function() {
576  $("#activeFormDiv").show();
577  $("#deletedFormDiv").hide();
578  return false;
579  });
580 
581  $(".formDiv").on("click", ".formPreview", function() {
582  var tr = $(this).closest("tr");
583  var grid = $(this).closest(".formGrid").data("kendoGrid");
584  var dataItem = grid.dataItem(tr);
585 
586  openFileWindow(dataItem.filename, dataItem.type);
587  return false;
588  });
589 
590  $(".formDiv").on("click", ".dataDownload", function() {
591  var tr = $(this).closest("tr");
592  var grid = $(this).closest(".formGrid").data("kendoGrid");
593  var dataItem = grid.dataItem(tr);
594 
595  $("#downloadForm [name='filename']").val(dataItem.dataFile);
596  $("#downloadForm [name='operation']").val("downloadFile");
597  $("#downloadForm").submit();
598  return false;
599  });
600 
601  showWaitWindow();
602  $.post("<?php echo $self; ?>&operation=readForms", {}, function(data) {
603  hideWaitWindow();
604  if (data.error.length > 0) {
605  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
606  } else {
607  putDataInGrids(data.formData, data.deletedFormData);
608  }
609  });
610  }
611 
612  <?php
613  /**
614  * function deleteRestoreClick(isRestore)
615  * This function handles what happens when the delete or restore button is clicked (after the confirmation window).
616  * It has a couple of parts:
617  * 1) Gather data from the four grids. These are named addTo... and removeFrom... because depending on if it restoring or deleting, it is opposite.
618  * 2) From the removeFrom... grids, add to the filenames array like {name: record.filename} where modifyTo true. Record the latest indices for both gridtypes.
619  * 3) Send a call with the parameters from #2.
620  * 4) Get the new files from the call return.
621  * 5) Remove the records from the removeFrom... grids with the modifyTo true.
622  * 6) Add the records from the call return to the addTo... grids.
623  *
624  * @param boolean isRestore -- If true, then gets data from the deleted grids and calls the "restoreFiles" call. Otherwise, gets data from the active grids and calls the "deleteFiles" call.
625  */
626  ?>
627  function deleteRestoreClick(isRestore) {
628  var addToFormGrid = null, removeFromFormGrid = null;
629  if (isRestore) {
630  addToFormGrid = $("#formGrid").data("kendoGrid");
631  removeFromFormGrid = $("#deletedFormGrid").data("kendoGrid");
632  } else {
633  removeFromFormGrid = $("#formGrid").data("kendoGrid");
634  addToFormGrid = $("#deletedFormGrid").data("kendoGrid");
635  }
636 
637  var removeFromFormData = removeFromFormGrid.dataSource.data();
638  var addToFormData = addToFormGrid.dataSource.data();
639 
640  var parseData = [];
641  var nextFormIndex = 1;
642 
643  for(var i = 0; i != removeFromFormData.length; i++) {
644  var record = removeFromFormData[i];
645  if (record.checked) {
646  parseData.push({name: record.filename});
647  }
648  if (record.index > nextFormIndex) {
649  nextFormIndex = record.index;
650  }
651  }
652  for(var i = 0; i != addToFormData.length; i++) {
653  var record = addToFormData[i];
654  if (record.index > nextFormIndex) {
655  nextFormIndex = record.index;
656  }
657  }
658 
659  var parameters = {files: kendo.stringify(parseData), nextFormIndex: ++ nextFormIndex};
660 
661  showWaitWindow();
662  $.post("<?php echo $self; ?>&operation=" + (isRestore ? "restoreFiles" : "removeFiles"), parameters, function(data) {
663  hideWaitWindow();
664 
665  if (data.error.length > 0) {
666  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
667  } else {
668  removeFromFormData = $.grep(removeFromFormData, function(n,i) { return !n.checked; });
669 
670  for(var i = 0; i != data.formData.length; i++) {
671  addToFormData.push(data.formData[i]);
672  }
673 
674  !isRestore ? putDataInGrids(removeFromFormData, addToFormData)
675  : putDataInGrids(addToFormData, removeFromFormData);
676 
677  $(".allCheckbox").prop("checked", false);
678  }
679  });
680  }
681 
682  <?php
683  /**
684  * function putDataInGrids(formData, deletedFormData)
685  * This utility function puts changed data back into the grids. It uses a tempData and the transport data function to get around parsing problems with the dataSource.data() function.
686  *
687  * @param array formData -- the new form data.
688  * @param array deletedFormData -- the new deleted form data.
689  */
690  ?>
691  function putDataInGrids(formData, deletedFormData) {
692  tempData = formData;
693  $("#formGrid").data("kendoGrid").dataSource.read();
694 
695  tempData = deletedFormData;
696  rowA = 0;
697  $("#deletedFormGrid").data("kendoGrid").dataSource.read();
698  }
699 
700  var activeWindows = [];
701  $(document).ready(function() {
702  init();
703  <?php printClickOverlayEvent(); ?>
704  });
705  </script>
706  <div class="container secureFormsDiv hcu-all-100">
707  <div class="row">
708  <div id="formValidateDiv" class="k-block k-error-colored formValidateDiv" style="display:none;"></div>
709  </div>
710  <div id="activeFormDiv" class="formDiv">
711  <h2>Secure Forms</h2>
712  <div class="row hcuSpacer hcu-edit-buttons">
713  <div class="col-xs-12">
714  <a href="#" id="deleteSelectedFormsBtn" class="k-button k-state-disabled">Delete selected forms</a>&nbsp; <a href="#" id="showDeletedBtn">Recently Deleted Forms</a>
715  </div>
716  </div>
717  <div class="row">
718  <div class="col-xs-12">
719  <div id="formGrid" class="formGrid checkboxGrid hcu-all-100"></div>
720  </div>
721  </div>
722  </div>
723  <div id="deletedFormDiv" class="formDiv" style="display:none;">
724  <div class="row h3">
725  <div class="col-xs-12">
726  Deleted Secure Forms
727  </div>
728  </div>
729  <div class="row hcuSpacer hcu-edit-buttons">
730  <div class="col-xs-12">
731  <a href="#" id="restoreSelectedFormsBtn" class="k-button k-state-disabled">Restore selected forms</a>&nbsp; <a href="#" id="showActiveBtn">Active Forms</a>
732  </div>
733  </div>
734  <div class="row">
735  <div class="col-xs-12">
736  <div id="deletedFormGrid" class="formGrid checkboxGrid hcu-all-100"></div>
737  </div>
738  </div>
739  </div>
740  &emsp;
741  </div>
742  <iframe name="hiddenFrame" style="display:none;"></iframe>
743  <form id="downloadForm" action="<?php echo $self; ?>" method="post" target="hiddenFrame" style="display:none;">
744  <input name="operation" value="">
745  <input name="filename" value="">
746  </form>
747 <?php }