Odyssey
userSearch.i
1 <?php
2 /**
3  * @package userSearch.i -- this contains the code to search for a user in the user hub + other places that need to select a user such as Secure Documents > Secure Messages.
4  */
5 require_once("aGroupSupport.i");
6 require_once("aMemberSupport.i");
7 
8 $showSQL = $SYSENV["devmode"];
9 $parameters = array("a" => array("operation" => ""));
10 $string = array("filter" => FILTER_DEFAULT);
11 HCU_ImportVars($parameters, "a", array("operation" => $string));
12 
13 switch($parameters["a"]["operation"]) {
14  case "userSearch":
15  $parameters = array("a" => array("memAccount" => "", "username" => "", "email" => "", "address" => "", "phone" => "", "partialMatch" => "", "fromUserHub" => ""));
16  HCU_ImportVars($parameters, "a", array("memAccount" => $string, "username" => $string, "email" => $string, "address" => $string, "phone" => $string,
17  "partialMatch" => $string, "fromUserHub" => $string));
18  $returnArray = readUserSearch($dbh, $Cu, $parameters);
19  header('Content-type: application/json');
20  if (!$showSQL) {
21  unset($returnArray["sql"]);
22  }
23  print HCU_JsonEncode($returnArray);
24  exit; // Since this is an included file, whatever is in the script will execute if not exited here.
25  case "userFind":
26  $parameters = array("a" => array("selectedUser" => "", "fromUserHub" => ""));
27  HCU_ImportVars ($parameters, "a", array("selectedUser" => $string, "fromUserHub" => $string));
28  extract($parameters["a"]);
29 
30  try {
31  $selectedUser = hcu_JsonDecode($selectedUser);
32  $thisThingHere = encryptUser($Cu, $selectedUser, false);
33  $counts = $fromUserHub == "Y" ? getUserHubCounts($dbh, $Cu, intval($selectedUser["user_id"])) : 0;
34  $groupEncryption = $fromUserHub ? encryptGroup($dbh, $Cu, $selectedUser) : null;
35  $returnArray = array("error" => array(), "code" => 0, "encryption" => $thisThingHere, "counts" => $counts, "groupEncryption" => $groupEncryption);
36  } catch(exception $e) {
37  $returnArray = array("error" => array($e->getMessage()), "code" => $e->getCode());
38  }
39 
40  header('Content-type: application/json');
41  if (!$showSQL) {
42  unset($returnArray["sql"]);
43  }
44  print HCU_JsonEncode($returnArray);
45  exit; // Since this is an included file, whatever is in the script will execute if not exited here.
46 
47 }
48 
49 /**
50  * function encryptUser($Cu, $unencryptedUser, $encoded=true)
51  * This encrypts the user record.
52  *
53  * @param string $Cu -- the credit union (used in making a key)
54  * @param string|array $unencryptedUser -- the user record to encrypt. If found one record in the search, then this is an array coming in. Otherwise it is a json_encoded string.
55  * @param boolean $encoded -- if false, user record come in as an array.
56  *
57  * @return array("message" => the encrypted message, "hash" => the hash of the encrypted message)
58  * @throws "User encryption failed."
59  */
60 function encryptUser($Cu, $unencryptedUser, $encoded = true) {
61  try {
62  if ($encoded) {
63  if (trim($unencryptedUser) == "") {
64  throw new exception("Need the user.", 1);
65  }
66  $unencryptedUser = hcu_JsonDecode($unencryptedUser);
67  }
68  if (!is_array($unencryptedUser)) {
69  throw new exception("User is not coded correctly.", 2);
70  }
71  if (!HCU_array_key_exists("user_id", $unencryptedUser)) {
72  throw new exception("User id is not in array.", 3);
73  }
74  if (!HCU_array_key_exists("group_id", $unencryptedUser)) {
75  throw new exception("Group id is not in array.", 5);
76  }
77  return HCU_PayloadEncode($Cu, $unencryptedUser);
78  } catch(exception $e) {
79  throw new exception("User encryption failed.", 1);
80  }
81 }
82 
83 /**
84  * function encryptGroup($dbh, $Cu, $user)
85  * This will encrypt the group for a group payload.
86  *
87  * @param something $dbh -- the database connection
88  * @param string $Cu -- the credit union
89  * @param array $user -- the user record
90  *
91  * @return the group payload
92  */
93 function encryptGroup($dbh, $Cu, $user) {
94  if (!HCU_array_key_exists("group_id", $user)) {
95  return null;
96  }
97 
98  $groupId = intval($user["group_id"]);
99  $sql = "select count(*) as count from ${Cu}user tu where tu.group_id = $groupId";
100 
101  $sth = db_query($sql, $dbh);
102  if (!$sth) {
103  throw new exception("Count query failed.", 100);
104  }
105  $count = intval(db_fetch_row($sth,0)[0]);
106 
107  $sql = "select u.user_id, u.user_name, u.email, array_to_string(ss.cellnumbers, ',') as cellnumber,
108  g.group_name, p.profile_code, g.group_id, p.profile_id, p.description as profile_desc, u.employee
109  from ${Cu}user u
110  left join (select uc.user_id, array_agg(distinct s.cellnumber::text) as cellnumbers from ${Cu}useraccounts uc
111  inner join cusms s on trim(uc.accountnumber) = trim(s.accountnumber) and s.cu = '${Cu}' group by uc.user_id
112  ) ss on u.user_id = ss.user_id
113  left join ${Cu}group g on u.group_id = g.group_id
114  left join cu_profile p on g.profile_id = p.profile_id
115  where u.group_id = $groupId and u.is_group_primary";
116 
117  $sth = db_query($sql, $dbh);
118 
119  $prims = array();
120  if (!$sth) {
121  throw new exception("primary user query failed!", 101);
122  }
123  for($i = 0; $row = db_fetch_assoc($sth, $i); $i++) {
124  $row["p_name"] = $row["user_name"];
125  $prims[] = $row;
126  $profileDesc = $row["profile_desc"];
127  }
128 
129  $group = array("group" => array("g_name" => $user["group_name"], "g_id" => $user["group_id"], "p_id" => $user["profile_id"], "g_profile" => $profileDesc,
130  "g_primary" => $prims, "g_count" => $count));
131 
132  return GroupEncrypt(null, $Cu, $group);
133 }
134 
135 /**
136  * function readUserSearch($dbh, $Cu)
137  * This read the user search
138  *
139  * @param $dbh -- the database connection
140  * @param $Cu -- the credit union
141  * @param $parameters -- the parameters from the input fields in the user search dialog.
142  *
143  * @return array("code" => 0 if no errors; nonzero otherwise, "error" => list of errors encountered, "sql" => list of SQL executed, "data" => results of search,
144  * "encryption" => if there is one record returned, then encrypt that record and send.)
145  */
146 function readUserSearch($dbh, $Cu, $parameters) {
147  $data = array();
148  $encryption = array("message" => "", "hash" => "");
149  try {
150  $sql = "from ${Cu}user u
151  left join (select uc.user_id, array_agg(distinct s.cellnumber::text) as cellnumbers, {{phoneExists}} as phoneexists from ${Cu}useraccounts uc
152  left join cusms s on trim(uc.accountnumber) = trim(s.accountnumber) and s.cu = '${Cu}'
153  {{innerWhere}} group by uc.user_id
154  ) ss on u.user_id = ss.user_id
155  left join ${Cu}group g on u.group_id = g.group_id
156  left join cu_profile p on g.profile_id = p.profile_id";
157 
158  $joins = array();
159  $where = array();
160 
161  $partialMatch = isset($parameters["a"]["partialMatch"]) && trim($parameters["a"]["partialMatch"]) == "Y";
162  $fromUserHub = isset($parameters["a"]["fromUserHub"]) && trim($parameters["a"]["fromUserHub"]) == "Y";
163  foreach($parameters["a"] as $key => $value) {
164  if ($key == "partialMatch" || $key == "fromUserHub" || !isset($value)) {
165  continue;
166  }
167 
168  $value = isset($value) ? strtolower(trim($value)) : "";
169  $notDone = true;
170  if ($value != "") {
171  switch($key) {
172  case "memAccount":
173  $sql = str_replace("{{innerWhere}}", "where lower(trim(uc.accountnumber)) = '" . prep_save($value, 12) . "'", $sql);
174  $sql = str_replace("{{phoneExists}}", "false", $sql);
175  $where[] = "ss.user_id is not null";
176  $notDone = false; // Here, query needs to inside subquery and it cannot be partial so we are done.
177  break;
178  case "username":
179  $sql = str_replace("{{innerWhere}}", "", $sql);
180  $sql = str_replace("{{phoneExists}}", "false", $sql);
181  $whereStub = "u.user_name is not null and lower(trim(u.user_name))";
182  $value = prep_save($value, 50);
183  break;
184  case "email":
185  $sql = str_replace("{{innerWhere}}", "", $sql);
186  $sql = str_replace("{{phoneExists}}", "false", $sql);
187  $whereStub = "u.email is not null and lower(trim(u.email))";
188  $value = prep_save($value, 255);
189  break;
190  case "phone":
191  $joins["contact"] = "left join ${Cu}usercontact c on u.contact = c.contact_id";
192  $value = trim(preg_replace('/\D+/', "", $value)); // Search on the number only. (123) 456-9889 searches the same as 123.456.9889.
193  $sql = str_replace("{{innerWhere}}", "", $sql);
194  $sql = str_replace("{{phoneExists}}", "bool_or(" . ($partialMatch ? "s.cellnumber like '%$value%'" : "s.cellnumber = '$value'") . ")", $sql);
195  $phoneOr = array();
196  $phoneOr[] = "ss.phoneexists";
197  $phoneOr[] = "c.phones is not null and replace(c.phones, '-', '') "
198  . ($partialMatch ? "~ E'.*\"\\\\d*$value\\\\d*\".*'" : "like '%\"$value\"%'");
199  $where[] = "(" . implode(" or ", $phoneOr) . ")";
200  $notDone = false;
201  break;
202  case "id": // Cannot get through the data call but through code.
203  $sql = str_replace("{{innerWhere}}", "", $sql);
204  $sql = str_replace("{{phoneExists}}", "false", $sql);
205  $where[] = "u.user_id = " . intval($value);
206  $notDone = false;
207  break;
208  }
209 
210  if ($notDone) { // Phone number has its own logic here.
211  if ($partialMatch) {
212  $value = str_replace("_", "^_", str_replace("%", "^%", str_replace("^", "^^", $value)));
213  // % and _ in the string are intrepreted as literals NOT wildcards.
214  $whereEnd = "like '%$value%' escape '^'";
215  // Use something else than the default backslash because that might be needed to escaped multiple times.
216  } else {
217  $whereEnd = "= '$value'";
218  }
219 
220  $where[] = "$whereStub $whereEnd";
221  }
222  }
223  }
224 
225  if (count($joins) != 0) {
226  $sql .= " " . implode(" ", $joins);
227  }
228  if (count($where) != 0) {
229  $sql .= " where " . implode(" and ", $where);
230  }
231 
232  $realSQL = "select u.user_id, u.user_name, u.email, u.employee, array_to_string(ss.cellnumbers, ',') as cellnumber,
233  g.group_name, p.profile_code, g.group_id, p.profile_id,
234  p.description as profile_desc
235  $sql
236  order by lower(u.user_name)";
237 
238  $sth = db_query($realSQL, $dbh);
239  if (!$sth) {
240  throw new exception("Search query failed.", 1);
241  }
242 
243  $primaryAccounts = array();
244  for($i = 0; $row = db_fetch_assoc($sth, $i); $i++) {
245  foreach($row as $key => $value) {
246  $value = is_null($value) ? "" : trim($value);
247  $row[$key] = $value;
248  }
249  $data[$row["user_id"]] = $row;
250  }
251  $data = array_values($data); // For safety. The query PROBABLY won't return any duplicate records.
252 
253  if (count($data) == 1) {
254  $encryption = encryptUser($Cu, $data[0], false);
255  $counts = $fromUserHub ? getUserHubCounts($dbh, $Cu, intval($data[0]["user_id"])) : array();
256  $groupEncryption = $fromUserHub ? encryptGroup($dbh, $Cu, $data[0]) : null;
257  return array("code" => 0, "error" => array(), "encryption" => $encryption, "data" => $data, "counts" => $counts, "groupEncryption" => $groupEncryption);
258  }
259  return array("code" => 0, "error" => array(), "total" => 0, "data" => $data);
260 
261  } catch(exception $e) {
262  return array("code" => $e->getCode(), "error" => array($e->getMessage()), "data" => array(), "total" => 0);
263  }
264 }
265 
266 /**
267  * function getUserHubCounts($dbh, $Cu, $userId)
268  * This will get all the necessary counts for the user hub
269  */
270 function getUserHubCounts($dbh, $Cu, $userId) {
271  $counts = array();
272  $sql = "select count(*) from cuadmeco where unread and not admdeleted and cu = '$Cu' and origination = 1 and user_id = $userId";
273 
274  $sth = db_query($sql, $dbh);
275  if (!$sth) {
276  throw new exception("Secure message query failed.", 2);
277  }
278  $counts["secureMessages"] = intval(db_fetch_row($sth, 0)[0]);
279  return $counts;
280 }
281 
282 /**
283  * function printUserSearch($self)
284  * This prints the user search open function and whatnot
285  *
286  * @param string $self -- main.prg?ft=$ft
287  * @param boolean $fromUserHub -- If from the user hub, then pass down the parameter to user search (gets badge counts on load.)
288  * @param boolean $hasAdvPermissions -- If true, then show the "New User" button. This is from the user hub screen only.
289  */
290 function printUserSearch($self, $callbackName, $fromUserHub = false, $hasAdvPermissions = false) {
291  /**
292  * function openUserSearch(callback)
293  * This opens up the user search with the sequence.
294  *
295  * @param function callback -- the function to call after a success or a failure. The first value passed back is "successfulOneRecord", "successfulSelection", "failedSearch",
296  * and "failedFind." On success, in order the encrypted message, the encrypted hash, and the unencrypted array are passed back.
297  */
298  ?>
299  function openUserSearch() {
300  var userSearchDialog = $("#userSearchDialog").data("kendoDialog");
301  var userFindDialog = $("#userFindDialog").data("kendoDialog");
302 
303  if (userSearchDialog == null) {
304  userSearchDialog = $("<div id='userSearchDialog' class='searchDialog'></div>").appendTo("body").kendoDialog({
305  title: "User Search",
306  content: $("#userSearchTemplate").html(),
307  actions: [
308  <?php if ($fromUserHub && !$hasAdvPermissions) { ?>
309  {text: "<i class='fa fa-plus'></i> New User", action: function(e) { return false;}}, <?php // Do nothing but show. ?>
310  <?php } else if ($fromUserHub) { ?>
311  {text: "<i class='fa fa-plus'></i> New User", action: function(e) {openAddNewUser(true);}}, <?php // Full ability. ?>
312  <?php } // Otherwise, no do not show it (not in DOM); it is not part of the feature. ?>
313  {text: "Cancel"},
314  {text: "Search", primary: true, action: function(e) {
315  if (!$.homecuValidator.validate()) {
316  return false;
317  }
318 
319  $("#userSearchDialog").data("mode", "valid");
320  var parameters = {};
321  var name = $("[name='userSearchSelect']:checked").data("val");
322  parameters[name] = $("[name='"+name+"']").val().trim();
323  parameters.partialMatch = $("[name='partialMatch']").prop("checked") ? "Y" : "N";
324 
325  runSearch(parameters, userSearchDialog);
326  return false;
327  }}],
328  visible: false,
329  minWidth: 400,
330  maxWidth: 450,
331  width: "90%",
332  open: function() {
333  $("#userSearchDialog").data("mode", "invalid");
334  if (window.activeWindows != null) {
335  window.activeWindows.push(this);
336  }
337 
338  $.homecuValidator.setup({formValidate:'userSearchForm', formStatusField: 'userSearchValidation'});
339  },
340  close: function() {
341  if (window.activeWindows != null) {
342  window.activeWindows.pop();
343  }
344  if ($("#userSearchDialog").data("mode") == "invalid" && typeof(<?php echo $callbackName; ?>) == "function") {
345  <?php echo $callbackName; ?>("invalidSearch");
346  }
347  },
348  show: function() {
349  $("[name='username']").focus();
350  <?php // Focus first text input. Needs the "show" because this happens after the open animation. The inputs don't exist on "open." ?>
351 
352  <?php if ($fromUserHub && !$hasAdvPermissions) { ?>
353  var tooltip = $(this.wrapper).data("kendoTooltip");
354  if (tooltip != null) {
355  tooltip.destroy();
356  }
357 
358  <?php // set up the tooltips this way so the defaults can be used ?>
359  var toolTipProps = homecuTooltip.defaults;
360  toolTipProps.filter = "button.k-button:eq(0)";
361  toolTipProps.content = "You do not have permission to add user.";
362 
363  $(this.wrapper).kendoTooltip(toolTipProps).data("kendoTooltip");
364  <?php } ?>
365  },
366  <?php if ($fromUserHub && !$hasAdvPermissions) { ?>
367  initOpen: function() {
368  $(this.wrapper).find("button.k-button:eq(0)").addClass("vsgDisabled dtooltip");
369  },
370  <?php } ?>
371  modal: true
372  }).data("kendoDialog");
373 
374  var noRecordsFoundDialog = $("<div id='noRecordsFoundDialog' class='searchDialog'></div>").appendTo("body").kendoDialog({
375  title: "No Users Found",
376  content: "No users were found.",
377  actions: [
378  <?php if ($fromUserHub && !$hasAdvPermissions) { ?>
379  {text: "<i class='fa fa-plus'></i> New User", action: function(e) { return false;}}, <?php // Do nothing but show. ?>
380  <?php } else if ($fromUserHub) { ?>
381  {text: "<i class='fa fa-plus'></i> New User", action: function(e) {openAddNewUser(true, $("#userSearchForm [name='username']").val());}}, <?php // Full ability. ?>
382  <?php } // Otherwise, no do not show it (not in DOM); it is not part of the feature. ?>
383  {text: "Cancel"},
384  {text: "Start Over", primary: true, action: function(e) {
385  $("#userFindDialog").data("mode", "startOver");
386  }}
387  ],
388  visible: false,
389  open: function() {
390  if (window.activeWindows != null) {
391  window.activeWindows.push(this);
392  }
393  $("#userFindDialog").data("mode", "invalid");
394  },
395  close: function() {
396  if (window.activeWindows != null) {
397  window.activeWindows.pop();
398  }
399  switch($("#userFindDialog").data("mode")) {
400  case "invalid":
401  // Restores the find results of the previously found user
402  var gridData = $("#userFindDialog").data("gridData");
403  var gridSort = $("#userFindDialog").data("gridSort");
404  var dataItem = $("#userFindDialog").data("dataItem");
405  var grid = $("#userFindGrid").data("kendoGrid");
406  grid.dataSource.data(gridData);
407  grid.dataSource.sort(gridSort);
408 
409  var selector = $(".userTD").filter(function() { return $(this).text().trim() == (dataItem.user_name+"").trim(); }).closest("tr");
410  grid.select(selector);
411 
412  if (typeof(<?php echo $callbackName; ?>) == "function") {
413  <?php echo $callbackName; ?>("invalidSearch");
414  }
415  break;
416  case "startOver":
417  $(".userSearchContents [name]").each(function() {
418  $(this).attr("type") == "checkbox" ? $(this).prop("checked", false) : $(this).val(null);
419  });
420  userSearchDialog.open();
421  break;
422  }
423  },
424  <?php if ($fromUserHub && !$hasAdvPermissions) { ?>
425  show: function() {
426  var tooltip = $(this.wrapper).data("kendoTooltip");
427  if (tooltip != null) {
428  tooltip.destroy();
429  }
430 
431  <?php // set up the tooltips this way so the defaults can be used ?>
432  var toolTipProps = homecuTooltip.defaults;
433  toolTipProps.filter = "button.k-button:eq(0)";
434  toolTipProps.content = "You do not have permission to add user.";
435 
436  $(this.wrapper).kendoTooltip(toolTipProps).data("kendoTooltip");
437  },
438  initOpen: function() {
439  var selector = "button.k-button:eq(0)";
440  $(this.wrapper).find("button.k-button:eq(0)").addClass("vsgDisabled dtooltip");
441  },
442  <?php } ?>
443  modal: true,
444  minWidth: 300,
445  maxWidth: 350,
446  }).data("kendoDialog");
447 
448  userFindDialog = $("<div id='userFindDialog' class='fusedGridDialog searchDialog'></div>").appendTo("body").kendoDialog({
449  title: "Select User",
450  content: '<div id="userFindValidation" class="k-block k-error-colored formValidateDiv" style="display:none;"></div><div id="userFindGrid"></div>',
451  actions: [
452  <?php if ($fromUserHub && !$hasAdvPermissions) { ?>
453  {text: "<i class='fa fa-plus'></i> New User", action: function(e) { return false;}}, <?php // Do nothing but show. ?>
454  <?php } else if ($fromUserHub) { ?>
455  {text: "<i class='fa fa-plus'></i> New User", action: function(e) {openAddNewUser(true);}}, <?php // Full ability. ?>
456  <?php } // Otherwise, no do not show it (not in DOM); it is not part of the feature. ?>
457  {text: "Cancel"},
458  {text: "Start Over", primary: true, action: function(e) {
459  $("#userFindDialog").data("mode", "startOver");
460  }}
461  ],
462  visible: false,
463  open: function() {
464  if (window.activeWindows != null)
465  window.activeWindows.push(this);
466  $("#userFindDialog").data("mode", "invalid");
467 
468  $.homecuValidator.setup({formValidate:'userFindDialog', formStatusField: 'userFindValidation'});
469  },
470  close: function() {
471  if (window.activeWindows != null) {
472  window.activeWindows.pop();
473  }
474  switch($("#userFindDialog").data("mode")) {
475  case "invalid":
476  // Restores the find results of the previously found user
477  var gridData = $("#userFindDialog").data("gridData");
478  var gridSort = $("#userFindDialog").data("gridSort");
479  var dataItem = $("#userFindDialog").data("dataItem");
480  var grid = $("#userFindGrid").data("kendoGrid");
481  grid.dataSource.data(gridData);
482  grid.dataSource.sort(gridSort);
483 
484  var selector = $(".userTD").filter(function() { return $(this).text().trim() == (dataItem.user_name+"").trim(); }).closest("tr");
485  grid.select(selector);
486 
487  if (typeof(<?php echo $callbackName; ?>) == "function") {
488  <?php echo $callbackName; ?>("invalidSearch");
489  }
490  break;
491  case "startOver":
492  $(".userSearchContents [name]").each(function() {
493  $(this).attr("type") == "checkbox" ? $(this).prop("checked", false) : $(this).val(null);
494  });
495  userSearchDialog.open();
496  break;
497  }
498  },
499  <?php if ($fromUserHub && !$hasAdvPermissions) { ?>
500  show: function() {
501  var tooltip = $(this.wrapper).data("kendoTooltip");
502  if (tooltip != null) {
503  tooltip.destroy();
504  }
505 
506  <?php // set up the tooltips this way so the defaults can be used ?>
507  var toolTipProps = homecuTooltip.defaults;
508  toolTipProps.filter = "button.k-button:eq(0)";
509  toolTipProps.content = "You do not have permission to add user.";
510 
511  $(this.wrapper).kendoTooltip(toolTipProps).data("kendoTooltip");
512  },
513  initOpen: function() {
514  var selector = "button.k-button:eq(0)";
515  $(this.wrapper).find("button.k-button:eq(0)").addClass("vsgDisabled dtooltip");
516  },
517  <?php } ?>
518  modal: true,
519  minWidth: 400,
520  maxWidth: 900,
521  maxHeight: 400
522  }).data("kendoDialog");
523 
524  $("#userFindDialog").data("gridData", []);
525  $("#userFindDialog").data("gridSort", {field: "user_id", dir: "asc"});
526  $("#userFindDialog").data("dataItem", null);
527 
528  var userGrid = $("#userFindGrid").kendoGrid({
529  dataSource: {
530  data: [],
531  schema: {
532  model: {
533  id: "user_id",
534  fields: {
535  user_id: {type: "number"},
536  user_name: {type: "string"},
537  email: {type: "string"},
538  cellnumber: {type: "number"},
539  group_name: {type: "string"},
540  profile_code: {type: "string"},
541  group_id: {type: "string"},
542  profile_id: {type: "string"},
543  description: {type: "string"}
544  }
545  }
546  }
547  },
548  autoBind: false,
549  selectable: "row",
550  sortable: true,
551  columns: [
552  {field: "user_name", title: "User", attributes: {"class": "userTD"}},
553  {field: "email", title: "Email"},
554  {field: "cellnumber", title: "Phone"}
555  ],
556  scrollable: true,
557  change: function(e) {
558  if (!$("#userFindGrid").data("inChange"))
559  {
560  $("#userFindGrid").data("inChange", true);
561  $("#userFindDialog").data("mode", "select");
562  var dataItem= this.dataItem(this.select()[0]);
563  $("#userFindDialog").data("dataItem", dataItem);
564  $("#userFindDialog").data("gridData", this.dataSource.data());
565  $("#userFindDialog").data("gridSort", this.dataSource.sort());
566  runSelect(userSearchDialog, userFindDialog);
567  $("#userFindGrid").data("inChange", false);
568  }
569  },
570  noRecords: {
571  template: "No Records Found"
572  },
573  width: "100%"
574  }).data("kendoGrid");
575 
576  $("body").on("keypress", function(e) {
577  if ([10,13].indexOf(e.which) != -1)
578  {
579  if ($("#gsSearch:visible").length != 0) {
580  <?php // This will prevent add user form validation from firing ?>
581  } else if ($("#gsConfirm:visible").length != 0) {
582  <?php // This will prevent add user form validation from firing ?>
583  } else if ($("#gsResults:visible").length != 0) {
584  <?php // This will prevent add user form validation from firing ?>
585  } else if ($("#gsNoResults:visible").length != 0) {
586  <?php // This will prevent add user form validation from firing ?>
587  } else if ($(".searchDialog:visible").length != 0) {
588  var dialog= $(".searchDialog:visible").data("kendoDialog");
589  var actions= dialog.options.actions;
590  for(var i=0; i!= actions.length; i++) {
591  if (actions[i].primary) {
592  if (actions[i].action() !== false) {
593  dialog.close();
594  }
595  break;
596  }
597  }
598  }
599  }
600  });
601 
602  $("[name='phone']").blur(function() {
603  var value = $(this).val().trim();
604  $(this).val(value.replace(/\D+/g, ""));
605  });
606 
607  $("#userSearchDialog [name='userSearchSelect']").click(function() {
608  var name = $(this).data("val").trim();
609  $("#userSearchDialog [type='text']").each(function() {
610  if (name == $(this).attr("name").trim()) {
611  $(this).prop("disabled", false);
612  $(this).attr("required", "required");
613  $(this).removeClass("vsgDisabled");
614  (this).focus();
615 
616  var partialMatch= $("[name='partialMatch']");
617  if ($(this).hasClass("disablePartial")) {
618  $(partialMatch).prop("disabled", true);
619  $(partialMatch).prop("checked", false);
620  $(partialMatch).closest("label").addClass("vsgDisabled");
621  } else {
622  $(partialMatch).prop("disabled", false);
623  $(partialMatch).closest("label").removeClass("vsgDisabled");
624  }
625  } else {
626  $(this).prop("disabled", true);
627  <?php // remove red outline around input when no longer relevant. ?>
628  $(this).removeClass("k-invalid");
629  $(this).css("border", "1px solid #ceced2");
630  $(this).val(null);
631  $(this).removeAttr("required");
632  $(this).addClass("vsgDisabled");
633  }
634  });
635  });
636 
637  var toolTipProps = homecuTooltip.defaults;
638  toolTipProps.filter = "[type='text'].vsgDisabled";
639  toolTipProps.content = "Search is single input.";
640 
641  $("#userSearchDialog").kendoTooltip(toolTipProps);
642 
643  var toolTipProps = homecuTooltip.defaults;
644  toolTipProps.filter = "label.vsgDisabled";
645  toolTipProps.content = "Search cannot be partial.";
646 
647  $("#userSearchDialog").kendoTooltip(toolTipProps);
648  } else {
649  // Clear values
650  $(".userSearchContents [name]").each(function() {
651  $(this).attr("type") == "checkbox" ? $(this).prop("checked", false) : $(this).val(null);
652  });
653  }
654  var length = $("#userFindGrid").data("kendoGrid").dataSource.data().length;
655  length <= 1 ? userSearchDialog.open() : userFindDialog.open();
656  }
657 
658  function runSelect(userSearchDialog, userFindDialog) {
659  switch($("#userFindDialog").data("mode")) {
660  case "invalid":
661  $("#userFindGrid").data("inChange", true); <?php // Do not trigger a change event with .data or .sort. ?>
662  <?php // Restores the find results of the previously found user ?>
663  var gridData = $("#userFindDialog").data("gridData");
664  var gridSort = $("#userFindDialog").data("gridSort");
665  var dataItem = $("#userFindDialog").data("dataItem");
666  var grid = $("#userFindGrid").data("kendoGrid");
667  grid.dataSource.data(gridData);
668  grid.dataSource.sort(gridSort);
669 
670  var selector = $(".userTD").filter(function() { return $(this).text().trim() == (dataItem.user_name+"").trim(); }).closest("tr");
671  grid.select(selector);
672 
673  if (typeof(<?php echo $callbackName; ?>) == "function") {
674  <?php echo $callbackName; ?>("invalidFind");
675  }
676  $("#userFindGrid").data("inChange", false);
677  userFindDialog.close();
678  break;
679  case "select":
680  var parameters = {selectedUser: kendo.stringify($("#userFindDialog").data("dataItem")), fromUserHub: "<?php echo $fromUserHub ? 'Y' : 'N'; ?>"};
681  showWaitWindow();
682  $.post("<?php echo $self; ?>&operation=userFind", parameters, function(data) {
683  hideWaitWindow();
684  if (data.error.length > 0) {
685  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
686  } else if (typeof(<?php echo $callbackName; ?>) == "function") {
687  var dataItem = $("#userFindDialog").data("dataItem");
688  <?php echo $callbackName; ?>("successfulSelection", data.encryption, dataItem, data.counts, data.groupEncryption, data.accountEncryption);
689  userFindDialog.close();
690  }
691  });
692  break;
693  case "startOver":
694  $(".userSearchContents [name]").each(function() {
695  $(this).attr("type") == "checkbox" ? $(this).prop("checked", false) : $(this).val(null);
696  });
697  userFindDialog.close();
698  userSearchDialog.open();
699  break;
700  }
701  }
702 
703  <?php
704  /**
705  * function openFindDialog ()
706  * For other scripts to call when the find has already been initialized.
707  */
708  ?>
709  function openFindDialog () {
710  var length = $("#userFindGrid").data("kendoGrid").dataSource.data().length;
711  var dialog = length == 0 ? $("#noRecordsFoundDialog").data("kendoDialog") : (length == 1 ? null : $("#userFindDialog").data("kendoDialog"));
712  if (dialog != null) {
713  dialog.open();
714  }
715  }
716 
717  <?php
718  /**
719  * function runSearch(parameters)
720  * This calls the data call to run the search. This happens with there is a criteria or if there is no criteria, then after the user says "yes" on the next dialog.
721  */
722  ?>
723  function runSearch(parameters, userSearchDialog) {
724  parameters.fromUserHub = "<?php echo $fromUserHub ? 'Y' : 'N'; ?>";
725  showWaitWindow();
726  $.post("<?php echo $self; ?>&operation=userSearch", parameters, function(data) {
727  hideWaitWindow();
728  if (data.error.length > 0) {
729  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
730  } else {
731  userSearchDialog.close();
732  if (data.encryption != null && typeof(<?php echo $callbackName; ?>) == "function") {
733  $("#userFindGrid").data("kendoGrid").dataSource.data(data.data);
734  <?php echo $callbackName; ?>("successfulOneRecord", data.encryption, data.data[0], data.counts, data.groupEncryption, data.accountEncryption);
735  } else if (data.data.length == 0) {
736  $("#noRecordsFoundDialog").data("kendoDialog").open();
737  } else {
738  $("#userFindGrid").data("kendoGrid").dataSource.data(data.data);
739  $("#userFindDialog").data("kendoDialog").open();
740  }
741  }
742  });
743  }
744 <?php }
745 
746 function printUserSearchTemplate() { ?>
747  <script id="userSearchTemplate" type="text/x-kendo-template">
748  <form id="userSearchForm" action="javascript:void()"><div class="userSearchContents container hcu-all-100">
749  <div class="row hcuSpacer"><div id="userSearchValidation" class="k-block k-error-colored formValidateDiv" style="display:none;"><div class="col-xs-12 hcu-no-padding">
750  </div></div></div>
751  <div class="row hcuSpacer">
752  <div class="col-xs-5 hcu-no-padding radio"><label><input type="radio" checked name="userSearchSelect" data-val="username"> Username</label></div>
753  <div class="col-xs-7 hcu-no-padding"><input name="username" type="text" maxlength="50" class="hcu-all-100 k-input k-textbox required" focus
754  data-required-msg="Username is required" required="required"></div>
755  </div>
756  <div class="row hcuSpacer">
757  <div class="col-xs-5 hcu-no-padding radio"><label><input type="radio" name="userSearchSelect" data-val="email"> Email</label></div>
758  <div class="col-xs-7 hcu-no-padding"><input name="email" type="text" maxlength="255" class="hcu-all-100 k-input k-textbox vsgDisabled" disabled
759  data-required-msg="Email is required"></div>
760  </div>
761  <div class="row hcuSpacer">
762  <div class="col-xs-5 hcu-no-padding radio"><label><input type="radio" name="userSearchSelect" data-val="memAccount"> Member Acct #</label></div>
763  <div class="col-xs-7 hcu-no-padding"><input name="memAccount" type="text" maxlength="12" class="hcu-all-100 k-input k-textbox vsgDisabled disablePartial" disabled
764  data-required-msg="Member account is required"></div>
765  </div>
766  <div class="row hcuSpacer">
767  <div class="col-xs-5 hcu-no-padding radio"><label><input type="radio" name="userSearchSelect" data-val="phone"> Phone</label></div>
768  <div class="col-xs-7 hcu-no-padding"><input name="phone" type="text" class="hcu-all-100 k-input k-textbox vsgDisabled" disabled
769  data-required-msg="Phone is required"></div>
770  </div>
771  <div class="row hcuSpacer">
772  <label class="col-xs-5 hcu-no-padding">&nbsp;</label>
773  <div class="col-xs-7 checkbox hcu-no-padding"><label><input name="partialMatch" type="checkbox"><span id="partialMatchText">Partial Match</span></label></div>
774  </div>
775  </div></form>
776  </script>
777 <?php }