student_files.module

This is the student_files module, which will facilitate uploading (securely) files to be associated with student accounts.

File

modules/student_files/student_files.module
View source
  1. <?php
  2. /**
  3. * @file
  4. * This is the student_files module, which will facilitate uploading (securely) files to be associated with student accounts.
  5. */
  6. /**
  7. * Implementation of hook_menu
  8. */
  9. function student_files_menu() {
  10. $items = array();
  11. $items["admin/config/student-files"] = array(
  12. "title" => "Student Files settings",
  13. "description" => "Configure settings related to the student_files module.",
  14. "page_callback" => "fp_render_form",
  15. "page_arguments" => array("student_files_settings_form", "system_settings"),
  16. "access_arguments" => array("administer_student_files"),
  17. "page_settings" => array(
  18. "menu_icon" => fp_get_module_path('system') . "/icons/page_white_stack.png",
  19. "menu_links" => array(
  20. 0 => array(
  21. "text" => "Admin Console",
  22. "path" => "admin-tools/admin",
  23. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  24. ),
  25. ),
  26. ),
  27. "type" => MENU_TYPE_NORMAL_ITEM,
  28. "tab_parent" => "admin-tools/admin",
  29. );
  30. // This will receive uploaded files for a student.
  31. $items["student-files/handle-upload/%"] = array(
  32. "page_callback" => "student_files_handle_upload",
  33. "page_arguments" => array(2),
  34. "access_arguments" => array("upload_student_files"),
  35. "type" => MENU_TYPE_CALLBACK,
  36. );
  37. $items["student-files/handle-download/%/%"] = array(
  38. "page_callback" => "student_files_handle_download",
  39. "page_arguments" => array(2, 3),
  40. "access_callback" => "student_files_user_may_download_student_file",
  41. "access_arguments" => array(2, 3),
  42. "type" => MENU_TYPE_CALLBACK,
  43. );
  44. $items["student-files/handle-delete/%/%"] = array(
  45. "page_callback" => "student_files_handle_delete",
  46. "page_arguments" => array(2, 3),
  47. "access_callback" => "student_files_user_may_delete_student_file",
  48. "access_arguments" => array(2, 3),
  49. "type" => MENU_TYPE_CALLBACK,
  50. );
  51. $items["admin-tools/upload-student-files"] = array(
  52. "title" => "Upload Student Files",
  53. "description" => "Upload files to any student's file area.",
  54. "page_callback" => "fp_render_form",
  55. "page_arguments" => array("student_files_upload_any_student_files_form"),
  56. "access_arguments" => array("upload_any_student_files"),
  57. "page_settings" => array(
  58. "menu_icon" => fp_get_module_path("student_files") . "/css/icons/page_add.png",
  59. "menu_links" => array(
  60. 0 => array(
  61. "text" => t("Admin Tools"),
  62. "path" => "admin-tools",
  63. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  64. ),
  65. ),
  66. ),
  67. "type" => MENU_TYPE_NORMAL_ITEM,
  68. "weight" => 100,
  69. );
  70. return $items;
  71. }
  72. /**
  73. * This is where we can upload (en masse?) to any arbitrary student.
  74. */
  75. function student_files_upload_any_student_files_form() {
  76. $form = array();
  77. // Add our javascript file
  78. fp_add_js(fp_get_module_path("student_files") . "/js/student_files.js");
  79. $form["#attributes"] = array("enctype" => 'multipart/form-data'); // allow the form itself to submit files.
  80. $form["mark_top"] = array(
  81. "value" => t("Use this form to upload files to any student, either based on the filename, or by specifying the student's
  82. CWID below."),
  83. );
  84. $form["student_method"] = array(
  85. "type" => "radios",
  86. "label" => t("Select how the recipient student will be selected:"),
  87. "options" => array(
  88. "filename" => t("Filename - The file(s) you upload must begin with the student's CWID, followed by a _ (underscore). For example:
  89. <em>33312943_new_file.txt</em>"),
  90. "manual" => t("Manual - Enter the student's CWID in the box below. This is the CWID which files will be saved under, regardless of filename."),
  91. ),
  92. "value" => "filename",
  93. "required" => TRUE,
  94. );
  95. $form["manual_cwid"] = array(
  96. "type" => "textfield",
  97. "label" => t("Manual CWID:"),
  98. "description" => t("Only enter a student's CWID if 'Manual' was selected above."),
  99. );
  100. $form["access_type"] = array(
  101. "type" => "radios",
  102. "label" => "Who will be able to see / download the uploaded file(s)?",
  103. "options" => array(
  104. "faculty" => "Faculty - Only faculty or staff users",
  105. "public" => "Any user with access to view the student's files, including the student themselves",
  106. ),
  107. "value" => "faculty",
  108. );
  109. $max_upload = ini_get('upload_max_filesize');
  110. $max_post = ini_get('post_max_size');
  111. $form["student_files"] = array(
  112. "type" => "file",
  113. "label" => "Select file(s):",
  114. "multiple" => TRUE, // allow multiple file uploads
  115. "description" => t("<b>Allowed files:</b> <em>%ext</em>
  116. <br><br>
  117. Note: In your php.ini file, these are the filesize limits in place for any upload here:
  118. <ul>
  119. <li>Upload max filesize: %max_up </li>
  120. <li>POST max size: %max_post </li>
  121. </ul>
  122. If you have problems with uploading multiple files, adjust these values.", array("%max_up" => $max_upload, "%max_post" => $max_post,
  123. "%ext" => strtolower(variable_get("student_files_allowed_extensions", "txt, pdf, doc, docx, xls, xlsx, ppt, pptx, rtf, odt, jpg, jpeg, png, gif, zip, 7z")))),
  124. );
  125. $form["submit_btn"] = array(
  126. "type" => "submit",
  127. "value" => "Submit",
  128. );
  129. return $form;
  130. }
  131. /**
  132. * Validate function.
  133. */
  134. function student_files_upload_any_student_files_form_validate($form, &$form_state) {
  135. $values = $form_state["values"];
  136. $db = get_global_database_handler();
  137. // Re-order the _FILES array to make it easier to work with
  138. $student_files = fp_re_array_files($_FILES["student_files"]);
  139. $form_state["student_files"] = $student_files;
  140. // Make sure if "manual" is selected, that the CWID entered actually exists.
  141. if ($values["student_method"] == "manual") {
  142. $n = @trim($db->get_student_name($values["manual_cwid"]));
  143. if (!$n) {
  144. // Student not found! Or at least their name wasn't found.
  145. form_error("student_method", t("Sorry, the CWID you entered could not be found."));
  146. return;
  147. }
  148. }
  149. // if a filename method selected, make sure a CWID is detectable and valid. Maybe save it to form_state for the _submit function.
  150. // If more than one file, check all the files...
  151. if ($values["student_method"] == "filename") {
  152. $is_empty = TRUE;
  153. foreach ($form_state["student_files"] as $c => $file) {
  154. if (trim($file["name"] == "")) continue;
  155. $is_empty = FALSE;
  156. $temp = explode("_", $file["name"]);
  157. $test_cwid = trim($temp[0]);
  158. $n = @trim($db->get_student_name($test_cwid));
  159. if (!$n) {
  160. // Student not found! Or at least their name wasn't found.
  161. form_error("student_files", t("Sorry, the file named %file either does not begin with a CWID, or the CWID does not match
  162. a current student. Please try again.", array("%file" => $file["name"])));
  163. return;
  164. }
  165. else {
  166. // This IS a valid student. Save the CWID with the form_state to make our lives easier later.
  167. $form_state["student_files"][$c]["cwid"] = $test_cwid;
  168. // Also save the filename where we have stripped off the CWID
  169. $form_state["student_files"][$c]["name"] = str_replace($test_cwid . "_", "", $file["name"]);
  170. }
  171. }
  172. if ($is_empty) {
  173. form_error("student_files", t("No files were selected. Please try again."));
  174. return;
  175. }
  176. } // if student_method = filename
  177. } // validate
  178. /**
  179. * We can assume at this point that eveything is peachy, so let's get to uploading!
  180. */
  181. function student_files_upload_any_student_files_form_submit($form, &$form_state) {
  182. $values = $form_state["values"];
  183. $cwid = @trim($values["manual_cwid"]);
  184. $method = $values["student_method"];
  185. $access_type = $values["access_type"];
  186. foreach ($form_state["student_files"] as $file) {
  187. $use_cwid = $cwid;
  188. if ($method == "filename") {
  189. $use_cwid = $file["cwid"];
  190. }
  191. $file["cwid"] = $use_cwid; // make sure its in there.
  192. // To get it to correctly save, we need to place a value into the $_FILES global array...
  193. $file["access_type"] = $access_type;
  194. // Now, call our upload handler.
  195. student_files_handle_upload($use_cwid, FALSE, $file);
  196. }
  197. // And that's it! We are now finished.
  198. } // submit handler
  199. /**
  200. * Returns TRUE or FALSE if the user has access to download this particular student's file.
  201. */
  202. function student_files_user_may_download_student_file($student_id, $fid) {
  203. global $user;
  204. $files_array = student_files_get_files_for_student($student_id);
  205. $file = @$files_array[$fid];
  206. if ($user->id == 1) return TRUE; // this is the admin user.
  207. // Is this a faculty only file, and the user is a student?
  208. if ($file["access_type"] == "faculty" && $user->is_student == TRUE) {
  209. return FALSE; // nope, can't view it.
  210. }
  211. // Is this a student, and this is a file for THEM?
  212. if ($file["student_id"] == $user->cwid && $file["access_type"] != "faculty") {
  213. return TRUE;
  214. }
  215. // Does this user have access to download advisee's files and is this student someone they are allowed to advise?
  216. if (user_has_permission("download_advising_student_files")) {
  217. // Now, is this user allowed to view THIS student's advising history?
  218. if (advise_can_access_view($student_id)) return TRUE;
  219. }
  220. // All else failed, return FALSE
  221. return FALSE;
  222. }
  223. /*
  224. function student_files_perm() {
  225. return array(
  226. "administer_student_files" => array(
  227. "title" => t("Administer student files settings"),
  228. ),
  229. "upload_any_student_files" => array(
  230. "title" => t("Upload any to student's files"),
  231. "description" => t("This lets the user upload to any student's files, using the student file upload tool on the Main tab."),
  232. ),
  233. "upload_student_files" => array(
  234. "title" => t("Upload student files"),
  235. "description" => t("This permission lets the user upload student files to any student they can normally view the history of.
  236. Files appear on the student's History tab."),
  237. ),
  238. "delete_own_student_files" => array(
  239. "title" => t("Delete own student files that the user uploaded themselves"),
  240. ),
  241. "delete_any_student_files" => array(
  242. "title" => t("Delete ANY student files that were uploaded by anyone"),
  243. ),
  244. "download_own_student_files" => array(
  245. "title" => t("Download own student files"),
  246. "description" => t("Download files for themselves (given to students, for example, but only if they are not faculty-only files.)"),
  247. ),
  248. "download_advising_student_files" => array(
  249. "title" => t("Download files for any student the user can 'View'"),
  250. "description" => t("If this user is also allowed to view the student's View tab, History, etc, then they are allowed to download
  251. files for that student. For example, the student is one of the user's advisees."),
  252. ),
  253. );
  254. }
  255. */
  256. /**
  257. * Returns TRUE or FALSE if the current user is allowed to delete the file.
  258. */
  259. function student_files_user_may_delete_student_file($student_id, $fid) {
  260. global $user;
  261. $files_array = student_files_get_files_for_student($student_id);
  262. $file = @$files_array[$fid];
  263. if ($user->id == 1) return TRUE; // this is the admin user.
  264. // Does this user have access to delete ANY file?
  265. if (user_has_permission("delete_any_student_files")) return TRUE;
  266. // Does this user have permission to delete OWN files, and they uploaded this file?
  267. if (user_has_permission("delete_own_student_files")) {
  268. if ($file["uploaded_by_cwid"] == $user->cwid) {
  269. // Yes, this user is the one who uploaded this file, so yes, they can delete it.
  270. return TRUE;
  271. }
  272. }
  273. // All else failed, so deny
  274. return FALSE;
  275. }
  276. /**
  277. * This actually finds and downloads the file for the user, decrypting if necessary.
  278. */
  279. function student_files_handle_download($student_id, $fid) {
  280. $files_array = student_files_get_files_for_student($student_id);
  281. $file = @$files_array[$fid];
  282. if (!$file) {
  283. display_not_found();
  284. die;
  285. }
  286. // Otherwise, now we proceed.
  287. $file_contents = file_get_contents($file["filepath"] . "/" . $file["filename"]);
  288. if ($file["is_encrypted"] == 1 && function_exists("encryption_decrypt")) {
  289. $file_contents = encryption_decrypt($file_contents);
  290. }
  291. // Okay, now let's spit it out to the browser for download.
  292. header('Content-type: ' . $file["filetype"]);
  293. header('Content-Disposition: attachment; filename="' . $file["original_filename"] . '"');
  294. print $file_contents;
  295. die;
  296. }
  297. function student_files_handle_delete($student_id, $fid) {
  298. // Get the file's information so we can unlink it from the file system.
  299. $files_array = student_files_get_files_for_student($student_id);
  300. $file = @$files_array[$fid];
  301. if (!$file) {
  302. display_not_found();
  303. die;
  304. }
  305. // Otherwise, now we proceed.
  306. if (!unlink($file["filepath"] . "/" . $file["filename"])) {
  307. // Couldn't delete for some reason.
  308. fp_add_message(t("Unable to delete file:") . " " . $file["filepath"] . "/" . $file["filename"] . t("
  309. Possibly a file permission issue on server, or file already deleted. If this problem continues, contact
  310. your server administrator."), "error");
  311. }
  312. else {
  313. // We DID delete sucessfully, let's get rid of it from our db table.
  314. db_query("DELETE FROM student_files WHERE fid = ?", $fid);
  315. fp_add_message(t("File deleted successfully."));
  316. }
  317. // Return to the history page.
  318. fp_goto("history", "current_student_id=$student_id");
  319. }
  320. /**
  321. * Handles the upload of a file which we assume is located at $_FILES["student_file_upload_file"], or the provided $file array.
  322. */
  323. function student_files_handle_upload($student_id, $bool_goto_history_when_done = TRUE, $file = array()) {
  324. global $user;
  325. $system_files_path = $GLOBALS["fp_system_settings"]["file_system_path"];
  326. $access_type = @$file["access_type"];
  327. if (count($file) == 0) {
  328. $file = $_FILES["student_file_upload_file"];
  329. $temp = fp_re_array_files($file);
  330. $file = $temp[0];
  331. $access_type = $_POST["access_type"];
  332. }
  333. $files_path = variable_get("student_files_path", "$system_files_path/custom/files/student_files");
  334. $sub_dir_pattern = variable_get("student_files_sub_dir_pattern", "%year/%student_cwid");
  335. $filename_pattern = variable_get("student_files_filename_pattern", "%student_cwid.%random.%ext");
  336. $encryption = variable_get("student_files_encryption", "yes");
  337. // Let's set up our eventual replacement pattern values.
  338. $r = array();
  339. $r["%year"] = date("Y");
  340. $r["%student_cwid"] = $student_id;
  341. $r["%timestamp"] = time();
  342. $r["%random"] = fp_get_random_string(7);
  343. $original_filename = $file["name"];
  344. $r["%original_filename"] = $original_filename;
  345. $is_encrypted = 0;
  346. $type = $file["type"];
  347. $tmp_name = $file["tmp_name"];
  348. if (trim($tmp_name) == "") {
  349. // No file was selected for upload!
  350. fp_add_message(t("No file was selected for upload. Please try again."), "error");
  351. if ($bool_goto_history_when_done) {
  352. fp_goto("history", "current_student_id=$student_id");
  353. }
  354. return;
  355. }
  356. // Figure out the extension of the original filename.
  357. $temp = explode(".", $original_filename);
  358. $r["%ext"] = $temp[count($temp) - 1];
  359. // Make sure that this extension is allowed.
  360. $allowed_extensions = csv_to_array(strtolower(variable_get("student_files_allowed_extensions", "txt,pdf,doc,docx,xls,xlsx,ppt,pptx,rtf,odt,jpg,jpeg,png,gif,zip,7z")));
  361. if (!in_array(strtolower($r["%ext"]), $allowed_extensions)) {
  362. // Meaning, this extension is not allowed!
  363. fp_add_message(t("Sorry, the file's type/extension (%ext) is not allowed. Please rename or select another file, then try again.", array("%ext" => $original_filename)), "error");
  364. if ($bool_goto_history_when_done) {
  365. fp_goto("history", "current_student_id=$student_id");
  366. }
  367. return;
  368. }
  369. // If we will be encrypting this, then the ext is actually .txt.enc or .pdf.enc. So we know its encrypted.
  370. if (module_enabled("encryption") && $encryption == "yes") {
  371. $r["%ext"] .= ".enc";
  372. }
  373. // Okay, create the replaced strings...
  374. $sub_dir = $filename = "";
  375. foreach ($r as $k => $v) {
  376. $sub_dir_pattern = str_replace($k, $v, $sub_dir_pattern);
  377. $filename_pattern = str_replace($k, $v, $filename_pattern);
  378. }
  379. $sub_dir = $sub_dir_pattern;
  380. $filename = $filename_pattern;
  381. // Okay, now let's make sure we can create the sub_dir if it doesn't already exist.
  382. if (!file_exists($files_path . "/" . $sub_dir)) {
  383. if (!mkdir($files_path . "/" . $sub_dir, 0777, TRUE)) {
  384. fp_add_message(t("Could not upload file because destination directory, %dir, could not be created or its parent
  385. directory is not writable.", array("%dir" => $files_path . "/" . $sub_dir)), "error");
  386. return;
  387. }
  388. }
  389. // If the filename is too long, shorten it. Linux won't allow more than 255 bytes (usually corresponds to chars, depending on file system),
  390. // Windows its 260 chars. Let's be safe and stop at 100 chars + ext.
  391. if (strlen($filename) > 100) {
  392. $filename = substr($filename, 0, 100) . "." . $r["%ext"];
  393. }
  394. // Make sure the filename doesn't already exist. If it does, we add a little more randomness to the end of the file.
  395. if (file_exists($files_path . "/" . $sub_dir . "/" . $filename)) {
  396. while (true) {
  397. $test_filename = $filename . "." . fp_get_random_string(5) . "." . $r["%ext"];
  398. if (!file_exists($files_path . "/" . $sub_dir . "/" . $test_filename)) {
  399. $filename = $test_filename;
  400. break;
  401. }
  402. }
  403. }
  404. // Okay, if we are here we can proceed with the copy.
  405. // if encryption is enabled, we must use the encryption module to do this instead of a simple copy.
  406. if (module_enabled("encryption") && $encryption === "yes" && encryption_get_key()) {
  407. // Yep, we should encrypt this file.
  408. // We need to do that by loading the file into memory, then getting the encrypted version, then writing it
  409. // out to the destination.
  410. $file_contents = file_get_contents($tmp_name);
  411. $enc_file_contents = encryption_encrypt($file_contents);
  412. if (!file_put_contents($files_path . "/" . $sub_dir . "/" . $filename, $enc_file_contents)) {
  413. fp_add_message(t("Could not upload file. Possibly because of permission issues on the destination directory,
  414. the disk is full, or some other reason."), "error");
  415. return;
  416. }
  417. $is_encrypted = 1;
  418. }
  419. else {
  420. // No encryption-- just copy it the traditional way.
  421. if (!copy($tmp_name, $files_path . "/" . $sub_dir . "/" . $filename)) {
  422. fp_add_message(t("Could not upload file. Possibly because of permission issues on the destination directory,
  423. the disk is full, or some other reason."), "error");
  424. return;
  425. }
  426. }
  427. // Okay, write to our database table our values.
  428. db_query("INSERT INTO student_files(student_id, original_filename, filepath, filename, filetype, uploaded_by_uid, uploaded_by_cwid, is_encrypted, posted, access_type)
  429. VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $student_id, $original_filename, $files_path . '/' . $sub_dir, $filename, $type,
  430. $user->id, $user->cwid, $is_encrypted, time(), $access_type);
  431. // Go back to history tab.
  432. fp_add_message(t("File %ofile was uploaded successfully for student %cwid.", array("%ofile" => $original_filename, "%cwid" => $student_id)));
  433. if ($bool_goto_history_when_done) {
  434. fp_goto("history", "current_student_id=$student_id");
  435. }
  436. }
  437. function student_files_settings_form() {
  438. $form = array();
  439. $files_path = $GLOBALS["fp_system_settings"]["file_system_path"];
  440. $form["student_files_path"] = array(
  441. "label" => t("Absolute system path to where student files are located/uploaded to:"),
  442. "type" => "textfield",
  443. "size" => 80,
  444. "maxlength" => 1000,
  445. "value" => variable_get("student_files_path", "$files_path/custom/files/student_files"),
  446. "description" => t("This is a directory which must be writable by the webserver. When this module
  447. was installed, %path was created automatically as the default location, but you
  448. may set this to any path which already exists and is writable by the server.", array("%path" => "$files_path/custom/files/student_files")),
  449. );
  450. $form["student_files_allowed_extensions"] = array(
  451. "label" => t("Allowed file extensions (CSV):"),
  452. "type" => "textfield",
  453. "size" => 80,
  454. "maxlength" => 1000,
  455. "value" => strtolower(variable_get("student_files_allowed_extensions", "txt, pdf, doc, docx, xls, xlsx, ppt, pptx, rtf, odt, jpg, jpeg, png, gif, zip, 7z")),
  456. "description" => t("Enter the allowed file extensions, separated by commas (no dots!), that are allowed to be uploaded.<br>Ex:
  457. <br><em>&nbsp; &nbsp; txt, pdf, doc, docx, xls, xlsx, ppt, pptx, rtf, odt, jpg, jpeg, png, gif, zip, 7z</em>"),
  458. );
  459. $form["student_files_sub_dir_pattern"] = array(
  460. "type" => "textfield",
  461. "label" => t("Sub directory pattern:"),
  462. "value" => variable_get("student_files_sub_dir_pattern", "%year/%student_cwid"),
  463. "description" => t("Enter the pattern of the sub directories for uploaded files.
  464. <br> Ex: %year/%student_cwid would places files in /2006/12345 under the above
  465. student files directory for a student with CWID 12345.
  466. <br>Available replacement patterns:
  467. <ul>
  468. <li>%year - the year the file was uploaded.</li>
  469. <li>%timestamp - the unix timstamp the file was uploaded.</li>
  470. <li>%student_cwid - the CWID of the student the file belongs to.</li>
  471. <li>%random - a random series of numbers and letters.</li>
  472. </ul>
  473. You may also enter static directory names like 'files' or 'uploads'. If unsure what to enter, leave blank."),
  474. );
  475. $form["student_files_filename_pattern"] = array(
  476. "type" => "textfield",
  477. "label" => t("Saved server filename pattern:"),
  478. "value" => variable_get("student_files_filename_pattern", "%student_cwid.%random.%ext"),
  479. "description" => t("Enter the pattern for the stored files on the server.
  480. <br> Ex: %student_cwid.%random.%ext might create a file named 12345.hgyK76.pdf under the above
  481. student files directory for a student with CWID 12345.
  482. If there are files with identical names being uploaded, the new file will automatically be given a random string
  483. to ensure nothing is overwritten.
  484. <br><b>Recommended:</b> It is recommended you do not use the original filename, especially if the files might contain
  485. sensitive information. The use of the %random replacement pattern is recommended.
  486. <br>Available replacement patterns:
  487. <ul>
  488. <li>%year - the year the file was uploaded.</li>
  489. <li>%timestamp - the unix timstamp the file was uploaded.</li>
  490. <li>%student_cwid - the CWID of the student the file belongs to.</li>
  491. <li>%random - a random series of numbers and letters.</li>
  492. <li>%original_filename - The original filename, including extension, of the uploaded file.</li>
  493. <li>%ext - The original filename extension from the uploaded file.</li>
  494. </ul>
  495. You may also enter static directory names like 'files' or 'uploads'. If unsure what to enter, leave blank."),
  496. );
  497. if (module_enabled("encryption")) {
  498. // The encryption module is installed. Let's add extra settings for it.
  499. $form["student_files_encryption"] = array(
  500. "type" => "select",
  501. "label" => "Encrypt uploaded files?",
  502. "options" => array("yes" => t("Yes"), "no" => t("No")),
  503. "value" => variable_get("student_files_encryption", "yes"),
  504. "description" => t("Since you have installed the 'encryption' module, when files are uploaded to a student's History tab,
  505. they can be automatically encrypted before being saved to the server. Do you wish
  506. to do this? If so, the extension \".enc\" will be added to the end of encrypted files.
  507. When files are downloaded through the Student Files module, they will be automatically decrypted
  508. for the end user.
  509. <br><br>
  510. Note: this does not affect files attached in Engagements, like text messages or email file attachments. To configure
  511. encryption of those files, see the Encryption settings page."),
  512. "prefix" => "<fieldset><legend>" . t("Encryption Settings") . "</legend>",
  513. "suffix" => "</fieldset>",
  514. );
  515. }
  516. return $form;
  517. }
  518. /**
  519. * We mainly want to make sure nothing got entered in an incorrect format here.
  520. */
  521. function student_files_settings_form_validate($form, &$form_state) {
  522. $values = $form_state["values"];
  523. // Make sure the absolute system path actually exists.
  524. $student_files_path = $values["student_files_path"];
  525. // Remove any trailing slashes from the student_files_path.
  526. $student_files_path = rtrim($student_files_path, "/");
  527. $form_state["values"]["student_files_path"] = $student_files_path;
  528. if (!file_exists($student_files_path)) {
  529. form_error("student_files_path", t("The student files path entered does not exist yet, or the system does not have access
  530. to view it. Make sure it exists and the web server user has file access to read and write
  531. to it."));
  532. return;
  533. }
  534. // Make sure the sub directory pattern doesn't have beginning or trailing slashes.
  535. $form_state["values"]["student_files_sub_dir_pattern"] = rtrim($form_state["values"]["student_files_sub_dir_pattern"], "/");
  536. $form_state["values"]["student_files_sub_dir_pattern"] = ltrim($form_state["values"]["student_files_sub_dir_pattern"], "/");
  537. // Make sure there are no /'s in the server filename pattern.
  538. if (strstr($form_state["values"]["student_files_filename_pattern"], "/")) {
  539. form_error("student_files_filename_pattern", t("Do not enter forward slashes (/) in the server filename pattern. If you wish to place
  540. files in subdirectories, use the sub directory pattern field."));
  541. return;
  542. }
  543. }
  544. /**
  545. * Implements hook_perm
  546. */
  547. function student_files_perm() {
  548. return array(
  549. "administer_student_files" => array(
  550. "title" => t("Administer student files settings"),
  551. ),
  552. "upload_any_student_files" => array(
  553. "title" => t("Upload any to student's files"),
  554. "description" => t("This lets the user upload to any student's files, using the student file upload tool on the Main tab."),
  555. ),
  556. "upload_student_files" => array(
  557. "title" => t("Upload student files"),
  558. "description" => t("This permission lets the user upload student files to any student they can normally view the history of.
  559. Files appear on the student's History tab."),
  560. ),
  561. "delete_own_student_files" => array(
  562. "title" => t("Delete own student files that the user uploaded themselves"),
  563. ),
  564. "delete_any_student_files" => array(
  565. "title" => t("Delete ANY student files that were uploaded by anyone"),
  566. ),
  567. "download_advising_student_files" => array(
  568. "title" => t("Download files for any student the user can 'View'"),
  569. "description" => t("If this user is also allowed to view the student's View tab, History, etc, then they are allowed to download
  570. files for that student. For example, the student is one of the user's advisees."),
  571. ),
  572. );
  573. }
  574. /**
  575. * Implememnt hook_content_alter
  576. */
  577. function student_files_content_alter(&$render, $content_id) {
  578. // We want to place our files area under the Comment History on the history tab.
  579. if ($content_id == "advise_history_right_column") {
  580. // Add our css.
  581. fp_add_css(fp_get_module_path("student_files") . "/css/student_files.css");
  582. $html = "";
  583. $student_id = $render["#student_id"];
  584. $files_array = student_files_get_files_for_student($student_id);
  585. $html .= "<div class='student-files-file-list'>
  586. <table border='0' width='100%' class='' cellpadding='0' cellspacing='0'>";
  587. $is_empty = TRUE;
  588. foreach ($files_array as $cur) {
  589. $fid = $cur["fid"]; // file id
  590. $posted = format_date(convert_time($cur["posted"]), "", "n/d/Y");
  591. $fac_name = fp_get_faculty_name($cur["uploaded_by_cwid"]);
  592. // Is this user allowed to see this file at all? (ie, this is a student and the file is for faculty only)
  593. if (!student_files_user_may_download_student_file($student_id, $fid)) {
  594. continue;
  595. }
  596. $extra_classes = "";
  597. if (strstr($cur["filetype"], "image")) $extra_classes .= " student-files-file-image ";
  598. if (strstr($cur["filetype"], "pdf")) $extra_classes .= " student-files-file-pdf ";
  599. if (strstr($cur["filetype"], "compressed")) $extra_classes .= " student-files-file-compressed ";
  600. if (strstr($cur["original_filename"], ".pdf")) $extra_classes .= " student-files-file-pdf ";
  601. if (strstr($cur["original_filename"], ".doc")) $extra_classes .= " student-files-file-word ";
  602. if (strstr($cur["original_filename"], ".ppt")) $extra_classes .= " student-files-file-ppt ";
  603. if (strstr($cur["original_filename"], ".xls")) $extra_classes .= " student-files-file-xls ";
  604. if (strstr($cur["original_filename"], ".zip")) $extra_classes .= " student-files-file-compressed ";
  605. $row_class = "";
  606. $row_class .= "student-files-access-type-" . $cur["access_type"];
  607. $del_link = "";
  608. if (student_files_user_may_delete_student_file($student_id, $fid)) {
  609. $del_link = "<span class='student-files-delete'>" . fp_get_js_confirm_link("Are you sure you wish to delete this file? This action cannot be undone.",
  610. "window.location=\"" . fp_url("student-files/handle-delete/$student_id/$fid") . "\"", "<i class='fa fa-remove'></i>", "action-link-remove", t("Delete?")) . "</span>";
  611. }
  612. $html .= "<tr class='$row_class'>
  613. <td valign='top' width='50%' class='student-files-filenames'>
  614. <div class='student-files-file $extra_classes'>
  615. " . l($cur["original_filename"], "student-files/handle-download/$student_id/$fid") . "</div>
  616. </td>
  617. <td valign='top' class='student-files-details-td'>
  618. <div class='student-files-posted'>$posted</div>
  619. <div class='student-files-fac-name'>$fac_name</div>
  620. </td>
  621. <td valign='top' class='student-files-delete-td'>
  622. $del_link
  623. </td>
  624. </tr>";
  625. $is_empty = FALSE;
  626. }
  627. if ($is_empty) {
  628. $html .= "No files have been uploaded for this student yet.";
  629. }
  630. $html .= "</table>
  631. </div>";
  632. // Create a region for uploading a new file.
  633. // Only if they have permission!
  634. $upload_form = "";
  635. if (user_has_permission("upload_student_files")) {
  636. $form = fp_render_form("student_files_little_upload_form", "normal", $student_id);
  637. $upload_form = fp_render_c_fieldset($form, t("Click to upload a new file"), TRUE, ' upload-file-fs');
  638. /*
  639. $upload_form = "<form class='tenpt' style='border: 1px solid #ccc; padding: 3px; margin: 5px;'
  640. action='" . fp_url("student-files/handle-upload/$student_id", "current_student_id=$student_id") . "'
  641. method='POST' enctype='multipart/form-data'>
  642. <b>" . t("Upload a new file:") . "</b>
  643. <input type='file' name='student_file_upload_file' id='student_file_upload_file'>
  644. <br><b>" . t("Visible to:") . "</b>
  645. &nbsp;<label><input type='radio' value='public' name='access_type'>Anyone (incl. students)</label>
  646. <label><input type='radio' value='faculty' name='access_type' checked=checked>Faculty/Staff</label>
  647. <div style='text-align: right; padding-top: 10px;'>
  648. <input type='submit' value='Upload' onClick='showUpdate(false);'>
  649. </div>
  650. </form>";
  651. *
  652. */
  653. }
  654. $render["student_files"] = array(
  655. "value" => "<div class='student-files-section-block'>
  656. " . fp_render_section_title(t("Student Files")) . "
  657. $upload_form
  658. $html
  659. </div>",
  660. );
  661. // Since we rendered a form, make sure we aren't showing the title on screen afterwards.
  662. fp_show_title(FALSE);
  663. }
  664. } // hook_content_alter
  665. function student_files_little_upload_form($student_id = "") {
  666. $form = array();
  667. $form["#attributes"] = array("enctype" => 'multipart/form-data'); // allow the form itself to submit files.
  668. $form["student_file_upload_file"] = array(
  669. "type" => "file",
  670. "description" => t("<b>Allowed files:</b> <em>%ext</em>", array("%ext" => strtolower(variable_get("student_files_allowed_extensions", "txt, pdf, doc, docx, xls, xlsx, ppt, pptx, rtf, odt, jpg, jpeg, png, gif, zip, 7z")))),
  671. );
  672. $form["access_type"] = array(
  673. "type" => "radios",
  674. "label" => t("Visible to:"),
  675. "options" => array("public" => t("Anyone (incl students)"), "faculty" => t("Faculty/Staff")),
  676. "value" => "faculty",
  677. );
  678. $form["student_id"] = array(
  679. "type" => "hidden",
  680. "value" => $student_id,
  681. );
  682. $form["current_student_id"] = array(
  683. "type" => "hidden",
  684. "value" => $student_id,
  685. );
  686. $form["submit_btn"] = array(
  687. "type" => "submit",
  688. "value" => t("Upload"),
  689. "attributes" => array("onClick" => "showUpdate(false);"),
  690. );
  691. return $form;
  692. }
  693. function student_files_little_upload_form_submit($form, $form_state) {
  694. $_POST["access_type"] = $form_state["values"]["access_type"];
  695. // Send it on along to be uploaded.
  696. student_files_handle_upload($form_state["values"]["student_id"], FALSE);
  697. }
  698. /**
  699. * Return an array of the files which belong to this student.
  700. */
  701. function student_files_get_files_for_student($student_id) {
  702. $rtn = array();
  703. $res = db_query("SELECT * FROM student_files
  704. WHERE student_id = ?
  705. ORDER BY posted DESC ", $student_id);
  706. while ($cur = db_fetch_array($res)) {
  707. $rtn[$cur["fid"]] = $cur;
  708. }
  709. return $rtn;
  710. }

Functions

Namesort descending Description
student_files_content_alter Implememnt hook_content_alter
student_files_get_files_for_student Return an array of the files which belong to this student.
student_files_handle_delete
student_files_handle_download This actually finds and downloads the file for the user, decrypting if necessary.
student_files_handle_upload Handles the upload of a file which we assume is located at $_FILES["student_file_upload_file"], or the provided $file array.
student_files_little_upload_form
student_files_little_upload_form_submit
student_files_menu Implementation of hook_menu
student_files_perm Implements hook_perm
student_files_settings_form
student_files_settings_form_validate We mainly want to make sure nothing got entered in an incorrect format here.
student_files_upload_any_student_files_form This is where we can upload (en masse?) to any arbitrary student.
student_files_upload_any_student_files_form_submit We can assume at this point that eveything is peachy, so let's get to uploading!
student_files_upload_any_student_files_form_validate Validate function.
student_files_user_may_delete_student_file Returns TRUE or FALSE if the current user is allowed to delete the file.
student_files_user_may_download_student_file Returns TRUE or FALSE if the user has access to download this particular student's file.