admin.groups.inc

  1. 6.x modules/admin/admin.groups.inc
  2. 4.x modules/admin/admin.groups.inc
  3. 5.x modules/admin/admin.groups.inc

File

modules/admin/admin.groups.inc
View source
  1. <?php
  2. /* This include file deals with Groups editing for FlightPath */
  3. /**
  4. * Validate handler for edit group form.
  5. */
  6. function admin_edit_group_form_validate(&$form, &$form_state) {
  7. $values = $form_state["values"];
  8. $group_name = trim($values["group_name"]);
  9. $group_id = $values["group_id"];
  10. $de_catalog_year = $values["de_catalog_year"];
  11. $school_id = 0;
  12. if (isset($values['schools_school'])) { // A school was set from the schools module.
  13. $school_id = intval($values['schools_school']); // Use our NEW school_id for validating.
  14. }
  15. $school_name = $andschool = "";
  16. if ($school_id > 0) $school_name = "School-" . $school_id;
  17. if (module_enabled("schools")) {
  18. $defs = schools_get_school_definitions();
  19. if (isset($defs[$school_id])) $school_name = $defs[$school_id];
  20. $andschool = " and school %school";
  21. }
  22. // We want to make sure the group_name is in a machine-name format,
  23. // and we need to make sure it is unique for this catalog year and school_id!
  24. $group_name = fp_get_machine_readable(strtolower($group_name));
  25. $form_state['values']['group_name'] = $group_name;
  26. // Check that group_name is unique (but exclude the current group_id from the check)
  27. $mycount = db_query("SELECT count(*) as mycount FROM draft_groups
  28. WHERE group_name = ?
  29. AND group_id != ?
  30. AND delete_flag = 0
  31. AND catalog_year = ?
  32. AND school_id = ?", $group_name, $group_id, $de_catalog_year, $school_id)->fetchColumn();
  33. if ($mycount > 0) {
  34. form_error("group_name", t("The 'Internal group machine name' %gn is already in use in FlightPath by another group
  35. in the catalog year %cy$andschool.
  36. Please change to a different name, and submit again. <b>Your work has NOT been saved.</b>
  37. ", array("%gn" => $group_name, "%cy" => $de_catalog_year, "%school" => $school_name)));
  38. return;
  39. }
  40. $db = get_global_database_handler();
  41. // Make sure that courses are for the correct school for this group.
  42. $courses = $values['courses'];
  43. // Okay, now we look at the actual "courses" box and assemble the group
  44. // in the database.
  45. $lines = explode("\n", $courses);
  46. for ($t = 0; $t < count($lines); $t++) {
  47. $line = trim($lines[$t]);
  48. if ($line == "") { continue; }
  49. // Get rid of extra whitespace.
  50. $line = str_replace(" ", " ", $line);
  51. $line = str_replace(" ", " ", $line);
  52. $line = str_replace(" ", " ", $line);
  53. $line = str_replace(" ", " ", $line);
  54. $line = str_replace(" ", " ", $line);
  55. $line = str_replace(" ", " ", $line);
  56. // Does this line contain at least one & symbol? If it does,
  57. // then this is a subgroup (branch). If not, then we can insert
  58. // the course as-is.
  59. if (strstr($line, "&")) {
  60. // This line DOES have an ampersand (&), so this is a sub group
  61. // within this group.
  62. $line = trim(str_replace("-", "", $line)); // get rid of attributes, if any.
  63. $line = trim(str_replace("*", "", $line)); // get rid of attributes, if any.
  64. $c_tokes = explode("&",$line);
  65. for ($cT = 0; $cT < count($c_tokes); $cT++)
  66. {
  67. $tokens = explode(" ", trim($c_tokes[$cT]));
  68. $subject_id = trim($tokens[0]);
  69. $course_num = trim($tokens[1]);
  70. // If the subject_id had a _A_ in it, convert this back
  71. // to an ampersand.
  72. $subject_id = str_replace("_A_", "&", $subject_id);
  73. if ($course_id = $db->get_course_id($subject_id, $course_num, "", TRUE, $school_id, TRUE)) {
  74. // Course was found correctly, no need to do anything.
  75. }
  76. else {
  77. // The course_id could not be found!
  78. // Different message if it's a school_id problem.
  79. if (module_enabled("schools")) {
  80. form_error("courses", t("<strong>Your work has NOT been saved.</strong> Course not found. You specified the course %course as a requirement,
  81. but this course could not be found. This could be due to a typo, or due to the course not belonging to the same school
  82. as the group (%schoolname). Please check the course (and possibly change the group's school back first), then try again.", array("%course" => "$subject_id $course_num", "%schoolname" => $school_name)));
  83. }
  84. else {
  85. // Not related to school (possibly).
  86. form_error("courses", t("<strong>Your work has NOT been saved.</strong> Course not found. You specified the course %course as a requirement,
  87. but this course could not be found. This could be due to a typo.
  88. Please check the course and try again.", array("%course" => "$subject_id $course_num")));
  89. }
  90. }
  91. } // for cT (tokens)
  92. } // if line contains &
  93. else {
  94. // Did NOT contain an ampersand (&), so this goes in the
  95. // regular course requirements.
  96. $line = trim(str_replace("-", "", $line)); // get rid of attributes, if any.
  97. $line = trim(str_replace("*", "", $line)); // get rid of attributes, if any.
  98. if ($line == "") continue; // blank line, so skip
  99. $tokens = explode(" ", $line);
  100. $subject_id = @trim($tokens[0]);
  101. $course_num = @trim($tokens[1]);
  102. if ($subject_id == "") continue; // blank line, or mal-formed, so skip.
  103. // If the subject_id had a _A_ in it, convert this back
  104. // to an ampersand.
  105. $subject_id = str_replace("_A_", "&", $subject_id);
  106. // We don't care about catalog year anymore...
  107. if ($course_id = $db->get_course_id($subject_id, $course_num, "", TRUE, $school_id, TRUE)) {
  108. // Course found normally, do nothing.
  109. }
  110. else {
  111. // Different message if it's a school_id problem.
  112. if (module_enabled("schools")) {
  113. form_error("courses", t("<strong>Your work has NOT been saved.</strong> Course not found. You specified the course %course as a requirement,
  114. but this course could not be found. This could be due to a typo, or due to the course not belonging to the same school
  115. as the group (%schoolname). Please check the course (and possibly change the group's school back first), then try again.", array("%course" => "$subject_id $course_num", "%schoolname" => $school_name)));
  116. }
  117. else {
  118. // Not related to school (possibly).
  119. form_error("courses", t("<strong>Your work has NOT been saved.</strong> Course not found. You specified the course %course as a requirement,
  120. but this course could not be found. This could be due to a typo.
  121. Please check the course and try again.", array("%course" => "$subject_id $course_num")));
  122. }
  123. }
  124. } // else (did not contain &)
  125. } // for t (lines of courses)
  126. } // .._validate
  127. function admin_edit_group_form_submit(&$form, &$form_state) {
  128. $values = $form_state["values"];
  129. $de_catalog_year = $values["de_catalog_year"];
  130. $db = get_global_database_handler();
  131. $db2 = new DatabaseHandler();
  132. $group_id = $values["group_id"];
  133. // Okay, we are trying to save the details of this group.
  134. // First thing we need to do is UPDATE the title, group_name,
  135. // priority, icon and comment.
  136. $group_name = trim($values["group_name"]);
  137. $title = trim($values["title"]);
  138. $priority = intval(trim($values["priority"]));
  139. $icon_filename = trim($values["icon_filename"]);
  140. $data_entry_comment = trim($values["data_entry_comment"]);
  141. $catalog_repeat = intval(trim($values["catalog_repeat"]));
  142. $public_note = trim($values["public_note"]);
  143. $school_id = 0;
  144. if (isset($values['schools_school'])) { // A school was set from the schools module.
  145. $school_id = intval($values['schools_school']); // Use our NEW school_id for validating.
  146. }
  147. // Save the entire post to the log.
  148. // Since we are making a change to the draft table(s), let's add a row
  149. // to draft instructions.
  150. $db->add_draft_instruction("-");
  151. // Are we trying to delete this group?
  152. if ($_POST["perform_action2"] == "delete_group" && user_has_permission("can_delete_data_entry")) {
  153. $res = db_query("UPDATE draft_groups
  154. SET delete_flag = '1'
  155. WHERE group_id = '?'
  156. AND catalog_year = '?'
  157. ", $group_id, $de_catalog_year);
  158. fp_add_message(t("The group @title (%name) has been deleted successfully for @year", array("@title" => $title, "%name" => $group_name, "@year" => $de_catalog_year)));
  159. watchdog("admin", "Deleted group: $group_name - $group_id ($de_catalog_year), school_id = $school_id");
  160. fp_goto("admin/groups", "de_catalog_year=$de_catalog_year");
  161. return;
  162. }
  163. // If the $group_id == new then create a new one.
  164. if ($group_id == "new") {
  165. $group_id = $db->request_new_group_id();
  166. $res = db_query("INSERT INTO draft_groups(group_id, catalog_year)
  167. values ('?','?') ", $group_id, $de_catalog_year);
  168. $values["group_id"] = $group_id;
  169. // Let's reset where we should redirect to after the form submits.
  170. $form["#redirect"] = array(
  171. "path" => "admin/groups/edit-group",
  172. "query" => "group_id=$group_id&de_catalog_year=$de_catalog_year",
  173. );
  174. $form_state['values']['group_id'] = $group_id; // set the new group id back into the array, for other modules to use.
  175. }
  176. $res = db_query("UPDATE draft_groups
  177. SET group_name = ?,
  178. title = ?,
  179. priority = ?,
  180. icon_filename = ?,
  181. catalog_repeat = ?,
  182. public_note = ?,
  183. data_entry_comment = ?
  184. WHERE
  185. group_id = ? ",
  186. $group_name, $title, $priority, $icon_filename, $catalog_repeat, $public_note, $data_entry_comment, $group_id);
  187. // We need to delete all the existing course & subgroup requirements from this group.
  188. // That entails first seeing what subgroups were required and deleting them,
  189. // then deleting the parent group's requirements.
  190. // First, find and delete the branches (child groups):
  191. $res = db_query("SELECT * FROM draft_group_requirements
  192. WHERE group_id = '?'
  193. AND child_group_id != '0' ", $group_id);
  194. while ($cur = db_fetch_array($res)) {
  195. $cg_id = $cur["child_group_id"];
  196. $res2 = db_query("DELETE FROM draft_group_requirements
  197. WHERE group_id = '?' ", $cg_id);
  198. }
  199. // Now delete the course requirements...
  200. $res = db_query("DELETE FROM draft_group_requirements
  201. WHERE group_id = '?' ", $group_id);
  202. $courses = trim($values["courses"]);
  203. // If a definition was set, then we will ignore what is in the POST
  204. // for the course requrements, and instead use the definition.
  205. if (trim($values["set_definition"] != "")) {
  206. $def = urldecode(trim($values["set_definition"]));
  207. //$cc = trim(get_courses_from_definition($def, $de_catalog_year));
  208. $temp2 = admin_get_courses_from_definition($def, "", $school_id);
  209. $cc = trim($temp2["text"]);
  210. if ($cc != "") {
  211. $courses = $cc;
  212. // UPDATE this group's definition!
  213. $res = db_query("UPDATE draft_groups
  214. SET definition = '?'
  215. WHERE
  216. group_id = '?' ", $def, $group_id);
  217. }
  218. //print_pre($cc);
  219. }
  220. else {
  221. // In other words, the setDefinition WAS blank.
  222. // Let's update the table. This is to fix a bug where they were unable
  223. // to clear definitions.
  224. $res = db_query("UPDATE draft_groups
  225. SET definition = ''
  226. WHERE
  227. group_id = '?' ", $group_id);
  228. }
  229. // If catalog_repeat == 1, then we need to perform that operation on the $courses text.
  230. if ($catalog_repeat == 1) {
  231. $courses = admin_process_catalog_repeats_for_group_courses_text($courses, $de_catalog_year, $school_id);
  232. }
  233. // Okay, now we look at the actual "courses" box and assemble the group
  234. // in the database.
  235. $lines = explode("\n", $courses);
  236. for ($t = 0; $t < count($lines); $t++) {
  237. $line = trim($lines[$t]);
  238. if ($line == "") { continue; }
  239. // Get rid of extra whitespace.
  240. $line = str_replace(" ", " ", $line);
  241. $line = str_replace(" ", " ", $line);
  242. $line = str_replace(" ", " ", $line);
  243. $line = str_replace(" ", " ", $line);
  244. $line = str_replace(" ", " ", $line);
  245. $line = str_replace(" ", " ", $line);
  246. // Does this line contain at least one & symbol? If it does,
  247. // then this is a subgroup (branch). If not, then we can insert
  248. // the course as-is.
  249. if (strstr($line, "&")) {
  250. // This line DOES have an ampersand (&), so this is a sub group
  251. // within this group.
  252. // First, we need to request a new branchID for this new group.
  253. if (!$branch_id = $db->request_new_group_id()) {
  254. die ("Error. Could not create new group (branch) ID.");
  255. }
  256. else {
  257. // Add this branch to the list of requirements for this group.
  258. $query = "INSERT INTO draft_group_requirements
  259. (group_id, child_group_id)
  260. values ('?','?') ";
  261. $res = db_query($query, $group_id, $branch_id);
  262. }
  263. $attributes = "";
  264. if (substr($line, 0, 1) == "-") $attributes .= "-"; // hidden attribute
  265. if (substr($line, 0, 1) == "*") $attributes .= "*"; // recommended attribute
  266. $line = trim(str_replace("-", "", $line)); // get rid of attributes, if any.
  267. $line = trim(str_replace("*", "", $line)); // get rid of attributes, if any.
  268. $c_tokes = explode("&",$line);
  269. for ($cT = 0; $cT < count($c_tokes); $cT++)
  270. {
  271. $tokens = explode(" ", trim($c_tokes[$cT]));
  272. $subject_id = trim($tokens[0]);
  273. $course_num = trim($tokens[1]);
  274. $min_grade = @trim($tokens[2]);
  275. $course_repeats = @trim($tokens[3]);
  276. if (strstr($min_grade, "[")) {
  277. // This is actually a specified repeat, not a min grade.
  278. $course_repeats = $min_grade;
  279. $min_grade = "";
  280. }
  281. $min_grade = str_replace("(","",$min_grade);
  282. $min_grade = str_replace(")","",$min_grade);
  283. $course_repeats = str_replace("[","",$course_repeats);
  284. $course_repeats = str_replace("]","",$course_repeats);
  285. $course_repeats = intval($course_repeats);
  286. $course_repeats--;
  287. if ($course_repeats < 0) { $course_repeats = 0; }
  288. // If the subject_id had a _A_ in it, convert this back
  289. // to an ampersand.
  290. $subject_id = str_replace("_A_", "&", $subject_id);
  291. if ($course_id = $db->get_course_id($subject_id, $course_num, "", TRUE, $school_id, TRUE)) {
  292. $query = "INSERT INTO draft_group_requirements
  293. (group_id, course_id,
  294. course_min_grade, course_repeats, attributes, data_entry_value)
  295. values (?,?,?,?, ?, ?) ";
  296. $res = db_query($query, $branch_id, $course_id, $min_grade, $course_repeats, $attributes, "$subject_id~$course_num");
  297. }
  298. else {
  299. // The course_id could not be found!
  300. form_error("courses", t("Course Not Found!
  301. You specified the course
  302. <b>%course</b> as a requirement, but this course
  303. could not be found in the catalog.
  304. It was removed from the list of requirements.
  305. Are you sure you typed it correctly? Please check
  306. your spelling, and add the course again.", array("%course" => "$subject_id $course_num")));
  307. }
  308. }
  309. }
  310. else {
  311. // Did NOT contain an ampersand (&), so this goes in the
  312. // regular course requirements.
  313. $attributes = "";
  314. if (substr($line, 0, 1) == "-") $attributes .= "-"; // hidden attribute
  315. if (substr($line, 0, 1) == "*") $attributes .= "*"; // recommended attribute
  316. $line = trim(str_replace("-", "", $line)); // get rid of attributes, if any.
  317. $line = trim(str_replace("*", "", $line)); // get rid of attributes, if any.
  318. $tokens = explode(" ", $line);
  319. $subject_id = @trim($tokens[0]);
  320. $course_num = @trim($tokens[1]);
  321. $min_grade = @trim($tokens[2]);
  322. $course_repeats = @trim($tokens[3]);
  323. if (strstr($min_grade, "[")) {
  324. // This is actually a specified repeat, not a min grade.
  325. $course_repeats = $min_grade;
  326. $min_grade = "";
  327. }
  328. $min_grade = str_replace("(","",$min_grade);
  329. $min_grade = strtoupper(str_replace(")","",$min_grade));
  330. $course_repeats = str_replace("[","",$course_repeats);
  331. $course_repeats = str_replace("]","",$course_repeats);
  332. $course_repeats--;
  333. if ($course_repeats < 0) { $course_repeats = 0; }
  334. // If the subject_id had a _A_ in it, convert this back
  335. // to an ampersand.
  336. $subject_id = str_replace("_A_", "&", $subject_id);
  337. // We don't care about catalog year anymore...
  338. if ($course_id = $db->get_course_id($subject_id, $course_num, "", TRUE, $school_id, TRUE)) {
  339. $query = "INSERT INTO draft_group_requirements
  340. (group_id, course_id,
  341. course_min_grade, course_repeats, attributes, data_entry_value)
  342. values (?,?,?,?,?,?) ";
  343. $res = db_query($query, $group_id, $course_id, $min_grade, $course_repeats, $attributes, "$subject_id~$course_num");
  344. }
  345. else {
  346. // The course_id could not be found!
  347. form_error("courses", t("Course Not Found!
  348. You specified the course
  349. <b>%course</b> as a requirement, but this course
  350. could not be found in the catalog.
  351. It was removed from the list of requirements.
  352. Are you sure you typed it correctly? Please check
  353. your spelling, and add the course again.", array("%course" => "$subject_id $course_num")));
  354. }
  355. }
  356. }
  357. fp_add_message("Group successfully updated.");
  358. watchdog("admin", "Updated group: $group_name - $group_id ($de_catalog_year), school_id = $school_id");
  359. // Clear previous values to make sure the Required Courses box gets updated,
  360. // even if its set to readonly.
  361. clear_session_form_values("admin_edit_group_form");
  362. }
  363. /**
  364. * This function will accept the $courses text (textarea) from a group, which spells out
  365. * all of the courses, and then assign specified repeats based on what is set for that course
  366. * in the course catalog.
  367. */
  368. function admin_process_catalog_repeats_for_group_courses_text($courses, $catalog_year, $school_id = 0) {
  369. $rtn = "";
  370. // Okay, now we look at the actual "courses" box and assemble the group
  371. // in the database.
  372. $lines = explode("\n", $courses);
  373. for ($t = 0; $t < count($lines); $t++) {
  374. $line = trim($lines[$t]);
  375. if ($line == "") { continue; }
  376. // Get rid of extra whitespace.
  377. $line = str_replace(" ", " ", $line);
  378. $line = str_replace(" ", " ", $line);
  379. $line = str_replace(" ", " ", $line);
  380. $new_line = "";
  381. // Does this line contain at least one & symbol? If it does,
  382. // then this is a subgroup (branch), and we need to look at all the courses
  383. // on that branch.
  384. if (strstr($line, "&")) {
  385. // If this branch contains an ampersand, I don't think I should attempt to process it at all.
  386. $new_line = $line;
  387. }
  388. else {
  389. // Did NOT contain an ampersand (&), so this goes in the
  390. // regular course requirements.
  391. $tokens = explode(" ", $line);
  392. $subject_id = @trim($tokens[0]);
  393. $course_num = @trim($tokens[1]);
  394. $min_grade = @trim($tokens[2]);
  395. $course_repeats = @trim($tokens[3]);
  396. if (strstr($min_grade, "[")) {
  397. // This is actually a specified repeat, not a min grade.
  398. $course_repeats = $min_grade;
  399. $min_grade = "";
  400. }
  401. $min_grade = str_replace("(","",$min_grade);
  402. $min_grade = strtoupper(str_replace(")","",$min_grade));
  403. $course_repeats = str_replace("[","",$course_repeats);
  404. $course_repeats = str_replace("]","",$course_repeats);
  405. $course_repeats--;
  406. if ($course_repeats < 0) { $course_repeats = 0; }
  407. // If the subject_id had a _A_ in it, convert this back
  408. // to an ampersand.
  409. $subject_id = str_replace("_A_", "&", $subject_id);
  410. // Okay, we now have a subject_id and course_number. Let's find out how many times
  411. // it can be repeated for credit.
  412. $max_cat_repeats = fp_get_max_catalog_repeats_for_course($subject_id, $course_num, $catalog_year, TRUE, $school_id);
  413. // Okay, now, let's rebuild this line.
  414. $subject_id = str_replace("&", "_A_", $subject_id);
  415. $new_line .= "$subject_id $course_num";
  416. // Was there a min grade?
  417. if ($min_grade != "") {
  418. $new_line .= " ($min_grade)";
  419. }
  420. // Specified repeats?
  421. if ($max_cat_repeats > 0) {
  422. $new_line .= " [$max_cat_repeats]";
  423. }
  424. } // else (does not contain &)
  425. // Add to our $rtn
  426. $rtn .= $new_line . "\n";
  427. } // for lines...
  428. return $rtn;
  429. } // admin_process_catalog_repeats_for_group_courses_text
  430. /**
  431. * This function lets the user edit a group.
  432. */
  433. function admin_edit_group_form() {
  434. $form = array();
  435. $m = 0;
  436. $group_id = $_REQUEST["group_id"];
  437. $db = get_global_database_handler();
  438. $school_id = 0;
  439. if ($group_id != "new") {
  440. $school_id = $db->get_school_id_for_group_id($group_id, TRUE);
  441. }
  442. $de_catalog_year = admin_get_de_catalog_year(TRUE, $school_id);
  443. fp_add_css(fp_get_module_path("admin") . "/css/admin.css");
  444. fp_add_js(fp_get_module_path("admin") . "/js/admin.js");
  445. $form["#redirect"] = array(
  446. "path" => "admin/groups/edit-group",
  447. "query" => "group_id=$group_id&de_catalog_year=$de_catalog_year",
  448. );
  449. if (user_has_permission("can_view_advanced")) {
  450. $form["mark" . $m++] = array(
  451. "type" => "markup",
  452. "value" => " <span class='tenpt' style='background-color: yellow; margin-left: 20px;'>
  453. adv: group_id = $group_id.
  454. Used by:
  455. <a href='javascript: adminPopupWindow(\"" . fp_url("admin/groups/popup-show-group-use", "group_id=$group_id") . "\");'>[degrees]</a>
  456. </span>",
  457. "weight" => 0,
  458. );
  459. }
  460. $group = new Group($group_id, null, -1, false, true);
  461. //print_pre($group->to_string());
  462. $group->load_descriptive_data();
  463. fp_set_title(t("Edit Group:") . " $group->title ($de_catalog_year)");
  464. $form["perform_action2"] = array(
  465. "type" => "hidden",
  466. "value" => "",
  467. );
  468. $form["set_definition"] = array(
  469. "type" => "hidden",
  470. "value" => urlencode($group->definition),
  471. );
  472. $form["scroll_top"] = array(
  473. "type" => "hidden",
  474. "value" => "",
  475. );
  476. $form["group_id"] = array(
  477. "type" => "hidden",
  478. "value" => $group_id,
  479. );
  480. $form["de_catalog_year"] = array(
  481. "type" => "hidden",
  482. "value" => $de_catalog_year,
  483. );
  484. // Actually draw the form out.
  485. $form["title"] = array(
  486. "type" => "textfield",
  487. "label" => t("Group title:"),
  488. "value" => $group->title,
  489. "maxlength" => 100,
  490. "required" => TRUE,
  491. "popup_description" => t("This is what FlightPath uses to refer to this group in screens and popups.
  492. Ex: Free Electives, Art Electives, Core Humanities, etc."),
  493. "weight" => 10,
  494. );
  495. $form["group_name"] = array(
  496. "type" => "textfield",
  497. "label" => t("Internal group machine name:"),
  498. "value" => $group->group_name,
  499. "maxlength" => 100,
  500. "required" => TRUE,
  501. "popup_description" => t("The group's <b>internal machine name</b> is internal to FlightPath, and is never seen by the average user.
  502. <br>
  503. You may use this to distinguish between groups with the same title.
  504. <br>Ex: <i>major_electives_sr</i> and <i>major_electives_jr</i>.
  505. <br>The field must be unique within each catalog year, and
  506. consist of only letters, numbers, and underscores. FlightPath will make
  507. sure it is unique when you save, and give you a chance to change it if it
  508. is not."),
  509. "weight" => 20,
  510. );
  511. $form["priority"] = array(
  512. "type" => "textfield",
  513. "label" => t("Priority:"),
  514. "value" => $group->priority,
  515. "maxlength" => 10,
  516. "size" => 10,
  517. "popup_description" => t("This should be a number, and it is very important, because it determines the
  518. order in which courses are assigned to groups in FlightPath.
  519. Higher numbers fill in FIRST! So a group with a priority of 100 would fill in before
  520. a group with a priority of 30."),
  521. "weight" => 30,
  522. );
  523. if (!$group->icon_filename) {
  524. $group->icon_filename = "major.gif"; // set a default if none is specified!
  525. }
  526. $form["icon_filename"] = array(
  527. "type" => "hidden",
  528. "value" => $group->icon_filename,
  529. "weight" => 40,
  530. );
  531. $form['icon_filename_markup'] = array(
  532. "label" => t("Icon:"),
  533. "value" => "<img src='" . fp_theme_location() . "/images/icons/$group->icon_filename' width='19'>
  534. $group->icon_filename
  535. &nbsp; &nbsp;
  536. <a href='javascript: adminPopupWindow(\"" . fp_url("admin/groups/popup-select-icon", "group_id=$group_id") . "\");'>[select another]</a>
  537. ",
  538. "weight" => 41,
  539. );
  540. $form["definition"] = array(
  541. "type" => "markup",
  542. "label" => t("Definition:"),
  543. "value" => "<i>" . nl2br($group->definition) . "</i>",
  544. "prefix" => "<div style='overflow: auto; max-height: 150px;' class='admin-groups-show-definition'>",
  545. "suffix" => "</div><a href='javascript: adminPopupWindow(\"" . fp_url("admin/groups/popup-edit-definition", "de_catalog_year=$de_catalog_year&group_id=$group_id") . "\");'
  546. >[" . t("edit definition") . "]</a>",
  547. "weight" => 50,
  548. );
  549. $form["mark" . $m++] = array(
  550. "type" => "markup",
  551. "value" => "<hr>",
  552. "weight" => 60,
  553. );
  554. $courses = admin_get_group_courses($group);
  555. $form["courses"] = array(
  556. "type" => "textarea",
  557. "label" => t("Required Courses:"),
  558. "rows" => 17,
  559. "cols" => 80,
  560. "value" => $courses,
  561. "weight" => 70,
  562. "popup_description" => t("Note: You may specify <i>hidden</i> courses by placing a - (minus sign) before the course name.
  563. <br> Ex: - ART 101
  564. <br> This will cause ART 101 not to show to the user as a choice, but FlightPath will still automatically fill in ART 101
  565. into this group, if the student completes it.
  566. <br><br>
  567. You may also <i>recommend</i> a course by place a * (asterisk) before the course name.
  568. <br> Ex: * ART 101
  569. <br>This will cause <b>ART 101</b> to appear as bold to the user when viewing the list of courses in this group.
  570. <br><br>
  571. Courses which may be repeated can be specified by placing the number of acceptible repeats in brackets after
  572. the course.
  573. <br>Ex: ART 101 [2]
  574. <br>This means that ART 101 may be repeated up to two times for this group. If using this feature, make sure
  575. that repeats are permissible for this course."),
  576. );
  577. // if a definition was specified, we need to disable the courses textarea.
  578. if (trim($group->definition)) {
  579. $form["courses"]["attributes"] = array("readonly"=>"readonly", "style" => "background-color: #ddd;'" );
  580. $form["courses"]["prefix"] = "<div class='admin-groups-courses-disabled'>
  581. " . t("Note: Because a definition was specified, you cannot directly
  582. edit the Required Courses. Manage these courses using the
  583. Edit Definition popup window.") . "</div>";
  584. }
  585. $form["catalog_repeat"] = array(
  586. "type" => "checkbox",
  587. "label" => t("Set Catalog Repeats"),
  588. "value" => $group->db_catalog_repeat,
  589. "popup_description" => t("If checked, this group will automatically assign specified repeats to courses
  590. which are determined to be repeatable for this catalog year.
  591. For example, if you enter
  592. ART 101, and in the course catalog that course may be taken two times, then
  593. when you save this group the line will be changed to ART 101 [2].
  594. This will work with definitions, but will not work in groups with branches.
  595. If you are unsure what to select, leave this box unchecked."),
  596. "weight" => 80,
  597. );
  598. $form["submit"] = array(
  599. "type" => "submit",
  600. "value" => "Submit",
  601. "prefix" => "<hr>",
  602. "weight" => 100,
  603. );
  604. // Advanced options
  605. $elements = array();
  606. $bool_start_closed = TRUE;
  607. if (@trim($group->public_note) != "" || trim($group->data_entry_comment) != "") {
  608. $bool_start_closed = FALSE;
  609. }
  610. $elements['public_note'] = array(
  611. 'type' => 'textarea',
  612. 'label' => t('Public Note'),
  613. 'rows' => 4,
  614. 'value' => @$group->public_note,
  615. 'description' => t("You may enter simple HTML in this field. Ex: &lt;b&gt;bold&lt;/b&gt; or &lt;i&gt;italics&lt;/i&gt;"),
  616. 'popup_description' => t("A public note will appear at the top of the group when displayed in the dialog popup in FlightPath."),
  617. "weight" => 50010,
  618. );
  619. $elements["data_entry_comment"] = array(
  620. "type" => "textarea",
  621. "label" => t("Optional Admin Comment: (only seen by other FlightPath administrators)"),
  622. "rows" => 3,
  623. "cols" => 80,
  624. "value" => $group->data_entry_comment,
  625. "weight" => 90,
  626. );
  627. // Place in our advanced options fs.
  628. $form['advanced_options_fs'] = array(
  629. 'type' => 'cfieldset',
  630. 'label' => t('View advanced options'),
  631. 'elements' => array($elements),
  632. 'start_closed' => $bool_start_closed,
  633. "weight" => 50100,
  634. );
  635. // Only show delete option based on permission
  636. if (user_has_permission("can_delete_data_entry")) {
  637. $form["mark" . $m++] = array(
  638. "type" => "markup",
  639. "value" => "<div align='right' class='groups-delete-group-wrapper'>
  640. " . t("Delete this group?") . " <input type='button' value='X'
  641. onClick='adminDeleteGroup(\"$group_id\");'>
  642. </div>",
  643. "weight" => 600000,
  644. );
  645. }
  646. return $form;
  647. }
  648. function admin_display_groups_popup_edit_definition() {
  649. $rtn = $tdef = "";
  650. fp_add_css(fp_get_module_path("admin") . "/css/admin.css");
  651. fp_add_js(fp_get_module_path("admin") . "/js/admin.js");
  652. $group_id = trim($_REQUEST["group_id"]);
  653. $group = new Group($group_id, null, -1, false, true);
  654. $group->load_descriptive_data();
  655. $school_id = intval($group->school_id);
  656. $de_catalog_year = admin_get_de_catalog_year(TRUE, $school_id);
  657. $school_name = "";
  658. if ($school_id > 0) $school_name = " School-" . $school_id;
  659. if (module_enabled("schools")) {
  660. $defs = schools_get_school_definitions();
  661. if (isset($defs[$school_id])) $school_name = $defs[$school_id];
  662. }
  663. if (isset($_REQUEST["definition"])) {
  664. $definition = trim($_REQUEST["definition"]);
  665. }
  666. else {
  667. $definition = $group->definition;
  668. }
  669. $results = admin_get_courses_from_definition($definition, "", $school_id);
  670. // This text will be used to describe how the definition works in a javascript alert box:
  671. $tdef .= t("Definitions provide a very quick way to add or remove many courses from a group.") . "<br><br>
  672. " . t("To view a complete set of instructions, <a href='https://getflightpath.com/node/11941' target='_balnk'>visit the documentation page by clicking here</a>.");
  673. $rtn .= "" . t("Edit Definition for %group (%cat)
  674. - @name", array("%group" => $group->title, "%cat" => $de_catalog_year, "@name" => $group->title));
  675. if ($school_name) {
  676. $rtn .= "<br><br>" . t("<strong>Note:</strong> This will only search for courses in the same school as the group <em>since its last save</em>.
  677. <br><strong>Searching in school: %schoolname", array("%schoolname" => $school_name)) . "</strong>";
  678. }
  679. $rtn .= "
  680. <br><br><form action='" . fp_url("admin/groups/popup-edit-definition", "de_catalog_year=$de_catalog_year&group_id=$group_id") . "' method='POST' id='mainform'>
  681. <table border='0' width='100%'>
  682. <tr>
  683. <td valign='top' align='right' width='45%'>
  684. <div class='tenpt' align='left'>" . t("Working Definition:") . "
  685. " . fp_get_js_alert_link($tdef, "<span class='pop-q-mark'><i class='fa fa-question-circle'></i></span>") . "</div>
  686. <textarea name='definition' id='definition' rows='10' style='min-width:100%; resize: none;' >$definition</textarea>
  687. <br>
  688. <input type='button' value='" . t("Generate ->") . "'
  689. onClick='showUpdate(); document.getElementById(\"mainform\").submit();'>
  690. <input type='hidden' name='school_id' value='$school_id'>
  691. </td>
  692. <td valign='top' align='right' class='tenpt' width='55%'>
  693. <div class='tenpt' align='left'>Results:" . " (" . $results["count"] . ")</div>
  694. <textarea rows='10' style='min-width:100%; resize: none;' readonly=readonly class='readonly'>{$results["text"]}</textarea>
  695. <br>";
  696. if ($school_name) {
  697. $rtn .= "<div>" . t("loads courses from all cat years in school %schoolname", array("%schoolname" => $school_name)) . "</div>";
  698. }
  699. else {
  700. $rtn .= "<div>" . t("loads courses from all cat years") . "</div>";
  701. }
  702. $rtn .= "
  703. </td>
  704. </tr>
  705. </table>
  706. </form>
  707. " . t("If you are satisfied with the results of this definition,
  708. click the Save to Group button. To cancel, simply close this window.") . "
  709. <br>
  710. <input type='button' value='" . t("Save to Group") . "' onClick='adminPopupSaveDefinition(\"\");'>
  711. ";
  712. // Give a little padding.
  713. return "<body style='padding:5px;'>$rtn</body>";
  714. }
  715. function admin_get_course_array_from_course_id_array($course_idArray) {
  716. // Convert an array of course_id's into their subject_id ~~ course_num format.
  717. // Pick non-excluded courses over excluded courses, when you have the option.
  718. $rtn_array = array();
  719. $db = new DatabaseHandler();
  720. // MUST use foreach since we used array_unique earlier. Can't use
  721. // count($arr) after you use array_unique!!
  722. foreach($course_idArray as $t => $value) {
  723. $new_course = new Course();
  724. $new_course->bool_use_draft = true;
  725. $new_course->db = $db;
  726. $new_course->course_id = $course_idArray[$t];
  727. $new_course->load_descriptive_data(false);
  728. array_push($rtn_array, "$new_course->subject_id ~~ $new_course->course_num");
  729. }
  730. return $rtn_array;
  731. }
  732. function admin_get_courses_from_definition($definition, $catalog_year = "", $school_id = 0) {
  733. $group_array = array();
  734. // Okay, first things first, let's trim this sucker and remove extra whitespace.
  735. $definition = trim($definition);
  736. $definition = str_replace(" "," ",$definition);
  737. $definition = str_replace(" "," ",$definition);
  738. $definition = str_replace(" "," ",$definition);
  739. // Okay, now let's break this up into lines...
  740. $d_lines = explode("\n",$definition);
  741. foreach($d_lines as $line)
  742. {
  743. $line = trim($line);
  744. if ($line == "") continue; // blank line
  745. // Let's get each of the parts... the instruction, and the course data.
  746. $tokens = explode(" ", $line);
  747. $instruction = strtolower(trim($tokens[0]));
  748. @$course_data = trim($tokens[1]);
  749. // We know that the course data can also be broken up, by the .
  750. $c_tokens = explode(".", $course_data);
  751. $subject_data = trim(strtoupper($c_tokens[0]));
  752. @$course_numData = trim(strtoupper($c_tokens[1]));
  753. if ($subject_data == "") continue; // blank or mal-formed?
  754. // Okay, so now, for this line, we have an instruction,
  755. // and some course data (possibly wild cards) to act on.
  756. //debugCT("$instruction $subject_data $course_numData");
  757. $t_array = admin_get_course_array_from_definition_data($subject_data, $course_numData, $catalog_year, $school_id, TRUE);
  758. // Okay, we got our list. Now what do we do with them?
  759. if ($instruction == "add" || $instruction == "+")
  760. {
  761. $group_array = array_merge($group_array, $t_array);
  762. $group_array = array_unique($group_array);
  763. }
  764. if ($instruction == "remove" || $instruction == "rem" || $instruction == "-" || $instruction == "del")
  765. {
  766. //print "<pre>" . print_r($t_array) . "</pre>";
  767. //debug_c_t(count($group_array));
  768. //$group_array = array_diff($group_array, $t_array);
  769. $group_array = admin_array_diff($group_array, $t_array);
  770. $group_array = array_unique($group_array);
  771. //debug_c_t(count($group_array));
  772. }
  773. }
  774. // Here's what we need to do:
  775. // In groupArray, we have the subject_id and course_num of every course in this definition.
  776. // We need to convert them to course_id's from the table,
  777. // and make sure we do not have duplicates.
  778. // First, get an array of course_id from the groupArray...
  779. $course_idArray = $group_array;
  780. // Take out duplicate entries (caused by eqv courses)...
  781. $course_idArray = array_unique($course_idArray);
  782. // Now, convert BACK into the "groupArray" structure (subject_id and course_num)...
  783. $group_array2 = admin_get_course_array_from_course_id_array($course_idArray);
  784. //print_r($group_array);
  785. // Place in alphabetical order.
  786. sort($group_array2);
  787. //var_dump($group_array2);
  788. $rtn = array();
  789. $rtn["text"] = "";
  790. $count = 1;
  791. // Now that we have the groupArray, we will turn it into a string...
  792. for ($t = 0; $t < count($group_array2); $t++)
  793. {
  794. $line = trim($group_array2[$t]);
  795. if ($line == "~~" || $line == "") continue;
  796. $count++;
  797. $temp = explode(" ~~ ", $line);
  798. $si = trim($temp[0]);
  799. $cn = trim($temp[1]);
  800. @$rtn["text"] .= "$si $cn\n";
  801. }
  802. $rtn["text"] = str_replace("&", "_A_", $rtn["text"]);
  803. //debug_c_t(count($group_array));
  804. $rtn["count"] = $count;
  805. return $rtn;
  806. }
  807. function admin_get_course_array_from_definition_data($subject_data, $course_numData, $catalog_year = "", $school_id = 0, $bool_check_allow_default_school = FALSE) {
  808. // Looks at the subjectData and course_numData fields, and constructs
  809. // a query to pull our every course which matches it.
  810. $rtn_array = array();
  811. $si = str_replace("*","%",$subject_data);
  812. $cn = str_replace("*","%",$course_numData);
  813. $params = array();
  814. $catalog_line = "";
  815. if ($catalog_year != "") {
  816. $catalog_line = "AND catalog_year = :catalog_year";
  817. $params[":catalog_year"] = $catalog_year;
  818. }
  819. $school_line = " AND school_id = :school_id ";
  820. // Should we ALSO check the default school, in addition to whatever we specified? Don't bother if what we specified was the default school.
  821. if ($bool_check_allow_default_school && module_enabled('schools') && variable_get('schools_allow_courses_from_default_school', 'yes') === 'yes' && $school_id != 0) {
  822. $school_line = " AND (school_id = :school_id OR school_id = 0) ";
  823. }
  824. $params[':subject_id'] = $si;
  825. $params[':course_num'] = $cn;
  826. $params[':school_id'] = $school_id;
  827. $query = "SELECT * FROM draft_courses
  828. WHERE subject_id LIKE :subject_id
  829. AND course_num LIKE :course_num
  830. AND course_id > 0
  831. $school_line
  832. $catalog_line
  833. GROUP BY subject_id, course_num
  834. ";
  835. $res = db_query($query, $params) ;
  836. while ($cur = db_fetch_array($res)) {
  837. $course_id = $cur["course_id"];
  838. if (in_array($course_id, $rtn_array)) continue;
  839. $rtn_array[] = $course_id;
  840. }
  841. return $rtn_array;
  842. }
  843. /**
  844. * I had to create my own version of array_diff, because the built-in PHP
  845. * version has a nasty bug where it doesn't work after a certain number of elements.
  846. */
  847. function admin_array_diff($array1, $array2) {
  848. // Return an array of values from array1 that
  849. // are NOT in array2.
  850. // This is my (Richard Peacock) own implementation of array_diff,
  851. // because something is broken with it, so I am programming
  852. // my own.
  853. $rtn = array();
  854. //for ($t = 0; $t < count($array1); $t++)
  855. // MUST use foreach instead of for(count($arr))
  856. // because I did array_unique on it!
  857. foreach($array1 as $t => $value)
  858. {
  859. if (in_array($array1[$t], $array2))
  860. {
  861. continue;
  862. } else {
  863. $rtn[] = $array1[$t];
  864. }
  865. }
  866. return $rtn;
  867. }
  868. /**
  869. * This popup is called from the edit group page. It lets the user
  870. * select an icon to assign to a group.
  871. */
  872. function admin_display_groups_popup_select_icon() {
  873. $rtn = "";
  874. fp_add_css(fp_get_module_path("admin") . "/css/admin.css");
  875. fp_add_js(fp_get_module_path("admin") . "/js/admin.js");
  876. $group_id = $_REQUEST["group_id"];
  877. $group = new Group();
  878. $group->group_id = $group_id;
  879. $group->bool_use_draft = true;
  880. $group->load_descriptive_data();
  881. $rtn = "<b>Please Select an Icon to use for $group->title (<i>$group->group_name</i>):</b>
  882. <div class='tenpt'>Current icon: <img src='" . fp_theme_location() . "/images/icons/$group->icon_filename' width='19'>
  883. $group->icon_filename.
  884. <br><br>
  885. Available Icons:
  886. <blockquote>";
  887. $handle = opendir(fp_theme_location(FALSE) . "/images/icons/.");
  888. $files = array();
  889. $accepted_exts = array("jpg", "gif", "png", "bmp", "JPG", "GIF", "PNG", "BMP", "jpeg");
  890. while($file = readdir($handle)) {
  891. if ($file != "." && $file != "..") {
  892. // Make sure it's extension is an image file.
  893. // Find out it's ext first.
  894. $temp = explode(".", $file);
  895. $ext = $temp[count($temp) - 1];
  896. if (in_array($ext, $accepted_exts)) {
  897. $files[] = $file;
  898. }
  899. }
  900. }
  901. // make sure they are alphabetized.
  902. sort($files);
  903. foreach($files as $file) {
  904. $rtn .= "<div style='padding: 5px;'>
  905. <input type='button' value='Select -> ' onClick='adminPopupSelectIcon(\"$file\");' >
  906. &nbsp; &nbsp;
  907. <img src='" . fp_theme_location() . "/images/icons/$file' width='19'>
  908. $file</div>";
  909. }
  910. $rtn .= "</blockquote></div>";
  911. return $rtn;
  912. }
  913. /**
  914. * Return back the courses in a group, suitable for the edit-group form.
  915. */
  916. function admin_get_group_courses(Group $group) {
  917. // Returns a plain text list of the courses in a group's requirements
  918. // for use in the edit_group_form.
  919. $rtn = "";
  920. $group_sort_policy = variable_get_for_school("group_requirement_sort_policy", "alpha", $group->school_id);
  921. // courses not in branches...
  922. $courses = array();
  923. $c_count = 0;
  924. $group->list_courses->load_course_descriptive_data();
  925. if ($group_sort_policy == 'database') {
  926. $group->list_courses->sort_group_requirement_id();
  927. }
  928. else {
  929. // By default, sort alphabetical
  930. $group->list_courses->sort_alphabetical_order();
  931. }
  932. $group->list_courses->reset_counter();
  933. while($group->list_courses->has_more())
  934. {
  935. $course_line = "";
  936. $attributes = "";
  937. $c = $group->list_courses->get_next();
  938. if (strstr($c->subject_id , "&"))
  939. {
  940. $c->subject_id = str_replace("&", "_A_", $c->subject_id);
  941. }
  942. if ($c->db_group_attributes != "") {
  943. $attributes = $c->db_group_attributes . " ";
  944. }
  945. $course_line .= trim("$attributes$c->subject_id $c->course_num");
  946. if (!$course_line) {
  947. // Some kind of problem, just skip this because it's blank.
  948. continue;
  949. }
  950. if ($c->min_grade != "" && $c->min_grade != "D")
  951. {
  952. //$rtn .= " ($c->min_grade)";
  953. $course_line .= " ($c->min_grade)";
  954. }
  955. //$rtn .= "\n";
  956. if (!isset($courses[$course_line]))
  957. {
  958. $courses[$course_line] = 0;
  959. }
  960. // This is to check for specified repeats.
  961. $courses[$course_line]++;
  962. }
  963. // Go through the $courses array to check for specified repeats.
  964. foreach($courses as $course => $rep_count)
  965. {
  966. $rep_line = " [$rep_count]";
  967. if ($rep_count == 1)
  968. {
  969. $rep_line = "";
  970. }
  971. $rtn .= "$course$rep_line\n";
  972. }
  973. // Now, get them branches!
  974. if (!$group->list_groups->is_empty)
  975. {
  976. $group->list_groups->reset_counter();
  977. while ($group->list_groups->has_more())
  978. {
  979. $courses = array();
  980. $g = $group->list_groups->get_next();
  981. $g->list_courses->load_course_descriptive_data();
  982. $g->list_courses->sort_alphabetical_order();
  983. $g->list_courses->reset_counter();
  984. while($g->list_courses->has_more())
  985. {
  986. $course_line = $attributes = "";
  987. $c = $g->list_courses->get_next();
  988. if (strstr($c->subject_id , "&"))
  989. {
  990. $c->subject_id = str_replace("&", "_A_", $c->subject_id);
  991. }
  992. if ($c->db_group_attributes != "") {
  993. $attributes = $c->db_group_attributes . " ";
  994. }
  995. $course_line = trim("$attributes$c->subject_id $c->course_num");
  996. if (!$course_line) {
  997. // Some kind of problem, just skip this because it's blank.
  998. continue;
  999. }
  1000. if ($c->min_grade != "" && $c->min_grade != "D")
  1001. {
  1002. $course_line .= " ($c->min_grade)";
  1003. }
  1004. if (!isset($courses[$course_line]))
  1005. {
  1006. $courses[$course_line] = 0;
  1007. }
  1008. // This is to check for specified repeats.
  1009. $courses[$course_line]++;
  1010. }
  1011. // Go through the $courses array to check for specified repeats.
  1012. foreach($courses as $course => $rep_count)
  1013. {
  1014. $rep_line = " [$rep_count]";
  1015. if ($rep_count == 1)
  1016. {
  1017. $rep_line = "";
  1018. }
  1019. $rtn .= "$course$rep_line & ";
  1020. }
  1021. // Take off the last &.
  1022. $rtn = trim($rtn);
  1023. $rtn = substr($rtn,0,-1);
  1024. $rtn = trim($rtn);
  1025. $rtn .= "\n";
  1026. }
  1027. }
  1028. return $rtn;
  1029. }
  1030. /**
  1031. * This function will display a list of all our groups.
  1032. */
  1033. function admin_display_groups() {
  1034. $rtn = "";
  1035. // Do this using $render array, so it can be altered
  1036. // by hook_content_alter
  1037. $render = array();
  1038. $render['#id'] = 'admin_display_groups';
  1039. $de_catalog_year = admin_get_de_catalog_year();
  1040. fp_add_css(fp_get_module_path("admin") . "/css/admin.css");
  1041. fp_add_js(fp_get_module_path("admin") . "/js/admin.js");
  1042. $db2 = new DatabaseHandler();
  1043. fp_set_title(t("Edit Groups for @de_catalog_year", array("@de_catalog_year" => $de_catalog_year)));
  1044. $render['upper_links'] = array(
  1045. 'value' => " Options:
  1046. <ul style='margin-top: 5px;'>
  1047. <li>" . l(t("Add a new group to this year"), "admin/groups/edit-group", "de_catalog_year=$de_catalog_year&group_id=new") . "</li>
  1048. <li>" . l(t("Process all group definitions & catalog repeats for this year"), "admin/groups/process-all-definitions", "de_catalog_year=$de_catalog_year") . "</li>
  1049. </li>
  1050. </ul>
  1051. <div align='center'>" . t("Hint: use CTRL-F to search groups quickly") . "</div>
  1052. ",
  1053. );
  1054. $html = "";
  1055. $html .= "<div class='degrees-filter'>";
  1056. $html .= fp_render_form("admin_groups_list_filter_form");
  1057. $html .= "</div>";
  1058. $render['degrees_filter'] = array(
  1059. 'value' => $html,
  1060. );
  1061. $render['groups_table_top'] = array(
  1062. 'value' => "<table border='0' cellpadding='5' cellspacing='5' width='100%' class='admin-groups-list'>
  1063. <tr>
  1064. <th>" . t("Title") . "</th>
  1065. <th>" . t("Internal Name") . "</th>
  1066. <th align='center'>Pri</th>
  1067. <th align='center'>i</th>
  1068. <th align='center'>" . t("Used") . "</th>
  1069. </tr>",
  1070. );
  1071. $on_mouse_over = " onmouseover=\"style.backgroundColor='#FFFF99'\"
  1072. onmouseout=\"style.backgroundColor='white'\" ";
  1073. $params = array();
  1074. $params[":catalog_year"] = $de_catalog_year;
  1075. $filter_name_value = @trim($_SESSION['groups_filter_name']);
  1076. $filter_school_value = @intval($_SESSION['groups_filter_school']);
  1077. $extra_where_conditions = "";
  1078. // Let's adjust the query based on filter selections (if any exist)
  1079. if ($filter_name_value) {
  1080. $extra_where_conditions .= " AND (group_name LIKE :name1 OR title LIKE :name2) ";
  1081. $params[":name1"] = "%$filter_name_value%";
  1082. $params[":name2"] = "%$filter_name_value%";
  1083. }
  1084. if (module_enabled('schools')) {
  1085. if ($filter_school_value) {
  1086. $extra_where_conditions .= " AND school_id = :school_id ";
  1087. $params[":school_id"] = $filter_school_value;
  1088. }
  1089. }
  1090. else {
  1091. // schools not enabled, so only search for school = 0
  1092. $extra_where_conditions .= " AND school_id = 0 ";
  1093. }
  1094. watchdog("admin", "Viewed admin groups list. Name filter: $filter_name_value. ($de_catalog_year), school_id: $filter_school_value", array(), WATCHDOG_DEBUG);
  1095. $res = db_query("SELECT * FROM draft_groups
  1096. WHERE catalog_year = :catalog_year
  1097. AND delete_flag = 0
  1098. $extra_where_conditions
  1099. ORDER BY title, group_name ", $params);
  1100. while($cur = db_fetch_array($res)) {
  1101. extract($cur, 3, "db");
  1102. $use_count = 0;
  1103. // Find out how many degree plans are using this particular group...
  1104. $res2 = db_query("SELECT count(id) AS count FROM draft_degree_requirements
  1105. WHERE group_id = '?' ", $db_group_id);
  1106. if (db_num_rows($res2) > 0) {
  1107. $cur2 = db_fetch_array($res2);
  1108. $use_count = $cur2["count"];
  1109. }
  1110. $def_flag = "";
  1111. if (trim($db_definition) != "") {
  1112. $def_flag = " (*)";
  1113. }
  1114. if ($db_title == "") {
  1115. $db_title = "[" . t("NO TITLE SPECIFIED") . "]";
  1116. }
  1117. $render['group_row_' . $db_group_id] = array(
  1118. 'value' => "<tr $on_mouse_over>
  1119. <td valign='top' ><a name='group_$db_group_id'></a>
  1120. " . l($db_title, "admin/groups/edit-group", "group_id=$db_group_id&de_catalog_year=$de_catalog_year") . "
  1121. </td>
  1122. <td valign='top' >
  1123. <i>$db_group_name</i>$def_flag
  1124. </td>
  1125. <td valign='top' >
  1126. $db_priority
  1127. </td>
  1128. <td valign='top' >
  1129. <img src='" . fp_theme_location() . "/images/icons/$db_icon_filename' width='19'>
  1130. </td>
  1131. <td valign='top' >
  1132. $use_count <a href='javascript: adminPopupWindow(\"" . fp_url("admin/groups/popup-show-group-use", "group_id=$db_group_id") . "\");'><i class='fa fa-window-restore'></i></a>
  1133. </td>
  1134. </tr>
  1135. ",
  1136. 'data' => array(
  1137. 'group_id' => $db_group_id,
  1138. 'db_row' => $cur,
  1139. 'use_count' => $use_count,
  1140. 'def_flag' => $def_flag,
  1141. ),
  1142. );
  1143. }
  1144. $render['groups_table_bottom'] = array(
  1145. 'value' => "</table>",
  1146. );
  1147. $rtn .= fp_render_content($render);
  1148. return $rtn;
  1149. }
  1150. function admin_groups_list_filter_form() {
  1151. $form = array();
  1152. $form['mark_top'] = array(
  1153. 'type' => 'markup',
  1154. 'value' => "<strong>" . t('Filter by...') . "</strong>",
  1155. 'weight' => 0,
  1156. );
  1157. $filter_name_value = trim($_SESSION['groups_filter_name']);
  1158. $form['filter_name'] = array(
  1159. 'type' => 'textfield',
  1160. 'label' => '',
  1161. 'value' => $filter_name_value,
  1162. 'attributes' => array("placeholder" => t("Enter any title or name")),
  1163. 'size' => 20,
  1164. 'weight' => 10,
  1165. );
  1166. // If we have enabled the schools module, then have a selector for that as well
  1167. if (module_enabled('schools')) {
  1168. $filter_school_value = @intval($_SESSION['groups_filter_school']);
  1169. $options = schools_get_schools_for_fapi(TRUE, TRUE, 'group', TRUE);
  1170. $options[0] = t('- All / Default -');
  1171. $form['filter_school'] = array(
  1172. 'type' => 'select',
  1173. 'label' => t('School:'),
  1174. 'options' => $options,
  1175. 'value' => $filter_school_value,
  1176. 'weight' => 20,
  1177. 'hide_please_select' => TRUE,
  1178. );
  1179. } // if schools enabled
  1180. $form['submit_btn'] = array(
  1181. 'type' => 'submit',
  1182. 'value' => t('Apply'),
  1183. 'weight' => 100,
  1184. );
  1185. $form['reset_btn'] = array(
  1186. 'type' => 'submit',
  1187. 'value' => t('Reset'),
  1188. 'weight' => 110,
  1189. );
  1190. return $form;
  1191. }
  1192. function admin_groups_list_filter_form_submit($form, $form_state) {
  1193. $values = $form_state['values'];
  1194. unset($_SESSION['groups_filter_name']);
  1195. unset($_SESSION['groups_filter_school']);
  1196. if ($values['submit_btn'] != '') {
  1197. $_SESSION['groups_filter_name'] = trim($values['filter_name']);
  1198. $_SESSION['groups_filter_school'] = $values['filter_school'];
  1199. }
  1200. }
  1201. function admin_process_all_definitions_form() {
  1202. $form = array();
  1203. $de_catalog_year = admin_get_de_catalog_year();
  1204. fp_set_title(t("Process all group definitions and settings for @year", array("@year" => $de_catalog_year)));
  1205. $m = 0;
  1206. $form["mark" . $m++] = array(
  1207. "type" => "markup",
  1208. "value" => t("This will cause all of the groups with definitions and other settings (ex: catalog repeats) to be cleared, and their
  1209. course requirements re-processed. This function can take several minutes, depending
  1210. on how many groups with definitions you have."),
  1211. );
  1212. $form["de_catalog_year"] = array(
  1213. "type" => "hidden",
  1214. "value" => $de_catalog_year,
  1215. );
  1216. $form["submit"] = array(
  1217. "type" => "submit",
  1218. "spinner" => TRUE,
  1219. "value" => t("Process groups"),
  1220. "description" => t("Can take several minutes to run. Do not navigate away from this tab or close the browser."),
  1221. );
  1222. return $form;
  1223. }
  1224. /**
  1225. * Actually perform the refreshing of definitions.
  1226. */
  1227. function admin_process_all_definitions_form_submit($form, $form_submit) {
  1228. $values = $form_submit["values"];
  1229. $db = get_global_database_handler();
  1230. $de_catalog_year = $values["de_catalog_year"];
  1231. watchdog("admin", "Processed group definitions for: $de_catalog_year");
  1232. // Okay, set up the batch....
  1233. $batch = array(
  1234. "operation" => array("admin_process_all_definitions_perform_batch_operation", array($de_catalog_year)),
  1235. "title" => t("Process all group definitions & settings for %year", array("%year" => $de_catalog_year)),
  1236. "file" => menu_get_module_path("admin") . "/admin.groups.inc",
  1237. "progress_message" => "Processing group @current of @total",
  1238. "display_percent" => TRUE,
  1239. );
  1240. // Set the batch...
  1241. batch_set($batch);
  1242. }
  1243. /**
  1244. * This actually is the batch operation for processing all of our group definitions.
  1245. */
  1246. function admin_process_all_definitions_perform_batch_operation(&$batch, $de_catalog_year) {
  1247. //////////////////////////// FIRST TIME ///////////////////////////////
  1248. // If this is our first time through, let's init our values.
  1249. if (!isset($batch["results"]["total"])) {
  1250. // Our first time through. Let's start up.
  1251. $batch["results"]["current"] = 0;
  1252. $batch["results"]["finished"] = FALSE;
  1253. // Change to count how many groups with definitions OR "catalog_repeat" set.
  1254. // We need a count of how many groups in this year have definitions to process.
  1255. $res = db_query("SELECT count(*) as `count` FROM draft_groups
  1256. WHERE (definition != '' OR catalog_repeat = 1)
  1257. AND catalog_year = ?
  1258. AND delete_flag = 0 ", $de_catalog_year);
  1259. $cur = db_fetch_array($res);
  1260. $batch["results"]["total"] = $cur["count"];
  1261. }
  1262. ////////////////////////////////////////////////////////////////////////
  1263. // Okay, we can now begin the actual batch process.
  1264. $current = $batch["results"]["current"];
  1265. $total = $batch["results"]["total"];
  1266. $limit = 1; // how many definitions to process per run of THIS function
  1267. $c = 0; // count of records.
  1268. $db = get_global_database_handler();
  1269. // Change to count how many groups with definitions OR "catalog_repeat" set.
  1270. // First, find every group which has a definition set.
  1271. $res = db_query("SELECT * FROM draft_groups
  1272. WHERE (definition != '' OR catalog_repeat = 1)
  1273. AND catalog_year = ?
  1274. AND delete_flag = 0
  1275. limit $current, $limit", $de_catalog_year);
  1276. while($cur = db_fetch_array($res)) {
  1277. if ($c >= $limit) {
  1278. break;
  1279. }
  1280. $def = trim($cur["definition"]);
  1281. $group_id = $cur["group_id"];
  1282. $group_name = $cur["group_name"];
  1283. $catalog_repeat = intval($cur['catalog_repeat']);
  1284. $school_id = intval($cur['school_id']);
  1285. // Only do definitions if there IS a definition.
  1286. if ($def != "") {
  1287. $temp = admin_get_courses_from_definition($def, "", $school_id);
  1288. $courses = trim($temp["text"]);
  1289. }
  1290. else {
  1291. // If there are no definitions, assemble a $courses string. admin_get_group_courses(Group $group)
  1292. $g = new Group($group_id, null, -1, false, true); // make sure we are loading from draft.
  1293. $courses = admin_get_group_courses($g);
  1294. }
  1295. // If the catalog_repeat flag is set, process that.
  1296. if ($catalog_repeat == 1) {
  1297. $courses = admin_process_catalog_repeats_for_group_courses_text($courses, $de_catalog_year, $school_id);
  1298. }
  1299. $ccount = 0;
  1300. fp_add_message(t("Working on %name", array("%name" => $group_name)));
  1301. // We need to delete all the existing course & subgroup requirements from this group.
  1302. // That entails first seeing what subgroups were required and deleting them,
  1303. // then deleting the parent group's requirements.
  1304. // First, find and delete the branches (child groups):
  1305. $res2 = db_query("SELECT * FROM draft_group_requirements
  1306. WHERE group_id = ?
  1307. AND child_group_id != '0' ", $group_id);
  1308. while ($cur2 = db_fetch_array($res2)) {
  1309. $cg_id = $cur2["child_group_id"];
  1310. $res22 = db_query("DELETE FROM draft_group_requirements
  1311. WHERE group_id = ? ", $cg_id);
  1312. }
  1313. // Now delete the course requirements...
  1314. $res2 = db_query("DELETE FROM draft_group_requirements
  1315. WHERE group_id = ? ", $group_id);
  1316. $lines = explode("\n", $courses);
  1317. for ($t = 0; $t < count($lines); $t++) {
  1318. $line = trim($lines[$t]);
  1319. if ($line == "") { continue; }
  1320. // Get rid of extra whitespace.
  1321. $line = str_replace(" ", " ", $line);
  1322. $line = str_replace(" ", " ", $line);
  1323. $line = str_replace(" ", " ", $line);
  1324. // Does this line contain at least one & symbol? If it does,
  1325. // then this is a subgroup (branch). If not, then we can insert
  1326. // the course as-is.
  1327. if (!strstr($line, "&")) {
  1328. // Did NOT contain an ampersand (&), so this goes in the
  1329. // regular course requirements.
  1330. $tokens = explode(" ", $line);
  1331. $subject_id = trim($tokens[0]);
  1332. $course_num = trim($tokens[1]);
  1333. @$min_grade = trim($tokens[2]);
  1334. @$course_repeats = trim($tokens[3]);
  1335. if (strstr($min_grade, "[")) {
  1336. // This is actually a specified repeat, not a min grade.
  1337. $course_repeats = $min_grade;
  1338. $min_grade = "";
  1339. }
  1340. $min_grade = str_replace("(","",$min_grade);
  1341. $min_grade = strtoupper(str_replace(")","",$min_grade));
  1342. $course_repeats = str_replace("[","",$course_repeats);
  1343. $course_repeats = str_replace("]","",$course_repeats);
  1344. $course_repeats--;
  1345. if ($course_repeats < 0) { $course_repeats = 0; }
  1346. // If the subject_id had a _A_ in it, convert this back
  1347. // to an ampersand.
  1348. $subject_id = str_replace("_A_", "&", $subject_id);
  1349. if ($course_id = $db->get_course_id($subject_id, $course_num, "", true, $school_id, TRUE)) {
  1350. $query = "INSERT INTO draft_group_requirements
  1351. (`group_id`,`course_id`,
  1352. `course_min_grade`,`course_repeats`,`data_entry_value`)
  1353. values (?, ?, ?, ?, ?) ";
  1354. $res2 = db_query($query, $group_id, $course_id, $min_grade, $course_repeats, "$subject_id~$course_num");
  1355. $ccount++;
  1356. }
  1357. else {
  1358. // The course_id could not be found!
  1359. fp_add_message(t("Course not found! You specified %course as a requirement in %gname,
  1360. but this course could not be found in the catalog. It was removed from
  1361. the list of requirements. Are you sure you typed it correctly? Please
  1362. check your spelling, and add the course again.", array("%course" => "$subject_id $course_num", "%gname" => $group_name)), "error");
  1363. }
  1364. } // if line does not contain &
  1365. else {
  1366. // ELSE, this was a branch! Insert it as well.
  1367. // This line DOES have an ampersand (&), so this is a sub group
  1368. // within this group.
  1369. // First, we need to request a new branchID for this new group.
  1370. if (!$branch_id = $db->request_new_group_id()) {
  1371. die ("Error. Could not create new group (branch) ID.");
  1372. }
  1373. else {
  1374. // Add this branch to the list of requirements for this group.
  1375. $query = "INSERT INTO draft_group_requirements
  1376. (group_id, child_group_id)
  1377. values ('?','?') ";
  1378. $res2 = db_query($query, $group_id, $branch_id);
  1379. }
  1380. $c_tokes = explode("&",$line);
  1381. for ($cT = 0; $cT < count($c_tokes); $cT++)
  1382. {
  1383. $tokens = explode(" ", trim($c_tokes[$cT]));
  1384. $subject_id = trim($tokens[0]);
  1385. $course_num = trim($tokens[1]);
  1386. $min_grade = @trim($tokens[2]);
  1387. $course_repeats = @trim($tokens[3]);
  1388. if (strstr($min_grade, "[")) {
  1389. // This is actually a specified repeat, not a min grade.
  1390. $course_repeats = $min_grade;
  1391. $min_grade = "";
  1392. }
  1393. $min_grade = str_replace("(","",$min_grade);
  1394. $min_grade = str_replace(")","",$min_grade);
  1395. $course_repeats = str_replace("[","",$course_repeats);
  1396. $course_repeats = str_replace("]","",$course_repeats);
  1397. $course_repeats--;
  1398. if ($course_repeats < 0) { $course_repeats = 0; }
  1399. // If the subject_id had a _A_ in it, convert this back
  1400. // to an ampersand.
  1401. $subject_id = str_replace("_A_", "&", $subject_id);
  1402. if ($course_id = $db->get_course_id($subject_id, $course_num, "", true, $school_id, TRUE)) {
  1403. $query = "INSERT INTO draft_group_requirements
  1404. (group_id, course_id,
  1405. course_min_grade, course_repeats, data_entry_value)
  1406. values (?,?,?,?,?) ";
  1407. $res2 = db_query($query, $branch_id, $course_id, $min_grade, $course_repeats, "$subject_id~$course_num");
  1408. }
  1409. else {
  1410. // The course_id could not be found!
  1411. fp_add_message(t("Course not found! You specified %course as a requirement in %gname,
  1412. but this course could not be found in the catalog. It was removed from
  1413. the list of requirements. Are you sure you typed it correctly? Please
  1414. check your spelling, and add the course again.", array("%course" => "$subject_id $course_num", "%gname" => $group_name)), "error");
  1415. }
  1416. } // for $cT
  1417. } // else it does contain &
  1418. } // for t < count lines
  1419. fp_add_message(t("%name processed. %count courses added.", array("%name" => $group_name, "%count" => $ccount)) . "<br><br>");
  1420. $c++;
  1421. } // while cur = db_fetch_array($res)
  1422. // Update our $batch results variables
  1423. $batch["results"]["current"] = $current + $c;
  1424. if ($batch["results"]["current"] >= $total) {
  1425. // We are finished!
  1426. $batch["results"]["finished"] = TRUE;
  1427. fp_add_message("<br><br><br>" . t("Group definitions have been processed for %year", array("%year" => $de_catalog_year)));
  1428. }
  1429. } // admin_process....batch_operation
  1430. /**
  1431. * Displays a popup showing where a particular group is being used in FlightPath.
  1432. */
  1433. function admin_display_groups_popup_show_group_use() {
  1434. $rtn = "";
  1435. $group_id = $_REQUEST["group_id"];
  1436. $group = new Group();
  1437. $group->group_id = $group_id;
  1438. $group->bool_use_draft = true;
  1439. $group->load_descriptive_data();
  1440. $defs = array();
  1441. if (module_enabled("schools")) {
  1442. $defs = schools_get_school_definitions(TRUE);
  1443. }
  1444. $rtn .= "<b>" . t("Degrees (from draft table) using @group_title (%group_name):", array("@group_title"=>$group->title, "%group_name" => $group->group_name)) . "</b>
  1445. <br><br>
  1446. <table border='0' cellspacing='5' width='100%'>
  1447. <tr>
  1448. <th>" . t("Degree") . "</th>
  1449. <th>" . t("Code") . "</th>
  1450. <th>" . t("Block") . "</th>
  1451. <th>" . t("Year") . "</th>
  1452. <th>" . t("School") . "</th>
  1453. </tr>
  1454. ";
  1455. $db = get_global_database_handler();
  1456. $res = db_query("SELECT * FROM draft_degrees a,
  1457. draft_degree_requirements b
  1458. WHERE a.degree_id = b.degree_id
  1459. AND b.group_id = ?
  1460. ORDER BY a.title, a.major_code, b.semester_num ", $group_id);
  1461. while($cur = db_fetch_array($res))
  1462. {
  1463. extract($cur, 3, "db");
  1464. $school_id = $db->get_school_id_for_degree_id($db_degree_id, TRUE);
  1465. $school_code = @$defs[$school_id]['school_code'];
  1466. if ($school_id === 0) {
  1467. $school_code = "-";
  1468. }
  1469. $rtn .= "<tr>
  1470. <td valign='top' class='tenpt' >
  1471. $db_title
  1472. </td>
  1473. <td valign='top' class='tenpt' >
  1474. $db_major_code
  1475. </td>
  1476. <td valign='top' class='tenpt' >
  1477. " . ($db_semester_num + 1) . "
  1478. </td>
  1479. <td valign='top' class='tenpt'>
  1480. $db_catalog_year
  1481. </td>
  1482. <td valign='top' class='tenpt'>
  1483. $school_code
  1484. </td>
  1485. </tr>
  1486. ";
  1487. }
  1488. $rtn .= "</table>";
  1489. return $rtn;
  1490. }

Functions

Namesort descending Description
admin_array_diff I had to create my own version of array_diff, because the built-in PHP version has a nasty bug where it doesn't work after a certain number of elements.
admin_display_groups This function will display a list of all our groups.
admin_display_groups_popup_edit_definition
admin_display_groups_popup_select_icon This popup is called from the edit group page. It lets the user select an icon to assign to a group.
admin_display_groups_popup_show_group_use Displays a popup showing where a particular group is being used in FlightPath.
admin_edit_group_form This function lets the user edit a group.
admin_edit_group_form_submit
admin_edit_group_form_validate Validate handler for edit group form.
admin_get_courses_from_definition
admin_get_course_array_from_course_id_array
admin_get_course_array_from_definition_data
admin_get_group_courses Return back the courses in a group, suitable for the edit-group form.
admin_groups_list_filter_form
admin_groups_list_filter_form_submit
admin_process_all_definitions_form
admin_process_all_definitions_form_submit Actually perform the refreshing of definitions.
admin_process_all_definitions_perform_batch_operation This actually is the batch operation for processing all of our group definitions.
admin_process_catalog_repeats_for_group_courses_text This function will accept the $courses text (textarea) from a group, which spells out all of the courses, and then assign specified repeats based on what is set for that course in the course catalog.