Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merging from main #107

Merged
merged 5 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ Web platform for Physics Assigments System.

This is the README file for the Dr_R web application built using Django. The application is designed to provide different functionalities for students (Deimos), instructors (Phobos), and general users (Astros).

## PreRequisites
You must have installed python3 on your machine.
As of now, the system only supports 3.11 versions. Beyond that,
`torch` which is used for the search engine, won't be able to install.

## Installation

1. Clone the repository:
Expand Down
4 changes: 2 additions & 2 deletions deimos/templates/deimos/answer_question.html
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ <h3 class="original-size">Question {{question_dict.question.number}}</h3>
{{answer.content|safe}}
{% endif %}
{% endif %}
<input type="hidden" value="{{answer.pk}}{{answer.get_answer_code}}" class="answer_id" name="mcq_answer_id_{{ forloop.counter0 }}"/>
<input type="hidden" value="0{{answer.get_answer_code}}" class="answer_info" name="mcq_answer_info_{{ forloop.counter0 }}"/>
<input type="hidden" value="{{answer.get_pk_ac}}" class="answer_id" name="mcq_answer_id_{{ forloop.counter0 }}"/>
<input type="hidden" value="0" class="answer_info" name="mcq_answer_info_{{ forloop.counter0 }}"/>
</div>
</div>
<br/>
Expand Down
31 changes: 8 additions & 23 deletions deimos/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def assignment_management(request, assignment_id, course_id=None):
student = get_object_or_404(Student, pk = request.user.pk)
assignment = get_object_or_404(Assignment, pk = assignment_id)
assignment_student = AssignmentStudent.objects.get(student=student, assignment=assignment)
questions = Question.objects.filter(assignment = assignment, parent_question=None)
questions = Question.objects.filter(assignment = assignment, parent_question=None).order_by('number')
qs_statuses = []
if assignment.course.name != 'Question Bank':
for question in questions:
Expand Down Expand Up @@ -125,15 +125,9 @@ def gradebook(request, course_id):
})


# List of all answer types
all_mcq_answer_types = {
'ea': ('mcq_expression_answers', 0),
'ta': ('mcq_text_answers',3),
'fa':('mcq_float_answers',1),
'fva': ('mcq_variable_float_answers',8),
'ia': ('mcq_image_answers',7),
'la': ('mcq_latex_answers',2),
}
mcq_related_names = ['mcq_expression_answers', 'mcq_text_answers','mcq_float_answers',
'mcq_variable_float_answers','mcq_image_answers','mcq_latex_answers']

# TODO: Add the action link in answer_question.html
# TODO: Implement question_view as well.
@login_required(login_url='astros:login')
Expand Down Expand Up @@ -187,11 +181,11 @@ def answer_question(request, question_id, assignment_id, course_id, student_id=N
# List of answer types that require content evaluation
answer_types_to_evaluate = ['mcq_expression_answers', 'mcq_variable_float_answers']
# Loop through each answer type
for key, answer_type in all_mcq_answer_types.items():
for mrn in mcq_related_names:
# Get the related manager for the answer type
answer_queryset = getattr(question, answer_type[0]).all()
answer_queryset = getattr(question, mrn).all()
# If the answer type requires content evaluation, process each answer
if answer_type[0] in answer_types_to_evaluate:
if mrn in answer_types_to_evaluate:
for answer in answer_queryset:
answer.content = question_student.evaluate_var_expressions_in_text(answer.content, add_html_style=True)

Expand Down Expand Up @@ -414,16 +408,7 @@ def validate_answer(request, question_id, landed_question_id=None,assignment_id=
return JsonResponse({'previously_submitted': previously_submitted})
attempt = QuestionAttempt.objects.create(question_student=question_student, \
content=str(simplified_answer))
answers = []

# Loop through each answer type and process accordingly
for answer_type_code, answer_field in all_mcq_answer_types.items():
# Use getattr to dynamically get the related manager for the answer type
answer_queryset = getattr(question, answer_field[0])
# Filter for is_answer=True and get a list of primary keys
answer_pks = list(answer_queryset.filter(is_answer=True).values_list('pk', flat=True))
# Convert primary keys to the desired string format and extend the answers list
answers.extend([str(pk) + str(answer_field[1]) for pk in answer_pks])
answers = question.get_mcq_pk_ac_list()

# Validating mcq submission
if len(simplified_answer) == len(answers):
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added media/phobos/images/question_images/aii.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion phobos/migrations/0050_alter_course_subject.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Generated by Django 4.2.2 on 2023-11-28 15:01
# Generated by Django 4.2.3 on 2023-12-03 05:10


from django.db import migrations, models

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.2.3 on 2023-12-03 07:15

import django.core.validators
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('phobos', '0050_alter_course_subject'),
]

operations = [
migrations.AlterField(
model_name='structuralquestionsettings',
name='margin_error',
field=models.FloatField(default=0.03, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]),
),
]
63 changes: 60 additions & 3 deletions phobos/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ class Question(models.Model):
So all the questions in an assignment may have the same weight (uniform distribution),
or different weights based on the instructor's input or automated (based on difficulty)
"""
# parent question must have an integer as number because that's what is used for ordering.
number = models.CharField(blank=False, null=False, max_length=5)
text = models.TextField(max_length= 2000, null=False, blank=False)
assignment = models.ForeignKey(Assignment, null=True, on_delete=models.CASCADE, \
Expand All @@ -215,6 +216,21 @@ def default_due_date(self):

def save(self, *args, **kwargs):
save_settings = kwargs.pop('save_settings', False)
""""
# TODO: Make the following work. It is supposed to check that the number saved is in the correct format
for non-Question-Bank questions.
number = kwargs.get('number', None)
if kwargs.get('parent_question', None) == None:
if not number.isdigit(): # we want number to be a digit because that's what is used for ordering
raise ValueError(f'Expected the attribute "number" of a parent_question to be an integer, but got {self.number}')

else: # if a sub_question
if not number[:-1].isdigit() or not number[-1].isalpha():
raise ValueError(f'Expected the format of "number" for a subquestion to be digits followed \
by a letter, but got {self.number}')

"""

super(Question, self).save(*args, **kwargs)
if save_settings:
if self.answer_type.startswith('MCQ') or self.answer_type.startswith('MATCHING'):
Expand All @@ -241,12 +257,34 @@ def save(self, *args, **kwargs):

super(Question, self).save(*args, **kwargs)

def delete(self, *args, **kwargs):
if not self.parent_question:
self.sub_questions.all().delete()
super(Question, self).delete(*args, **kwargs)

def get_num_points(self):
if self.answer_type.startswith('MCQ') or self.answer_type.startswith('MATCHING'):
return self.mcq_settings.num_points
else:
return self.struct_settings.num_points


def get_mcq_pk_ac_list(self): # ac == answer_code
output = []
# List of all answer types
mcq_related_names = ['mcq_expression_answers', 'mcq_text_answers','mcq_float_answers',
'mcq_variable_float_answers','mcq_image_answers','mcq_latex_answers']
for mrn in mcq_related_names:
for mcq in getattr(self, mrn).all():
output.append(mcq.get_pk_ac())
return output

def get_mcq_answers(self):
output = []
mcq_related_names = ['mcq_expression_answers', 'mcq_text_answers','mcq_float_answers',
'mcq_variable_float_answers','mcq_image_answers','mcq_latex_answers']
for mrn in mcq_related_names:
output.extend(getattr(self, mrn).all())
return output

def __str__(self):
return f"Question {self.number} for {self.assignment}"
Expand Down Expand Up @@ -285,7 +323,7 @@ class StructuralQuestionSettings(BaseQuestionSettings):
question = models.OneToOneField(Question, on_delete=models.CASCADE, related_name='struct_settings')
max_num_attempts = models.IntegerField(default=5, validators=[MinValueValidator(1)])
deduct_per_attempt = models.FloatField(default=0.05, blank=True, null=True)
margin_error = models.FloatField(default=0.03, blank=True, null=True, validators=[MinValueValidator(0), MaxValueValidator(1)])
margin_error = models.FloatField(default=0.03, blank=False, null=False, validators=[MinValueValidator(0), MaxValueValidator(1)])
percentage_pts_units = models.FloatField(default=0.03, blank=True, null=True, validators=[MinValueValidator(0), MaxValueValidator(1)])
units_num_attempts = models.IntegerField(default=2, validators=[MinValueValidator(1)])

Expand Down Expand Up @@ -359,7 +397,7 @@ class AnswerBase(models.Model):
"""
Class for structural answers.
"""
question = models.ForeignKey(Question, on_delete=models.CASCADE)
question = models.OneToOneField(Question, on_delete=models.CASCADE)
content = models.TextField(blank=False, null=False)
answer_unit = models.CharField(max_length=50, blank=True, null=True) # Optional field for the units of the answer
preface = models.CharField(max_length=20, blank=True, null=True)
Expand All @@ -370,6 +408,12 @@ class Meta:
def __str__(self):
return f"Answer for {self.question}: {self.content}"

def get_pk_ac(self):
"""
Returns 'pk_answercode', which is used for question editing and answer validation.
"""
return f'{self.pk}_{self.get_answer_code()}'

class FloatAnswer(AnswerBase):
"""
Answer to a `structural Question` may be an algebraic expression, a vector, or a float.
Expand Down Expand Up @@ -452,6 +496,12 @@ class Meta:

def __str__(self):
return f"MCQ Answer for {self.question}: {self.content}"

def get_pk_ac(self):
"""
Returns 'pk_answercode', which is used for question editing and answer validation.
"""
return f'{self.pk}_{self.get_answer_code()}'

class MCQFloatAnswer(MCQAnswerBase):
"""
Expand Down Expand Up @@ -553,6 +603,7 @@ def delete(self, *args, **kwargs):

def get_answer_code(self):
return 7

class MatchingAnswer(models.Model):
"""
A question may be a matching pairs question
Expand All @@ -564,6 +615,12 @@ class MatchingAnswer(models.Model):
def __str__(self):
return f"Matching pair answer for {self.question}"

def get_pk_ac(self):
"""
Returns 'pk_answercode', which is used for question editing and answer validation.
"""
return f'{self.pk}_{self.get_answer_code()}'

def get_answer_code(self):
return 9

Expand Down
27 changes: 0 additions & 27 deletions phobos/static/phobos/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -721,33 +721,6 @@ more than assignment display */
margin-left: 10px;

}
.question-settings {
background-color: white;
width:90vw;
position:absolute;
min-height: 300vh;
margin: auto;
overflow-y: auto; /* Add a scrollbar if the content overflows */
top:4%;
right:0%;
border-radius: 1%;
z-index:4;
padding:1%;
transition: width 1s ease, height 1s ease, display 1.1s ease;
}
.question-settings #close-x-settings{
color:#007bff;

}
.question-settings #close-x-settings:hover{
font-size: larger;
cursor:pointer;
}
.question-settings.hide {
width: 0px;
/*height: 0px;*/
display: none;
}

.side-info {
background-color: white;
Expand Down
Loading
Loading