Skip to content
from __future__ import annotations
__copyright__ = "Copyright (C) 2018 Dong Zhuang"
__license__ = """
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
from datetime import datetime
from zoneinfo import ZoneInfo
import factory
from django.contrib.auth import get_user_model
from django.contrib.auth.hashers import make_password
from django.utils.timezone import now, timedelta
from django.utils.translation import gettext_lazy as _
from factory import fuzzy
from course import constants, models
from course.auth import make_sign_in_key
from course.constants import participation_permission as pperm
from tests.base_test_mixins import SINGLE_COURSE_SETUP_LIST
from tests.constants import QUIZ_FLOW_ID
UTC = ZoneInfo("UTC")
DEFAULT_COURSE_IDENTIFIER = SINGLE_COURSE_SETUP_LIST[0]["course"]["identifier"]
DEFAULT_FLOW_ID = QUIZ_FLOW_ID
DEFAULT_GRADE_IDENTIFIER = "la_quiz"
DEFAULT_GRADE_AGGREGATION_STRATEGY = constants.grade_aggregation_strategy.use_latest
DEFAULT_GOPP_TITLE = "TEST RELATE Test Quiz"
def get_default_gopp_name(title=DEFAULT_GOPP_TITLE):
return (
_("Flow: %(flow_desc_title)s")
% {"flow_desc_title": title})
class UserFactory(factory.django.DjangoModelFactory):
class Meta:
model = get_user_model()
username = factory.Sequence(lambda n: "testuser_%03d" % n)
email = factory.Sequence(lambda n: "test_factory_%03d@example.com" % n)
status = constants.user_status.active
password = factory.Sequence(lambda n: "password_%03d" % n)
institutional_id = factory.Sequence(lambda n: "institutional_id%03d" % n)
class CourseFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.Course
django_get_or_create = ("identifier", "git_source")
identifier = DEFAULT_COURSE_IDENTIFIER
name = "test-course"
number = factory.Sequence(lambda n: "%03d" % n)
time_period = "Spring"
git_source = SINGLE_COURSE_SETUP_LIST[0]["course"]["git_source"]
notify_email = factory.Sequence(lambda n: "test_notify_%03d@example.com" % n)
from_email = factory.Sequence(lambda n: "test_from_%03d@example.com" % n)
active_git_commit_sha = "some_sha"
class ParticipationRoleFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.ParticipationRole
django_get_or_create = ("course", "identifier",)
course = factory.SubFactory(CourseFactory)
identifier = "student"
class ParticipationFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.Participation
user = factory.SubFactory(UserFactory)
course = factory.SubFactory(CourseFactory)
enroll_time = factory.LazyFunction(now)
status = constants.participation_status.active
@factory.post_generation
def roles(self, create, extracted, **kwargs):
if not create:
# Simple build, do nothing.
return
if extracted:
for role in extracted:
if isinstance(role, str):
role = ParticipationRoleFactory(
course=self.course, identifier=role)
else:
assert isinstance(role, models.ParticipationRole)
self.roles.add(role)
return
role = ParticipationRoleFactory(course=self.course)
self.roles.set([role])
@factory.post_generation
def tags(self, create, extracted, **kwargs):
if not create:
# Simple build, do nothing.
return
if extracted:
for tag in extracted:
if isinstance(tag, str):
tag = ParticipationTagFactory(
course=self.course, name=tag)
else:
assert isinstance(tag, models.ParticipationTag)
self.tags.add(tag)
return
class ParticipationTagFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.ParticipationTag
django_get_or_create = ("course", "name", "shown_to_participant")
course = factory.SubFactory(CourseFactory)
name = fuzzy.FuzzyText()
shown_to_participant = True
class FlowSessionFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.FlowSession
course = factory.lazy_attribute(lambda x: x.participation.course)
participation = factory.SubFactory(ParticipationFactory)
user = factory.lazy_attribute(lambda x: x.participation.user)
active_git_commit_sha = factory.lazy_attribute(
lambda x: x.course.active_git_commit_sha)
flow_id = DEFAULT_FLOW_ID
start_time = factory.LazyFunction(now)
in_progress = False
expiration_mode = constants.flow_session_expiration_mode.end
completion_time = factory.lazy_attribute(
lambda x: now() if not x.in_progress else None)
class GradingOpportunityFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.GradingOpportunity
django_get_or_create = ("course", "identifier",)
course = factory.SubFactory(CourseFactory)
identifier = DEFAULT_GRADE_IDENTIFIER
name = get_default_gopp_name()
flow_id = DEFAULT_FLOW_ID
aggregation_strategy = DEFAULT_GRADE_AGGREGATION_STRATEGY
shown_in_grade_book = True
shown_in_participant_grade_book = True
result_shown_in_participant_grade_book = True
class FlowPageDataFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.FlowPageData
flow_session = factory.SubFactory(FlowSessionFactory)
page_ordinal = 1
page_type = "TestPageType"
group_id = "TestGroupId"
page_id = "TestPageId"
data = {}
title = "TestPageTitle"
class FlowPageVisitFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.FlowPageVisit
page_data = factory.SubFactory(FlowPageDataFactory)
flow_session = factory.lazy_attribute(lambda x: x.page_data.flow_session)
visit_time = factory.LazyFunction(now)
user = factory.lazy_attribute(
lambda x: x.page_data.flow_session.participation.user
if x.page_data.flow_session.participation is not None else None)
answer = None
class FlowPageVisitGradeFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.FlowPageVisitGrade
visit = factory.SubFactory(FlowPageVisitFactory)
grade_time = factory.lazy_attribute(lambda x: x.visit.visit_time)
correctness = None
class EventFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.Event
course = factory.SubFactory(CourseFactory)
kind = "default_kind"
ordinal = factory.Sequence(lambda n: n)
time = factory.LazyFunction(now)
class GradeChangeFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.GradeChange
opportunity = factory.SubFactory(GradingOpportunityFactory)
participation = factory.SubFactory(ParticipationFactory)
state = constants.grade_state_change_types.graded
attempt_id = None
points = None
max_points = 10
comment = None
due_time = None
creator = None
grade_time = now()
flow_session = factory.SubFactory(FlowSessionFactory)
class ParticipationPreapprovalFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.ParticipationPreapproval
email = factory.Sequence(lambda n: "test_preappro_%03d@preapprv.com" % n)
institutional_id = factory.Sequence(lambda n: "%03d" % n)
course = factory.SubFactory(CourseFactory)
@factory.post_generation
def roles(self, create, extracted, **kwargs):
if not create:
# Simple build, do nothing.
return
if extracted:
for role in extracted:
if isinstance(role, str):
role = ParticipationRoleFactory(
course=self.course, identifier=role)
else:
assert isinstance(role, models.ParticipationRole)
self.roles.set([role])
return
else:
role = ParticipationRoleFactory(course=self.course)
self.roles.set([role])
def generate_random_hash():
import hashlib
from random import random
hash = hashlib.sha1()
hash.update(str(random()).encode())
hash.hexdigest()
return hash.hexdigest()[:10]
class AuthenticationTokenFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.AuthenticationToken
user = factory.lazy_attribute(lambda x: x.participation.user)
participation = factory.SubFactory(ParticipationFactory)
description = factory.Sequence(
lambda n: "test description %03d" % n)
@factory.post_generation
def restrict_to_participation_role(self, create, extracted, **kwargs):
if not create:
# Simple build, do nothing.
return
else:
prole_kwargs = {"course": self.participation.course}
if self.participation.has_permission(
pperm.access_files_for, "instructor"):
prole_kwargs["identifier"] = "instructor"
role = ParticipationRoleFactory(**prole_kwargs)
self.restrict_to_participation_role = role
@factory.post_generation
def token_hash(self, create, extracted, **kwargs):
if not create:
return
else:
token = make_sign_in_key(self.user)
self.token_hash = make_password(token)
class InstantFlowRequestFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.InstantFlowRequest
# django_get_or_create = ('course', 'flow_id')
course = factory.SubFactory(CourseFactory)
flow_id = "my_flow_id"
start_time = fuzzy.FuzzyDateTime(
now() - timedelta(minutes=20),
now() + timedelta(minutes=15))
end_time = factory.lazy_attribute(
lambda x: x.start_time + timedelta(minutes=20))
cancelled = False
class FlowRuleExceptionFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.FlowRuleException
flow_id = DEFAULT_FLOW_ID
participation = factory.SubFactory(ParticipationFactory)
creation_time = fuzzy.FuzzyDateTime(
datetime(2019, 1, 1, tzinfo=UTC),
datetime(2019, 1, 31, tzinfo=UTC))
kind = constants.flow_rule_kind.start
rule = {
"if_before": "some_date",
}
active = True
class InstantMessageFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.InstantMessage
django_get_or_create = ("participation", "text")
participation = factory.SubFactory(ParticipationFactory)
text = fuzzy.FuzzyText()
time = fuzzy.FuzzyDateTime(
datetime(2019, 2, 1, tzinfo=UTC),
datetime(2019, 3, 1, tzinfo=UTC))
class ExamFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.Exam
django_get_or_create = ("course", "description")
course = factory.SubFactory(CourseFactory)
description = "desc of exam"
flow_id = DEFAULT_FLOW_ID
active = True
listed = True
no_exams_before = fuzzy.FuzzyDateTime(
datetime(2019, 1, 1, tzinfo=UTC),
datetime(2019, 1, 31, tzinfo=UTC))
no_exams_after = fuzzy.FuzzyDateTime(
datetime(2019, 2, 1, tzinfo=UTC),
datetime(2019, 3, 1, tzinfo=UTC))
class ExamTicketFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.ExamTicket
django_get_or_create = ("exam", "participation")
exam = factory.SubFactory(ExamFactory)
participation = factory.SubFactory(ParticipationFactory)
creation_time = now()
state = constants.exam_ticket_states.valid
code = fuzzy.FuzzyText()
valid_start_time = fuzzy.FuzzyDateTime(
datetime(2019, 1, 1, tzinfo=UTC),
datetime(2019, 1, 31, tzinfo=UTC))
valid_end_time = fuzzy.FuzzyDateTime(
datetime(2019, 2, 1, tzinfo=UTC),
datetime(2019, 3, 1, tzinfo=UTC))
restrict_to_facility = ""
from __future__ import division
from __future__ import annotations
__copyright__ = "Copyright (C) 2014 Andreas Kloeckner"
__copyright__ = "Copyright (C) 2018 Dong Zhuang"
__license__ = """
Permission is hereby granted, free of charge, to any person obtaining a copy
......@@ -22,44 +23,47 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
from django.test import TestCase, Client
from accounts.models import User
class CourseCreationTest(TestCase):
@classmethod
def setUpTestData(cls): # noqa
# Set up data for the whole TestCase
cls.admin = User.objects.create_superuser(
username="testadmin",
password="test",
email="test@example.com",
first_name="Test",
last_name="Admin")
cls.admin.save()
def test_course_creation(self):
c = Client()
self.assertTrue(c.login(
username="testadmin",
password="test"))
resp = c.post("/new-course/", dict(
identifier="test-course",
name="Test Course",
number="CS123",
time_period="Fall 2016",
hidden=True,
listed=True,
accepts_enrollment=True,
git_source="git://github.com/inducer/relate-sample",
course_file="course.yml",
events_file="events.yml",
enrollment_approval_required=True,
enrollment_required_email_suffix=None,
from_email="inform@tiker.net",
notify_email="inform@tiker.net"))
self.assertTrue(resp.status_code == 302)
self.assertTrue("/course" in resp.url)
from django.core.mail.backends.locmem import EmailBackend as LocMemEmailBackend
def my_customized_get_full_name_method(first_name, last_name):
return f"{first_name.title()} {last_name.title()}"
def my_customized_get_full_name_method_invalid(first_name, last_name):
return None
my_customized_get_full_name_method_invalid_str = "some_string"
def my_custom_get_masked_profile_method_valid(u):
return "{}{}".format("User", str(u.pk + 100))
my_custom_get_masked_profile_method_invalid_str = "some_string"
def my_get_masked_profile_method_return_none(u):
return
def my_get_masked_profile_method_return_empty_string(u):
return " "
class MyFakeEmailBackend(LocMemEmailBackend):
pass
class MyFakeQuestionType:
pass
# used to test check.register_startup_checks_extra
def my_custom_check_func1():
return ["my_custom_check_msg.E001"]
def my_custom_check_func2():
return ["my_custom_check_msg.W001"]
username,Institutional ID,first name,last name,laquiz,feedback
test_student,1234,Student,Test,86.66,This is the feedback for test_student
test_student2,1235,Student2,Test2,90,This is the not imported feedback
test_student,1234,Student,Test,86.66,
test_student2,1235,Student2,Test2,90,This is the not imported feedback
username,Institutional ID,first name,last name,laquiz,feedback
test_student,1234,Student,Test,-,This is the feedback for test_student
test_student2,1235,Student2,Test2,90,This is the not imported feedback
chunks:
-
title: "Shown to instructor"
id: hidden
rules:
-
if_has_role: [instructor]
weight: 100
shown: True
-
weight: 0
shown: False
content: |
# Hello instructors
Hi!
-
title: "empty rules"
id: no_actual_rules
rules: []
content: |
# All visitor can see this
Welcome!
-
title: "Display order"
id: orders
rules:
-
if_after: 2018-01-01
weight: 200
-
weight: 50
content: |
# Where am I?
event_kinds:
lecture:
title: Lecture {nr}
exam:
title: Exam {nr}
color: red
test:
foo: bar
events:
"lecture 1":
title: "Alternative title for lecture 1"
color: red
description: |
*Pre-lecture material:* [Linear algebra pre-quiz](flow:prequiz-linear-algebra) (not for credit)
* What is Scientific Computing?
* Python intro
"lecture 2":
description: "Can you see this?"
show_description_from: lecture 2
show_description_until: lecture 3
"test":
no_description: no description to show
show_description_from: lecture 2
show_description_until: lecture 3
unenrolled:
- "cc.png"
in_exam:
- "*.jpeg"
ta:
- "django-logo.png"
type: FileUploadQuestion
id: proof
maximum_megabytes: 0.5
value: 5
prompt: |
# Upload a file
mime_types:
- application/pdf
- text/plain
rubric: |
uploaded?
{% from "yaml-macros.yml" import indented_include %}
title: "RELATE Test Quiz"
description: |
# RELATE Test Quiz
rules:
start:
-
if_has_fewer_sessions_than: 2
may_start_new_session: True
may_list_existing_sessions: True
-
may_start_new_session: False
may_list_existing_sessions: True
access:
-
permissions: [view, submit_answer, end_session, see_correctness, change_answer, see_answer_after_submission, see_session_time]
grade_identifier: la_quiz
grade_aggregation_strategy: use_latest
grading:
-
credit_percent: 100
groups:
-
id: intro
pages:
-
type: Page
id: welcome
content: |
# Welcome to the test quiz for RELATE!
Don't be scared.
-
id: quiz_start
shuffle: False
pages:
-
type: TextQuestion
id: half
value: 5
prompt: |
# A half
What's a half?
answers:
- type: float
value: 0.5
rtol: 1e-4
- <plain>half
- <plain>a half
-
{{ indented_include("questions/pdf-file-upload-example.yml", 8) }}
# The page_ids of included pages should the same as those in the sample repo.
# Notice, don't do analysis and download test for this flow desc using
# submit_page_answer_by_ordinal_and_test helper.
{% from "yaml-macros.yml" import indented_include %}
title: "RELATE Test Quiz"
description: |
# RELATE Test Quiz
rules:
start:
-
if_before: end_week 1
if_has_role: [student, ta, instructor]
if_has_fewer_sessions_than: 4
may_start_new_session: True
may_list_existing_sessions: True
-
may_start_new_session: False
may_list_existing_sessions: True
access:
-
permissions: [view, submit_answer, end_session, see_correctness, see_answer_after_submission]
grade_identifier: la_quiz
grade_aggregation_strategy: use_latest
grading:
-
credit_percent: 100
groups:
-
id: intro
pages:
-
type: Page
id: welcome
content: |
# Welcome to the test quiz for RELATE!
Don't be scared.
-
id: quiz_start
shuffle: False
pages:
-
{{ indented_include("questions/pdf-file-upload-example.yml", 8) }}
-
type: TextQuestion
id: half
value: 5
prompt: |
# A half
What's a half?
answers:
- type: float
value: 0.5
rtol: 1e-4
- <plain>half
- <plain>a half
-
{{ indented_include("questions/krylov.yml", 8) }}
-
type: MultipleChoiceQuestion
id: matrix_props
is_optional_page: True
shuffle: False
credit_mode: proportional
prompt: |
# Matrix properties
You know that the matrix $A$ satisfies $A=A^T$.
Which of the following is true about $A$?
choices:
- ~CORRECT~ $A$ has real eigenvalues.
- $A$ has eigenvalues with positive real part.
- $(x,y) = x^TAy$ is an inner product.
- ~CORRECT~ $A$ has orthogonal eigenvectors.
- $AA^T=I$
-
{{ indented_include("questions/survey-age-question.yml", 8) }}
-
id: quiz_tail
shuffle: False
pages:
-
type: FileUploadQuestion
id: anyup
access_rules:
add_permissions:
- change_answer
is_optional_page: True
maximum_megabytes: 0.5
prompt: |
# Upload your favorite file
Upload anything you like below.
mime_types:
- application/octet-stream
rubric: |
Have they uploaded a file?
-
type: TextQuestion
id: neumann
value: 0
prompt: |
# Neumann series
What's $\operatorname{Id} + A + A^2 +A^3+\cdots$?
answers:
- <sym_expr>1/(1-A)
# The page_ids of included pages should the same as those in the sample repo.
# Notice, don't do analysis and download test for this flow desc using
# submit_page_answer_by_ordinal_and_test helper.
{% from "yaml-macros.yml" import indented_include %}
title: "RELATE Test Quiz"
description: |
# RELATE Test Quiz
rules:
start:
-
if_before: end_week 1
if_has_role: [student, ta, instructor]
if_has_fewer_sessions_than: 4
may_start_new_session: True
may_list_existing_sessions: True
-
may_start_new_session: False
may_list_existing_sessions: True
access:
-
permissions: [view, submit_answer, change_answer, end_session, see_correctness, see_answer_after_submission]
grade_identifier: la_quiz
grade_aggregation_strategy: use_latest
grading:
-
credit_percent: 100
groups:
-
id: intro
pages:
-
type: Page
id: welcome
content: |
# Welcome to the test quiz for RELATE!
Don't be scared.
-
id: quiz_start
shuffle: False
pages:
-
{{ indented_include("questions/pdf-file-upload-example.yml", 8) }}
-
type: TextQuestion
id: half
value: 5
prompt: |
# A half
What's a half?
answers:
- type: float
value: 0.5
rtol: 1e-4
- <plain>half
- <plain>a half
-
{{ indented_include("questions/survey-age-question.yml", 8) }}
{% from "yaml-macros.yml" import indented_include %}
title: "RELATE Test Quiz"
description: |
# RELATE Test Quiz
rules:
start:
-
if_has_fewer_sessions_than: 100
may_start_new_session: True
may_list_existing_sessions: True
-
may_start_new_session: False
access:
-
permissions: [view, submit_answer, end_session, see_correctness, see_answer_after_submission]
grade_identifier: la_quiz
grade_aggregation_strategy: use_latest
grading:
-
credit_percent: 100
groups:
-
id: intro
pages:
-
type: Page
id: welcome
content: |
# Welcome to the test quiz for RELATE!
Don't be scared.
-
id: quiz_start
shuffle: False
pages:
-
type: TextQuestion
id: half
value: 5
prompt: |
# A half
What's a half?
answers:
- type: float
value: 0.5
rtol: 1e-4
- <plain>half
- <plain>a half
-
{{ indented_include("questions/krylov.yml", 8) }}
-
id: quiz_tail
shuffle: False
pages:
-
{{ indented_include("questions/non-ascii-choices.yml", 8) }}
{% from "yaml-macros.yml" import indented_include %}
title: "RELATE Test Quiz"
description: |
# RELATE Test Quiz
rules:
start:
-
if_has_fewer_sessions_than: 100
may_start_new_session: True
may_list_existing_sessions: True
-
may_start_new_session: False
access:
-
permissions: [view, submit_answer, end_session, see_correctness, see_answer_after_submission]
grade_identifier: la_quiz
grade_aggregation_strategy: use_latest
grading:
-
credit_percent: 100
groups:
-
id: intro
pages:
-
type: Page
id: welcome
content: |
# Welcome to the test quiz for RELATE!
Don't be scared.
-
id: quiz_start
shuffle: False
pages:
-
{{ indented_include("questions/krylov.yml", 8) }}
-
id: quiz_tail
shuffle: False
pages:
-
{{ indented_include("questions/non-ascii-choices.yml", 8) }}
# The page_ids of included pages should the same as those in the sample repo.
# Notice, don't do analysis and download test for this flow desc using
# submit_page_answer_by_ordinal_and_test helper.
{% from "yaml-macros.yml" import indented_include %}
title: "RELATE Test Quiz"
description: |
# RELATE Test Quiz
rules:
start:
-
if_before: end_week 1
if_has_role: [student, ta, instructor]
if_has_fewer_sessions_than: 4
may_start_new_session: True
may_list_existing_sessions: True
-
may_start_new_session: False
may_list_existing_sessions: True
access:
-
permissions: [view, submit_answer, end_session, see_correctness, see_answer_after_submission]
grade_identifier: la_quiz
grade_aggregation_strategy: use_latest
grading:
-
credit_percent: 100
groups:
-
id: intro
pages:
-
type: Page
id: welcome
content: |
# Welcome to the test quiz for RELATE!
Don't be scared.
-
id: quiz_tail
shuffle: False
pages:
-
{{ indented_include("questions/any-file-upload-example.yml", 8) }}
# The page_ids of included pages should the same as those in the sample repo.
# Notice, don't do analysis and download test for this flow desc using
# submit_page_answer_by_ordinal_and_test helper.
{% from "yaml-macros.yml" import indented_include %}
title: "RELATE Test Quiz"
description: |
# RELATE Test Quiz
rules:
start:
-
if_before: end_week 1
if_has_role: [student, ta, instructor]
if_has_fewer_sessions_than: 4
may_start_new_session: True
may_list_existing_sessions: True
-
may_start_new_session: False
may_list_existing_sessions: True
access:
-
permissions: [view, submit_answer, change_answer, end_session, see_correctness]
grade_identifier: la_quiz
grade_aggregation_strategy: use_latest
grading:
-
credit_percent: 100
groups:
-
id: intro
pages:
-
type: Page
id: welcome
content: |
# Welcome to the test quiz for RELATE!
Don't be scared.
-
id: quiz_start
shuffle: False
pages:
-
type: TextQuestion
id: half
access_rules:
remove_permissions:
- see_correctness
value: 5
prompt: |
# A half
What's a half?
answers:
- type: float
value: 0.5
rtol: 1e-4
- <plain>half
- <plain>a half
-
type: MultipleChoiceQuestion
id: ice_cream_toppings
access_rules:
remove_permissions:
- change_answer
credit_mode: exact
value: 1
shuffle: False
prompt: |
# Ice Cream Toppings
Which of the following are ice cream toppings?
choices:
- ~CORRECT~ Sprinkles
- ~CORRECT~ Chocolate chunks
- Vacuum cleaner dust
- Spider webs
- ~CORRECT~ Almond bits
-
type: SurveyTextQuestion
id: fear
widget: textarea
prompt: |
# Psychology Survey
What's your biggest fear?
-
type: ChoiceQuestion
id: krylov
access_rules:
add_permissions:
- change_answer
value: 2
prompt: |
# Krylov-space methods
What form of a matrix is produced by Arnoldi iteration?
choices:
- ~CORRECT~ Upper Hessenberg form
- Diagonal
- Schur form
- Tridiagonal form
-
type: ChoiceQuestion
id: lsq
value: 1
shuffle: False
access_rules:
add_permissions:
- see_answer_after_submission
prompt: |
# Least squares problems
Let $m\ge n$ and $\boldsymbol A$ be an $m\times n$ matrix. Which of the
following conditions suffices to guarantee that
the least squares system $\boldsymbol A \boldsymbol x\cong \boldsymbol b$
has a *unique* solution?
choices:
- Always
- When $\operatorname{rank}(\boldsymbol A)=m$
- ~CORRECT~ When $\operatorname{rank}(\boldsymbol A)=n$
- When $\boldsymbol b$ lies in $\operatorname{span}(\boldsymbol A)$
- This is a really long option, but *certainly* not the correct one.
Instead, it tests whether Markdown works in choice questions.
-
type: SurveyChoiceQuestion
id: age_group
access_rules: []
prompt: |
# Age
How old are you?
choices:
- 0-10 years
- 11-20 years
- 21-30 years
- 31-40 years
- 41-50 years
- 51-60 years
- 61-70 years
- 71-80 years
- 81-90 years
- older
{% from "yaml-macros.yml" import indented_include %}
title: "RELATE Test Quiz"
description: |
# RELATE Test Quiz
rules:
start:
-
if_has_fewer_sessions_than: 2
may_start_new_session: True
may_list_existing_sessions: True
-
may_start_new_session: False
may_list_existing_sessions: True
access:
-
permissions: [view, submit_answer, end_session, see_correctness, change_answer, see_answer_after_submission, see_session_time]
grade_identifier: la_quiz
grade_aggregation_strategy: use_latest
grading:
-
credit_percent: 100
groups:
-
id: intro
pages:
-
type: Page
id: welcome
content: |
# Welcome to the test quiz for RELATE!
Don't be scared.
-
id: quiz_start
shuffle: False
pages:
-
type: TextQuestion
id: half
value: 5
prompt: |
# A half
What's a half?
answers:
- type: float
value: 0.5
rtol: 1e-4
- <plain>half
- <plain>a half
-
id: quiz_tail
shuffle: False
pages:
-
type: TextQuestion
id: half2
is_optional_page: True
prompt: |
# A half
What's a half?
answers:
- <plain>half
- <plain>a half
-
{{ indented_include("questions/matrix-properties.yml", 8) }}
{% from "yaml-macros.yml" import indented_include %}
title: "RELATE Test Quiz"
description: |
# RELATE Test Quiz
rules:
start:
-
if_before: end_week 1
if_has_role: [student, ta, instructor]
if_has_fewer_sessions_than: 4
may_start_new_session: True
may_list_existing_sessions: True
-
may_start_new_session: False
may_list_existing_sessions: True
access:
-
permissions: [view, submit_answer, end_session, see_correctness, see_answer_after_submission]
grade_identifier: la_quiz_fake
grade_aggregation_strategy: use_latest
grading:
-
credit_percent: 100
groups:
-
id: group0
pages:
-
type: Page
title: welcome
id: welcome
content: |
# Welcome to the test quiz for RELATE!
Don't be scared.
-
id: group1
shuffle: False
pages:
-
{{ indented_include("questions/krylov.yml", 8) }}
-
type: TextQuestion
id: half1
value: 5
prompt: |
# A half
What's a half?
answers:
- <plain>half
- <plain>a half
-
id: group2
shuffle: True
max_page_count: 3
pages:
-
type: TextQuestion
id: half2
value: 5
prompt: |
# A half
What's a half?
answers:
- <plain>half
- <plain>a half
-
{{ indented_include("questions/matrix-properties.yml", 8) }}
-
{{ indented_include("questions/survey-age-question.yml", 8) }}
-
id: group3
shuffle: False
pages:
-
type: ChoiceQuestion
id: lsq
value: 1
shuffle: False
prompt: |
# Least squares problems
choices:
- Always
- When $\operatorname{rank}(\boldsymbol A)=m$
- ~CORRECT~ When $\operatorname{rank}(\boldsymbol A)=n$
- When $\boldsymbol b$ lies in $\operatorname{span}(\boldsymbol A)$
- This is a really long option, but *certainly* not the correct one.
-
id: group4
shuffle: False
pages:
-
type: ChoiceQuestion
id: lsq2
value: 1
shuffle: False
prompt: |
# Least squares problems
choices:
- Always
- When $\operatorname{rank}(\boldsymbol A)=m$
- ~CORRECT~ When $\operatorname{rank}(\boldsymbol A)=n$
- When $\boldsymbol b$ lies in $\operatorname{span}(\boldsymbol A)$
- This is a really long option, but *certainly* not the correct one.
\ No newline at end of file
{% from "yaml-macros.yml" import indented_include %}
title: "RELATE Test Quiz"
description: |
# RELATE Test Quiz
rules:
start:
-
if_before: end_week 1
if_has_role: [student, ta, instructor]
if_has_fewer_sessions_than: 4
may_start_new_session: True
may_list_existing_sessions: True
-
may_start_new_session: False
may_list_existing_sessions: True
access:
-
permissions: [view, submit_answer, end_session, see_correctness, see_answer_after_submission]
grade_identifier: la_quiz_fake
grade_aggregation_strategy: use_latest
grading:
-
credit_percent: 100
groups:
-
id: group0
pages:
-
type: Page
title: welcome (renamed)
id: welcome
content: |
# Welcome to the test quiz for RELATE!
Don't be scared.
-
id: group1
shuffle: False
pages:
-
{{ indented_include("questions/krylov.yml", 8) }}
-
type: TextQuestion
id: half1_id_renamed
value: 5
prompt: |
# A half
What's a half?
answers:
- <plain>half
- <plain>a half
-
id: group2
shuffle: True
max_page_count: 2
pages:
-
type: TextQuestion
id: half2
value: 5
prompt: |
# A half
What's a half?
answers:
- <plain>half
- <plain>a half
-
{{ indented_include("questions/matrix-properties.yml", 8) }}
-
{{ indented_include("questions/survey-age-question.yml", 8) }}
-
id: group3
shuffle: False
max_page_count: 1
pages:
-
type: TextQuestion
id: half_again2
value: 5
prompt: |
# A half
What's a half?
answers:
- <plain>half
- <plain>a half
-
type: ChoiceQuestion
id: lsq
value: 1
shuffle: False
prompt: |
# Least squares problems
choices:
- Always
- When $\operatorname{rank}(\boldsymbol A)=m$
- ~CORRECT~ When $\operatorname{rank}(\boldsymbol A)=n$
- When $\boldsymbol b$ lies in $\operatorname{span}(\boldsymbol A)$
- This is a really long option, but *certainly* not the correct one.