Skip to content

Commit

Permalink
Implemented answer validation view for structural float and expression
Browse files Browse the repository at this point in the history
  • Loading branch information
arielfayol37 committed Aug 18, 2023
1 parent 49b70ba commit 9fdb6b8
Show file tree
Hide file tree
Showing 14 changed files with 111 additions and 16 deletions.
6 changes: 6 additions & 0 deletions attacks.txt.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
If the validation of algebraic expressions is done on
the front-end using mathjs' symbolicEqual() function.
So someone can modify the fetch() that gets the real answer
from the server.
Hence the reason why sympy is used in the backend for that,
and not mathjs.
Binary file modified db.sqlite3
Binary file not shown.
Binary file modified deimos/__pycache__/urls.cpython-311.pyc
Binary file not shown.
Binary file modified deimos/__pycache__/views.cpython-311.pyc
Binary file not shown.
16 changes: 11 additions & 5 deletions deimos/static/deimos/js/action_menu.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
let menuToggle = document.querySelector('.menuToggle');
menuToggle.addEventListener('click', (event)=>{
event.preventDefault();
menuToggle.classList.toggle('active');
})
document.addEventListener('DOMContentLoaded',()=>{

const menuToggle = document.querySelector('.menuToggle');
if (menuToggle != null){
menuToggle.addEventListener('click', (event)=>{
event.preventDefault();
menuToggle.classList.toggle('active');
})
}

})
21 changes: 20 additions & 1 deletion deimos/static/deimos/js/answer_input.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
document.addEventListener('DOMContentLoaded', ()=> {
const answerFieldsDiv = document.querySelector('.answer-fields');
const form = document.querySelector('#question-form');
let currentAction = form.getAttribute('action');
const validateAnswerActionURL = extractQuestionPath(window.location.href) + '/validate_answer';
//console.log(newActionURL);
//form.setAttribute('action', newActionURL);
const submitBtn = document.querySelector('submit-btn');
const formattedAnswerDiv = document.querySelector('.formatted-answer');
const calculatorDiv = document.querySelector('.calculator');
const inputedMcqAnswersDiv = document.querySelector('.inputed-mcq-answers');
var num_true_counter = 0;
const screen = document.querySelector('#screen');

/*-----------------------------Question submission-----------------------*/

submitBtn.addEventListener('click', (event){
event.preventDefault();
})

/*----------------------------DISPLAYING LATEX-------------------------*/

function displayLatex(){
Expand Down Expand Up @@ -81,6 +90,7 @@ displayLatex();


form.addEventListener('submit', (event)=>{
event.preventDefault();
if (!(screen === null)){
const userInputNode = math.parse(screen.value);
var userInputString = userInputNode.toString();
Expand All @@ -104,4 +114,13 @@ function setCharAt(str,index,chr) {
return str.substring(0,index) + chr + str.substring(index+1);
}

function extractQuestionPath(url) {
const startIndex = url.indexOf('courses');
if (startIndex !== -1) {
return url.substring(startIndex);
} else {
return null; // If 'courses' not found in URL
}
}

});
8 changes: 4 additions & 4 deletions deimos/templates/deimos/answer_question.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,22 @@ <h3>Question {{question.number}}</h3>
<br/> <br/>
{% endfor %}
</div>
<input type="submit" class="btn btn-success exempt" value="Submit Answer">
<input type="submit" class="btn btn-success exempt" id="submit-btn" value="Submit Answer">
<br/> <br/>
{% elif is_fr %}

<div>
<textarea placeholder="Enter answer" class="w-100 question-input-field"></textarea>
</div>
<div> <input type="submit" class="btn btn-success exempt" value="Submit Answer"></div>
<div> <input type="submit" class="btn btn-success exempt" id="submit-btn" value="Submit Answer"></div>
<br/><br/>
{% else %}

<input type="hidden" value="{{answer.pk}}" name="structural_answer_id_0"/>
{% for q_type in question_type %} <!--expecting to iterate only over one item-->
<input type="hidden" value="{{q_type}}" name="structural_answer_info_0"/>
{% endfor %}
<input type="submit" class="btn btn-success exempt" value="Submit Answer">
<input type="submit" class="btn btn-success exempt" id="submit-btn" value="Submit Answer">
<div class="formatted-answer"></div>
{% include 'deimos/calci.html' %}
<br/>
Expand Down Expand Up @@ -88,7 +88,7 @@ <h3>Question {{question.number}}</h3>
{% endblock %}
{% block scripts%}

<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/9.5.0/math.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/11.9.1/math.js"></script>
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script id="MathJax-script" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<script src="{% static 'deimos/js/question.js' %}"></script>
Expand Down
2 changes: 2 additions & 0 deletions deimos/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

path('courses/<int:course_id>/assignments/<int:assignment_id>/questions/<int:question_id>',\
views.answer_question, name='answer_question'),
path('courses/<int:course_id>/assignments/<int:assignment_id>/questions/<int:question_id>/validate_answer',\
views.validate_answer, name='validate_answer'),
path('question_nav', views.question_nav, name='question_nav'),
path('action_menu', views.action_menu, name='action_menu')
]
46 changes: 42 additions & 4 deletions deimos/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from django.utils.timesince import timesince
from phobos.models import QuestionChoices
import random
from sympy import symbols, simplify, Eq

# Create your views here.
@login_required(login_url='astros:login')
Expand Down Expand Up @@ -96,8 +97,8 @@ def answer_question(request, question_id, assignment_id=None, course_id=None):
question = Question.objects.get(pk=question_id)
if not QuestionStudent.objects.filter(question=question, student=student).exists():
quest = QuestionStudent.objects.create(question=question, student=student)
is_mcq = False
is_fr = False
is_mcq = False #nis mcq
is_fr = False # is free response
answers = []
is_latex = []
question_type = []
Expand Down Expand Up @@ -139,7 +140,7 @@ def answer_question(request, question_id, assignment_id=None, course_id=None):
answers.extend(question.float_answers.all())
question_type = [1]
elif question.answer_type == QuestionChoices.STRUCTURAL_TEXT:
is_fr = True
is_fr = True
answers.extend(question.text_answers.all())
question_type = [4]
context = {
Expand All @@ -148,13 +149,37 @@ def answer_question(request, question_id, assignment_id=None, course_id=None):
'assignment_id': assignment_id,
'course_id': course_id,
"is_mcq": is_mcq,
"is_fr": is_fr, #is free response
"is_fr": is_fr,
"answers_is_latex_question_type": zip(answers, is_latex, question_type),
'question_type': question_type, # For structural
'answer': answers[0]
}
return render(request, 'deimos/answer_question.html',
context)

def validate_answer(request, question_id, submitted_answer, assignment_id=None, course_id=None):
student = get_object_or_404(Student, pk=request.user.pk)
if request.method == 'POST':
question = Question.objects.get(pk=question_id)
question_student = QuestionStudent(student=student, question=question)
attempt = QuestionAttempt.objects.create(question_student=question_student)
correct = False
if question.answer_type == QuestionChoices.STRUCTURAL_EXPRESSION:
# assert question.expression_answers.count() == 1
answer = question.expression_answers.first() # There should be only one answer.
correct = compare_expressions(answer.content, submitted_answer)
elif question.answer_type == QuestionChoices.STRUCTURAL_FLOAT:
# assert question.float_answers.count() == 1
answer = question.float_answers.first()
correct = compare_expressions(answer.content, submitted_answer)

if correct:
attempt.num_points = question.num_points - (question.deduct_per_attempt * question_student.get_num_attempts())
return JsonResponse({
'correct': correct
})



def login_view(request):
if request.method == "POST":
Expand Down Expand Up @@ -227,7 +252,20 @@ def is_student_enrolled(student_id, course_id):
is_enrolled = Enrollment.objects.filter(student=student, course=course).exists()

return is_enrolled
def compare_expressions(e1, e2):
""" Given two strings e1 and e2,
returns True if they are algebraically equivalent,
returns False otherwise
"""
su = set(e1) | set(e2)
so = symbols(' '.join(su))
sym_e1 = simplify(e1, symbols=so)
sym_e2 = simplify(e2, symbols=so)
same = Eq(sym_e1, sym_e2)
return True if same==True else False


#--------------------Depecrated functions used in development--------------------
def question_nav(request):
return render(request, 'deimos/question_nav.html', {})

Expand Down
Binary file modified phobos/__pycache__/models.cpython-311.pyc
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.2.3 on 2023-08-18 20:33

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('phobos', '0018_assignment_category_alter_question_answer_type'),
]

operations = [
migrations.AddField(
model_name='question',
name='deduct_per_attempt',
field=models.FloatField(default=0.05),
),
migrations.AlterField(
model_name='question',
name='answer',
field=models.CharField(blank=True, max_length=1000, null=True),
),
]
Binary file not shown.
3 changes: 2 additions & 1 deletion phobos/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,8 @@ class Question(models.Model):
choices = QuestionChoices.choices,
default = QuestionChoices.STRUCTURAL_TEXT
)
answer = models.CharField(max_length=1000, null=True, blank=True)
answer = models.CharField(max_length=1000, null=True, blank=True) # TODO: delete this attribute.
deduct_per_attempt = models.FloatField(default=0.05)

def __str__(self):
return f"Question {self.number} ranked {self.difficulty_level} for {self.assignment}"
Expand Down
2 changes: 1 addition & 1 deletion phobos/templates/phobos/create_question.html
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ <h3>Create a Question</h3>
{% endblock %}
{% block scripts%}

<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/9.5.0/math.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/11.9.1/math.js"></script>
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<script src="{% static 'phobos/js/subtopics.js' %}"></script>
Expand Down

0 comments on commit 9fdb6b8

Please sign in to comment.