Coverage for e2xgrader/server_extensions/apps/formgrader/handlers.py: 38%

130 statements  

« prev     ^ index     » next       coverage.py v7.4.2, created at 2024-03-14 13:22 +0100

1import os 

2 

3from e2xcore import format_url 

4from nbgrader.api import MissingEntry 

5from nbgrader.server_extensions.formgrader.base import ( 

6 BaseHandler, 

7 check_notebook_dir, 

8 check_xsrf, 

9) 

10from nbgrader.server_extensions.formgrader.handlers import ( 

11 SubmissionNavigationHandler as NbgraderSubmissionNavigationHandler, 

12) 

13from tornado import web 

14 

15 

16class ExportGradesHandler(BaseHandler): 

17 @web.authenticated 

18 @check_xsrf 

19 def get(self): 

20 html = self.render("export_grades.tpl", base_url=self.base_url) 

21 self.write(html) 

22 

23 

24class GradebookAssignmentsHandler(BaseHandler): 

25 @web.authenticated 

26 @check_xsrf 

27 @check_notebook_dir 

28 def get(self): 

29 view = self.get_argument("view", "notebook") 

30 if view == "task": 

31 template = os.path.join("task_view", "gradebook_assignments.tpl") 

32 else: 

33 template = "gradebook_assignments.tpl" 

34 html = self.render(template, base_url=self.base_url) 

35 self.write(html) 

36 

37 

38class GradebookNotebooksHandler(BaseHandler): 

39 @web.authenticated 

40 @check_xsrf 

41 @check_notebook_dir 

42 def get(self, assignment_id): 

43 view = self.get_argument("view", "notebook") 

44 if view == "task": 

45 template = os.path.join("task_view", "gradebook_notebooks.tpl") 

46 else: 

47 template = "gradebook_notebooks.tpl" 

48 html = self.render( 

49 template, assignment_id=assignment_id, base_url=self.base_url 

50 ) 

51 self.write(html) 

52 

53 

54class GradebookTasksHandler(BaseHandler): 

55 @web.authenticated 

56 @check_xsrf 

57 def get(self, assignment_id, notebook_id): 

58 html = self.render( 

59 "task_view/gradebook_tasks.tpl", 

60 assignment_id=assignment_id, 

61 notebook_id=notebook_id, 

62 base_url=self.base_url, 

63 ) 

64 self.write(html) 

65 

66 

67class GradebookNotebookSubmissionsHandler(BaseHandler): 

68 @web.authenticated 

69 @check_xsrf 

70 @check_notebook_dir 

71 def get(self, assignment_id, notebook_id): 

72 view = self.get_argument("view", "notebook") 

73 if view == "task": 

74 template = os.path.join("task_view", "gradebook_notebook_submissions.tpl") 

75 else: 

76 template = "gradebook_notebook_submissions.tpl" 

77 task_id = self.get_argument("filter", "") 

78 

79 html = self.render( 

80 template, 

81 assignment_id=assignment_id, 

82 notebook_id=notebook_id, 

83 base_url=self.base_url, 

84 task_id=task_id, 

85 ) 

86 self.write(html) 

87 

88 

89class SubmissionNavigationHandler(NbgraderSubmissionNavigationHandler): 

90 def _assignment_notebook_list_url(self, assignment_id, notebook_id, task_id): 

91 if len(task_id) < 1: 

92 return "{}/formgrader/gradebook/{}/{}".format( 

93 self.base_url, assignment_id, notebook_id 

94 ) 

95 return format_url( 

96 f"{self.base_url}/formgrader/gradebook/{assignment_id}/{notebook_id}/", 

97 dict(view="task", filter=task_id), 

98 ) 

99 

100 def _next(self, assignment_id, notebook_id, submission, task_id): 

101 # find next submission 

102 submission_ids = self._get_submission_ids(assignment_id, notebook_id) 

103 ix = submission_ids.index(submission.id) 

104 if ix == (len(submission_ids) - 1): 

105 return self._assignment_notebook_list_url( 

106 assignment_id, notebook_id, task_id 

107 ) 

108 else: 

109 return format_url( 

110 self._submission_url(submission_ids[ix + 1]), dict(task=task_id) 

111 ) 

112 

113 def _prev(self, assignment_id, notebook_id, submission, task_id): 

114 # find previous submission 

115 submission_ids = self._get_submission_ids(assignment_id, notebook_id) 

116 ix = submission_ids.index(submission.id) 

117 if ix == 0: 

118 return self._assignment_notebook_list_url( 

119 assignment_id, notebook_id, task_id 

120 ) 

121 else: 

122 return format_url( 

123 self._submission_url(submission_ids[ix - 1]), dict(task=task_id) 

124 ) 

125 

126 def _next_incorrect(self, assignment_id, notebook_id, submission, task_id): 

127 # find next incorrect submission 

128 submission_ids = self._get_incorrect_submission_ids( 

129 assignment_id, notebook_id, submission 

130 ) 

131 ix_incorrect = submission_ids.index(submission.id) 

132 if ix_incorrect == (len(submission_ids) - 1): 

133 return self._assignment_notebook_list_url( 

134 assignment_id, notebook_id, task_id 

135 ) 

136 else: 

137 return format_url( 

138 self._submission_url(submission_ids[ix_incorrect + 1]), 

139 dict(task=task_id), 

140 ) 

141 

142 def _prev_incorrect(self, assignment_id, notebook_id, submission, task_id): 

143 # find previous incorrect submission 

144 submission_ids = self._get_incorrect_submission_ids( 

145 assignment_id, notebook_id, submission 

146 ) 

147 ix_incorrect = submission_ids.index(submission.id) 

148 if ix_incorrect == 0: 

149 return self._assignment_notebook_list_url( 

150 assignment_id, notebook_id, task_id 

151 ) 

152 else: 

153 return format_url( 

154 self._submission_url(submission_ids[ix_incorrect - 1]), 

155 dict(task=task_id), 

156 ) 

157 

158 @web.authenticated 

159 @check_xsrf 

160 @check_notebook_dir 

161 def get(self, submission_id, action): 

162 try: 

163 submission = self.gradebook.find_submission_notebook_by_id(submission_id) 

164 assignment_id = submission.assignment.assignment.name 

165 notebook_id = submission.notebook.name 

166 task_id = self.get_argument("task", "") 

167 except MissingEntry: 

168 raise web.HTTPError(404, "Invalid submission: {}".format(submission_id)) 

169 

170 handler = getattr(self, "_{}".format(action)) 

171 self.redirect( 

172 handler(assignment_id, notebook_id, submission, task_id), permanent=False 

173 ) 

174 

175 

176class SubmissionHandler(BaseHandler): 

177 @web.authenticated 

178 @check_xsrf 

179 @check_notebook_dir 

180 def get(self, submission_id): 

181 try: 

182 submission = self.gradebook.find_submission_notebook_by_id(submission_id) 

183 assignment_id = submission.assignment.assignment.name 

184 notebook_id = submission.notebook.name 

185 student_id = submission.student.id 

186 except MissingEntry: 

187 raise web.HTTPError(404, "Invalid submission: {}".format(submission_id)) 

188 

189 # redirect if there isn't a trailing slash in the uri 

190 if os.path.split(self.request.path)[1] == submission_id: 

191 url = self.request.path + "/" 

192 if self.request.query: 

193 url += "?" + self.request.query 

194 return self.redirect(url, permanent=True) 

195 

196 filename = os.path.join( 

197 os.path.abspath( 

198 self.coursedir.format_path( 

199 self.coursedir.autograded_directory, student_id, assignment_id 

200 ) 

201 ), 

202 "{}.ipynb".format(notebook_id), 

203 ) 

204 relative_path = os.path.relpath(filename, self.coursedir.root) 

205 indices = self.api.get_notebook_submission_indices(assignment_id, notebook_id) 

206 ix = indices.get(submission.id, -2) 

207 

208 task_id = self.get_argument("task", "") 

209 

210 resources = { 

211 "assignment_id": assignment_id, 

212 "notebook_id": notebook_id, 

213 "submission_id": submission.id, 

214 "index": ix, 

215 "total": len(indices), 

216 "base_url": self.base_url, 

217 "student": student_id, 

218 "last_name": submission.student.last_name, 

219 "first_name": submission.student.first_name, 

220 "notebook_path": self.url_prefix + "/" + relative_path, 

221 "keyword": task_id, 

222 } 

223 

224 if not os.path.exists(filename): 

225 resources["filename"] = filename 

226 html = self.render("formgrade_404.tpl", resources=resources) 

227 self.clear() 

228 self.set_status(404) 

229 self.write(html) 

230 

231 else: 

232 html, _ = self.exporter.from_filename(filename, resources=resources) 

233 self.write(html) 

234 

235 

236root_path = os.path.dirname(__file__) 

237template_path = os.path.join(root_path, "templates") 

238static_path = os.path.join(root_path, "static") 

239 

240_navigation_regex = r"(?P<action>next_incorrect|prev_incorrect|next|prev)" 

241 

242default_handlers = [ 

243 (r"/formgrader/export_grades/?", ExportGradesHandler), 

244 (r"/formgrader/gradebook/?", GradebookAssignmentsHandler), 

245 (r"/formgrader/gradebook/([^/]+)/?", GradebookNotebooksHandler), 

246 (r"/formgrader/gradebook/tasks/([^/]+)/([^/]+)/?", GradebookTasksHandler), 

247 (r"/formgrader/gradebook/([^/]+)/([^/]+)/?", GradebookNotebookSubmissionsHandler), 

248 ( 

249 r"/formgrader/submissions/(?P<submission_id>[^/]+)/%s/?" % _navigation_regex, 

250 SubmissionNavigationHandler, 

251 ), 

252 (r"/formgrader/submissions/([^/]+)/?", SubmissionHandler), 

253]