/controllers/code.php

https://github.com/fyhuang/paperless · PHP · 214 lines · 139 code · 35 blank · 40 comment · 36 complexity · 5e1c8a8f4ed3d6c70d0c92adb40ba5e3 MD5 · raw file

  1. <?php
  2. require_once("models/AssignmentFile.php");
  3. require_once("models/AssignmentComment.php");
  4. require_once("models/Model.php");
  5. require_once("permissions.php");
  6. require_once("utils.php");
  7. /*
  8. * Controller that handles the syntax highlighted code view
  9. * for a student, assignment pair and other ajax actions.
  10. */
  11. class CodeHandler extends ToroHandler {
  12. /*
  13. * Gets the file contents, file names, and appropriate AssignmentFile model objects
  14. * corresponding to a given student, assignment pair.
  15. * TODO: Don't use a hardcoded path / we need to allow multiple base search paths
  16. * TODO: Handle error when a pathname is not found
  17. */
  18. private function getAssignmentFiles($class, $student, $assignment, $sl) {
  19. $dirname = SUBMISSIONS_PREFIX . "/" . $class . "/" . SUBMISSIONS_DIR . "/" . $sl . "/". $assignment . "/" . $student . "/";
  20. if(!is_dir($dirname)) return null; // TODO handle error
  21. $dir = opendir($dirname);
  22. $files = array();
  23. $file_contents = array();
  24. $assignment_files = array();
  25. $string = explode("_", $student); // if it was student_1 just take student
  26. $student_suid = $string[0];
  27. $submission_number = $string[1];
  28. $last_dir = SUBMISSIONS_PREFIX . "/" . $class . "/" . SUBMISSIONS_DIR . "/" . $sl . "/". $assignment . "/" . $student_suid;
  29. $last_submission = getLastSubmissionNumber($last_dir);
  30. $release = False;
  31. while($file = readdir($dir)) {
  32. if($file == "release"){
  33. $release = True;
  34. }else if(isCodeFileForClass($file, $class) && valid_size($dirname, $file)) {
  35. $assn = AssignmentFile::loadFile($class, $student, $assignment, $file, $submission_number);
  36. // If we could load it by submission number, we are done
  37. if(is_null($assn)){
  38. $assn = AssignmentFile::loadFile($class, $student, $assignment, $file);
  39. // Now we try to load and see if an old file was there.
  40. if(is_null($assn)){
  41. //It wasn't so create a new one.
  42. $assn = AssignmentFile::createFile($class, $assignment, $student_suid, $file, $submission_number);
  43. $assn->saveFile();
  44. }else{
  45. //If it was, update the old one.
  46. if($submission_number == $last_submission){
  47. //echo "set submission number";
  48. $assn->setSubmissionNumber($submission_number);
  49. //print_r($assn);
  50. }else{
  51. $assn = AssignmentFile::createFile($class, $assignment, $student_suid, $file, $submission_number);
  52. //echo "created new file";
  53. }
  54. $assn->saveFile();
  55. }
  56. }
  57. $assignment_files[] = $assn;
  58. $files[] = $file;
  59. $file_contents[] = htmlentities(file_get_contents($dirname . $file));
  60. }
  61. }
  62. return array($files, $file_contents, $assignment_files, $release);
  63. }
  64. /*
  65. * Displays the syntax highlighted code for a student, assignment pair
  66. */
  67. public function get($class, $assignment, $student, $print=False) {
  68. if($print){
  69. $this->smarty->assign("print_view", $print);
  70. }
  71. $this->smarty->assign("code_file", $student);
  72. $suid = explode("_", $student); // if it was student_1 just take student
  73. $suid = $suid[0];
  74. $studentDisplayName = Model::getDisplayName($suid);
  75. $this->smarty->assign("student_display", $studentDisplayName);
  76. // if the username is something other than the owner of these files, require
  77. // it to be a SL
  78. if($suid != USERNAME) {
  79. $role = Permissions::requireRole(POSITION_SECTION_LEADER, $class);
  80. }else{
  81. // Otherwise require this student to be in the class
  82. $role = Permissions::requireRole(POSITION_STUDENT, $class);
  83. }
  84. $sl = Model::getSectionLeaderForStudent($suid, $class);
  85. list($files, $file_contents, $assignment_files, $release) = $this->getAssignmentFiles($class, $student, $assignment, $sl);
  86. if(count($files) == 0){
  87. $this->smarty->assign("message", "Nothing here yet.");
  88. }
  89. if($role == POSITION_SECTION_LEADER){
  90. $this->smarty->assign("sl_class", $class);
  91. $this->smarty->assign("interactive", 1);
  92. $showComments = True;
  93. }
  94. if($role == POSITION_STUDENT){
  95. $this->smarty->assign("student_class", $class);
  96. $showComments = $release;
  97. }
  98. if($role > POSITION_SECTION_LEADER){
  99. $this->smarty->assign("admin_class", $class);
  100. $showComments = True;
  101. }
  102. // assign template vars
  103. $this->smarty->assign("code", true);
  104. $string = explode("_", $student); // if it was student_1 just take student
  105. $student_suid = $string[0];
  106. $this->smarty->assign("numbered_submission", $student);
  107. $this->smarty->assign("class", htmlentities($class));
  108. $this->smarty->assign("student", htmlentities($student_suid));
  109. $this->smarty->assign("assignment", htmlentities($assignment));
  110. $this->smarty->assign("files", $files);
  111. $this->smarty->assign("file_contents", $file_contents);
  112. $this->smarty->assign("assignment_files", $assignment_files);
  113. $this->smarty->assign("sl", $sl);
  114. $this->smarty->assign("release", $release);
  115. $this->smarty->assign("showComments", $showComments);
  116. // display the template
  117. $this->smarty->display("code.html");
  118. }
  119. /*
  120. * Handles adding and deleting comments. Note: when a comment is edited it is
  121. * first deleted and then re-added to the database.
  122. * TODO: Log / handle an error when we don't have a valid path
  123. * TODO: We probably need to filter user input somehow
  124. * TODO: This should output (via echo or whatever) some valid JSON that is used
  125. * to confirm the request succeeded
  126. */
  127. public function post_xhr($class, $assignment, $student) {
  128. // only section leaders should be able to add comments
  129. Permissions::requireRole(POSITION_SECTION_LEADER, $class);
  130. $parts = explode("_", $student); // if it was student_1 just take student
  131. $suid = $parts[0];
  132. $submission_number = $parts[1];
  133. $sl = Model::getSectionLeaderForStudent($suid, $class);
  134. $dirname = SUBMISSIONS_PREFIX . "/" . $class . "/" . SUBMISSIONS_DIR . "/" . $sl . "/". $assignment . "/" . $student . "/";
  135. if(!isset($_POST['action'])) {
  136. echo json_encode(array("status" => "fail"));
  137. return;
  138. }
  139. if($_POST['action'] == "release"){
  140. if($_POST['release'] == "create"){
  141. createRelease($dirname);
  142. }else{
  143. deleteRelease($dirname);
  144. }
  145. echo json_encode(array("status" => "ok"));
  146. return;
  147. }
  148. $curFile = AssignmentFile::loadFile($class, $suid, $assignment, $_POST['filename'], $submission_number);
  149. $id = $curFile->getID();
  150. if(!isset($id)){ // echo "no valid assnment found";
  151. echo json_encode(array("status" => "fail"));
  152. return;
  153. }
  154. $commenter = Model::getUserID(USERNAME);
  155. $student = Model::getUserID($suid);
  156. if($_POST['action'] == "create") {
  157. $newComment = AssignmentComment::create($curFile->getID(), $_POST['rangeLower'],
  158. $_POST['rangeHigher'], $_POST['text'], $commenter, $student);
  159. $newComment->save();
  160. } else if($_POST['action'] == "delete") {
  161. // find the comment to delete:
  162. foreach($curFile->getAssignmentComments() as $comment) {
  163. if( $comment->getStartLine() == $_POST['rangeLower'] &&
  164. $comment->getEndLine() == $_POST['rangeHigher'] &&
  165. $comment->getCommentText() == $_POST['text'] ) {
  166. $comment->delete();
  167. break;
  168. }
  169. // TODO: Probably a better way to delete comments would be to associate with a unique id
  170. // if( $comment->getID() == $_POST['commentID'] ) {
  171. // $comment->delete();
  172. // break;
  173. // }
  174. }
  175. }
  176. echo json_encode(array("status" => "ok", "action" => $_POST['action']));
  177. }
  178. }
  179. ?>