Пример #1
0
class NoticeListAPI(Resource):
    # url: /course/<int:id>/notices
    method_decorators = {"get": [get_course_allowed, auth_required, resource_found_required("course")],
                         "post": [teacher_required, auth_required, resource_found_required("course")]}

    def get(self, cid):
        notices = g.current_course.notices
        data = Notice.list_to_json(notices)
        return make_resp(data)

    def post(self, cid):
        data = notice_create_reqparser.parse_args()
        new_notice = Notice(data['title'], data['content'])
        new_notice.course = g.current_course

        try:
            students = new_notice.course.students
            for student in students:
                send_notice(student, new_notice)
        except:
            pass

        db.session.add(new_notice)
        db.session.commit()
        return make_resp(new_notice.to_json(detail=True))
Пример #2
0
class DiscussionAPI(Resource):
    # url: /course/<int:cid>/discussions/<string:discus_id>
    method_decorators = [get_course_allowed, resource_found_required("course"),
                         resource_found_required("discussion"), auth_required]

    def get(self, cid, discus_id):
        # get a discussion and its comments
        discussion = g.current_discussion
        return make_resp(discussion.to_json(detail=True))
Пример #3
0
class CommentLikeAPI(Resource):
    # url: /courses/<int:cid>/comments/<string:comment_id>/like
    method_decorators = [get_course_allowed, resource_found_required('course'),
                         resource_found_required("comment"), auth_required]

    def post(self, cid, comment_id):
        if g.current_user.liked(comment_id, "comment"):
            return api_abort(400, "already liked")
        g.current_user.like(comment_id, "comment")
        return "OK"
Пример #4
0
class TaskListAPI(Resource):
    # url: /<int:cid>/tasks/?per_page=&page=&type="exam"/"test"

    method_decorators = {"get": [get_course_allowed, auth_required, resource_found_required('course')],
                         "post": [teacher_required, auth_required, resource_found_required('course')]}

    def get(self, cid):
        # course = g.current_course
        # return make_resp(Task.list_to_json(course.tasks, g.current_user))
        task_query = Task.query.filter_by(course_id=cid)
        task_type = request.args.get("type")
        if task_type is not None:
            task_query = task_query.filter_by(type=task_type)

        per_page = int(request.args.get("per_page", 20))
        page = int(request.args.get("page", 1))
        tasks_pagination = task_query.paginate(page, per_page=per_page, error_out=False)
        data = Task.page_to_json(tasks_pagination, g.current_user, cid)
        return make_resp(data)

    def post(self, cid):
        course = g.current_course
        data = task_create_reqparser.parse_args()
        new_task = Task(data['type'], data['name'], data['t_begin'], data['t_end'],
                        int(data['ans_visible']), data['introduce'], data['expires'])
        probs = eval(data['problems'])
        prob_list = []
        for v in probs.values():
            prob_list.append(v)
        prob_order_set = set()
        for prob in prob_list:
            prob = prob_parser(prob)

            if not prob:
                return api_abort(400, 'bad prob param')
            if prob['order'] in prob_order_set:
                return api_abort(400, 'duplicate of order')
            prob_order_set.add(prob['order'])

            new_prob = create_prob(prob)
            new_task.problems.append(new_prob)
        new_task.judge_max_score()
        [new_task.students.append(student) for student in course.students]
        r.sadd("task_finished:"+str(new_task.id), g.current_user.id)
        course.tasks.append(new_task)
        db.session.commit()
        resp = new_task.to_json(g.current_user, detail=True)
        return make_resp(resp)
Пример #5
0
class ReplyAPI(Resource):
    # /course/comment/<string:comment_id>/replies
    method_decorators = [resource_found_required("comment"), auth_required]

    def get(self, comment_id):
        comment = g.current_comment
        return make_resp(comment.to_json())
Пример #6
0
class CommentAPI(Resource):
    # url: /course/discussions/<string:discus_id>/comments?page=&per_page=
    method_decorators = [resource_found_required("discussion"), auth_required]

    def get(self, discus_id):
        per_page = int(request.args.get("per_page", 20))
        page = int(request.args.get("page", 1))
        comments_pagination = Comment.query.filter_by(discussion_id=discus_id).paginate(page, per_page=per_page, error_out=False)
        data = Comment.page_to_json(comments_pagination, discus_id)
        return make_resp(data)

    def post(self, discus_id):
        # post a comment
        data = comment_reqparser.parse_args()
        new_comment = Comment(data['content'], data['reply'])
        new_comment.author = g.current_user
        new_comment.discussion = g.current_discussion
        db.session.add(new_comment)
        if data['reply'] is not None:
            comment_reply = Comment.query.get(data['reply'])
            if comment_reply is None:
                return api_abort(404, "comment reply is not exist")
            replies = pickle.loads(comment_reply.replies)
            replies.append(new_comment.id)
            comment_reply.replies = pickle.dumps(replies)
        db.session.commit()
        return make_resp(g.current_discussion.to_json(detail=True))
Пример #7
0
class CorrectAnswerAPI(Resource):
    # url: /task/answers/correct_answer?task_answer_id=<string:uuid>
    method_decorators = [auth_required, resource_found_required('task_answer')]

    def post(self):
        if not g.current_user.is_teacher(g.current_task_answer.task.course):
            return api_abort(403, "not the teacher")
        #  要是想以另一种形式返回也行
        check_res_list = check_answer_reqparser.parse_args()['check_res']
        check_res_list = eval(check_res_list)
        answers = dict()
        answer = g.current_task_answer.answers
        for ans in answer:
            answers[int(ans.order)] = ans

        for check_res in check_res_list:
            order = check_res['order']
            ans = answers[order]
            score = check_res['score'] if check_res[
                'score'] is not None else ans.score
            if score > ans.problem.max_score:
                return api_abort(
                    400,
                    "the score of answer ordered {} is too high".format(order))
            ans.score = score
            ans.comment = check_res.get("comment", None)

        g.current_task_answer.judge_score()
        db.session.commit()
        return make_resp("OK")
Пример #8
0
class ProbStatisticAPI(Resource):
    # url: /task/<string:tid>/statistic/problems?order=<int:order>&detail=True
    method_decorators = [
        edit_task_allowed,
        resource_found_required("task"), auth_required
    ]

    def get(self, tid):
        order = request.args.get("order", None)
        if order is None:
            return api_abort(400, "param order is needed")
        order = int(order)

        problem = None
        for prob in g.current_task.problems:
            if prob.order == order:
                problem = prob
                break
        if problem is None:
            return api_abort(400,
                             "problem order {} is not found".format(order))

        detail = request.args.get("detail", False)
        data = problem.statistic(detail)
        return make_resp(data)
Пример #9
0
class MovieUploadAPI(Resource):
    method_decorators = [teacher_required, auth_required, resource_found_required('course')]

    def post(self, cid):
        # expected str chapter and file document, if chapter not exist, create it.
        data = upload_reqparser.parse_args()
        chapter_name = data['chapter']
        name = data['name']
        chapter = Chapter.query.filter_by(name=chapter_name, course_id=g.current_course.id).first()
        if chapter is None:
            chapter = Chapter(chapter_name)
            chapter.course = g.current_course
            db.session.add(chapter)

        course = g.current_course
        movie = request.files.get('movie')
        if movie is None:
            return api_abort(400, "movie is None")

        new_media_uuid = Media.save_media(movie, 'course/{}/movie'.format(course.id), name=name)
        media_uuid_list = pickle.loads(chapter.movies)
        media_uuid_list.append(new_media_uuid)
        chapter.movies = pickle.dumps(media_uuid_list)
        db.session.commit()
        return make_resp(chapter.to_json(with_movies=True))
Пример #10
0
class MediaAPI(Resource):
    # url: /course/media/<string:media_id>
    method_decorators = [resource_found_required("media")]

    def get(self, media_id):
        media = g.current_media
        return make_resp(media.to_json())
Пример #11
0
class ChapterListAPI(Resource):
    # url: /course/<int:cid>/chapters
    method_decorators = [resource_found_required('course'), auth_required]

    def get(self, cid):
        chapters = g.current_course.chapters
        return make_resp(Chapter.list_to_json(chapters))
Пример #12
0
class TaskStuStatusAPI(Resource):
    # url:/task/<string:tid>/statistic/stu_status
    method_decorators = [
        edit_task_allowed, auth_required,
        resource_found_required("task")
    ]

    def get(self, tid):
        task = g.current_task
        students = task.students
        key = "task_finished:" + str(task.id)
        stu_list = []
        for student in students:
            score = 0
            task_answer = set(student.answers).intersection(
                set(g.current_task.answers))
            if task_answer:
                score = task_answer.pop().score

            if not r.sismember(key, student.id):
                finished = False
            else:
                finished = True

            data = {
                "name": student.name,
                "student_id": student.student_id,
                "finished": finished,
                "score": score
            }

            stu_list.append(data)

        return make_resp(stu_list)
Пример #13
0
class JoinStatusAPI(Resource):
    # url: /<int:cid>/join/status
    method_decorators = [auth_required, resource_found_required('course')]

    def get(self, cid):
        status = 1 if g.current_user in g.current_course.students else 0
        return make_resp(status)
Пример #14
0
class CommitStatisticsAPI(Resource):
    # url: /course/<int:cid>/commit/statistics?commit_id=
    method_decorators = [teacher_required, resource_found_required("course"), auth_required]

    def get(self, cid):
        key = "commits:" + str(g.current_course.id)
        commits = r.lrange(key, 0, r.llen(key))

        # find commit by commit id
        commit_id = request.args.get("commit_id")
        if commit_id is not None:
            status = 0
            for commit in commits:
                if commit['id'] == commit_id:
                    commits = [commit]
                    status = 1
                    break
            if not status:
                return api_abort(404, "resource commit not found")
        commit_list = []
        for commit in commits:
            commit_list.append(pickle.loads(commit))

        data = {
            "count": len(commits),
            "commits": commit_list
        }
        return make_resp(data)
Пример #15
0
class MovieListAPI(Resource):
    # url: /course/<int:cid>/movies
    method_decorators = [resource_found_required('course')]

    def get(self, cid):
        course = g.current_course
        chapters = course.chapters
        data = Chapter.list_to_json(chapters, with_movies=True)
        return make_resp(data)
Пример #16
0
class GetStudentsAPI(Resource):
    # url: /<int:cid>/students
    method_decorators = [resource_found_required('course')]

    def get(self, cid):
        students = g.current_course.students
        page = request.args.get("page", 1)
        per_page = request.args.get("per_page", 20)
        students = students[(page-1)*per_page:page*per_page]
        data = User.list_to_json(students)
        return make_resp(data)
Пример #17
0
class TaskStatisticAPI(Resource):
    # url: /task/<string:tid>/statistic?detail=True
    method_decorators = [
        edit_task_allowed,
        resource_found_required("task"), auth_required
    ]

    def get(self, tid):
        detail = request.args.get("detail", False)
        data = g.current_task.statistic(detail)
        return make_resp(data)
Пример #18
0
class TaskAPI(Resource):
    # url: /task/<int:tid>
    # if finished, will return the correct answer
    method_decorators = {
        "get":
        [get_course_allowed, auth_required,
         resource_found_required('task')],
        "delete":
        [edit_task_allowed, auth_required,
         resource_found_required('task')]
    }

    def get(self, tid):
        set_exam_expires(g.current_user, g.current_task)
        return make_resp(g.current_task.to_json(g.current_user, detail=True))

    def delete(self, tid):
        db.session.delete(g.current_task)
        db.session.commit()
        return make_resp({})
Пример #19
0
class CourseAPI(Resource):
    # url: /<int:id>
    method_decorators = {"get": [resource_found_required('course'), auth_required],
                         "put": [teacher_required, auth_required, resource_found_required('course')],
                         "delete": [teacher_required, auth_required, resource_found_required('course')]}

    def get(self, cid):
        return make_resp(g.current_course.to_json(detail=True))

    def put(self, cid):
        course = g.current_course
        data = course_put_reqparser.parse_args()
        edit_module(course, data)
        db.session.commit()
        return course.to_json(detail=True)

    def delete(self, cid):
        course = g.current_course
        data = course.to_json(detail=True)
        db.session.delete(course)
        db.session.commit()
        return make_resp(data)
Пример #20
0
class CourseAvatarAPI(Resource):
    # url: avatars/course/<int:cid>
    method_decorators = {"get": [resource_found_required('course')],
                         "post": [auth_required, resource_found_required("course")]}

    def get(self, cid):
        url = Media.load_media_from_uuid(g.current_course.avatar, return_model=True).url
        return redirect(url)

    def post(self, cid):
        if not g.current_user.is_teacher(g.current_course):
            return api_abort(403, "permission denied")

        old_media = Media.load_media_from_uuid(g.current_course.avatar, return_model=True)
        new_media = request.files.get("avatar")
        if new_media is None:
            return api_abort(400, "file missing")
        new_media_uuid = Media.save_media(new_media, "avatars/course", commit=False)
        old_media.delete() if old_media is not None else 1
        g.current_course.avatar = new_media_uuid
        db.session.commit()
        return "OK"
Пример #21
0
class JoinCourseAPI(Resource):
    # url: /join/<int:cid>
    method_decorators = [auth_required, resource_found_required('course')]

    def post(self, cid):
        course = g.current_course
        user = g.current_user
        if course in user.courses:
            return api_abort(400, "you already in the course")
        if user.is_teacher(course):
            return api_abort(403, "you are the teacher!")
        if not course.public:
            return api_abort(403, "can only join the public course")
        course.students.append(user)
        db.session.commit()
        return make_resp(course.to_json())
Пример #22
0
class ProblemAPIByOrder(Resource):
    # url: /task/<string:tid>/problems/<int:order>
    method_decorators = [
        get_course_allowed, auth_required,
        resource_found_required('task')
    ]

    def get(self, tid, order):
        task = g.current_task
        problem = None
        for prob in task.problems:
            if prob.order == order:
                problem = prob
                break
        if problem is None:
            return api_abort(404, "problem order {} not found".format(order))
        return make_resp(problem.to_json())
Пример #23
0
class DiscussionListAPI(Resource):
    # url: /course/<int:cid>/discussions/
    method_decorators = [get_course_allowed, resource_found_required("course"), auth_required]

    def get(self, cid):
        # get discussions
        discussions = g.current_course.discussions
        return make_resp(Discussion.list_to_json(discussions))

    def post(self, cid):
        # post a discussion
        data = discussion_reqparser.parse_args()
        new_discussion = Discussion(data['content'])
        new_discussion.master = g.current_user
        new_discussion.course = g.current_course
        db.session.add(new_discussion)
        db.session.commit()
        return make_resp(new_discussion.to_json(detail=True))
Пример #24
0
class ImportStuAPI(Resource):
    # url: course/<int:cid>/students/import
    method_decorators = [teacher_required, auth_required, resource_found_required('course')]

    def post(self, cid):
        course = g.current_course
        data = parse_excel(request, 'excel_file')  # it's a list
        for item in data:
            item = deal_import_data(item)
            user = User.query.filter_by(school=item['school'], student_id=item['student_id']).first()
            if user is None:
                key = item['school'] + ":" + item['student_id']
                item['courses'].append(course.id)
                r.set(key, pickle.dumps(item))
            else:
                user.courses.append(course)
                user.name = item['name']
                db.session.commit()
        return make_resp(course.to_json(detail=True))
Пример #25
0
class AnswerAPIByOrder(Resource):
    # url: /task/<string:tid>/answers/<int:order>
    method_decorators = [
        get_course_allowed, auth_required,
        resource_found_required('task')
    ]

    def get(self, tid, order):
        task = g.current_task
        user = g.current_user
        task_answer = set(task.answers).intersection(set(user.answers))
        if not task_answer:
            return api_abort(404, "you have not finished the problem")
        task_answer = task_answer.pop()
        answers = task_answer.answers
        answer_return = None
        for answer in answers:
            if answer.problem.order == order:
                answer_return = answer
                break
        if answer_return is None:
            return api_abort(404, "answer order {} not found".format(order))
        return make_resp(answer_return.to_json())
Пример #26
0
class TaskAnswerAPI(Resource):
    # url: /task/<string:tid>/answers?uncheck=<bool>
    method_decorators = [auth_required, resource_found_required('task')]

    def get(self, tid):
        task = g.current_task
        user = g.current_user
        uncheck = request.args.get('uncheck', 0)
        task_answer = None
        if uncheck:
            if not user.is_teacher(task.course):
                return api_abort(403, 'not the teacher')
            for answer in task.answers:
                if not answer.status:
                    task_answer = answer
                    break
            if task_answer is None:
                return api_abort(404, "all answers checked")
        else:
            task_answer = set(user.answers).intersection(set(task.answers))
            if not task_answer:
                return api_abort(404, "have not finished the task")
            task_answer = task_answer.pop()
        return make_resp(task_answer.to_json(detail=True))
Пример #27
0
class NoticeAPI(Resource):
    # url: /course/<int:cid>/notices/<string:notice_id>
    method_decorators = {"get": [get_course_allowed, auth_required, resource_found_required("notice"),
                                 resource_found_required("course")],
                         "post": [get_course_allowed, auth_required, resource_found_required("notice"),
                                 resource_found_required("course")],
                         "delete": [teacher_required, auth_required, resource_found_required("course"),
                                    resource_found_required("notice")]}

    def get(self, cid, notice_id):
        return make_resp(g.current_notice.to_json(detail=True))

    def post(self, cid, notice_id):
        key_notice_read = "read:{}".format(notice_id)
        key_user_cnt = "read:{}:{}".format(cid, g.current_user.id)
        r.sadd(key_notice_read, g.current_user.id)
        r.incr(key_user_cnt)
        return "OK"

    def delete(self, cid, notice_id):
        db.session.delete(g.current_notice)
        db.session.commit()
        return "OK"
Пример #28
0
class AnswerSubmitAPI(Resource):
    # url: /task/<string:tid>/submit
    method_decorators = [
        get_course_allowed, auth_required,
        resource_found_required('task')
    ]

    def post(self, tid):
        user = g.current_user
        task = g.current_task
        if user.is_teacher(task.course):
            return api_abort(403, "you are the teacher")
        time_now = time()
        if not task.time_begin <= time_now <= task.time_end:
            return api_abort(403, "not in the time")

        # delete existed answer
        exist_task_answer = set(task.answers).intersection(set(user.answers))
        if exist_task_answer:
            exist_task_answer = exist_task_answer.pop()
            for answer in exist_task_answer.answers:
                if answer.media is not None:
                    medias = Media.load_medias_from_uuid_list(
                        pickle.loads(answer.media), return_model=True)
                    for media in medias:
                        media.delete()
            db.session.delete(exist_task_answer)

        new_task_answer = TaskAnswer()
        answers = answer_submit_reqparser.parse_args()['answers']
        if not isinstance(answers, list):
            answers = eval(answers)
        problems = dict()
        prob_order_set = set()
        for prob in task.problems:
            problems[prob.order] = prob
            prob_order_set.add(prob.order)

        answer_order_set = set()
        for answer in answers:
            if not isinstance(answer, dict):
                answer = eval(answer)
            content = answer.get('content', None)
            if content == 'undefined':
                content = None
            order = answer.get("order", None)
            if order is None:
                return api_abort(400, "order is needed")
            answer_order_set.add(order)
            medias = request.files.getlist('answer' + str(order))
            media_uuid_list = Media.save_medias(
                medias, 'answer') if len(medias) is not 0 else None
            new_answer = Answer(order, content, media_uuid_list)
            new_answer.student = user
            new_answer.problem = problems[order]
            if new_answer.problem.type is not "subjective":
                new_answer.judge_score()
            new_task_answer.answers.append(new_answer)

        if answer_order_set.difference(prob_order_set):
            return api_abort(400, "answer order over the max order")
        for order in prob_order_set.difference(answer_order_set):
            medias = request.files.getlist('answer' + str(order), None)
            media_uuid_list = Media.save_medias(
                medias, 'answer') if len(medias) is not 0 else None
            new_answer = Answer(order, medias=media_uuid_list)
            new_answer.student = user
            new_answer.problem = problems[order]
            new_task_answer.answers.append(new_answer)

        new_task_answer.student = user
        new_task_answer.task = task
        new_task_answer.judge_score()
        r.sadd("task_finished:" + task.id, user.id)
        db.session.add(new_task_answer)
        db.session.commit()
        data = new_task_answer.to_json(detail=True)
        return make_resp(data)
Пример #29
0
class ProbAPIByID(Resource):
    # url: /task/problem/<string:prob_id>
    method_decorators = [auth_required, resource_found_required('problem')]

    def get(self, prob_id):
        return make_resp(g.current_problem.to_json())
Пример #30
0
class UserAPI(Resource):
    # url: /user/<int:uid>
    method_decorators = [resource_found_required('user')]

    def get(self, uid):
        return make_resp(g.current_user.to_json(detail=False))