Coverage for model/course.py: 100%
148 statements
« prev ^ index » next coverage.py v7.3.2, created at 2024-11-05 04:22 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2024-11-05 04:22 +0000
1from typing import Optional
2from flask import Blueprint, request
4from mongo import *
5from .auth import *
6from .utils import *
7from mongo.utils import *
8from mongo.course import *
9from mongo import engine
10from datetime import datetime
12__all__ = ['course_api']
14course_api = Blueprint('course_api', __name__)
17@course_api.route('/', methods=['GET', 'POST', 'PUT', 'DELETE'])
18@login_required
19def get_courses(user):
21 @Request.json('course', 'new_course', 'teacher')
22 @identity_verify(0, 1)
23 def modify_courses(user, course, new_course, teacher):
24 r = None
25 if user.role == 1:
26 teacher = user.username
27 try:
28 if request.method == 'POST':
29 r = Course.add_course(course, teacher)
30 if request.method == 'PUT':
31 co = Course(course)
32 co.edit_course(user, new_course, teacher)
33 if request.method == 'DELETE':
34 co = Course(course)
35 co.delete_course(user)
36 except ValueError:
37 return HTTPError('Not allowed name.', 400)
38 except NotUniqueError:
39 return HTTPError('Course exists.', 400)
40 except PermissionError:
41 return HTTPError('Forbidden.', 403)
42 except engine.DoesNotExist as e:
43 return HTTPError(f'{e} not found.', 404)
44 return HTTPResponse('Success.')
46 if request.method == 'GET':
47 data = [{
48 'course': c.course_name,
49 'teacher': c.teacher.info,
50 } for c in Course.get_user_courses(user)]
51 return HTTPResponse('Success.', data=data)
52 else:
53 return modify_courses()
56@course_api.route('/<course_name>', methods=['GET', 'PUT'])
57@login_required
58def get_course(user, course_name):
59 course = Course(course_name)
61 if not course:
62 return HTTPError('Course not found.', 404)
64 if not course.permission(user, Course.Permission.VIEW):
65 return HTTPError('You are not in this course.', 403)
67 @Request.json('TAs', 'student_nicknames')
68 def modify_course(TAs, student_nicknames):
69 if not course.permission(user, Course.Permission.MODIFY):
70 return HTTPError('Forbidden.', 403)
71 else:
72 tas = []
73 for ta in TAs:
74 permit_user = User(ta).obj
75 if not User(ta):
76 return HTTPResponse(f'User: {ta} not found.', 404)
77 tas.append(permit_user)
79 for permit_user in set(course.tas) - set(tas):
80 course.remove_user(permit_user)
81 for permit_user in set(tas) - set(course.tas):
82 course.add_user(permit_user)
83 course.tas = tas
85 try:
86 course.update_student_namelist(student_nicknames)
87 except engine.DoesNotExist as e:
88 return HTTPError(str(e), 404)
89 return HTTPResponse('Success.')
91 if request.method == 'GET':
92 return HTTPResponse(
93 'Success.',
94 data={
95 "teacher": course.teacher.info,
96 "TAs": [ta.info for ta in course.tas],
97 "students":
98 [User(name).info for name in course.student_nicknames]
99 },
100 )
101 else:
102 return modify_course()
105@course_api.route('/<course_name>/grade/<student>',
106 methods=['GET', 'POST', 'PUT', 'DELETE'])
107@login_required
108def grading(user, course_name, student):
109 course = Course(course_name)
111 if not course:
112 return HTTPError('Course not found.', 404)
113 if not course.permission(user, Course.Permission.VIEW):
114 return HTTPError('You are not in this course.', 403)
115 if student not in course.student_nicknames.keys():
116 return HTTPError('The student is not in the course.', 404)
117 if course.permission(user, Course.Permission.SCORE) and \
118 (user.username != student or request.method != 'GET'):
119 return HTTPError('You can only view your score.', 403)
121 def get_score():
122 return HTTPResponse(
123 'Success.',
124 data=[{
125 'title': score['title'],
126 'content': score['content'],
127 'score': score['score'],
128 'timestamp': score['timestamp'].timestamp()
129 } for score in course.student_scores.get(student, [])])
131 @Request.json('title', 'content', 'score')
132 def add_score(title, content, score):
133 score_list = course.student_scores.get(student, [])
134 if title in [score['title'] for score in score_list]:
135 return HTTPError('This title is taken.', 400)
136 score_list.append({
137 'title': title,
138 'content': content,
139 'score': score,
140 'timestamp': datetime.now()
141 })
142 course.student_scores[student] = score_list
143 course.save()
144 return HTTPResponse('Success.')
146 @Request.json('title', 'new_title', 'content', 'score')
147 def modify_score(title, new_title, content, score):
148 score_list = course.student_scores.get(student, [])
149 title_list = [score['title'] for score in score_list]
150 if title not in title_list:
151 return HTTPError('Score not found.', 404)
152 index = title_list.index(title)
153 if new_title is not None:
154 if new_title in title_list:
155 return HTTPError('This title is taken.', 400)
156 title = new_title
157 score_list[index] = {
158 'title': title,
159 'content': content,
160 'score': score,
161 'timestamp': datetime.now()
162 }
163 course.student_scores[student] = score_list
164 course.save()
165 return HTTPResponse('Success.')
167 @Request.json('title')
168 def delete_score(title):
169 score_list = course.student_scores.get(student, [])
170 title_list = [score['title'] for score in score_list]
171 if title not in title_list:
172 return HTTPError('Score not found.', 404)
173 index = title_list.index(title)
174 del score_list[index]
175 course.student_scores[student] = score_list
176 course.save()
177 return HTTPResponse('Success.')
179 methods = {
180 'GET': get_score,
181 'POST': add_score,
182 'PUT': modify_score,
183 'DELETE': delete_score
184 }
185 return methods[request.method]()
188@course_api.route('/<course_name>/scoreboard', methods=['GET'])
189@login_required
190@Request.args('pids: str', 'start', 'end')
191@Request.doc('course_name', 'course', Course)
192def get_course_scoreboard(
193 user,
194 pids: str,
195 start: Optional[str],
196 end: Optional[str],
197 course: Course,
198):
199 try:
200 pids = pids.split(',')
201 pids = [int(pid.strip()) for pid in pids]
202 except:
203 return HTTPError('Error occurred when parsing `pids`.', 400)
205 if start:
206 try:
207 start = float(start)
208 except:
209 return HTTPError('Type of `start` should be float.', 400)
210 if end:
211 try:
212 end = float(end)
213 except:
214 return HTTPError('Type of `end` should be float.', 400)
216 if not course.permission(user, Course.Permission.GRADE):
217 return HTTPError('Permission denied', 403)
219 ret = course.get_scoreboard(pids, start, end)
221 return HTTPResponse(
222 'Success.',
223 data=ret,
224 )