Coverage for e2xgrader/server_extensions/apps/e2xgraderapi/apihandlers.py: 56%

93 statements  

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

1import json 

2 

3from e2xcore.handlers.base import E2xApiHandler 

4from nbgrader.server_extensions.formgrader.apihandlers import ( 

5 AssignmentCollectionHandler, 

6 AssignmentHandler, 

7) 

8from nbgrader.server_extensions.formgrader.base import check_notebook_dir, check_xsrf 

9from tornado import web 

10 

11from e2xgrader.exporters import GradeExporter 

12 

13 

14class E2xAssignmentCollectionHandler(E2xApiHandler, AssignmentCollectionHandler): 

15 """ 

16 Inherit from E2xApiHandler to overwrite the internal NbgraderAPI with the E2xAPI 

17 """ 

18 

19 @web.authenticated 

20 @check_xsrf 

21 @check_notebook_dir 

22 def get(self): 

23 include_score = self.get_argument("include_score", "True").lower() == "true" 

24 self.write(json.dumps(self.api.get_assignments(include_score=include_score))) 

25 

26 

27class E2xAssignmentHandler(E2xApiHandler, AssignmentHandler): 

28 """ 

29 Inherit from E2xApiHandler to overwrite the internal NbgraderAPI with the E2xAPI 

30 """ 

31 

32 @web.authenticated 

33 @check_xsrf 

34 @check_notebook_dir 

35 def get(self, assignment_id): 

36 include_score = self.get_argument("include_score", "True").lower() == "true" 

37 assignment = self.api.get_assignment(assignment_id, include_score=include_score) 

38 if assignment is None: 

39 raise web.HTTPError(404) 

40 self.write(json.dumps(assignment)) 

41 

42 

43class SolutionCellCollectionHandler(E2xApiHandler): 

44 @web.authenticated 

45 @check_xsrf 

46 def get(self, assignment_id, notebook_id): 

47 cells = self.api.get_solution_cell_ids(assignment_id, notebook_id) 

48 self.write(json.dumps(cells)) 

49 

50 

51class SubmittedTaskCollectionHandler(E2xApiHandler): 

52 @web.authenticated 

53 @check_xsrf 

54 def get(self, assignment_id, notebook_id, task_id): 

55 submissions = self.api.get_task_submissions(assignment_id, notebook_id, task_id) 

56 self.write(json.dumps(submissions)) 

57 

58 

59class GenerateFeedbackHandler(E2xApiHandler): 

60 @web.authenticated 

61 @check_xsrf 

62 def post(self, assignment_id, student_id): 

63 hide_cells = json.loads(self.get_argument("hide_cells", "false")) 

64 self.write( 

65 json.dumps( 

66 self.api.generate_feedback( 

67 assignment_id, student_id, hide_cells=hide_cells 

68 ) 

69 ) 

70 ) 

71 

72 

73class GenerateAllFeedbackHandler(E2xApiHandler): 

74 @web.authenticated 

75 @check_xsrf 

76 def post(self, assignment_id): 

77 hide_cells = json.loads(self.get_argument("hide_cells", "false")) 

78 self.write( 

79 json.dumps(self.api.generate_feedback(assignment_id, hide_cells=hide_cells)) 

80 ) 

81 

82 

83class GraderHandler(E2xApiHandler): 

84 @web.authenticated 

85 @check_xsrf 

86 def get(self): 

87 e2xgrader_settings = self.settings.get("e2xgrader", dict()) 

88 grader_settings = e2xgrader_settings.get("graders", list()) 

89 self.write(json.dumps(grader_settings)) 

90 

91 

92class ExportGradesHandler(E2xApiHandler): 

93 def initialize(self) -> None: 

94 self.__exporter = GradeExporter() 

95 self.set_header("Content-Type", 'text/csv; charset="utf-8"') 

96 self.set_header("Content-Disposition", "attachment; filename=grades.csv") 

97 

98 @web.authenticated 

99 @check_xsrf 

100 def get(self): 

101 level = self.get_argument("level", "notebook") 

102 if level == "task": 

103 self.__exporter.tasks = True 

104 elif level == "assignment": 

105 self.__exporter.notebooks = False 

106 normalize = self.get_argument("normalize", "false") 

107 if normalize.lower() == "max_score": 

108 self.__exporter.include_max_score = True 

109 else: 

110 self.__exporter.normalize = normalize.lower() == "true" 

111 self.write(self.__exporter.get_grades().to_csv()) 

112 self.finish() 

113 

114 

115class AnnotationCollectionHandler(E2xApiHandler): 

116 @web.authenticated 

117 @check_xsrf 

118 @check_notebook_dir 

119 def get(self): 

120 solution_cells = self.api.get_annotations(self.get_argument("submission_id")) 

121 if solution_cells is None: 

122 raise web.HTTPError(404) 

123 return self.write(json.dumps(solution_cells)) 

124 

125 

126class AnnotationHandler(E2xApiHandler): 

127 @web.authenticated 

128 @check_xsrf 

129 @check_notebook_dir 

130 def put(self, solution_cell_id): 

131 data = self.get_json_body() 

132 solution_cell = self.api.save_annotation( 

133 submission_id=data.get("submission_id"), 

134 name=data.get("name"), 

135 annotation=data.get("annotation"), 

136 ) 

137 if solution_cell is None: 

138 raise web.HTTPError(404) 

139 

140 self.write(json.dumps(solution_cell)) 

141 

142 

143default_handlers = [ 

144 (r"/formgrader/api/assignments", E2xAssignmentCollectionHandler), 

145 (r"/formgrader/api/assignment/([^/]+)", E2xAssignmentHandler), 

146 (r"/formgrader/api/solution_cells/([^/]+)/([^/]+)", SolutionCellCollectionHandler), 

147 ( 

148 r"/formgrader/api/submitted_tasks/([^/]+)/([^/]+)/([^/]+)", 

149 SubmittedTaskCollectionHandler, 

150 ), 

151 ( 

152 r"/formgrader/api/assignment/([^/]+)/generate_feedback", 

153 GenerateAllFeedbackHandler, 

154 ), 

155 ( 

156 r"/formgrader/api/assignment/([^/]+)/([^/]+)/generate_feedback", 

157 GenerateFeedbackHandler, 

158 ), 

159 ( 

160 r"/formgrader/api/export_grades/?", 

161 ExportGradesHandler, 

162 ), 

163 (r"/formgrader/api/annotations", AnnotationCollectionHandler), 

164 (r"/formgrader/api/annotation/([^/]+)", AnnotationHandler), 

165]