admin.module

  1. 7.x modules/admin/admin.module
  2. 6.x modules/admin/admin.module
  3. 5.x modules/admin/admin.module

The administrative configurations for FlightPath.

File

modules/admin/admin.module
View source
  1. <?php
  2. /**
  3. * @file
  4. * The administrative configurations for FlightPath.
  5. *
  6. *
  7. */
  8. /**
  9. * Implementation of hook_menu
  10. *
  11. */
  12. function admin_menu() {
  13. $items = array();
  14. $items["admin-tools"] = array(
  15. "title" => "Admin Tools",
  16. "page_callback" => "admin_display_tools_screen",
  17. "access_arguments" => array("can_access_admin_tools"),
  18. "tab_family" => "admin",
  19. "page_settings" => array(
  20. "page_hide_report_error" => TRUE,
  21. ),
  22. "type" => MENU_TYPE_NORMAL_ITEM,
  23. );
  24. $items["admin-tools/admin"] = array(
  25. "title" => t("FlightPath Admin Console"),
  26. "description" => t("This area contains the bulk of settings, degree entry, and other configurations for FlightPath."),
  27. "page_callback" => "admin_display_main",
  28. "access_arguments" => array("can_access_admin"),
  29. "page_settings" => array(
  30. "menu_links" => array(
  31. 0 => array(
  32. "text" => "Admin Tools",
  33. "path" => "admin-tools",
  34. ),
  35. ),
  36. "menu_icon" => fp_get_module_path('system') . "/icons/FlightPath_Academics_plane_only.png",
  37. ),
  38. 'weight' => 999,
  39. "type" => MENU_TYPE_NORMAL_ITEM,
  40. );
  41. $items["admin/config/urgent-message"] = array(
  42. "title" => "Edit urgent message",
  43. "description" => "Set a message which will be displayed to all users on every page",
  44. "page_callback" => "fp_render_form",
  45. "page_arguments" => array("admin_urgent_message_form", "system_settings"),
  46. "access_arguments" => array("can_edit_urgent_message"),
  47. "page_settings" => array(
  48. "menu_icon" => fp_get_module_path('admin') . "/icons/error.png",
  49. "page_hide_report_error" => TRUE,
  50. "menu_links" => array(
  51. 0 => array(
  52. "text" => "Admin Console",
  53. "path" => "admin-tools/admin",
  54. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  55. ),
  56. ),
  57. ),
  58. "type" => MENU_TYPE_NORMAL_ITEM,
  59. );
  60. $items["admin/config/watchdog"] = array(
  61. "title" => "Watchdog (logs)",
  62. "description" => "View log messages from throughout the system",
  63. "page_callback" => "admin_display_watchdog",
  64. "access_arguments" => array("display_watchdog"),
  65. "page_settings" => array(
  66. "menu_icon" => fp_get_module_path('system') . "/icons/application_view_list.png",
  67. "page_show_title" => TRUE,
  68. "page_hide_report_error" => TRUE,
  69. "menu_links" => array(
  70. 0 => array(
  71. "text" => "Admin Console",
  72. "path" => "admin-tools/admin",
  73. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  74. ),
  75. ),
  76. ),
  77. "type" => MENU_TYPE_NORMAL_ITEM,
  78. );
  79. $items["admin/config/watchdog/%"] = array(
  80. "title" => "View Watchdog Entry",
  81. "page_callback" => "admin_display_watchdog_entry",
  82. "page_arguments" => array(3),
  83. "access_arguments" => array("display_watchdog"),
  84. "page_settings" => array(
  85. "page_show_title" => TRUE,
  86. "page_hide_report_error" => TRUE,
  87. "menu_links" => array(
  88. 0 => array(
  89. "text" => "Admin Console",
  90. "path" => "admin-tools/admin",
  91. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  92. ),
  93. 1 => array(
  94. "text" => "Watchdog",
  95. "path" => "admin/config/watchdog",
  96. "query" => "de_catalog_year=%DE_CATALOG_YEAR%&sev_filter=%SEV_FILTER%&page=%PAGE%&type_filter=%TYPE_FILTER%",
  97. ),
  98. ),
  99. ),
  100. "type" => MENU_TYPE_CALLBACK,
  101. );
  102. $items["admin/duplicate-year"] = array(
  103. "title" => "Duplicate entire catalog year",
  104. "page_callback" => "fp_render_form",
  105. "page_arguments" => array("admin_duplicate_year_form"),
  106. "access_arguments" => array("can_edit_data_entry"),
  107. "page_settings" => array(
  108. "page_hide_report_error" => TRUE,
  109. "menu_links" => array(
  110. 0 => array(
  111. "text" => "Admin Console",
  112. "path" => "admin-tools/admin",
  113. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  114. ),
  115. ),
  116. ),
  117. "type" => MENU_TYPE_NORMAL_ITEM,
  118. "tab_parent" => "admin-tools/admin",
  119. );
  120. $items["admin/edit-advising-settings"] = array(
  121. "title" => "Edit advising settings",
  122. "page_callback" => "fp_render_form",
  123. "page_arguments" => array("admin_advising_settings_form", "system_settings"),
  124. "access_arguments" => array("can_edit_advising_settings"),
  125. "page_settings" => array(
  126. "page_hide_report_error" => TRUE,
  127. "menu_links" => array(
  128. 0 => array(
  129. "text" => "Admin Console",
  130. "path" => "admin-tools/admin",
  131. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  132. ),
  133. ),
  134. ),
  135. "type" => MENU_TYPE_NORMAL_ITEM,
  136. "tab_parent" => "admin-tools/admin",
  137. );
  138. $items["admin/apply-draft-changes"] = array(
  139. "title" => "Apply draft changes",
  140. "page_callback" => "fp_render_form",
  141. "page_arguments" => array("admin_apply_draft_changes_form"),
  142. "access_arguments" => array("can_apply_draft_changes"),
  143. "page_settings" => array(
  144. "page_hide_report_error" => TRUE,
  145. "menu_links" => array(
  146. 0 => array(
  147. "text" => "Admin Console",
  148. "path" => "admin-tools/admin",
  149. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  150. ),
  151. ),
  152. ),
  153. "type" => MENU_TYPE_NORMAL_ITEM,
  154. "tab_parent" => "admin-tools/admin",
  155. );
  156. ///////////////////////////////////////////////////////
  157. ////////////////////// Degree Editing ///////////////////
  158. $items["admin/degrees"] = array(
  159. "title" => "Degrees",
  160. "page_callback" => "admin_display_degrees",
  161. "access_arguments" => array("can_access_data_entry"),
  162. "page_settings" => array(
  163. "page_hide_report_error" => TRUE,
  164. "menu_links" => array(
  165. 0 => array(
  166. "text" => "Admin Console",
  167. "path" => "admin-tools/admin",
  168. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  169. ),
  170. ),
  171. ),
  172. "file" => menu_get_module_path("admin") . "/admin.degrees.inc",
  173. "type" => MENU_TYPE_NORMAL_ITEM,
  174. );
  175. $items["admin/degrees/edit-degree/%/%"] = array(
  176. "title" => "Edit Degree",
  177. "page_callback" => "fp_render_form",
  178. "page_arguments" => array("admin_edit_degree_form", "normal", 3, 4),
  179. "access_arguments" => array("can_edit_data_entry"),
  180. "page_settings" => array(
  181. "page_hide_report_error" => TRUE,
  182. "menu_links" => array(
  183. 0 => array(
  184. "text" => "Admin Console",
  185. "path" => "admin-tools/admin",
  186. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  187. ),
  188. 1 => array(
  189. "text" => "Degrees",
  190. "path" => "admin/degrees",
  191. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  192. ),
  193. ),
  194. ),
  195. "file" => menu_get_module_path("admin") . "/admin.degrees.inc",
  196. "type" => MENU_TYPE_NORMAL_ITEM,
  197. );
  198. $items["admin/degrees/popup-add-group"] = array(
  199. "title" => "Add Group",
  200. "page_callback" => "admin_display_degrees_popup_add_group",
  201. "access_arguments" => array("can_edit_data_entry"),
  202. "page_settings" => array(
  203. "page_is_popup" => TRUE,
  204. "page_hide_report_error" => TRUE,
  205. ),
  206. "file" => menu_get_module_path("admin") . "/admin.degrees.inc",
  207. "type" => MENU_TYPE_CALLBACK,
  208. );
  209. $items["admin/degrees/popup-add-group2"] = array(
  210. "title" => "Add Group",
  211. "page_callback" => "admin_display_degrees_popup_add_group2",
  212. "access_arguments" => array("can_edit_data_entry"),
  213. "page_settings" => array(
  214. "page_is_popup" => TRUE,
  215. "page_hide_report_error" => TRUE,
  216. ),
  217. "file" => menu_get_module_path("admin") . "/admin.degrees.inc",
  218. "type" => MENU_TYPE_CALLBACK,
  219. );
  220. $items["admin/degrees/add-degree"] = array(
  221. "title" => "Add Degree",
  222. "page_callback" => "fp_render_form",
  223. "page_arguments" => array("admin_add_degree_form"),
  224. "access_arguments" => array("can_edit_data_entry"),
  225. "page_settings" => array(
  226. "page_hide_report_error" => TRUE,
  227. "menu_links" => array(
  228. 0 => array(
  229. "text" => "Admin Console",
  230. "path" => "admin-tools/admin",
  231. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  232. ),
  233. 1 => array(
  234. "text" => "Degrees",
  235. "path" => "admin/degrees",
  236. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  237. ),
  238. ),
  239. ),
  240. "file" => menu_get_module_path("admin") . "/admin.degrees.inc",
  241. "type" => MENU_TYPE_NORMAL_ITEM,
  242. );
  243. $items["admin/degrees/copy-degree"] = array(
  244. "title" => "Copy Degree",
  245. "page_callback" => "fp_render_form",
  246. "page_arguments" => array("admin_copy_degree_form"),
  247. "access_arguments" => array("can_edit_data_entry"),
  248. "page_settings" => array(
  249. "page_hide_report_error" => TRUE,
  250. "menu_links" => array(
  251. 0 => array(
  252. "text" => "Admin Console",
  253. "path" => "admin-tools/admin",
  254. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  255. ),
  256. 1 => array(
  257. "text" => "Degrees",
  258. "path" => "admin/degrees",
  259. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  260. ),
  261. ),
  262. ),
  263. "file" => menu_get_module_path("admin") . "/admin.degrees.inc",
  264. "type" => MENU_TYPE_CALLBACK,
  265. );
  266. ///////////////////////////////////////////////////////
  267. ////////////////////// Group Editing ///////////////////
  268. $items["admin/groups"] = array(
  269. "title" => "Groups",
  270. "page_callback" => "admin_display_groups",
  271. "access_arguments" => array("can_access_data_entry"),
  272. "page_settings" => array(
  273. "page_hide_report_error" => TRUE,
  274. "menu_links" => array(
  275. 0 => array(
  276. "text" => "Admin Console",
  277. "path" => "admin-tools/admin",
  278. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  279. ),
  280. ),
  281. ),
  282. "file" => menu_get_module_path("admin") . "/admin.groups.inc",
  283. "type" => MENU_TYPE_NORMAL_ITEM
  284. );
  285. $items["admin/groups/edit-group"] = array(
  286. "title" => "Edit Group",
  287. "page_callback" => "fp_render_form",
  288. "page_arguments" => array("admin_edit_group_form"),
  289. "access_arguments" => array("can_edit_data_entry"),
  290. "page_settings" => array(
  291. "page_hide_report_error" => TRUE,
  292. "menu_links" => array(
  293. 0 => array(
  294. "text" => "Admin Console",
  295. "path" => "admin-tools/admin",
  296. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  297. ),
  298. 1 => array(
  299. "text" => "Groups",
  300. "path" => "admin/groups",
  301. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  302. ),
  303. ),
  304. ),
  305. "file" => menu_get_module_path("admin") . "/admin.groups.inc",
  306. "type" => MENU_TYPE_NORMAL_ITEM,
  307. );
  308. $items["admin/groups/popup-select-icon"] = array(
  309. "title" => "Select Icon",
  310. "page_callback" => "admin_display_groups_popup_select_icon",
  311. "access_arguments" => array("can_edit_data_entry"),
  312. "page_settings" => array(
  313. "page_is_popup" => TRUE,
  314. "page_hide_report_error" => TRUE,
  315. ),
  316. "file" => menu_get_module_path("admin") . "/admin.groups.inc",
  317. "type" => MENU_TYPE_CALLBACK,
  318. );
  319. $items["admin/groups/popup-edit-definition"] = array(
  320. "title" => "Edit Definition",
  321. "page_callback" => "admin_display_groups_popup_edit_definition",
  322. "access_arguments" => array("can_edit_data_entry"),
  323. "page_settings" => array(
  324. "page_is_popup" => TRUE,
  325. "page_hide_report_error" => TRUE,
  326. ),
  327. "file" => menu_get_module_path("admin") . "/admin.groups.inc",
  328. "type" => MENU_TYPE_CALLBACK,
  329. );
  330. $items["admin/groups/popup-show-group-use"] = array(
  331. "title" => "Group Use",
  332. "page_callback" => "admin_display_groups_popup_show_group_use",
  333. "access_arguments" => array("can_edit_data_entry"),
  334. "page_settings" => array(
  335. "page_is_popup" => TRUE,
  336. "page_hide_report_error" => TRUE,
  337. ),
  338. "file" => menu_get_module_path("admin") . "/admin.groups.inc",
  339. "type" => MENU_TYPE_CALLBACK,
  340. );
  341. $items["admin/groups/process-all-definitions"] = array(
  342. "title" => "Process all Definitions",
  343. "page_callback" => "fp_render_form",
  344. "page_arguments" => array("admin_process_all_definitions_form"),
  345. "access_arguments" => array("can_edit_data_entry"),
  346. "page_settings" => array(
  347. "page_hide_report_error" => TRUE,
  348. "menu_links" => array(
  349. 0 => array(
  350. "text" => "Admin Console",
  351. "path" => "admin-tools/admin",
  352. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  353. ),
  354. 1 => array(
  355. "text" => "Groups",
  356. "path" => "admin/groups",
  357. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  358. ),
  359. ),
  360. ),
  361. "file" => menu_get_module_path("admin") . "/admin.groups.inc",
  362. "type" => MENU_TYPE_NORMAL_ITEM,
  363. );
  364. /////////////////////////////////////////////////
  365. /////////////////// Courses editing ////////////////
  366. $items["admin/courses"] = array(
  367. "title" => "Courses",
  368. "page_callback" => "admin_display_courses",
  369. "access_arguments" => array("can_access_data_entry"),
  370. "page_settings" => array(
  371. "page_hide_report_error" => TRUE,
  372. "menu_links" => array(
  373. 0 => array(
  374. "text" => "Admin Console",
  375. "path" => "admin-tools/admin",
  376. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  377. ),
  378. ),
  379. ),
  380. "file" => menu_get_module_path("admin") . "/admin.courses.inc",
  381. "type" => MENU_TYPE_NORMAL_ITEM,
  382. );
  383. $items["admin/courses/edit-course"] = array(
  384. "title" => "Edit Course",
  385. "page_callback" => "fp_render_form",
  386. "page_arguments" => array("admin_edit_course_form"),
  387. "access_arguments" => array("can_edit_data_entry"),
  388. "page_settings" => array(
  389. "page_hide_report_error" => TRUE,
  390. "menu_links" => array(
  391. 0 => array(
  392. "text" => "Admin Console",
  393. "path" => "admin-tools/admin",
  394. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  395. ),
  396. 1 => array(
  397. "text" => "Courses",
  398. "path" => "admin/courses",
  399. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  400. ),
  401. ),
  402. ),
  403. "file" => menu_get_module_path("admin") . "/admin.courses.inc",
  404. "type" => MENU_TYPE_NORMAL_ITEM,
  405. );
  406. return $items;
  407. }
  408. /**
  409. * This page displays all the tools that the user has access to use.
  410. */
  411. function admin_display_tools_screen() {
  412. fp_add_css(fp_get_module_path("admin") . '/css/admin.css');
  413. $rtn = "";
  414. $rtn .= "<div class='display-admin-tools-page'>";
  415. $rtn .= fp_render_menu_block("", "admin-tools");
  416. $rtn .= "</div>";
  417. return $rtn;
  418. }
  419. /**
  420. * hook_cron
  421. */
  422. function admin_cron() {
  423. // Delete courses and groups which has been marked with "delete_flag = 1"
  424. $last_run = intval(variable_get("admin_last_run_delete_flag_removal", 0));
  425. $check_against = strtotime("NOW - 7 DAYS"); // don't run any more often than once every 7 days
  426. $c = 0;
  427. if ($check_against > $last_run) {
  428. $res = db_query("DELETE FROM draft_courses
  429. WHERE delete_flag = 1 ");
  430. $c = db_affected_rows($res);
  431. watchdog("admin", "Delete from flagged draft_courses db complete. $c items removed.", array(), WATCHDOG_DEBUG);
  432. $res = db_query("SELECT * FROM draft_groups
  433. WHERE delete_flag = 1 ");
  434. while ($cur = db_fetch_object($res)) {
  435. $group_id = $cur->group_id;
  436. $res2 = db_query("DELETE FROM draft_group_requirements WHERE group_id = ?", array($group_id));
  437. db_query("DELETE FROM draft_groups WHERE group_id = ?", array($group_id));
  438. $c++;
  439. }
  440. watchdog("admin", "Delete from flagged draft_groups db complete. $c items removed.", array(), WATCHDOG_DEBUG);
  441. variable_set("admin_last_run_delete_flag_removal", time());
  442. } // check against > last_run, so we should do it.
  443. } // hook_cron
  444. /**
  445. * This form will allow the user to duplicate an entire year's worth of data to a new
  446. * catalog year.
  447. *
  448. */
  449. function admin_duplicate_year_form() {
  450. $form = array();
  451. $m = 0;
  452. $form["mark" . $m++] = array(
  453. "value" => "<p>" . t("This form will allow you to duplicate an entire year's worth of data
  454. (courses, degrees, groups) into a new year. This is used to create a new
  455. year of data, based on the previous year, for example. <b>It will completely
  456. delete the 'destination' year data, if it already exists!</b> Use carefully.
  457. <br><br>
  458. The new year will be placed in DRAFT, and will not be visible in FlightPath
  459. until draft changes are applied.
  460. <br><br>
  461. <u>It would be wise</u> to back up your database before proceeding.") . "</p><hr>",
  462. );
  463. $form["source_year"] = array(
  464. "type" => "textfield",
  465. "label" => t("Source year:"),
  466. "size" => 10,
  467. "required" => TRUE,
  468. "description" => t("Enter the 4-digit source year you are copying FROM. For example,
  469. 2007. If you are copying from '2007-2008' then just enter
  470. 2007."),
  471. );
  472. $form["destination_year"] = array(
  473. "type" => "textfield",
  474. "label" => t("Destination year:"),
  475. "size" => 10,
  476. "required" => TRUE,
  477. "description" => t("Enter the 4-digit source year you are copying TO. <b><u>If this year
  478. all ready exists in the system, all data for this year will be DELETED.</u></b>
  479. If you are copying to '2009-2010' then just enter
  480. 2009."),
  481. );
  482. $form["passcode"] = array(
  483. "type" => "password",
  484. "label" => t("For added security, you must enter the Apply Draft Changes password:"),
  485. "required" => TRUE,
  486. "description" => t("This is a password set up in FlightPath's settings, to provide an extra layer
  487. of security for this powerful action. Draft changes will not actually be applied,
  488. this is simply used as an added layer of security."),
  489. );
  490. $form["submit"] = array(
  491. "type" => "submit",
  492. "value" => t("Submit"),
  493. "spinner" => TRUE,
  494. "description" => t("This action may take <b><u>several minutes</u></b> to complete."),
  495. "prefix" => "<hr>",
  496. );
  497. return $form;
  498. }
  499. /**
  500. * Before we duplicate the year, make sure the password is correct.
  501. */
  502. function admin_duplicate_year_form_validate($form, &$form_state) {
  503. $values = $form_state["values"];
  504. // Check to make sure they entered the transfer passcode correctly.
  505. if ($values["passcode"] != variable_get("admin_transfer_passcode", sha1(mt_rand()))) {
  506. form_error("passcode", t("Sorry, but the password you entered is not correct. Check with the FlightPath administrator
  507. (or check the admin settings pages) to learn the password."));
  508. return;
  509. }
  510. }
  511. /**
  512. * This function will set up a batch operation so we can duplicate an entire year with less chance of time or memory
  513. * running out.
  514. *
  515. * @param unknown_type $form
  516. * @param unknown_type $form_state
  517. */
  518. function admin_duplicate_year_form_submit($form, &$form_state) {
  519. $values = $form_state["values"];
  520. $new_year = $values["destination_year"];
  521. $old_year = $values["source_year"];
  522. // We are going to keep track of all the operations we need to do in this $ops array.
  523. $ops = array();
  524. $ops[]['delete_new_year'] = TRUE;
  525. // We need to break up how many courses we copy at a time, so let's query to get a count.
  526. $count = db_result(db_query("SELECT COUNT(*) as mycount FROM draft_courses WHERE catalog_year = ? ", array($old_year)));
  527. for ($t = 0; $t < $count; $t = $t + 150) { // 150 is how many to do on each pass.
  528. $ops[]['copy_courses'] = $t;
  529. }
  530. // We need to break up the groups the same way we did the courses...
  531. $count = db_result(db_query("SELECT count(*) FROM draft_groups WHERE catalog_year = ? ", array($old_year)));
  532. for ($t = 0; $t < $count; $t = $t + 3) { // 3 is how many to do on each pass, because groups are much more detailed.
  533. $ops[]['copy_groups'] = $t;
  534. }
  535. $ops[]['copy_degree_tracks'] = TRUE;
  536. // We also want to break up the degrees for the same reasons as the others.
  537. // We need to break up the groups the same way we did the courses...
  538. $count = db_result(db_query("SELECT count(*) FROM draft_degrees WHERE catalog_year = ? ", array($old_year)));
  539. for ($t = 0; $t < $count; $t = $t + 15) { // 15 is how many to do on each pass.
  540. $ops[]['copy_degrees'] = $t;
  541. }
  542. $ops[]['hook_admin_duplicate_year'] = TRUE;
  543. // Okay, set up the batch....
  544. $batch = array(
  545. "operation" => array("admin_duplicate_year_perform_batch_operation", array($ops, $old_year, $new_year)),
  546. "title" => t("Duplicate catalog year"),
  547. "success_message" => t("Duplication from $old_year to $new_year completed successfully."),
  548. "progress_message" => "Working on @current of @total operations. This may take some time, do not close this window/tab.",
  549. "display_percent" => TRUE,
  550. );
  551. // Set the batch...
  552. batch_set($batch);
  553. }
  554. /**
  555. * The is the batch operation to duplicate from $old_year to $new_year
  556. */
  557. function admin_duplicate_year_perform_batch_operation(&$batch, $ops, $old_year, $new_year) {
  558. set_time_limit (300); // Extend time limit since this may take a little while.
  559. // if this is our first time through, let's init our values.
  560. if (!isset($batch["results"]["total"])) {
  561. // Our first time through. Let's start up.
  562. $batch["results"]["total"] = count($ops);
  563. $batch["results"]["current"] = 0;
  564. $batch["results"]["finished"] = FALSE;
  565. unset($_SESSION['admin_duplicate_year']);
  566. $_SESSION['admin_duplicate_year'] = array();
  567. $_SESSION['admin_duplicate_year']['courses'] = array();
  568. $_SESSION['admin_duplicate_year']['groups'] = array();
  569. $_SESSION['admin_duplicate_year']['degrees'] = array();
  570. }
  571. $op_command = key($ops[$batch['results']['current']]);
  572. $op_val = $ops[$batch['results']['current']][$op_command];
  573. $db = get_global_database_handler();
  574. watchdog('debug', "$op_command");
  575. if ($op_command == 'delete_new_year') {
  576. ///////////////////// DELETION ///////////////////////////////////////////
  577. // We must first begin by deleting any entries for the new_year
  578. // from our tables. This is because we may have to run this
  579. // more than once while debugging and such.
  580. $res = db_query("DELETE FROM draft_courses WHERE catalog_year = ? ", $new_year);
  581. $res = db_query("DELETE FROM draft_degree_tracks WHERE catalog_year = ? ", $new_year);
  582. // For degrees, we first need to select all of the new_year degrees.
  583. $res = db_query("SELECT * FROM draft_degrees WHERE catalog_year = ? ", $new_year);
  584. while ($cur = db_fetch_array($res)) {
  585. $res2 = db_query("DELETE FROM draft_degree_requirements WHERE degree_id = ? ", $cur["degree_id"]);
  586. }
  587. $res = db_query("DELETE FROM draft_degrees WHERE catalog_year = ? ", $new_year);
  588. // For groups, begin by selecting all the groups in that year...
  589. $res = db_query("SELECT * FROM draft_groups WHERE catalog_year = ? ", $new_year);
  590. while ($cur = db_fetch_array($res))
  591. {
  592. // Now, select all the requirements and see if there are any sub groups...
  593. $res2 = db_query("SELECT * FROM draft_group_requirements WHERE group_id = ? ", $cur["group_id"]);
  594. while ($cur2 = db_fetch_array($res2))
  595. {
  596. if ($cur2["child_group_id"] > 0)
  597. {
  598. // Delete the child group.
  599. $res3 = db_query("DELETE FROM draft_group_requirements WHERE group_id = ? ", $cur2["child_group_id"]);
  600. }
  601. }
  602. // Now, delete the original requirement.
  603. $res3 = db_query("DELETE FROM draft_group_requirements WHERE group_id = ? ", $cur["group_id"]);
  604. }
  605. $res = db_query("DELETE FROM draft_groups WHERE catalog_year = ? ", $new_year);
  606. } // delete_new_year
  607. /////////////
  608. /////////////
  609. if ($op_command == 'copy_courses') {
  610. $start_position = intval($op_val);
  611. /////////////////////// COPY COURSES //////////////////////////////////////////////////
  612. // Copy all of the courses from the old_year to the new_year.
  613. $res = db_query("SELECT * FROM draft_courses WHERE catalog_year = ?
  614. LIMIT $start_position, 150 ", array($old_year));
  615. while ($cur = db_fetch_array($res))
  616. {
  617. extract($cur, 3, "db");
  618. //$course = new Course($db_course_id, FALSE, $db, FALSE, $old_year);
  619. $course = new stdClass();
  620. $course->course_id = $db_course_id;
  621. $course->subject_id = $db_subject_id;
  622. $course->course_num = $db_course_num;
  623. $course->db_exclude = $db_exclude;
  624. $course->min_hours = $db_min_hours;
  625. $course->max_hours = $db_max_hours;
  626. $course->repeat_hours = $db_repeat_hours;
  627. $course->school_id = $db_school_id;
  628. $course->title = $db_title;
  629. $course->description = $db_description;
  630. //$course_id, $c->subject_id,$c->course_num,$catalog_year,$c->title,$c->description,$min_hours,$max_hours,
  631. // $c->repeat_hours,$c->db_exclude,$c->school_id)
  632. // Now, duplicate it for the new_year.
  633. // The FALSE at the end means don't bother deleting any existing course, since we have already done that.
  634. $db->duplicate_course_for_year($course, $new_year, FALSE);
  635. // Store what courses we are working on, for other modules.
  636. $_SESSION['admin_duplicate_year']['courses'][] = $db_course_id;
  637. }
  638. } // copy_courses
  639. //////////////
  640. //////////////
  641. if ($op_command == 'copy_groups') {
  642. //////////////////////// COPY GROUPS ///////////////////////////////////////////////
  643. // Now, let's copy over the groups.
  644. $group_id_array = array();
  645. $subgroup_id_array = array();
  646. $start_position = intval($op_val);
  647. $res = db_query("SELECT * FROM draft_groups WHERE catalog_year = ?
  648. LIMIT $start_position, 3 ", $old_year);
  649. while ($cur = db_fetch_array($res))
  650. {
  651. extract($cur, 3, "db");
  652. // First, let's request a new group ID for this new group.
  653. $new_group_id = $db->request_new_group_id();
  654. $group_id_array[$db_group_id] = $new_group_id;
  655. // Now, let's insert this top-level group back into the table
  656. // as the new_year, with the new_group_id.
  657. $query = "INSERT INTO draft_groups(`group_id`,`group_name`,
  658. `title`,`public_note`,`definition`,`icon_filename`,`catalog_year`,
  659. `priority`,`delete_flag`,`data_entry_comment`, `catalog_repeat`,school_id)
  660. VALUES (?,?,?,?,?,?,?,?,?,?,?,?) ";
  661. $res2 = db_query($query, array($new_group_id, $db_group_name, $db_title, $db_public_note,
  662. $db_definition, $db_icon_filename, $new_year,
  663. $db_priority, $db_delete_flag, $db_data_entry_comment,
  664. $db_catalog_repeat, $db_school_id));
  665. // Okay, now we need to go through the requirements for the group, and copy
  666. // those over to the new_year.
  667. $res3 = db_query("SELECT * FROM draft_group_requirements
  668. WHERE group_id = ? ", $db_group_id);
  669. while($cur3 = db_fetch_array($res3))
  670. {
  671. extract($cur3, 3, "db3");
  672. $child_group_id = 0;
  673. // Was there a child_group (a branch)? If so, we need to copy that
  674. // over too, with a new child_group_id.
  675. if ($db3_child_group_id > 0)
  676. {
  677. // First, create the child group...
  678. $new_sub_group_id = $db->request_new_group_id();
  679. $subgroup_id_array[$db3_child_group_id] = $new_sub_group_id;
  680. $res4 = db_query("SELECT * FROM draft_group_requirements
  681. WHERE group_id = ? ", $db3_child_group_id);
  682. while($cur4 = db_fetch_array($res4))
  683. {
  684. extract($cur4, 3, "db4");
  685. $res5 = db_query("INSERT INTO draft_group_requirements
  686. (`group_id`,`course_id`,`course_min_grade`,
  687. `course_repeats`,`attributes`,`data_entry_value`)
  688. VALUES (?,?,?,?,?,?) ", array($new_sub_group_id, $db4_course_id,
  689. $db4_course_min_grade,$db4_course_repeats,$db4_attributes,
  690. $db4_data_entry_value));
  691. }
  692. // Now, add the replace the db3_child_group_id with this new id
  693. // so it will get added as a requirement.
  694. $child_group_id = $new_sub_group_id;
  695. }
  696. // Add the row into the table...
  697. $res5 = db_query("INSERT INTO draft_group_requirements
  698. (`group_id`,`course_id`,`course_min_grade`,
  699. `course_repeats`,`attributes`,`data_entry_value`,`child_group_id`)
  700. VALUES (?,?,?,?,?,?,?) ", array($new_group_id, $db3_course_id,
  701. $db3_course_min_grade, $db3_course_repeats, $db3_attributes,
  702. $db3_data_entry_value, $child_group_id));
  703. }
  704. }
  705. // Store what groups we are working on, for other modules.
  706. $_SESSION['admin_duplicate_year']['groups'] += $group_id_array; // Since we are going in multiple rounds, add to the array.
  707. } // copy_groups
  708. ////////////////////////////
  709. ////////////////////////////
  710. if ($op_command == 'copy_degree_tracks') {
  711. $res = db_query("SELECT * FROM draft_degree_tracks WHERE catalog_year = ? ", $old_year);
  712. while ($cur = db_fetch_array($res))
  713. {
  714. extract($cur, 3, "db");
  715. $res2 = db_query("INSERT INTO draft_degree_tracks
  716. (`catalog_year`,`major_code`,`track_code`,`track_title`,
  717. `track_short_title`,`track_description`,school_id)
  718. VALUES
  719. (?,?,?,?,?,?,?) ", array($new_year,$db_major_code,$db_track_code,$db_track_title,
  720. $db_track_short_title,$db_track_description,$db_school_id));
  721. }
  722. }
  723. ////////////////
  724. ////////////////
  725. if ($op_command == 'copy_degrees') {
  726. //////////////////////// COPY DEGREES ///////////////////////////////////////////
  727. // Now, on to transfering the degrees.
  728. // We will have to use the groupIDArray we constructed earlier, which
  729. // looks like $arr[old_id] = new_id.
  730. // Do the tracks first, since they are easier and straight forward...
  731. $start_position = intval($op_val);
  732. $group_id_array = $_SESSION['admin_duplicate_year']['groups']; // Load from last time, when we copied groups.
  733. // Now, let's do the degrees themselves.
  734. $res = db_query("SELECT * FROM draft_degrees WHERE catalog_year = ?
  735. LIMIT $start_position, 15 ", $old_year);
  736. while ($cur = db_fetch_array($res))
  737. {
  738. extract($cur, 3, "db");
  739. $new_degree_id = $db->request_new_degree_id();
  740. // Store what degrees we are working on, for other modules.
  741. $_SESSION['admin_duplicate_year']['degrees'][] = array(
  742. 'src' => $db_degree_id,
  743. 'src_catalog_year' => $old_year,
  744. 'school_id' => $db_school_id,
  745. 'dest' => $new_degree_id,
  746. 'dest_major_code' => $db_major_code,
  747. 'dest_catalog_year' => $new_year,
  748. );
  749. // add in the top-level degree to the table.
  750. $res2 = db_query("INSERT INTO draft_degrees
  751. (degree_id, major_code, degree_type, degree_level, degree_class, title,
  752. semester_titles_csv, catalog_year, exclude, public_note,
  753. allow_dynamic, advising_weight, override_degree_hours, min_tracks, max_tracks, default_tracks, track_selection_config, school_id)
  754. VALUES
  755. (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  756. ", array($new_degree_id, $db_major_code, $db_degree_type, $db_degree_level, $db_degree_class, $db_title,
  757. $db_semester_titles_csv, $new_year, $db_exclude, $db_public_note,
  758. $db_allow_dynamic, $db_advising_weight, $db_override_degree_hours, $db_min_tracks, $db_max_tracks,
  759. $db_default_tracks, $db_track_selection_config, $db_school_id));
  760. // now, pull out all of the degree_requirements.
  761. $res3 = db_query("SELECT * FROM draft_degree_requirements
  762. WHERE degree_id = ? ", array($db_degree_id));
  763. while($cur3 = db_fetch_array($res3))
  764. {
  765. extract($cur3, 3, "db3");
  766. // If there is a required group, we must convert it to the
  767. // new groupID !
  768. $required_group_id = intval($db3_group_id);
  769. if ($db3_group_id > 0 && trim($db3_group_id) != "")
  770. {
  771. $o_group_id = $db3_group_id;
  772. $required_group_id = $group_id_array[$db3_group_id];
  773. if ($required_group_id < 1 || $required_group_id == "")
  774. {
  775. //die("could not find new group for $old_year $db3_group_id! Group id is $required_group_id");
  776. fp_add_message(t("Couldn't find the specified group with ID $db3_group_id in catalog year $old_year, required by degree with ID $db_degree_id ($db_major_code). The group was possibly deleted?
  777. Be aware that any degrees in the new year will be missing this group requirement."), 'error', TRUE);
  778. }
  779. }
  780. $res4 = db_query("INSERT INTO draft_degree_requirements
  781. (degree_id, semester_num, group_id, group_requirement_type,
  782. group_hours_required, group_min_hours_allowed, group_min_grade, course_id,
  783. course_min_grade, course_requirement_type, data_entry_value)
  784. VALUES
  785. (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  786. ", array($new_degree_id, $db3_semester_num, $required_group_id, $db3_group_requirement_type,
  787. $db3_group_hours_required, $db3_group_min_hours_allowed, $db3_group_min_grade, $db3_course_id,
  788. $db3_course_min_grade, $db3_course_requirement_type, $db3_data_entry_value));
  789. }
  790. } // while draft_degrees
  791. } // copy_degrees
  792. ////////////////////
  793. ////////////////////
  794. // Allows other modules to act.
  795. if ($op_command == 'hook_admin_duplicate_year') {
  796. invoke_hook('admin_duplicate_year', array($old_year, $new_year));
  797. }
  798. $batch['results']['current']++;
  799. // Have we finished?
  800. if ($batch["results"]["current"] >= $batch["results"]["total"]) {
  801. $batch["results"]["finished"] = TRUE;
  802. watchdog("admin", "Duplicated all degree/group/courses data from $old_year to $new_year");
  803. fp_add_message(t("The copy operation is now completed. You may view the new year
  804. by using the Data Entry links on the admin main menu. Remember, you must
  805. apply draft changes before they will be visible in FlightPath."));
  806. }
  807. } // admin_duplicate_year_perform_batch_operation
  808. /**
  809. * This function should perform the actual copy of data!
  810. *
  811. * @param unknown_type $form
  812. * @param unknown_type $form_state
  813. */
  814. function z__admin_duplicate_year_form_submit($form, &$form_state) {
  815. set_time_limit (300); // Extend time limit since this may take a little while.
  816. $values = $form_state["values"];
  817. // We are going to keep track of all the operations we need to do in this $ops array.
  818. $ops = array();
  819. // Check to make sure they entered the transfer passcode correctly.
  820. $db = get_global_database_handler();
  821. // Okay, we made it this far, let's proceed with the copy!
  822. $new_year = $values["destination_year"];
  823. $old_year = $values["source_year"];
  824. $form_state['duplication']['src_catalog_year'] = $old_year;
  825. $form_state['duplication']['dest_catalog_year'] = $new_year;
  826. // TODO: We need to switch to using the Batch API for this.
  827. // TODO: Each section should be its own operation.
  828. // TODO: Deletion of dest data
  829. // TODO: Duplication of Courses, Groups, Degrees, then other modules' hooks
  830. ///////////////////// DELETION ///////////////////////////////////////////
  831. // We must first begin by deleting any entries for the new_year
  832. // from our tables. This is because we may have to run the parser
  833. // more than once while debugging and such.
  834. $res = db_query("DELETE FROM draft_courses WHERE `catalog_year`= ? ", $new_year);
  835. $res = db_query("DELETE FROM draft_degree_tracks WHERE `catalog_year` = ? ", $new_year);
  836. // For degrees, we first need to select all of the new_year degrees.
  837. $res = db_query("SELECT * FROM draft_degrees WHERE `catalog_year` = ? ", $new_year);
  838. while ($cur = db_fetch_array($res)) {
  839. $res2 = db_query("DELETE FROM draft_degree_requirements WHERE `degree_id`='{$cur["degree_id"]}' ");
  840. }
  841. $res = db_query("DELETE FROM draft_degrees WHERE `catalog_year`=? ", $new_year);
  842. // For groups, begin by selecting all the groups in that year...
  843. $res = db_query("SELECT * FROM draft_groups WHERE `catalog_year`=? ", $new_year);
  844. while ($cur = db_fetch_array($res))
  845. {
  846. // Now, select all the requirements and see if there are any sub groups...
  847. $res2 = db_query("SELECT * FROM draft_group_requirements WHERE `group_id`='{$cur["group_id"]}' ");
  848. while ($cur2 = db_fetch_array($res2))
  849. {
  850. if ($cur2["child_group_id"] > 0)
  851. {
  852. // Delete the child group.
  853. $res3 = db_query("DELETE FROM draft_group_requirements WHERE `group_id`='{$cur2["child_group_id"]}' ");
  854. }
  855. }
  856. // Now, delete the original requirement.
  857. $res3 = db_query("DELETE FROM draft_group_requirements WHERE `group_id`='{$cur["group_id"]}' ");
  858. }
  859. $res = db_query("DELETE FROM draft_groups WHERE `catalog_year`=? ", $new_year);
  860. //////////////////////////////////////////////////////////////////////////
  861. // Okay, we have deleted any possible old entries for the new year.
  862. /////////////////////// COPY COURSES //////////////////////////////////////////////////
  863. // Our first step is to copy all of the courses from the old_year to the new_year.
  864. $res = db_query("SELECT * FROM draft_courses WHERE `catalog_year`=? ", $old_year);
  865. while ($cur = db_fetch_array($res))
  866. {
  867. extract($cur, 3, "db");
  868. $course = new Course($db_course_id, false, $db, false, $old_year);
  869. $course->subject_id = $db_subject_id;
  870. $course->course_num = $db_course_num;
  871. $course->db_exclude = $db_exclude;
  872. $course->min_hours = $db_min_hours;
  873. $course->max_hours = $db_max_hours;
  874. $course->repeat_hours = $db_repeat_hours;
  875. $course->school_id = $db_school_id;
  876. // Now, duplicate it for the new_year.
  877. $db->duplicate_course_for_year($course, $new_year);
  878. // Store what courses we are working on, for other modules.
  879. $form_state['courses'][] = $db_course_id;
  880. }
  881. //////////////////////// COPY GROUPS ///////////////////////////////////////////////
  882. // Now, let's copy over the groups.
  883. $group_id_array = array();
  884. $subgroup_id_array = array();
  885. $res = db_query("SELECT * FROM draft_groups WHERE `catalog_year`=? ", $old_year);
  886. while ($cur = db_fetch_array($res))
  887. {
  888. extract($cur, 3, "db");
  889. // First, let's request a new group ID for this new group.
  890. $new_group_id = $db->request_new_group_id();
  891. $group_id_array[$db_group_id] = $new_group_id;
  892. //$db_data_entry_comment = mysql_real_escape_string($db_data_entry_comment);
  893. // Now, let's insert this top-level group back into the table
  894. // as the new_year, with the new_group_id.
  895. $query = "INSERT INTO draft_groups(`group_id`,`group_name`,
  896. `title`,`public_note`,`definition`,`icon_filename`,`catalog_year`,
  897. `priority`,`delete_flag`,`data_entry_comment`, `catalog_repeat`,school_id)
  898. VALUES (?,?,?,?,?,?,?,?,?,?,?,?) ";
  899. $res2 = db_query($query, $new_group_id,$db_group_name,$db_title,$db_public_note,
  900. $db_definition,$db_icon_filename,$new_year,
  901. $db_priority,$db_delete_flag,$db_data_entry_comment,$db_catalog_repeat,$db_school_id);
  902. // Okay, now we need to go through the requirements for the group, and copy
  903. // those over to the new_year.
  904. $res3 = db_query("SELECT * FROM draft_group_requirements
  905. WHERE `group_id`='$db_group_id' ");
  906. while($cur3 = db_fetch_array($res3))
  907. {
  908. extract($cur3, 3, "db3");
  909. $child_group_id = 0;
  910. // Was there a child_group (a branch)? If so, we need to copy that
  911. // over too, with a new child_group_id.
  912. if ($db3_child_group_id > 0)
  913. {
  914. // First, create the child group...
  915. $new_sub_group_id = $db->request_new_group_id();
  916. $subgroup_id_array[$db3_child_group_id] = $new_sub_group_id;
  917. $res4 = db_query("SELECT * FROM draft_group_requirements
  918. WHERE `group_id`='$db3_child_group_id' ");
  919. while($cur4 = db_fetch_array($res4))
  920. {
  921. extract($cur4, 3, "db4");
  922. $res5 = db_query("INSERT INTO draft_group_requirements
  923. (`group_id`,`course_id`,`course_min_grade`,
  924. `course_repeats`,`attributes`,`data_entry_value`)
  925. VALUES (?,?,?,?,?,?) ",
  926. $new_sub_group_id,$db4_course_id,
  927. $db4_course_min_grade,$db4_course_repeats,$db4_attributes,
  928. $db4_data_entry_value);
  929. }
  930. // Now, add the replace the db3_child_group_id with this new id
  931. // so it will get added as a requirement.
  932. $child_group_id = $new_sub_group_id;
  933. }
  934. // Add the row into the table...
  935. $res5 = db_query("INSERT INTO draft_group_requirements
  936. (`group_id`,`course_id`,`course_min_grade`,
  937. `course_repeats`,`attributes`,`data_entry_value`,`child_group_id`)
  938. VALUES (?,?,?,?,?,?,?) ",
  939. array($new_group_id,$db3_course_id,
  940. $db3_course_min_grade,$db3_course_repeats,$db3_attributes,
  941. $db3_data_entry_value,$child_group_id));
  942. }
  943. }
  944. // Store what groups we are working on, for other modules.
  945. $form_state['groups'] = $group_id_array;
  946. //////////////////////// COPY DEGREES ///////////////////////////////////////////
  947. // Now, on to transfering the degrees.
  948. // We will have to use the groupIDArray we constructed earlier, which
  949. // looks like $arr[old_id] = new_id.
  950. // Do the tracks first, since they are easier and straight forward...
  951. $res = db_query("SELECT * FROM draft_degree_tracks WHERE `catalog_year`='$old_year' ");
  952. while ($cur = db_fetch_array($res))
  953. {
  954. extract($cur, 3, "db");
  955. $res2 = db_query("INSERT INTO draft_degree_tracks
  956. (`catalog_year`,`major_code`,`track_code`,`track_title`,
  957. `track_short_title`,`track_description`,school_id)
  958. VALUES
  959. (?,?,?,?,?,?,?) ",
  960. $new_year,$db_major_code,$db_track_code,$db_track_title,
  961. $db_track_short_title,$db_track_description,$db_school_id);
  962. }
  963. // Now, let's do the degrees themselves.
  964. $res = db_query("SELECT * FROM draft_degrees WHERE `catalog_year`='$old_year' ");
  965. while ($cur = db_fetch_array($res))
  966. {
  967. extract($cur, 3, "db");
  968. $new_degree_id = $db->request_new_degree_id();
  969. // Store what degrees we are working on, for other modules.
  970. $form_state['degrees'][] = array(
  971. 'src' => $db_degree_id,
  972. 'src_catalog_year' => $old_year,
  973. 'school_id' => $db_school_id,
  974. 'dest' => $new_degree_id,
  975. 'dest_major_code' => $db_major_code,
  976. 'dest_catalog_year' => $new_year,
  977. );
  978. // add in the top-level degree to the table.
  979. $res2 = db_query("INSERT INTO draft_degrees
  980. (degree_id, major_code, degree_type, degree_level, degree_class, title,
  981. semester_titles_csv, catalog_year, exclude, public_note,
  982. allow_dynamic, advising_weight, override_degree_hours, min_tracks, max_tracks, default_tracks, track_selection_config, school_id)
  983. VALUES
  984. (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  985. ", $new_degree_id,$db_major_code,$db_degree_type, $db_degree_level, $db_degree_class, $db_title,
  986. $db_semester_titles_csv, $new_year, $db_exclude, $db_public_note,
  987. $db_allow_dynamic, $db_advising_weight, $db_override_degree_hours, $db_min_tracks, $db_max_tracks, $db_default_tracks, $db_track_selection_config,$db_school_id);
  988. // now, pull out all of the degree_requirements.
  989. $res3 = db_query("SELECT * FROM draft_degree_requirements
  990. WHERE degree_id = ? ", array($db_degree_id));
  991. while($cur3 = db_fetch_array($res3))
  992. {
  993. extract($cur3, 3, "db3");
  994. // If there is a required group, we must convert it to the
  995. // new groupID !
  996. $required_group_id = intval($db3_group_id);
  997. if ($db3_group_id > 0 && trim($db3_group_id) != "")
  998. {
  999. $required_group_id = $group_id_array[$db3_group_id];
  1000. if ($required_group_id < 1 || $required_group_id == "")
  1001. {
  1002. //die("could not find new group for $old_year $db3_group_id! Group id is $required_group_id");
  1003. fp_add_message(t("Couldn't find the specified group with ID $db3_group_id in catalog year $old_year, required by degree with ID $db_degree_id ($db_major_code). The group was possibly deleted?
  1004. Be aware that any degrees in the new year will be missing this group requirement."), 'error');
  1005. }
  1006. }
  1007. $res4 = db_query("INSERT INTO draft_degree_requirements
  1008. (degree_id, semester_num, group_id, group_requirement_type,
  1009. group_hours_required, group_min_hours_allowed, group_min_grade, course_id,
  1010. course_min_grade, course_requirement_type, data_entry_value)
  1011. VALUES
  1012. (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  1013. ", $new_degree_id, $db3_semester_num, $required_group_id, $db3_group_requirement_type,
  1014. $db3_group_hours_required, $db3_group_min_hours_allowed, $db3_group_min_grade, $db3_course_id,
  1015. $db3_course_min_grade, $db3_course_requirement_type, $db3_data_entry_value);
  1016. }
  1017. }
  1018. // TODO: run other modules' hooks for duplication, again, as one of the batch operations
  1019. // TODO: hook_admin_duplicate_year($source_year, $destination_year, &$form_state)
  1020. watchdog("admin", "Duplicated all degree/group/courses data from $old_year to $new_year");
  1021. fp_add_message(t("The copy operation is now completed. You may view the new year
  1022. by using the Data Entry links on the admin main menu. Remember, you must
  1023. apply draft changes before they will be visible in FlightPath."));
  1024. }
  1025. /**
  1026. * This is a systems settings form, which lets
  1027. * the user edit advising variabled for FlightPath.
  1028. */
  1029. function admin_advising_settings_form($school_id = 0) {
  1030. $form = array();
  1031. $school_id = intval($school_id);
  1032. $fs = ""; // The field name suffix. We will add this to the end of all of our field names. If this is the default school, leave blank.
  1033. if (module_enabled("schools")) {
  1034. $school_name = schools_get_school_name_for_id($school_id);
  1035. fp_set_title(t("Edit %school school advising settings", array('%school' => $school_name)));
  1036. if ($school_id !== 0) {
  1037. $fs = "~~school_" . $school_id;
  1038. }
  1039. }
  1040. $form['school_id'] = array(
  1041. 'type' => 'hidden',
  1042. 'value' => $school_id,
  1043. );
  1044. $form["available_advising_term_ids" . $fs] = array(
  1045. "type" => "textarea",
  1046. "rows" => 2,
  1047. "label" => t("Available advising term id(s)"),
  1048. "value" => fp_space_csv(variable_get_for_school("available_advising_term_ids", "", $school_id, TRUE)),
  1049. "description" => t("These are the terms for which advisors may advise a student to take
  1050. a course. They should follow the structure established on the
  1051. school data settings page.
  1052. Separate term id's by commas. Ex: 200940, 200941, 200960. Make sure to enter
  1053. in the order that they should appear in FlightPath."),
  1054. );
  1055. $form["advising_term_id" . $fs] = array(
  1056. "type" => "textarea",
  1057. "rows" => 2,
  1058. "label" => t("Default advising term id"),
  1059. "value" => fp_space_csv(variable_get_for_school("advising_term_id", "", $school_id, TRUE)),
  1060. "description" => t("Of the available term ids above, this is the default that FlightPath
  1061. is set to when an advisor logs in. Ex: 200940.
  1062. <br><strong>Only enter one Term ID in this box.</strong>"),
  1063. );
  1064. $form["current_catalog_year" . $fs] = array(
  1065. "type" => "textfield",
  1066. "size" => 10,
  1067. "label" => t("Current catalog year"),
  1068. "value" => variable_get_for_school("current_catalog_year", "", $school_id, TRUE),
  1069. "description" => t("This is the year which What If loads degrees from, as well as other important functions.
  1070. Only change this once you have fully loaded a new catalog year."),
  1071. );
  1072. $form["current_draft_catalog_year" . $fs] = array(
  1073. "type" => "textfield",
  1074. "size" => 10,
  1075. "label" => t("Current DRAFT catalog year"),
  1076. "value" => variable_get_for_school("current_draft_catalog_year", "", $school_id, TRUE),
  1077. "description" => t("While in Draft mode, this is the year which Blank Degree Search loads degrees from. What If
  1078. mode will always use the Current catalog year, set above.
  1079. You may change this while working on a new catalog. It will not affect any other
  1080. users of the system. While not working on a new catalog, set this
  1081. to the same as the Current catalog year."),
  1082. );
  1083. $form["not_released_grades_terms" . $fs] = array(
  1084. "type" => "textarea",
  1085. "rows" => 2,
  1086. "label" => t("NOT released grades terms"),
  1087. "value" => fp_space_csv(variable_get_for_school("not_released_grades_terms", "", $school_id, TRUE)),
  1088. "description" => t("Enter the term_id's, separated by commas,
  1089. which are NOT released and should NOT be visible to either advisors or students.
  1090. Coures in these terms will only show midterm grades or no grades at all.
  1091. Ex: 201240, 201240:S1") . "<br>" . t("If left blank, grades will be visible to
  1092. students and advisors as soon as they appear in the database."),
  1093. );
  1094. return $form;
  1095. }
  1096. /**
  1097. * Convienence function to get semester's default regular name.
  1098. */
  1099. function admin_get_semester_name($semester_num) {
  1100. $semester = new Semester($semester_num);
  1101. $title = $semester->title;
  1102. /**
  1103. $ar = array(t("Freshman Year"), t("Sophomore Year"), t("Junior Year"), t("Senior Year"));
  1104. $s = $ar[$semester_num];
  1105. if ($s == "")
  1106. {
  1107. $s = t("Year") . " " . ($semester_num + 1);
  1108. }
  1109. */
  1110. return $title;
  1111. }
  1112. /**
  1113. * This form lets the user apply draft changes (if they can supply the passcode)
  1114. */
  1115. function admin_apply_draft_changes_form() {
  1116. $form = array();
  1117. $m = 0;
  1118. $form["mark" . $m++] = array(
  1119. "type" => "markup",
  1120. "value" => t("You can use this form to apply your draft changes to the production database, making changes
  1121. to degrees, courses, and groups visible to all users of the system."),
  1122. );
  1123. $form["passcode"] = array(
  1124. "type" => "password",
  1125. "label" => t("For added security, you must enter the Apply Draft Changes password:"),
  1126. "required" => TRUE,
  1127. "description" => t("This is a password set up in FlightPath's System Settings, to provide an extra layer
  1128. of security for this powerful action."),
  1129. );
  1130. $form["submit"] = array(
  1131. "type" => "submit",
  1132. "value" => t("Submit"),
  1133. "spinner" => TRUE,
  1134. "description" => t("Note: This action may take several seconds to complete. Do not close this tab or refresh the browser."),
  1135. "prefix" => "<hr>",
  1136. );
  1137. return $form;
  1138. }
  1139. /**
  1140. * Before we apply changes, make sure the password is correct.
  1141. */
  1142. function admin_apply_draft_changes_form_validate($form, &$form_state) {
  1143. $values = $form_state["values"];
  1144. // Check to make sure they entered the transfer passcode correctly.
  1145. if ($values["passcode"] != variable_get("admin_transfer_passcode", sha1(mt_rand()))) {
  1146. form_error("passcode", t("Sorry, but the password you entered is not correct. Check with the FlightPath administrator
  1147. (or check the admin settings pages) to learn the password."));
  1148. return;
  1149. }
  1150. }
  1151. /**
  1152. * Handles the actual moving of draft courses into production.
  1153. */
  1154. function z__admin_apply_draft_changes_form_submit($form, $form_submit) {
  1155. $values = $form_submit["values"];
  1156. $db = get_global_database_handler();
  1157. $de_catalog_year = admin_get_de_catalog_year();
  1158. // Keep the script from timing out prematurely...
  1159. set_time_limit(99999); // around 27 hours (so it runs a really long time).
  1160. // First, set maintenance mode...
  1161. variable_set("maintenance_mode", TRUE);
  1162. // Okay, so what we gotta do is truncate the draft tables,
  1163. // then copy the draft tables in.
  1164. $table_array = array(
  1165. "courses",
  1166. "degree_requirements",
  1167. "degree_tracks",
  1168. "degrees",
  1169. "group_requirements",
  1170. "groups",
  1171. );
  1172. foreach($table_array as $table_name) {
  1173. $draft_table_name = "draft_$table_name";
  1174. // First, truncate existing...
  1175. $query = "truncate table `$table_name`";
  1176. $res = db_query($query);
  1177. // Now, copy in draft changes...
  1178. $query = "INSERT INTO `$table_name`
  1179. SELECT * FROM `$draft_table_name` ";
  1180. $res = db_query($query);
  1181. }
  1182. $db2 = new DatabaseHandler();
  1183. // Now, we need to go through the draft_instructions table,
  1184. // and perform each instruction one at a time.
  1185. $res = db_query("SELECT * FROM draft_instructions
  1186. ORDER BY `id` ");
  1187. while($cur = db_fetch_array($res))
  1188. {
  1189. $instruction = trim($cur["instruction"]);
  1190. $temp = explode(",",$instruction);
  1191. if (trim($temp[0]) == "update_course_id") {
  1192. $db2->update_course_id(trim($temp[1]), trim($temp[2]), trim($temp[3]));
  1193. }
  1194. if (trim($temp[0]) == "update_course_requirement_from_name") {
  1195. $db2->update_course_requirement_from_name(trim($temp[1]), trim($temp[2]), trim($temp[3]), trim($temp[4]));
  1196. }
  1197. // TODO: Maybe invoke another hook here, to let other modules act on the instruction?
  1198. }
  1199. // Once this is done, truncate the draft_instructions table.
  1200. $res = db_query("TRUNCATE TABLE draft_instructions");
  1201. // Invoke a hook to allow other modules to apply_draft_changes as well
  1202. invoke_hook("apply_draft_changes");
  1203. // Rebuild our course cache file.
  1204. unset($_SESSION['fp_cache_course_inventory_last_generated']);
  1205. if (file_exists(fp_get_files_path() . "/cache_data/courses_serialized.info")) {
  1206. $x = unlink(fp_get_files_path() . "/cache_data/courses_serialized.info");
  1207. if (!$x) {
  1208. fpm("Cannot delete cache_data/courses_serialized.info under custom/files. Permission error or file does not exist?");
  1209. watchdog("system", "Cannot delete cache_data/courses_serialized.info under custom/files. Permission error or file does not exist?", array(), WATCHDOG_ERROR);
  1210. }
  1211. }
  1212. variable_set('cache_course_inventory_last_generated', 0); // reset this so it will be regenerated.
  1213. // Builds new courses cache file on the hard drive.
  1214. system_reload_and_cache_course_inventory();
  1215. // And we are done! Set maintenance mode back to none
  1216. variable_set("maintenance_mode", FALSE);
  1217. // Send emails to notify programmers...
  1218. $notify = variable_get("notify_apply_draft_changes_email_address", "");
  1219. if ($notify != "") {
  1220. mail($notify, "FlightPath Apply Draft Changes", "Someone has applied draft changes to FlightPath, which updated degree plans, groups, and courses.");
  1221. }
  1222. fp_add_message(t("Successfully updated the production database with draft changes. Your changes are now live and visible on production for all users."));
  1223. watchdog("admin", "Draft changes applied.");
  1224. }
  1225. /**
  1226. * We are going to set up a batch operation for apply draft changes, to reduce the chance of it timing out with large
  1227. * amounts of data.
  1228. */
  1229. function admin_apply_draft_changes_form_submit($form, $form_submit) {
  1230. // We are going to keep track of all the operations we need to do in this $ops array.
  1231. $ops = array();
  1232. $ops[]['truncate_prod_and_copy'] = 'courses';
  1233. $ops[]['truncate_prod_and_copy'] = 'degree_requirements';
  1234. $ops[]['truncate_prod_and_copy'] = 'degree_tracks';
  1235. $ops[]['truncate_prod_and_copy'] = 'degrees';
  1236. $ops[]['truncate_prod_and_copy'] = 'group_requirements';
  1237. $ops[]['truncate_prod_and_copy'] = 'groups';
  1238. $ops[]['perform_draft_instructions'] = TRUE;
  1239. $ops[]['invoke_apply_draft_changes'] = TRUE;
  1240. $ops[]['rebuild_cache_course_inventory'] = TRUE;
  1241. // Okay, set up the batch....
  1242. $batch = array(
  1243. "operation" => array("admin_apply_draft_changes_perform_batch_operation", array($ops)),
  1244. "title" => t("Apply draft changes"),
  1245. "success_message" => t("Draft changes have been applied successfully."),
  1246. "progress_message" => "Working on @current of @total operations...",
  1247. "display_percent" => TRUE,
  1248. );
  1249. // Set the batch...
  1250. batch_set($batch);
  1251. }
  1252. function admin_apply_draft_changes_perform_batch_operation(&$batch, $ops) {
  1253. // if this is our first time through, let's init our values.
  1254. if (!isset($batch["results"]["total"])) {
  1255. // Our first time through. Let's start up.
  1256. $batch["results"]["total"] = count($ops);
  1257. $batch["results"]["current"] = 0;
  1258. $batch["results"]["finished"] = FALSE;
  1259. // First, set maintenance mode...
  1260. variable_set("maintenance_mode", TRUE);
  1261. }
  1262. $op_command = key($ops[$batch['results']['current']]);
  1263. $op_val = $ops[$batch['results']['current']][$op_command];
  1264. if ($op_command == 'truncate_prod_and_copy') {
  1265. $table_name = $op_val;
  1266. $draft_table_name = "draft_$table_name";
  1267. // First, truncate existing...
  1268. $query = "truncate table `$table_name`";
  1269. $res = db_query($query);
  1270. // Now, copy in draft changes...
  1271. $query = "INSERT INTO `$table_name`
  1272. SELECT * FROM `$draft_table_name` ";
  1273. $res = db_query($query);
  1274. } // truncate prod and copy
  1275. /////////////
  1276. /////////////
  1277. if ($op_command == 'perform_draft_instructions') {
  1278. $db = get_global_database_handler();
  1279. // Now, we need to go through the draft_instructions table,
  1280. // and perform each instruction one at a time.
  1281. $res = db_query("SELECT * FROM draft_instructions
  1282. ORDER BY `id` ");
  1283. while($cur = db_fetch_array($res))
  1284. {
  1285. $instruction = trim($cur["instruction"]);
  1286. $temp = explode(",",$instruction);
  1287. if (trim($temp[0]) == "update_course_id") {
  1288. $db->update_course_id(trim($temp[1]), trim($temp[2]), trim($temp[3]));
  1289. }
  1290. if (trim($temp[0]) == "update_course_requirement_from_name") {
  1291. $db->update_course_requirement_from_name(trim($temp[1]), trim($temp[2]), trim($temp[3]), trim($temp[4]));
  1292. }
  1293. // TODO: Maybe invoke another hook here, to let other modules act on the instruction?
  1294. } // while
  1295. // Once this is done, truncate the draft_instructions table.
  1296. $res = db_query("TRUNCATE TABLE draft_instructions");
  1297. } // perform_draft_instructions
  1298. /////////////////
  1299. /////////////////
  1300. if ($op_command == 'invoke_apply_draft_changes') {
  1301. // Invoke a hook to allow other modules to apply_draft_changes as well
  1302. invoke_hook("apply_draft_changes");
  1303. }
  1304. ///////////////
  1305. ///////////////
  1306. if ($op_command == 'rebuild_cache_course_inventory') {
  1307. // Rebuild our course cache file.
  1308. unset($_SESSION['fp_cache_course_inventory_last_generated']);
  1309. if (file_exists(fp_get_files_path() . "/cache_data/courses_serialized.info")) {
  1310. $x = unlink(fp_get_files_path() . "/cache_data/courses_serialized.info");
  1311. if (!$x) {
  1312. fpm("Cannot delete cache_data/courses_serialized.info under custom/files. Permission error or file does not exist?");
  1313. watchdog("system", "Cannot delete cache_data/courses_serialized.info under custom/files. Permission error or file does not exist?", array(), WATCHDOG_ERROR);
  1314. }
  1315. }
  1316. variable_set('cache_course_inventory_last_generated', 0); // reset this so it will be regenerated.
  1317. // Builds new courses cache file on the hard drive.
  1318. system_reload_and_cache_course_inventory();
  1319. } // rebuild cache course inventory
  1320. $batch['results']['current']++;
  1321. // Have we finished?
  1322. if ($batch["results"]["current"] >= $batch["results"]["total"]) {
  1323. $batch["results"]["finished"] = TRUE;
  1324. // Send emails to notify programmers
  1325. $notify = variable_get("notify_apply_draft_changes_email_address", "");
  1326. if ($notify != "") {
  1327. mail($notify, "FlightPath Apply Draft Changes", "Someone has applied draft changes to FlightPath, which updated degree plans, groups, and courses.");
  1328. }
  1329. fp_add_message(t("Successfully updated the production database with draft changes. Your changes are now live and visible on production for all users."));
  1330. watchdog("admin", "Draft changes applied.");
  1331. // Remove maintenance mode...
  1332. variable_set("maintenance_mode", FALSE);
  1333. }
  1334. } // admin_apply_draft_changes_perform_batch_operation
  1335. /**
  1336. * Get the "de_catalog_year" from the REQUEST.
  1337. * If it's not there or invalid, pull it from our system settings.
  1338. */
  1339. function admin_get_de_catalog_year($bool_set_earliest_if_blank = TRUE, $school_id = 0) {
  1340. global $current_student_id;
  1341. $db = get_global_database_handler();
  1342. if ($current_student_id) {
  1343. $school_id = $db->get_school_id_for_student_id($current_student_id);
  1344. }
  1345. $de_catalog_year = @$_REQUEST["de_catalog_year"];
  1346. if ($bool_set_earliest_if_blank) {
  1347. if (!$de_catalog_year || $de_catalog_year < variable_get_for_school("earliest_catalog_year", 2006, $school_id)) {
  1348. $de_catalog_year = variable_get_for_school("earliest_catalog_year", 2006, $school_id);
  1349. }
  1350. }
  1351. return $de_catalog_year;
  1352. }
  1353. /**
  1354. * This is an implementation of hook_menu_handle_replacement_pattern.
  1355. * It will search for and replace replacement patterns which we are aware of it in $str.
  1356. */
  1357. function admin_menu_handle_replacement_pattern($str) {
  1358. if (!$str) $str = ""; // Compat for PHP 8.2, force it to be a string if it was NULL or FALSE.
  1359. if (strpos($str, "%DE_CATALOG_YEAR%") !== 0) {
  1360. // It contains this replacement pattern!
  1361. $str = str_replace("%DE_CATALOG_YEAR%", admin_get_de_catalog_year(), $str);
  1362. }
  1363. if (strpos($str, "%SEV_FILTER%") !== 0) {
  1364. // It contains this replacement pattern!
  1365. $sev_filter = (string) @$_GET["sev_filter"];
  1366. $str = str_replace("%SEV_FILTER%", $sev_filter, $str);
  1367. }
  1368. if (strpos($str, "%TYPE_FILTER%") !== 0) {
  1369. // It contains this replacement pattern!
  1370. $type_filter = (string) @$_GET["type_filter"];
  1371. $str = str_replace("%TYPE_FILTER%", $type_filter, $str);
  1372. }
  1373. if (strpos($str, "%PAGE%") !== 0) {
  1374. // It contains this replacement pattern!
  1375. $page = "";
  1376. if (isset($_GET['page']) && !is_array($_GET["page"]) && !is_object($_GET['page'])) {
  1377. $page = (string) $_GET["page"];
  1378. }
  1379. $str = str_replace("%PAGE%", $page, $str);
  1380. }
  1381. return $str;
  1382. }
  1383. function admin_perm() {
  1384. return array(
  1385. "can_access_admin_tools" => array(
  1386. "title" => t("Access Admin Tools"),
  1387. "description" => t("Allow the user to access the Admin Tools screen."),
  1388. ),
  1389. "can_access_admin" => array(
  1390. "title" => t("Access administrative console"),
  1391. "description" => t("This is a powerful permission! This allows a
  1392. user to access the 'admin console' for FlightPath."),
  1393. ),
  1394. "can_edit_urgent_message" => array(
  1395. "title" => t("Edit urgent message"),
  1396. "description" => t("The user may edit the 'Urgent Message' which appears at the top of every page, if set."),
  1397. ),
  1398. "can_access_data_entry" => array(
  1399. "title" => t("Access Data Entry"),
  1400. "description" => t("The user can access (view) the data-entry portion of the admin console. Degree plans, groups, and courses."),
  1401. ),
  1402. "can_edit_data_entry" => array(
  1403. "title" => t("Edit Data Entry"),
  1404. "description" => t("This is a powerful permission! The user can edit degree plans, groups, and courses."),
  1405. ),
  1406. "can_delete_data_entry" => array(
  1407. "title" => t("Delete Data Entry items"),
  1408. "description" => t("This is a VERY powerful permission! The user can delete degree plans, groups, and courses."),
  1409. ),
  1410. "can_view_advanced" => array(
  1411. "title" => t("View advanced"),
  1412. "description" => t("The user may see advanced information on-screen, for example, internal ID numbers for degrees and courses."),
  1413. ),
  1414. "can_apply_draft_changes" => array(
  1415. "title" => t("Apply draft changes"),
  1416. "description" => t("The user may move draft changes into production."),
  1417. ),
  1418. "can_edit_advising_settings" => array(
  1419. "title" => t("Edit advising settings"),
  1420. "description" => t("The user may edit advising settings, like available term IDs and the current catalog year."),
  1421. ),
  1422. "display_watchdog" => array(
  1423. "title" => t("View watchdog (log) entries"),
  1424. "description" => t("The user may view the recent watchdog log entries. This represents a security concern, so give this only to trusted users."),
  1425. ),
  1426. );
  1427. }
  1428. /**
  1429. * Meant to be fed into "fp_system_settings_form()", this function
  1430. * returns an array which will automatically save values to our "variables" table.
  1431. */
  1432. function admin_urgent_message_form() {
  1433. $form = array();
  1434. $form["mark_top"] = array(
  1435. "type" => "markup",
  1436. "value" => "<p>" . t("Any message you enter here will be displayed at the top of every page <b>for all users</b> in the system.
  1437. This is used to alert users that the system is about to be taken offline, or any other urgently-needed information.") . "</p>",
  1438. );
  1439. $form["urgent_msg"] = array(
  1440. "type" => "textarea",
  1441. "label" => "Global Urgent Message:",
  1442. "value" => variable_get("urgent_msg", ""),
  1443. 'description' => t("To delete this message, simple delete all the text in this box and save."),
  1444. );
  1445. return $form;
  1446. }
  1447. /**
  1448. * Display the details of a particular watchdog entry, specified by its table id.
  1449. */
  1450. function admin_display_watchdog_entry($wid) {
  1451. $rtn = "";
  1452. fp_add_css(fp_get_module_path("admin") . '/css/admin.css');
  1453. $severity_array = array(
  1454. 5 => "notice",
  1455. 1 => "alert",
  1456. 3 => "error",
  1457. 7 => "debug",
  1458. );
  1459. $res = db_query("SELECT * FROM watchdog WHERE wid = '?' ", $wid);
  1460. $cur = db_fetch_object($res);
  1461. $msg = t($cur->message, unserialize($cur->variables));
  1462. $severity = $severity_array[$cur->severity];
  1463. $when = format_date(convert_time($cur->timestamp), "short");
  1464. // Display
  1465. $rtn .= "
  1466. <br>
  1467. <div class='watchdog-entry'>
  1468. <div class='watchdog-field'>
  1469. <label>ID:</label>
  1470. $cur->wid
  1471. </div>
  1472. <div class='watchdog-field'>
  1473. <label>Type:</label>
  1474. $cur->type
  1475. </div>
  1476. <div class='watchdog-field'>
  1477. <label>Time:</label>
  1478. $when ($cur->timestamp)
  1479. </div>
  1480. <div class='watchdog-field'>
  1481. <label>Severity:</label>
  1482. $severity
  1483. </div>
  1484. <div class='watchdog-field'>
  1485. <label>User:</label>
  1486. $cur->user_name | id: $cur->user_id | cwid: $cur->cwid | is_student: $cur->is_student | is_faculty: $cur->is_faculty
  1487. </div>
  1488. <div class='watchdog-field'>
  1489. <label>IP:</label>
  1490. $cur->ip
  1491. </div>
  1492. <div class='watchdog-field'>
  1493. <label>Location:</label>
  1494. " . str_replace("&curren", "&amp;curren", fp_trim($cur->location)) . "
  1495. </div>
  1496. <div class='watchdog-field'>
  1497. <label>Ref:</label>
  1498. " . str_replace("&curren", "&amp;curren", fp_trim($cur->referer)) . "
  1499. </div>
  1500. <hr>
  1501. <div class='watchdog-field'>
  1502. <label class='block'>Message:</label>
  1503. $msg
  1504. </div>
  1505. <div class='watchdog-field'>
  1506. <label class='block'>Extra:</label>
  1507. $cur->extra_data
  1508. </div>
  1509. </div>
  1510. ";
  1511. return $rtn;
  1512. }
  1513. /**
  1514. * Displays recent watchdog entries, from the watchdog table
  1515. *
  1516. */
  1517. function z__admin_display_watchdog() {
  1518. fp_add_css(fp_get_module_path("admin") . '/css/admin.css');
  1519. $rtn = "";
  1520. $rtn .= "<p>View recent watchdog entries</p>";
  1521. $severity_array = array(
  1522. 5 => "notice",
  1523. 1 => "alert",
  1524. 3 => "error",
  1525. 7 => "debug",
  1526. );
  1527. $results_per_page = 50;
  1528. $type_line = $severity_line = $limit_start = "";
  1529. @$sev_filter = $_GET["sev_filter"];
  1530. @$type_filter = $_GET["type_filter"];
  1531. @$page = $_GET["page"];
  1532. $limit_start = 0;
  1533. if ($page != "" && is_numeric($page)) {
  1534. $limit_start = $results_per_page * ($page - 1);
  1535. }
  1536. else {
  1537. $page = 1;
  1538. }
  1539. // Filters:
  1540. $rtn .= "<form method='GET' action='" . fp_url("admin/config/watchdog") . "' class='watchdog-filters'>
  1541. ";
  1542. $rtn .= "Filter by:
  1543. <span class='type-filter'>
  1544. Type:
  1545. <select name='type_filter'>
  1546. <option value=''>-Any-</option>";
  1547. $res = db_query("SELECT distinct(type) as type
  1548. FROM watchdog
  1549. ORDER BY type");
  1550. while ($cur = db_fetch_object($res)) {
  1551. $sel = ($type_filter == $cur->type) ? "selected" : "";
  1552. $rtn .= "<option value='$cur->type' $sel>$cur->type</option>";
  1553. }
  1554. $rtn .= "</select>
  1555. </span>";
  1556. $rtn .= "
  1557. <span class='severity-filter'>
  1558. Severity:
  1559. <select name='sev_filter'>
  1560. <option value=''>-Any-</option>";
  1561. foreach ($severity_array as $key => $value) {
  1562. $sel = "";
  1563. if ($sev_filter == $key) $sel = "selected";
  1564. $rtn .= "<option value='$key' $sel>$value</option>";
  1565. }
  1566. $rtn .= "</select>
  1567. </span>";
  1568. $rtn .= "<input type='submit' value='&gt;'>";
  1569. // Hack if clean URLs are not enabled:
  1570. $rtn .= "<input type='hidden' name='q' value='admin/config/watchdog'>";
  1571. $rtn .= "</form>";
  1572. $params = array();
  1573. if (@$_GET["type_filter"] != "") {
  1574. //$type_line = " AND type = '" . mysql_real_escape_string($_GET["type_filter"]) . "' ";
  1575. $type_line = " AND `type` = :type ";
  1576. $params[":type"] = $_GET["type_filter"];
  1577. }
  1578. if (@$_GET["sev_filter"] != "") {
  1579. //$severity_line = " AND severity = '" . mysql_real_escape_string($_GET["sev_filter"]) . "' ";
  1580. $severity_line = " AND severity = :sev ";
  1581. $params[":sev"] = $_GET["sev_filter"];
  1582. }
  1583. $pol = "even";
  1584. $rtn .= "<table class='watchdog-table' cellspacing='0' cellpadding='4'>
  1585. <tr>
  1586. <th>ID</th>
  1587. <th>When</th>
  1588. <th>Type</th>
  1589. <th>Msg</th>
  1590. <th>Severity</th>
  1591. <th>User</th>
  1592. </tr>";
  1593. // Okay, let's display the recent watchdog entries.
  1594. $query = "SELECT * FROM watchdog
  1595. WHERE 1
  1596. $type_line
  1597. $severity_line
  1598. ORDER BY wid DESC
  1599. ";
  1600. $res = db_query($query . " LIMIT $limit_start, $results_per_page", $params);
  1601. while ($cur = db_fetch_object($res)) {
  1602. $pol = ($pol == "even") ? "odd" : "even";
  1603. $o_msg = t($cur->message, unserialize($cur->variables));
  1604. $o_type = $cur->type;
  1605. // shorten msg if necessary
  1606. $msg = substr(strip_tags($o_msg), 0, 130);
  1607. if ($msg != $o_msg) {
  1608. $msg = trim($msg) . "...";
  1609. }
  1610. $type = substr($o_type, 0, 20);
  1611. if ($type != $o_type) {
  1612. $type = trim($type) . "...";
  1613. }
  1614. $severity = $severity_array[$cur->severity];
  1615. $when = format_date(convert_time($cur->timestamp), "short");
  1616. $rtn .= "
  1617. <tr class='row-$pol row-$severity'>
  1618. <td valign='top'>" . l($cur->wid, "admin/config/watchdog/$cur->wid", "sev_filter=$sev_filter&type_filter=$type_filter&page=$page") . "</td>
  1619. <td valign='top'>$when</td>
  1620. <td valign='top'>$type</td>
  1621. <td valign='top'>$msg</td>
  1622. <td valign='top'>$severity</td>
  1623. <td valign='top'>$cur->user_name</td>
  1624. </tr>
  1625. ";
  1626. }
  1627. $rtn .= "</table>";
  1628. // Now, do the page
  1629. // Figure out the total number of results
  1630. $total = db_result(db_query("SELECT count(wid) as count
  1631. FROM watchdog WHERE 1
  1632. $type_line
  1633. $severity_line", $params));
  1634. // Now, divide by the number of results per page.
  1635. $pages = ceil($total / $results_per_page);
  1636. $base_query = "sev_filter=$sev_filter&type_filter=$type_filter";
  1637. $rtn .= "<div class='fp-pager'>";
  1638. if ($page > 1) {
  1639. $rtn .= "<span class='pager-link pager-first'>" . l("&laquo; first", "admin/config/watchdog", $base_query . "&page=1") . "</span>";
  1640. $rtn .= "<span class='pager-link pager-prev'>" . l("&lt; prev", "admin/config/watchdog", $base_query . "&page=" . ($page - 1)) . "</span>";
  1641. }
  1642. else {
  1643. $rtn .= "<span class='pager-link pager-first'>&laquo; first</span>";
  1644. $rtn .= "<span class='pager-link pager-prev'>&lt; prev</span>";
  1645. }
  1646. // page numbers here
  1647. // Let's get the previous X page numbers, and next X (if possible)
  1648. $start_page_num = $page - 5;
  1649. if ($start_page_num < 1) $start_page_num = 1;
  1650. $end_page_num = $page + 5;
  1651. if ($end_page_num > $pages) $end_page_num = $pages;
  1652. if ($start_page_num > 1) {
  1653. $rtn .= "<span class='pager-elip'>...</span>";
  1654. }
  1655. for ($t = $start_page_num; $t <= $end_page_num; $t++) {
  1656. if ($page == $t) {
  1657. // current page
  1658. $rtn .= "<span class='pager-link pager-number pager-current'>$t</span>";
  1659. }
  1660. else {
  1661. $rtn .= "<span class='pager-link pager-number'>" . l($t, "admin/config/watchdog", $base_query . "&page=$t") . "</span>";
  1662. }
  1663. }
  1664. if ($end_page_num < $pages) {
  1665. $rtn .= "<span class='pager-elip'>...</span>";
  1666. }
  1667. if ($page < $pages) {
  1668. $rtn .= "<span class='pager-link pager-next'>" . l("next &gt;", "admin/config/watchdog", $base_query . "&page=" . ($page + 1)) . "</span>";
  1669. $rtn .= "<span class='pager-link pager-last'>" . l("last &raquo;", "admin/config/watchdog", $base_query . "&page=$pages") . "</span>";
  1670. }
  1671. else {
  1672. $rtn .= "<span class='pager-link pager-next'>next &gt;</span>";
  1673. $rtn .= "<span class='pager-link pager-last'>last &raquo;</span>";
  1674. }
  1675. $rtn .= "</div>";
  1676. return $rtn;
  1677. }
  1678. function admin_display_watchdog() {
  1679. fp_add_css(fp_get_module_path("admin") . '/css/admin.css');
  1680. $rtn = "";
  1681. $rtn .= "<p>View recent watchdog entries</p>";
  1682. $severity_array = array(
  1683. 5 => "notice",
  1684. 1 => "alert",
  1685. 3 => "error",
  1686. 7 => "debug",
  1687. );
  1688. $results_per_page = 50;
  1689. $type_line = $severity_line = $limit_start = "";
  1690. @$sev_filter = $_GET["sev_filter"];
  1691. @$type_filter = $_GET["type_filter"];
  1692. @$page = intval($_GET["page"]);
  1693. $limit_start = 0;
  1694. if ($page > 0) {
  1695. $limit_start = $results_per_page * ($page - 1);
  1696. }
  1697. // Filters:
  1698. $rtn .= "<form method='GET' action='" . fp_url("admin/config/watchdog") . "' class='watchdog-filters'>
  1699. ";
  1700. $rtn .= "Filter by:
  1701. <span class='type-filter'>
  1702. Type:
  1703. <select name='type_filter'>
  1704. <option value=''>-Any-</option>";
  1705. $res = db_query("SELECT distinct(type) as type
  1706. FROM watchdog
  1707. ORDER BY type");
  1708. while ($cur = db_fetch_object($res)) {
  1709. $sel = ($type_filter == $cur->type) ? "selected" : "";
  1710. $rtn .= "<option value='$cur->type' $sel>$cur->type</option>";
  1711. }
  1712. $rtn .= "</select>
  1713. </span>";
  1714. $rtn .= "
  1715. <span class='severity-filter'>
  1716. Severity:
  1717. <select name='sev_filter'>
  1718. <option value=''>-Any-</option>";
  1719. foreach ($severity_array as $key => $value) {
  1720. $sel = "";
  1721. if ($sev_filter == $key) $sel = "selected";
  1722. $rtn .= "<option value='$key' $sel>$value</option>";
  1723. }
  1724. $rtn .= "</select>
  1725. </span>";
  1726. $rtn .= "<input type='submit' value='&gt;'>";
  1727. // Hack if clean URLs are not enabled:
  1728. $rtn .= "<input type='hidden' name='q' value='admin/config/watchdog'>";
  1729. $rtn .= "</form>";
  1730. $params = array();
  1731. if (@$_GET["type_filter"] != "") {
  1732. //$type_line = " AND type = '" . mysql_real_escape_string($_GET["type_filter"]) . "' ";
  1733. $type_line = " AND `type` = :type ";
  1734. $params[":type"] = $_GET["type_filter"];
  1735. }
  1736. if (@$_GET["sev_filter"] != "") {
  1737. //$severity_line = " AND severity = '" . mysql_real_escape_string($_GET["sev_filter"]) . "' ";
  1738. $severity_line = " AND severity = :sev ";
  1739. $params[":sev"] = $_GET["sev_filter"];
  1740. }
  1741. $pol = "even";
  1742. $table_headers = array();
  1743. $table_headers[] = array("label" => "ID", "field" => "wid");
  1744. $table_headers[] = array("label" => "When", "field" => "a.timestamp");
  1745. $table_headers[] = array("label" => "Type", "field" => "a.type");
  1746. $table_headers[] = array("label" => "Msg");
  1747. $table_headers[] = array("label" => "Severity", "field" => "a.severity");
  1748. $table_headers[] = array("label" => "User", "field" => "user_name");
  1749. // Set our initial sort, if none is already set.
  1750. theme_table_header_sortable_set_initial_sort("wid", 'DESC');
  1751. $rtn .= "<table class='watchdog-table' cellspacing='0' cellpadding='4'>";
  1752. // Draw our our table headers, with links....
  1753. $rtn .= theme_table_header_sortable($table_headers);
  1754. // Get our order by clause based on selected table header, if any.
  1755. $order_by = theme_table_header_sortable_order_by($table_headers);
  1756. $res = pager_query("SELECT * FROM watchdog a
  1757. WHERE 1
  1758. $type_line
  1759. $severity_line
  1760. $order_by", $params, 50, 0, "SELECT COUNT(wid) FROM watchdog a
  1761. WHERE 1
  1762. $type_line
  1763. $severity_line
  1764. $order_by", $params);
  1765. while ($cur = db_fetch_object($res)) {
  1766. $pol = ($pol == "even") ? "odd" : "even";
  1767. $o_msg = t($cur->message, unserialize($cur->variables));
  1768. $o_type = $cur->type;
  1769. // shorten msg if necessary
  1770. $msg = substr(strip_tags($o_msg), 0, 130);
  1771. if ($msg != $o_msg) {
  1772. $msg = trim($msg) . "...";
  1773. }
  1774. $type = substr($o_type, 0, 20);
  1775. if ($type != $o_type) {
  1776. $type = trim($type) . "...";
  1777. }
  1778. $severity = $severity_array[$cur->severity];
  1779. $when = format_date(convert_time($cur->timestamp), "short");
  1780. $rtn .= "
  1781. <tr class='row-$pol row-$severity'>
  1782. <td valign='top'>" . l($cur->wid, "admin/config/watchdog/$cur->wid", "sev_filter=$sev_filter&type_filter=$type_filter&page=$page") . "</td>
  1783. <td valign='top'>$when</td>
  1784. <td valign='top'>$type</td>
  1785. <td valign='top'>$msg</td>
  1786. <td valign='top'>$severity</td>
  1787. <td valign='top'>$cur->user_name</td>
  1788. </tr>
  1789. ";
  1790. }
  1791. $rtn .= "</table>";
  1792. // Display the pager that was generated by the pager_query above!
  1793. $rtn .= theme_pager();
  1794. return $rtn;
  1795. } // admin display watchdog
  1796. /**
  1797. * This is the "main" page for the admin module. It's what the user
  1798. * first sees when the click to go to the Admin page.
  1799. */
  1800. function admin_display_main() {
  1801. // Use default_school.
  1802. $de_catalog_year = admin_get_de_catalog_year(FALSE, 0);
  1803. // Has the system cron been run recently?
  1804. $cron_last_run = variable_get("cron_last_run", 0);
  1805. if ($cron_last_run < strtotime("NOW -7 DAYS")) {
  1806. // Warn admin that they need to have cron set up! It's been over a week!
  1807. fpm(t("Your system's cron process hasn't run in over a week. In order for FlightPath
  1808. to continue to function properly, a cron process much be configured.
  1809. You may @run_link or see the @status_link page for instructions.",
  1810. array("@status_link" => l(t("System status"), "admin/config/status"),
  1811. "@run_link" => l(t("run cron now"), "admin/config/run-cron"))));
  1812. }
  1813. $rtn = "";
  1814. fp_add_css(fp_get_module_path("admin") . "/css/admin.css");
  1815. fp_add_js(fp_get_module_path("admin") . "/js/admin.js");
  1816. $rtn .= "<table class='fp-semester-table admin-display-main-table' cellpadding='5'>
  1817. <tr>
  1818. <td valign='top' class='system-configuration-left'>
  1819. " . fp_render_menu_block(t("System Configuration"), "admin/config") . "
  1820. </td>
  1821. <td valign='top' class='advising-settings-right'>
  1822. ";
  1823. // Advising Settings
  1824. $rtn .= fp_render_section_title("Advising Settings", "admin-advising-settings");
  1825. $defs = array(0 => '');
  1826. if (module_enabled("schools")) {
  1827. $defs = schools_get_school_definitions();
  1828. }
  1829. foreach ($defs as $school_id => $school_name) {
  1830. $rtn .= "<div class='admin-advising-settings'><!--SCHOOL_NAME-->
  1831. <ul>
  1832. <li>" . t("Available terms for advising: %v", array("%v" => fp_space_csv(variable_get_for_school("available_advising_term_ids", "", $school_id)))) . "</li>
  1833. <li>" . t("Default advising term: %v", array("%v" => fp_space_csv(variable_get_for_school("advising_term_id", "", $school_id)))) . "</li>
  1834. <li>" . t("Current catalog year: %v", array("%v" => variable_get_for_school("current_catalog_year", "", $school_id))) . "</li>
  1835. <li>" . t("Current draft catalog year: %v", array("%v" => variable_get_for_school("current_draft_catalog_year", "", $school_id))) . "</li>
  1836. <li>" . t("Not released grades terms: %v", array("%v" => fp_space_csv(variable_get_for_school("not_released_grades_terms", "", $school_id)))) . "</li>
  1837. </ul>";
  1838. $url_suffix = "";
  1839. if (intval($school_id) != 0) {
  1840. $url_suffix .= "/" . $school_id;
  1841. }
  1842. if (user_has_permission("can_edit_advising_settings")) {
  1843. $rtn .= l("<i class='fa fa-pencil'></i> " . t("Edit Advising Settings") . "<!--SCHOOL_EDIT_LINK-->", "admin/edit-advising-settings" . $url_suffix);
  1844. }
  1845. if ($school_name) {
  1846. $rtn = str_replace("<!--SCHOOL_NAME-->", "<label>" . $school_name . "</label>", $rtn);
  1847. $rtn = str_replace("<!--SCHOOL_EDIT_LINK-->", t(" for ") . "<em>$school_name</em>", $rtn);
  1848. }
  1849. $rtn .= "</div>";
  1850. } // foreach
  1851. $rtn .= "</td>
  1852. </tr>";
  1853. $rtn .= "</table><br>"; // close table
  1854. // TODO: Similar to the advising settings, do we just loop for each school?
  1855. $current_catalog_year = variable_get("current_catalog_year", 2006); // TODO: how to figure out school?
  1856. $earliest_catalog_year = variable_get("earliest_catalog_year", 2006); // TODO: how to figure out school?
  1857. if (user_has_permission("can_access_data_entry")) {
  1858. $rtn .= fp_render_section_title("Degree & Course Management", "degree-course-management");
  1859. $rtn .= "<div class='data-entry-cats'>";
  1860. // Have a pulldown here of years, then use javascript to hide/show relavant groups.
  1861. $rtn .= "&nbsp; &nbsp; &nbsp; " . t("Select a catalog year") . ": <select id='data-entry-select-cats' onChange='adminHideDECats();'>";
  1862. $selected_cat = ($de_catalog_year != "") ? $de_catalog_year : $current_catalog_year;
  1863. for ($t = $current_catalog_year +1; $t >= $earliest_catalog_year; $t--) {
  1864. $sel = ($t == $selected_cat) ? "selected" : "";
  1865. $rtn .= "<option value='$t' $sel>$t-" . ($t+1) . "</option>";
  1866. }
  1867. $rtn .= "</select> &nbsp; &nbsp;" . fp_get_js_alert_link(t("Newly duplicated year not showing up?<br><br>Make sure you have the correct 'Current Catalog Year' set under Edit Advising Settings."));
  1868. for ($t = $current_catalog_year +1; $t >= $earliest_catalog_year; $t--) {
  1869. $rtn .= "<ul class='data-entry-for-cat data-entry-for-cat-$t'>";
  1870. $rtn .= "<li>" . l(t("Degree plans for @year", array("@year" => "$t-" . ($t+1))), "admin/degrees", "de_catalog_year=$t") . "</li>";
  1871. $rtn .= "<li>" . l(t("Groups for @year", array("@year" => "$t-" . ($t+1))), "admin/groups", "de_catalog_year=$t") . "</li>";
  1872. $rtn .= "<li>" . l(t("Courses for @year", array("@year" => "$t-" . ($t+1))), "admin/courses", "de_catalog_year=$t") . "</li>";
  1873. $rtn .= "</ul>";
  1874. }
  1875. if (user_has_permission("can_edit_data_entry")) {
  1876. $rtn .= "<b>" . t("Administrator function:") . "</b><ul>
  1877. <li>" . l(t("Duplicate entire year worth of data to new year"), "admin/duplicate-year") . "</li>
  1878. </ul>";
  1879. }
  1880. $rtn .= "</div>";
  1881. // Draft changes?
  1882. $res = db_query("SELECT * FROM draft_instructions");
  1883. if (db_num_rows($res) > 0) {
  1884. $rtn .= "<div class='draft-changes-waiting-msg'>
  1885. " . t("Draft changes have been made which have yet to be applied.
  1886. When you are ready for your draft changes to appear in
  1887. production, click the link below.") . "</div>";
  1888. }
  1889. $rtn .= "<ul class='data-entry-draft-waiting'>
  1890. <li>" . l(t("Apply draft changes"), "admin/apply-draft-changes") . "</li>
  1891. </ul>";
  1892. }
  1893. return $rtn;
  1894. }

Functions

Namesort ascending Description
z__admin_duplicate_year_form_submit This function should perform the actual copy of data!
z__admin_display_watchdog Displays recent watchdog entries, from the watchdog table
z__admin_apply_draft_changes_form_submit Handles the actual moving of draft courses into production.
admin_urgent_message_form Meant to be fed into "fp_system_settings_form()", this function returns an array which will automatically save values to our "variables" table.
admin_perm
admin_menu_handle_replacement_pattern This is an implementation of hook_menu_handle_replacement_pattern. It will search for and replace replacement patterns which we are aware of it in $str.
admin_menu Implementation of hook_menu
admin_get_semester_name Convienence function to get semester's default regular name.
admin_get_de_catalog_year Get the "de_catalog_year" from the REQUEST. If it's not there or invalid, pull it from our system settings.
admin_duplicate_year_perform_batch_operation The is the batch operation to duplicate from $old_year to $new_year
admin_duplicate_year_form_validate Before we duplicate the year, make sure the password is correct.
admin_duplicate_year_form_submit This function will set up a batch operation so we can duplicate an entire year with less chance of time or memory running out.
admin_duplicate_year_form This form will allow the user to duplicate an entire year's worth of data to a new catalog year.
admin_display_watchdog_entry Display the details of a particular watchdog entry, specified by its table id.
admin_display_watchdog
admin_display_tools_screen This page displays all the tools that the user has access to use.
admin_display_main This is the "main" page for the admin module. It's what the user first sees when the click to go to the Admin page.
admin_cron hook_cron
admin_apply_draft_changes_perform_batch_operation
admin_apply_draft_changes_form_validate Before we apply changes, make sure the password is correct.
admin_apply_draft_changes_form_submit We are going to set up a batch operation for apply draft changes, to reduce the chance of it timing out with large amounts of data.
admin_apply_draft_changes_form This form lets the user apply draft changes (if they can supply the passcode)
admin_advising_settings_form This is a systems settings form, which lets the user edit advising variabled for FlightPath.