def parse(self, **kwargs): worksheet = GoogleSheetsParser.get_worksheet(self, '1iw-Wv4omM8GoAhdF3yKBKXQzECZBFClRJIVsOrqcynU') i = 2 while True: values_list = worksheet.row_values(i) i += 1 if not values_list[0]: break try: exam = Exam.objects.get( name=values_list[0] ) except ObjectDoesNotExist: exam = Exam( name=values_list[0] ) self.exam_count += 1 exam.save() return [ 'New Exams: ' + str(self.exam_count), ]
def add(): data = request.json or request.data or request.form res_code = 200 res = dict(status="fail") name = data.get("name") branch_id = data.get("branch_id") for key in ("name", "branch_id"): val = data.get(key) if not val: res["statusText"] = errors.BLANK_VALUES_FOR_REQUIRED_FIELDS.text res["statusData"] = errors.BLANK_VALUES_FOR_REQUIRED_FIELDS.type( [key]) return jsonify(res), res_code exam = Exam.query.filter_by(branch_id=branch_id, name=name).first() if exam: res["statusText"] = errors.CUSTOM_ERROR.text res["statusData"] = errors.CUSTOM_ERROR.type( 'Exam with name "%s" already exists' % exam.name) return jsonify(res), res_code exam = Exam(name=name, branch_id=branch_id) db.session.add(exam) db.session.commit() res["status"] = "success" res["exam"] = exam.serialize() return jsonify(res), res_code
def exam_statistic(): sumary = Exam.get_sumary(request.args) time_line = Exam.get_timeline(request.args) statistic = Exam.get_statistic(request.args) return { 'sumary': sumary, 'time_line': time_line, 'statistic': statistic }
def test_enroll_students_to_exam_as_student(self): """Student can enroll him self to one exam""" exams_ids = [exam.id for exam in Exam.get_query().all()] # Select 5 students students = Student.get_query().limit(5).all() students_enrolls = { student.id: (subscription.exam_id for subscription in StudentSubscription.get_query().filter( StudentSubscription.student_id == student.id).all()) for student in students } # Determine which exams the students is not enrolled in students_not_enrolled = { student_id: set(exams_ids) - set(exams_ids_) for student_id, exams_ids_ in students_enrolls.items() } sub_count_before = StudentSubscription.get_query().count() try: for student in students: # Enroll the student in all the exams he is not enrolled to token = generate_user_token(student.username, STUDENT_PERMISSIONS) for exam_id in students_not_enrolled[student.id]: res = self.client.post(f'/api/v1/enrolls/{exam_id}', headers={ 'Content-Type': 'application/json', 'Authorization': f'bearer {token}' }, json=[]) self.assertEqual(res.status_code, 200, res.get_json()) data = res.get_json() self.check_fields_list(data, ['success', 'new_enrolls']) # Must be one because he is was not enrolled to this exam self.assertEqual(data['new_enrolls'], 1) # The student should be enrolled to all exams now sub_count = ((StudentSubscription.get_query().filter( StudentSubscription.student_id == student.id).count())) self.assertEqual(sub_count, len(exams_ids)) # All students should be enrolled to all exams sub_count_after = StudentSubscription.get_query().count() self.assertEqual(len(students) * len(exams_ids), sub_count_after) finally: # Restore the database to its initial state deletion_list = [] for student_id, exams_ids in students_not_enrolled.items(): for exam_id in exams_ids: deletion_list.append((StudentSubscription.get_query( ).filter( StudentSubscription.student_id == student_id).filter( StudentSubscription.exam_id == exam_id).first())) Exam.persist_changes({'delete': deletion_list}) sub_count_after = StudentSubscription.get_query().count() self.assertEqual(sub_count_after, sub_count_before)
def create_fixture_exams(count=10): print(f'Inserting {count} exams...') teachers = Teacher.query.all() exams = [ Exam(**generate_random_exam(random.choice(teachers).id)) for _ in range(count) ] if Exam.persist_changes({'insert': exams}): print(f'The {len(exams)} exams were added...') else: print(f'Cannot insert exams.')
def post(self, node_id): parser = reqparse.RequestParser() parser.add_argument('answer', type=str) parser.add_argument('question', type=int, location='args') args = parser.parse_args() question_id = args['question'] exam = Exam.get_or_none(Exam.node_id == node_id) current_attempt = Attempt.get_or_none((Attempt.user == current_user.id) & (Attempt.exam == exam)) with open(f"uploads/{exam.json_file}", "r") as json_file: data = json.load(json_file) if args['answer'] == data[question_id - 1]['answer']: current_attempt.correct += 1 else: current_attempt.incorrect += 1 user_answers = json.loads(current_attempt.answers) user_answers[str(question_id)] = args['answer'] current_attempt.answers = json.dumps(user_answers) current_attempt.save() return user_answers
def get(self, request): exams = Exam.get_user_subjects(request.user).order_by()\ .values_list("subject", "subject__verbose_name", "subject__colour")\ .distinct() return render(request, "tests.html", context={ "papers": exams, })
def test_enroll_students_to_exam_student_enroll_others(self): """A student cannot enroll others students""" exams_ids = set(exam.id for exam in Exam.get_query().all()) # Select two students and determines which exams they are not enrolled # to not_enr_exams = [] students = Student.get_query().limit(2).all() for student in students: student_subscriptions = \ (StudentSubscription.get_query() .filter(StudentSubscription.student_id == student.id) .all()) enr_exams = [exam.id for exam in student_subscriptions] not_enr_exams_ids = exams_ids - set(enr_exams) not_enr_exams.append(list(not_enr_exams_ids)) for i in range(len(students)): token = generate_user_token(students[i].username, STUDENT_PERMISSIONS) exam_id = not_enr_exams[(i + 1) % 2][0] student_id = students[(i + 1) % 2].id res = self.client.post(f'/api/v1/enrolls/{exam_id}', headers={ 'Content-Type': 'application/json', 'Authorization': f'bearer {token}' }, json=[student_id]) self.assertEqual(res.status_code, 403, res.get_json()) data = res.get_json() self.assertEqual(data['description'], 'Cannot enroll others students.', data)
def show_question(request, student_id, exam_id, question_id): #if Exam(connection).is_exam_active(exam_id) != True: # return redirect('/{student_id}/tests/{exam_id}'.format(student_id = student_id, exam_id = exam_id)) if request.method == "POST": variable = request.POST['text_area'] print(variable) return redirect("/{student_id}/tests/{exam_id}/{question_id}".format( student_id=student_id, exam_id=exam_id, question_id=question_id + 1)) else: time_left = Exam(connection).get_exam_time_left(7) question, question_amount = Question(connection).get_question( exam_id, question_id) return render( request, "question.html", { "question_amount": question_amount, "range": range(1, question_amount + 1), "student_id": student_id, "exam_id": exam_id, 'question': question, 'time': time_left })
def test_edit_exam_teacher(self): """Teacher edit their exam properly""" exam = Exam.query.first() teacher = Teacher.get_by_id(exam.author_id) # Generate a header for a teacher token = generate_user_token(teacher.username, TEACHER_PERMISSIONS) from_date = datetime.now().replace(microsecond=0) exam_body = { 'title': '', 'description': '', 'exercises': '[]', 'exam_duration': 300, 'shuffle_exercises': True, 'max_retries': 1, 'from_date': from_date, 'to_date': from_date + timedelta(days=10) } res = self.client.patch(f'/api/v1/exams/{exam.id}', headers={'Content-Type': 'application/json', 'Authorization': f'bearer {token}'}, json=exam_body) self.assertEqual(res.status_code, 200, res.get_json()) data = res.get_json() self.check_fields_list(data, ['success', 'updated']) self.assertTrue(data['success']) self.assertEqual(data['updated'], exam.id) exam = Exam.get_by_id(exam.id) for key, value in exam_body.items(): self.assertEqual(value, getattr(exam, key), f'{key}: {value}')
def test_list_enrolled_students_others_exams(self): """Teacher cannot list enrolled students of another teacher's exam""" teacher1 = (Teacher.get_query().join(Exam).order_by( Teacher.id).first()) teacher2 = (Teacher.get_query().join(Exam).order_by( Teacher.id.desc()).first()) exam1 = Exam.get_query().filter(Exam.author_id == teacher1.id).first() exam2 = Exam.get_query().filter(Exam.author_id == teacher2.id).first() tests_cases = ((teacher1, exam2), (teacher2, exam1)) for teacher, exam in tests_cases: token = generate_user_token(teacher.username, TEACHER_PERMISSIONS) res = self.client.get(f'/api/v1/enrolls/{exam.id}', headers={ 'Content-Type': 'application/json', 'Authorization': f'bearer {token}' }) self.assertEqual(res.status_code, 403, res.get_json())
def show_tests(request, user_id): exams = Exam(connection).get_exam_details(user_id) return render(request, "show_tests.html", { "test_details": exams[0], "time_remain": exams[1], "index": len(exams[0]) })
def delete(self, node_id): exam = Exam.get(Exam.node_id == node_id) os.remove('uploads/' + exam.json_file) exam.delete_instance() return f"Deleted ID {exam.id}."
def get(self): exams = Exam.select() user_exams = [ exam for exam in exams\ for role in exam.roles.split(",")\ if current_user.has_role(role) and not exam.locked ] return user_exams
def get(self, node_id): exam = Exam.get_or_none(Exam.node_id == node_id) if exam is None: return '', 406 if exam.locked: return "Locked.", 423 user_roles = [role.name for role in list(current_user.roles.select())] if not bool(set(user_roles).intersection(set(exam.roles.split(','))))\ and not current_user.has_role("admin"): return "You can't do this.", 403 last_attempt = Attempt.get_or_none((Attempt.user == current_user.id) & (Attempt.exam == exam)) if last_attempt is None: time_start = datetime.now() attempt = Attempt(user=current_user.id, exam=exam, time_start=time_start) attempt.save() elif (last_attempt.time_start > datetime.now() - timedelta(minutes=exam.time)): return { "message": "There's a valid attempt still going.", "time_start": last_attempt.time_start.ctime() } else: if last_attempt.times > exam.attempts: return "Number of attempts exceeded." last_attempt.correct = 0 last_attempt.incorrect = 0 time_start = datetime.now() last_attempt.time_start = time_start last_attempt.times += 1 last_attempt.answers = '{}' last_attempt.save() with open(f"uploads/{exam.json_file}", "r") as json_file: data = json.load(json_file) return {"time": exam.time, "max_questions": len(data)}
def test_detail(request, student_id, exam_id): test_details = Exam(connection).single_exam_details(exam_id) print(test_details) student = Student(connection).get_student_by_id(student_id) #(3, 'Midterm 3', datetime.datetime(2020, 4, 7, 20, 0), 120, '*****@*****.**', 'ENGR 101') return render(request, "test.html", { "test_detail": test_details, "student": student })
def get(self, node_id): parser = reqparse.RequestParser() parser.add_argument('question', type=int, location='args', required=False) args = parser.parse_args() exam = Exam.get_or_none(Exam.node_id == node_id) user_roles = [role.name for role in list(current_user.roles.select())] if not bool(set(user_roles).intersection(set(exam.roles.split(','))))\ and not current_user.has_role("admin"): return "You can't do this.", 403 attempt = Attempt.get_or_none((Attempt.user == current_user.id) & (Attempt.exam == exam)) # Get a question question_id = args.get('question') if question_id is not None: if attempt is None: return "You have not started your attempt." if attempt.times > exam.attempts: return "Number of attempts exceeded." if attempt.time_start < datetime.now() - timedelta( minutes=exam.time): return {"timeUp": True} with open(f"uploads/{exam.json_file}", "r") as json_file: data = json.load(json_file) question = data[question_id - 1] del question['answer'] if data.index(question) == (len(data) - 1): question['last'] = True return question exam_dict = marshal(exam, exam_fields) if attempt is not None: exam_dict["attempts_left"] = exam.attempts - attempt.times else: exam_dict["attempts_left"] = exam.attempts return exam_dict
def post(self): parser = reqparse.RequestParser() parser.add_argument('name') parser.add_argument('description') parser.add_argument('roles', type=str) parser.add_argument('time', type=int) parser.add_argument('attempts', type=int) parser.add_argument('file', location='files', type=werkzeug.datastructures.FileStorage) args = parser.parse_args() file = args['file'] exam = Exam(**args) # Check if file exists, rename if so filename = werkzeug.utils.secure_filename(file.filename) if os.path.isfile(f'uploads/{filename}'): filename = str(int(datetime.now().timestamp())) + "-" + filename exam.json_file = filename exam.roles = args['roles'] file.save(f"uploads/{filename}") exam.save() return exam
def test_delete_exam_teacher_others_exams(self): """Teacher trying to archive others teachers exam""" teacher = Teacher.query.order_by(Teacher.id.desc()).first() token = generate_user_token(teacher.username, TEACHER_PERMISSIONS) exams_ids = [exam.id for exam in Exam.get_query().all() if exam.author_id != teacher.id][:10] for exam_id in exams_ids: res = self.client.delete(f'/api/v1/exams/{exam_id}', headers={ 'Content-Type': 'application/json', 'Authorization': f'bearer {token}'}) self.assertEqual(res.status_code, 403, res.get_json())
def get(self, node_id): exam = Exam.get_or_none(Exam.node_id == node_id) if exam is None: return '', 406 current_attempt = Attempt.get((Attempt.user == current_user.id) & (Attempt.exam == exam)) current_attempt.time_start -= timedelta(minutes=exam.time) current_attempt.save() return "Finished."
def paper_upload(): data = MultiDict(mapping=request.json) form = PaperUploadForm(data) if not form.validate(): raise FormValidateError(form.errors) # todo 插入数据库 attachments = request.json.get('attachments', []) exam = Exam(name=form.name.data, section=form.section.data, subject=form.subject.data, paper_types=form.paper_types.data, \ province_id=form.province_id.data, city_id=form.city_id.data, area_id=form.area_id.data,\ school_id=form.school_id.data, exam_date=form.exam_date.data, year=form.year.data, grade=form.grade.data, is_fast=form.is_fast.data, state=0, attachments=attachments, upload_user=g.user.id, order=PAPER_TYPE_ORDER[form.paper_types.data]) result = exam.save() ExamLog.log(exam.id, g.user.id, EXAM_STATUS['未审核'], 'UPLOAD') if result.id is not None: return render_api({}) raise JsonOutputException('添加失败')
def get(self, node_id): exam = Exam.get_or_none(Exam.node_id == node_id) submitters = list(Attempt.select()) if exam is None: return '', 406 with open(f"uploads/{exam.json_file}", "r") as json_file: data = json.load(json_file) return { "submitters": marshal(submitters, result_fields), "max_questions": len(data) }
def put(self, node_id): parser = reqparse.RequestParser() parser.add_argument('name', required=False) parser.add_argument('description', required=False) parser.add_argument('roles', type=str, required=False) parser.add_argument('time', type=int, required=False) parser.add_argument('attempts', type=int, required=False) parser.add_argument('file', location='files', required=False, type=werkzeug.datastructures.FileStorage) parser.add_argument('locked', required=False, type=int) exam = Exam.get(Exam.node_id == node_id) args = parser.parse_args() if args['locked'] is not None: exam.locked = args['locked'] else: exam.name = args['name'] exam.description = args['description'] exam.time = args['time'] exam.attempts = args['attempts'] exam.roles = args['roles'].strip(",").replace(" ", "") file = args['file'] if file is not None: # Check if file exists, rename if so filename = werkzeug.utils.secure_filename(file.filename) if os.path.isfile(f'uploads/{filename}'): filename = str(int( datetime.now().timestamp())) + "-" + filename exam.json_file = filename file.save(f"uploads/{filename}") exam.save() return exam
def test_list_enrolled_students_teacher(self): """Return the names of students enrolled to one exam""" teacher = Teacher.get_query().first() exams = Exam.get_query().filter(Exam.author_id == teacher.id).all() token = generate_user_token(teacher.username, TEACHER_PERMISSIONS) for exam in exams: res = self.client.get(f'/api/v1/enrolls/{exam.id}', headers={ 'Content-Type': 'application/json', 'Authorization': f'bearer {token}' }) self.assertEqual(res.status_code, 200, res.get_json()) data = res.get_json() self.check_fields_list(data, ['success', 'students']) self.assertTrue(data['success']) enroll_count = (StudentSubscription.get_query().filter( StudentSubscription.exam_id == exam.id).count()) self.assertEqual(len(data['students']), enroll_count)
def list_quest_review_log(): query = Preprocess.query.\ filter_by(operator_id=g.user.id).\ order_by(Preprocess.created_at.desc()).\ join(Exam, Exam.id==Preprocess.exam_id) if request.args.get('name'): query = query.filter( Exam.name.like('%{}%'.format(request.args.get('name')))) if request.args.get('subject'): query = query.filter(Exam.subject == request.args.get('subject')) if request.args.get('paper_types'): query = query.filter( Exam.paper_types == request.args.get('paper_types')) if request.args.get('province_id'): query = query.filter( Exam.province_id == request.args.get('province_id')) if request.args.get('city_id'): query = query.filter(Exam.city_id == request.args.get('city_id')) if request.args.get('area_id'): query = query.filter(Exam.area_id == request.args.get('area_id')) if request.args.get('school_id'): query = query.filter(Exam.school_id == request.args.get('school_id')) if request.args.get('year'): query = query.filter(Exam.year == request.args.get('year')) if request.args.get('grade'): query = query.filter(Exam.grade == request.args.get('grade')) res = pagination(query) items = res.get('items', []) items = Exam.bind_auto(items, [ 'name', 'section', 'school_id', 'subject', 'grade', 'paper_types', 'province_id', 'city_id', 'area_id' ]) items = School.bind_auto(items, 'name', 'exam_school_id', 'id', 'school') items = Region.bind_auto(items, 'name', 'exam_province_id', 'id', 'province') items = Region.bind_auto(items, 'name', 'exam_city_id', 'id', 'city') items = Region.bind_auto(items, 'name', 'exam_area_id', 'id', 'area') res['items'] = items return render_api(res)
def test_delete_exam_teacher(self): """Teacher archiving their exam""" exam = Exam.query.first() new_exam_dict = generate_random_exam(exam.author_id) new_exam = Exam(**new_exam_dict) new_exam.insert() try: teacher = Teacher.get_by_id(new_exam.author_id) token = generate_user_token(teacher.username, TEACHER_PERMISSIONS) res = self.client.delete(f'/api/v1/exams/{new_exam.id}', headers={ 'Content-Type': 'application/json', 'Authorization': f'bearer {token}'}) self.assertEqual(res.status_code, 200, res.get_json()) data = res.get_json() self.check_fields_list(data, ['success', 'deleted']) self.assertTrue('success') self.assertEqual(data['deleted'], new_exam.id) self.assertIsNone(Exam.get_by_id(new_exam.id)) finally: new_exam.delete()
def get_exam_suggest(): res = Exam.get_suggest(request.args) return res
def get_exam(id): data = Exam.get_exam(id) if data is not None: return {'code': 0, 'data': data} else: raise JsonOutputException('没有数据')
def get_check_exams(): data = Exam.list_all_exams() return render_api(data)
def get_exams(): data = Exam.get_exams(g.user.id) return render_api(data)