Ejemplo n.º 1
0
    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),
        ]
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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
    }
Ejemplo n.º 4
0
 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)
Ejemplo n.º 5
0
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.')
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
 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,
     })
Ejemplo n.º 8
0
 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)
Ejemplo n.º 9
0
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
            })
Ejemplo n.º 10
0
    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}')
Ejemplo n.º 11
0
 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())
Ejemplo n.º 12
0
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])
    })
Ejemplo n.º 13
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}."
Ejemplo n.º 14
0
    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
Ejemplo n.º 15
0
    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)}
Ejemplo n.º 16
0
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
    })
Ejemplo n.º 17
0
    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
Ejemplo n.º 18
0
    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
Ejemplo n.º 19
0
 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())
Ejemplo n.º 20
0
    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."
Ejemplo n.º 21
0
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('添加失败')
Ejemplo n.º 22
0
    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)
        }
Ejemplo n.º 23
0
    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
Ejemplo n.º 24
0
 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)
Ejemplo n.º 25
0
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)
Ejemplo n.º 26
0
 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()
Ejemplo n.º 27
0
def get_exam_suggest():
    res = Exam.get_suggest(request.args)
    return res
Ejemplo n.º 28
0
def get_exam(id):
    data = Exam.get_exam(id)
    if data is not None:
        return {'code': 0, 'data': data}
    else:
        raise JsonOutputException('没有数据')
Ejemplo n.º 29
0
def get_check_exams():
    data = Exam.list_all_exams()
    return render_api(data)
Ejemplo n.º 30
0
def get_exams():
    data = Exam.get_exams(g.user.id)
    return render_api(data)