diff options
Diffstat (limited to 'api/views.py')
-rw-r--r-- | api/views.py | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/api/views.py b/api/views.py new file mode 100644 index 0000000..8d2da83 --- /dev/null +++ b/api/views.py @@ -0,0 +1,432 @@ +from yaksh.models import ( + Question, Quiz, QuestionPaper, QuestionSet, AnswerPaper, Course, Answer +) +from api.serializers import ( + QuestionSerializer, QuizSerializer, QuestionPaperSerializer, + AnswerPaperSerializer, CourseSerializer +) +from rest_framework.views import APIView +from rest_framework.response import Response +from rest_framework import status +from rest_framework import permissions +from rest_framework.authtoken.models import Token +from rest_framework.decorators import ( + api_view, authentication_classes, permission_classes +) +from django.http import Http404 +from django.contrib.auth import authenticate +from yaksh.code_server import get_result as get_result_from_code_server +from yaksh.settings import SERVER_POOL_PORT, SERVER_HOST_NAME +import json + + +class QuestionList(APIView): + """ List all questions or create a new question. """ + + def get(self, request, format=None): + questions = Question.objects.filter(user=request.user) + serializer = QuestionSerializer(questions, many=True) + return Response(serializer.data) + + def post(self, request, format=None): + serializer = QuestionSerializer(data=request.data) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + +class CourseList(APIView): + """ List all courses """ + + def get(self, request, format=None): + courses = Course.objects.filter(students=request.user) + serializer = CourseSerializer(courses, many=True) + return Response(serializer.data) + + +class StartQuiz(APIView): + """ Retrieve Answerpaper. If does not exists then create one """ + + def get_quiz(self, pk, user): + try: + return Quiz.objects.get(pk=pk) + except Quiz.DoesNotExist: + raise Http404 + + def get(self, request, course_id, quiz_id, format=None): + context = {} + user = request.user + quiz = self.get_quiz(quiz_id, user) + questionpaper = quiz.questionpaper_set.first() + + last_attempt = AnswerPaper.objects.get_user_last_attempt( + questionpaper, user, course_id) + if last_attempt and last_attempt.is_attempt_inprogress(): + serializer = AnswerPaperSerializer(last_attempt) + context["time_left"] = last_attempt.time_left() + context["answerpaper"] = serializer.data + return Response(context) + + can_attempt, msg = questionpaper.can_attempt_now(user, course_id) + if not can_attempt: + return Response({'message': msg}) + if not last_attempt: + attempt_number = 1 + else: + attempt_number = last_attempt.attempt_number + 1 + ip = request.META['REMOTE_ADDR'] + answerpaper = questionpaper.make_answerpaper(user, ip, attempt_number, + course_id) + serializer = AnswerPaperSerializer(answerpaper) + context["time_left"] = answerpaper.time_left() + context["answerpaper"] = serializer.data + return Response(context, status=status.HTTP_201_CREATED) + + +class QuestionDetail(APIView): + """ Retrieve, update or delete a question """ + + def get_question(self, pk, user): + try: + return Question.objects.get(pk=pk, user=user) + except Question.DoesNotExist: + raise Http404 + + def get(self, request, pk, format=None): + question = self.get_question(pk, request.user) + serializer = QuestionSerializer(question) + return Response(serializer.data) + + def put(self, request, pk, format=None): + question = self.get_question(pk, request.user) + serializer = QuestionSerializer(question, data=request.data) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + def delete(self, request, pk, format=None): + question = self.get_question(pk, request.user) + question.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + + +class AnswerPaperList(APIView): + + def get_questionpaper(self, pk): + try: + return QuestionPaper.objects.get(pk=pk) + except QuestionPaper.DoesNotExist: + raise Http404 + + def get_course(self, pk): + try: + return Course.objects.get(pk=pk) + except Course.DoesNotExist: + raise Http404 + + def get_answerpapers(self, user): + return AnswerPaper.objects.filter(question_paper__quiz__creator=user) + + def get(self, request, format=None): + user = request.user + answerpapers = self.get_answerpapers(user) + serializer = AnswerPaperSerializer(answerpapers, many=True) + return Response(serializer.data) + + def is_user_allowed(self, user, course): + ''' if user is student or teacher or creator then allow ''' + return user in course.students.all() or user in course.teachers.all() \ + or user == course.creator + + def post(self, request, format=None): + try: + questionpaperid = request.data['question_paper'] + attempt_number = request.data['attempt_number'] + course_id = request.data['course'] + except KeyError: + return Response(status=status.HTTP_400_BAD_REQUEST) + user = request.user + ip = request.META['REMOTE_ADDR'] + questionpaper = self.get_questionpaper(questionpaperid) + course = self.get_course(course_id) + if not self.is_user_allowed(user, course): + return Response(status=status.HTTP_400_BAD_REQUEST) + answerpaper = questionpaper.make_answerpaper(user, ip, attempt_number, + course_id) + serializer = AnswerPaperSerializer(answerpaper) + return Response(serializer.data, status=status.HTTP_201_CREATED) + + +class AnswerValidator(APIView): + + def get_answerpaper(self, pk, user): + try: + return AnswerPaper.objects.get(pk=pk, user=user) + except AnswerPaper.DoesNotExist: + raise Http404 + + def get_question(self, pk, answerpaper): + try: + question = Question.objects.get(pk=pk) + if question in answerpaper.questions.all(): + return question + else: + raise Http404 + except AnswerPaper.DoesNotExist: + raise Http404 + + def get_answer(self, pk): + try: + return Answer.objects.get(pk=pk) + except Answer.DoesNotExist: + raise Http404 + + def post(self, request, answerpaper_id, question_id, format=None): + user = request.user + answerpaper = self.get_answerpaper(answerpaper_id, user) + question = self.get_question(question_id, answerpaper) + try: + if question.type == 'mcq' or question.type == 'mcc': + user_answer = request.data['answer'] + elif question.type == 'integer': + user_answer = int(request.data['answer'][0]) + elif question.type == 'float': + user_answer = float(request.data['answer'][0]) + elif question.type == 'string': + user_answer = request.data['answer'] + else: + user_answer = request.data['answer'] + except KeyError: + return Response(status=status.HTTP_400_BAD_REQUEST) + # save answer uid + answer = Answer.objects.create(question=question, answer=user_answer) + answerpaper.answers.add(answer) + answerpaper.save() + json_data = None + if question.type in ['code', 'upload']: + json_data = question.consolidate_answer_data(user_answer, user) + result = answerpaper.validate_answer(user_answer, question, json_data, + answer.id) + + # updaTE RESult + if question.type not in ['code', 'upload']: + if result.get('success'): + answer.correct = True + answer.marks = question.points + answer.error = json.dumps(result.get('error')) + answer.save() + answerpaper.update_marks(state='inprogress') + return Response(result) + + def get(self, request, uid): + answer = self.get_answer(uid) + url = '{0}:{1}'.format(SERVER_HOST_NAME, SERVER_POOL_PORT) + result = get_result_from_code_server(url, uid) + # update result + if result['status'] == 'done': + final_result = json.loads(result.get('result')) + answer.error = json.dumps(final_result.get('error')) + if final_result.get('success'): + answer.correct = True + answer.marks = answer.question.points + answer.save() + answerpaper = answer.answerpaper_set.get() + answerpaper.update_marks(state='inprogress') + return Response(result) + + +class QuizList(APIView): + """ List all quizzes or create a new quiz """ + + def get(self, request, format=None): + quizzes = Quiz.objects.filter(creator=request.user) + serializer = QuizSerializer(quizzes, many=True) + return Response(serializer.data) + + def post(self, request, format=None): + serializer = QuizSerializer(data=request.data) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + +class QuizDetail(APIView): + """ Retrieve, update or delete a quiz """ + + def get_quiz(self, pk, user): + try: + return Quiz.objects.get(pk=pk, creator=user) + except Quiz.DoesNotExist: + raise Http404 + + def get(self, request, pk, format=None): + quiz = self.get_quiz(pk, request.user) + serializer = QuizSerializer(quiz) + return Response(serializer.data) + + def put(self, request, pk, format=None): + quiz = self.get_quiz(pk, request.user) + serializer = QuizSerializer(quiz, data=request.data) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + def delete(self, request, pk, format=None): + quiz = self.get_quiz(pk, request.user) + quiz.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + + +class QuestionPaperList(APIView): + """ List all question papers or create a new question paper """ + + def get_questionpapers(self, user): + return QuestionPaper.objects.filter(quiz__creator=user) + + def questionpaper_exists(self, quiz_id): + return QuestionPaper.objects.filter(quiz=quiz_id).exists() + + def check_quiz_creator(self, user, quiz_id): + try: + Quiz.objects.get(pk=quiz_id, creator=user) + except Quiz.DoesNotExist: + raise Http404 + + def check_questions_creator(self, user, question_ids): + for question_id in question_ids: + try: + Question.objects.get(pk=question_id, user=user) + except Question.DoesNotExist: + raise Http404 + + def check_questionsets_creator(self, user, questionset_ids): + for question_id in questionset_ids: + try: + questionset = QuestionSet.objects.get(pk=question_id) + for question in questionset.questions.all(): + Question.objects.get(pk=question.id, user=user) + except (QuestionSet.DoesNotExist, Question.DoesNotExist): + raise Http404 + + def get(self, request, format=None): + questionpapers = self.get_questionpapers(request.user) + serializer = QuestionPaperSerializer(questionpapers, many=True) + return Response(serializer.data) + + def post(self, request, format=None): + serializer = QuestionPaperSerializer(data=request.data) + if serializer.is_valid(): + user = request.user + quiz_id = request.data.get('quiz') + question_ids = request.data.get('fixed_questions', []) + questionset_ids = request.data.get('random_questions', []) + if self.questionpaper_exists(quiz_id): + return Response({'error': 'Already exists'}, + status=status.HTTP_409_CONFLICT) + self.check_quiz_creator(user, quiz_id) + self.check_questions_creator(user, question_ids) + self.check_questionsets_creator(user, questionset_ids) + serializer.save() + return Response(serializer.data, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status.HTTP_400_BAD_REQUEST) + + +class QuestionPaperDetail(APIView): + """ Retrieve, update or delete a question paper""" + + def get_questionpaper(self, pk, user): + try: + return QuestionPaper.objects.get(pk=pk, quiz__creator=user) + except QuestionPaper.DoesNotExist: + raise Http404 + + def get(self, request, pk, format=None): + questionpaper = self.get_questionpaper(pk, request.user) + serializer = QuestionPaperSerializer(questionpaper) + return Response(serializer.data) + + def check_quiz_creator(self, user, quiz_id): + try: + Quiz.objects.get(pk=quiz_id, creator=user) + except Quiz.DoesNotExist: + raise Http404 + + def check_questions_creator(self, user, question_ids): + for question_id in question_ids: + try: + Question.objects.get(pk=question_id, user=user) + except Question.DoesNotExist: + raise Http404 + + def check_questionsets_creator(self, user, questionset_ids): + for question_id in questionset_ids: + try: + questionset = QuestionSet.objects.get(pk=question_id) + for question in questionset.questions.all(): + Question.objects.get(pk=question.id, user=user) + except (QuestionSet.DoesNotExist, Question.DoesNotExist): + raise Http404 + + def put(self, request, pk, format=None): + user = request.user + questionpaper = self.get_questionpaper(pk, user) + serializer = QuestionPaperSerializer(questionpaper, data=request.data) + if serializer.is_valid(): + user = request.user + quiz_id = request.data.get('quiz') + question_ids = request.data.get('fixed_questions', []) + questionset_ids = request.data.get('random_questions', []) + self.check_quiz_creator(user, quiz_id) + self.check_questions_creator(user, question_ids) + self.check_questionsets_creator(user, questionset_ids) + serializer.save() + return Response(serializer.data) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + def delete(self, request, pk, format=None): + questionpaper = self.get_questionpaper(pk, request.user) + questionpaper.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + + +class GetCourse(APIView): + def get(self, request, pk, format=None): + course = Course.objects.get(id=pk) + serializer = CourseSerializer(course) + return Response(serializer.data) + + +@api_view(['POST']) +@authentication_classes(()) +@permission_classes(()) +def login(request): + data = {} + if request.method == "POST": + username = request.data.get('username') + password = request.data.get('password') + user = authenticate(username=username, password=password) + if user is not None and user.is_authenticated: + token, created = Token.objects.get_or_create(user=user) + data = { + 'token': token.key + } + return Response(data, status=status.HTTP_201_CREATED) + + +class QuitQuiz(APIView): + def get_answerpaper(self, answerpaper_id): + try: + return AnswerPaper.objects.get(id=answerpaper_id) + except AnswerPaper.DoesNotExist: + raise Http404 + + def get(self, request, answerpaper_id, format=None): + answerpaper = self.get_answerpaper(answerpaper_id) + answerpaper.status = 'completed' + answerpaper.save() + serializer = AnswerPaperSerializer(answerpaper) + return Response(serializer.data)
\ No newline at end of file |