Newer
Older
course_identifier or self.get_default_course_identifier())
kwargs = {"course_identifier": course_identifier}
if participation_id is not None:
kwargs["participation_id"] = participation_id
return reverse("relate-view_participant_grades", kwargs=kwargs)
def get_view_participant_grades(self, participation_id, course_identifier=None):
return self.client.get(self.view_participant_grades_url(
participation_id, course_identifier))
def get_view_my_grades(self, course_identifier=None):
return self.client.get(self.view_participant_grades_url(
participation_id=None, course_identifier=course_identifier))
@classmethod
def get_gradebook_by_opp_url(
cls, gopp_identifier, view_page_grades=False, course_identifier=None):
course_identifier = (
course_identifier or cls.get_default_course_identifier())
opp_id = GradingOpportunity.objects.get(
course__identifier=course_identifier,
identifier=gopp_identifier).pk
url = cls.get_gradebook_url_by_opp_id(opp_id, course_identifier)
if view_page_grades:
url += "?view_page_grades=1"
return url
cls, client, gopp_identifier, *, # noqa: N805
view_page_grades=False, course_identifier=None,
force_login_instructor=True):
course_identifier = (
course_identifier or cls.get_default_course_identifier())
if force_login_instructor:
switch_to = cls.get_default_instructor_user(course_identifier)
else:
switch_to = cls.get_logged_in_user(client)
with cls.temporarily_switch_to_user(client, switch_to):
return client.get(cls.get_gradebook_by_opp_url(
gopp_identifier, view_page_grades, course_identifier))
cls, client, gopp_identifier, post_data, *, # noqa: N805
view_page_grades=False,
course_identifier=None,
force_login_instructor=True):
course_identifier = (
course_identifier or cls.get_default_course_identifier())
if force_login_instructor:
switch_to = cls.get_default_instructor_user(course_identifier)
else:
switch_to = cls.get_logged_in_user(client)
with cls.temporarily_switch_to_user(client, switch_to):
return client.post(
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
cls.get_gradebook_by_opp_url(
gopp_identifier, view_page_grades, course_identifier),
data=post_data)
@classmethod
def get_reopen_session_url(cls, gopp_identifier, flow_session_id=None,
course_identifier=None):
course_identifier = (
course_identifier or cls.get_default_course_identifier())
opp_id = GradingOpportunity.objects.get(
course__identifier=course_identifier,
identifier=gopp_identifier).pk
if flow_session_id is None:
flow_session_id = cls.get_default_flow_session_id(course_identifier)
kwargs = {"course_identifier": course_identifier,
"opportunity_id": opp_id,
"flow_session_id": flow_session_id}
return reverse("relate-view_reopen_session", kwargs=kwargs)
@classmethod_with_client
def get_reopen_session_view(cls, client, # noqa: N805
gopp_identifier, *, flow_session_id=None,
course_identifier=None, force_login_instructor=True):
course_identifier = (
course_identifier or cls.get_default_course_identifier())
if force_login_instructor:
switch_to = cls.get_default_instructor_user(course_identifier)
else:
switch_to = cls.get_logged_in_user()
with cls.temporarily_switch_to_user(client, switch_to):
return client.get(
cls.get_reopen_session_url(
gopp_identifier, flow_session_id, course_identifier))
@classmethod_with_client
def post_reopen_session_view(cls, client, # noqa: N805
gopp_identifier, data, *,
flow_session_id=None, course_identifier=None,
force_login_instructor=True):
course_identifier = (
course_identifier or cls.get_default_course_identifier())
if force_login_instructor:
switch_to = cls.get_default_instructor_user(course_identifier)
else:
switch_to = cls.get_logged_in_user()
with cls.temporarily_switch_to_user(client, switch_to):
return client.post(
cls.get_reopen_session_url(
gopp_identifier, flow_session_id, course_identifier), data=data)
@classmethod
def get_single_grade_url(cls, participation_id, opp_id,
course_identifier=None):
course_identifier = (
course_identifier or cls.get_default_course_identifier())
kwargs = {"course_identifier": course_identifier,
"opportunity_id": opp_id,
"participation_id": participation_id}
return reverse("relate-view_single_grade", kwargs=kwargs)
@classmethod_with_client
def get_view_single_grade(cls, client, # noqa: N805
participation, gopp, *,
course_identifier=None, force_login_instructor=True):
course_identifier = (
course_identifier or cls.get_default_course_identifier())
opp_id = GradingOpportunity.objects.get(
course__identifier=course_identifier,
identifier=gopp.identifier).pk
if force_login_instructor:
switch_to = cls.get_default_instructor_user(course_identifier)
else:
switch_to = cls.get_logged_in_user(client)
with cls.temporarily_switch_to_user(client, switch_to):
return client.get(cls.get_single_grade_url(
participation.pk, opp_id, course_identifier))
@classmethod_with_client
def post_view_single_grade(cls, client, # noqa: N805
participation, gopp, data, *,
course_identifier=None, force_login_instructor=True):
course_identifier = (
course_identifier or cls.get_default_course_identifier())
opp_id = GradingOpportunity.objects.get(
course__identifier=course_identifier,
identifier=gopp.identifier).pk
if force_login_instructor:
switch_to = cls.get_default_instructor_user(course_identifier)
else:
switch_to = cls.get_logged_in_user(client)
with cls.temporarily_switch_to_user(client, switch_to):
return client.post(cls.get_single_grade_url(
participation.pk, opp_id, course_identifier),
data=data)
@classmethod_with_client
def get_logged_in_user(cls, client): # noqa: N805
logged_in_user_id = client.session["_auth_user_id"]
from django.contrib.auth import get_user_model
logged_in_user = get_user_model().objects.get(
pk=int(logged_in_user_id))
except KeyError:
logged_in_user = None
return logged_in_user
@classmethod_with_client
def temporarily_switch_to_user(cls, client, switch_to): # noqa: N805
return _ClientUserSwitcher(
client, cls.get_logged_in_user(client), switch_to)
@classmethod
def get_default_course(cls):
if Course.objects.count() > 1:
raise AttributeError(
"'course' arg can not be omitted for "
"testcases with more than one courses")
raise NotImplementedError
def get_default_course_identifier(cls):
if Course.objects.count() > 1:
raise AttributeError(
"'course_identifier' arg can not be omitted for "
"testcases with more than one courses")
raise NotImplementedError
@classmethod
def get_latest_session_id(cls, course_identifier):
flow_session_qset = FlowSession.objects.filter(
course__identifier=course_identifier).order_by("-pk")[:1]
if flow_session_qset:
return flow_session_qset[0].id
else:
return None
@classmethod
def get_default_flow_session_id(cls, course_identifier):
raise NotImplementedError
def update_default_flow_session_id(cls, course_identifier):
raise NotImplementedError
@classmethod
def get_default_instructor_user(cls, course_identifier):
return Participation.objects.filter(
course__identifier=course_identifier,
roles__identifier="instructor",
status=participation_status.active
).first().user
@classmethod
def update_course_attribute(cls, attrs, course=None):
# course instead of course_identifier because we need to do
# refresh_from_db
assert isinstance(attrs, dict)
course = course or cls.get_default_course()
if attrs:
course.__dict__.update(attrs)
course.save()
course.refresh_from_db()
def get_view_start_flow_url(cls, flow_id, course_identifier=None):
course_identifier = course_identifier or cls.get_default_course_identifier()
return reverse("relate-view_start_flow", kwargs=kwargs)
@classmethod_with_client
def start_flow(cls, client, flow_id, *, # noqa: N805
course_identifier=None,
ignore_cool_down=True, assume_success=True):
"""
Notice: be cautious to use this in setUpTestData, because this will
create many related objects in db, if those objects are changed in
individual test, other tests followed might fail.
"""
existing_session_count = FlowSession.objects.all().count()
if ignore_cool_down:
cool_down_seconds = 0
else:
cool_down_seconds = settings.RELATE_SESSION_RESTART_COOLDOWN_SECONDS
with override_settings(
RELATE_SESSION_RESTART_COOLDOWN_SECONDS=cool_down_seconds):
resp = client.post(
cls.get_view_start_flow_url(flow_id, course_identifier))
if assume_success:
assert resp.status_code == 302, resp.content
new_session_count = FlowSession.objects.all().count()
assert new_session_count == existing_session_count + 1
_, _, params = resolve(resp.url)
del params["page_ordinal"]
cls.default_flow_params = params
cls.update_default_flow_session_id(course_identifier)
@classmethod_with_client
def end_flow(cls, client, *, # noqa: N805
course_identifier=None, flow_session_id=None,
post_parameter="submit"):
if not course_identifier or not flow_session_id:
if cls.default_flow_params is None:
raise RuntimeError(
"There's no started flow_sessions, or "
"the session is not started by start_flow")
resp = client.post(
cls.get_finish_flow_session_view_url(
course_identifier, flow_session_id),
data={post_parameter: [""]})
return resp
@classmethod
def get_resume_flow_url(cls, course_identifier=None, flow_session_id=None):
flow_params = cls.get_flow_params(course_identifier, flow_session_id)
return reverse("relate-view_resume_flow", kwargs=flow_params)
@classmethod
def get_flow_params(cls, course_identifier=None, flow_session_id=None):
course_identifier = (
course_identifier or cls.get_default_course_identifier())
if flow_session_id is None:
flow_session_id = cls.get_default_flow_session_id(course_identifier)
return {
"course_identifier": course_identifier,
"flow_session_id": flow_session_id
}
@classmethod
def get_page_params(cls, course_identifier=None, flow_session_id=None,
page_params = cls.get_flow_params(course_identifier, flow_session_id)
if page_ordinal is None:
page_ordinal = 0
page_params.update({"page_ordinal": page_ordinal})
return page_params
def get_page_ordinal_via_page_id(
cls, page_id, course_identifier=None, flow_session_id=None,
with_group_id=False):
flow_params = cls.get_flow_params(course_identifier, flow_session_id)
return (
get_flow_page_ordinal_from_page_id(
flow_params["flow_session_id"], page_id,
with_group_id=with_group_id))
cls, page_ordinal, course_identifier=None, flow_session_id=None,
flow_params = cls.get_flow_params(course_identifier, flow_session_id)
return (
get_flow_page_id_from_page_ordinal(
flow_params["flow_session_id"], page_ordinal,
with_group_id=with_group_id))
def get_page_view_url_by_ordinal(
cls, viewname, page_ordinal, course_identifier=None,
page_params = cls.get_page_params(
course_identifier, flow_session_id, page_ordinal)
return reverse(viewname, kwargs=page_params)
def get_page_view_url_by_page_id(
cls, viewname, page_id, course_identifier=None, flow_session_id=None):
page_ordinal = cls.get_page_ordinal_via_page_id(
page_id, course_identifier, flow_session_id)
return cls.get_page_view_url_by_ordinal(
viewname, page_ordinal, course_identifier, flow_session_id)
def get_page_url_by_ordinal(
cls, page_ordinal, course_identifier=None, flow_session_id=None,
visit_id=None):
url = cls.get_page_view_url_by_ordinal(
"relate-view_flow_page",
page_ordinal, course_identifier, flow_session_id)
if visit_id is not None:
url += "?visit_id=%s" % str(visit_id)
return url
def get_page_url_by_page_id(
cls, page_id, course_identifier=None, flow_session_id=None,
visit_id=None):
page_ordinal = cls.get_page_ordinal_via_page_id(
page_id, course_identifier, flow_session_id)
return cls.get_page_url_by_ordinal(
page_ordinal, course_identifier, flow_session_id, visit_id)
def get_page_grading_url_by_ordinal(
cls, page_ordinal, course_identifier=None, flow_session_id=None):
return cls.get_page_view_url_by_ordinal(
"relate-grade_flow_page",
page_ordinal, course_identifier, flow_session_id)
def get_page_grading_url_by_page_id(
cls, page_id, course_identifier=None, flow_session_id=None):
page_ordinal = cls.get_page_ordinal_via_page_id(
page_id, course_identifier, flow_session_id)
return cls.get_page_grading_url_by_ordinal(
page_ordinal, course_identifier, flow_session_id)
@classmethod_with_client
def post_answer_by_ordinal(cls, client, # noqa: N805
page_ordinal, answer_data, *,
course_identifier=None, flow_session_id=None, visit_id=None):
submit_data = answer_data
submit_data.update({"submit": ["Submit final answer"]})
resp = client.post(
cls.get_page_url_by_ordinal(
page_ordinal, course_identifier, flow_session_id, visit_id),
submit_data)
return resp
cls, client, page_id, answer_data, *, # noqa: N805
course_identifier=None, flow_session_id=None, visit_id=None):
page_ordinal = cls.get_page_ordinal_via_page_id(
page_id, course_identifier, flow_session_id)
return cls.post_answer_by_ordinal(client,
page_ordinal, answer_data,
course_identifier=course_identifier,
flow_session_id=flow_session_id, visit_id=visit_id)
@classmethod_with_client
def post_answer_by_ordinal_class(cls, client, # noqa: N805
page_ordinal, answer_data,
course_identifier, flow_session_id):
submit_data = answer_data
submit_data.update({"submit": ["Submit final answer"]})
page_params = {
"course_identifier": course_identifier,
"flow_session_id": flow_session_id,
}
page_url = reverse("relate-view_flow_page", kwargs=page_params)
resp = client.post(page_url, submit_data)
return resp
@classmethod_with_client
def post_answer_by_page_id_class(cls, client, # noqa: N805
page_id, answer_data, course_identifier, flow_session_id):
page_ordinal = get_flow_page_ordinal_from_page_id(flow_session_id, page_id)
return cls.post_answer_by_ordinal_class(page_ordinal, answer_data,
course_identifier, flow_session_id)
@classmethod_with_client
def post_grade_by_ordinal(cls, client, # noqa: N805
page_ordinal, grade_data, *,
course_identifier=None, flow_session_id=None,
force_login_instructor=True):
post_data = {"submit": [""]}
post_data.update(grade_data)
page_params = cls.get_page_params(
course_identifier, flow_session_id, page_ordinal)
force_login_user = cls.get_logged_in_user(client)
force_login_user = cls.get_default_instructor_user(
page_params["course_identifier"])
with cls.temporarily_switch_to_user(client, force_login_user):
response = client.post(
cls.get_page_grading_url_by_ordinal(**page_params),
@classmethod_with_client
def post_grade_by_page_id(cls, client, # noqa: N805
page_id, grade_data, *,
course_identifier=None, flow_session_id=None,
force_login_instructor=True):
page_ordinal = cls.get_page_ordinal_via_page_id(
page_id, course_identifier, flow_session_id)
return cls.post_grade_by_ordinal(client,
page_ordinal, grade_data,
course_identifier=course_identifier,
flow_session_id=flow_session_id,
force_login_instructor=force_login_instructor)
def assertSessionScoreEqual( # noqa
cls, expected_score, course_identifier=None, flow_session_id=None):
if flow_session_id is None:
flow_params = cls.get_flow_params(course_identifier, flow_session_id)
flow_session_id = flow_params["flow_session_id"]
flow_session = FlowSession.objects.get(id=flow_session_id)
if expected_score is not None:
from decimal import Decimal
assert flow_session.points == Decimal(str(expected_score)), (
"The flow session got '%s' in stead of '%s'"
% (str(flow_session.points), str(Decimal(str(expected_score))))
)
assert flow_session.points is None, (
"This flow session unexpectedly got %s instead of None"
% flow_session.points)
def get_page_submit_history_url_by_ordinal(
cls, page_ordinal, course_identifier=None, flow_session_id=None):
return cls.get_page_view_url_by_ordinal(
"relate-get_prev_answer_visits_dropdown_content",
page_ordinal, course_identifier, flow_session_id)
def get_page_grade_history_url_by_ordinal(
cls, page_ordinal, course_identifier=None, flow_session_id=None):
return cls.get_page_view_url_by_ordinal(
"relate-get_prev_grades_dropdown_content",
page_ordinal, course_identifier, flow_session_id)
def get_page_submit_history_by_ordinal(
cls, client, page_ordinal, *, # noqa: N805
course_identifier=None, flow_session_id=None):
resp = client.get(
cls.get_page_submit_history_url_by_ordinal(
page_ordinal, course_identifier, flow_session_id),
HTTP_X_REQUESTED_WITH="XMLHttpRequest")
def get_page_grade_history_by_ordinal(
cls, client, page_ordinal, *, # noqa: N805
course_identifier=None, flow_session_id=None):
resp = client.get(
cls.get_page_grade_history_url_by_ordinal(
page_ordinal, course_identifier, flow_session_id),
HTTP_X_REQUESTED_WITH="XMLHttpRequest")
return resp
def assertSubmitHistoryItemsCount( # noqa
self, page_ordinal, expected_count, course_identifier=None,
flow_session_id=None):
resp = self.get_page_submit_history_by_ordinal(
page_ordinal, course_identifier=course_identifier,
flow_session_id=flow_session_id)
import json
result = json.loads(resp.content.decode())["result"]
self.assertEqual(len(result), expected_count)
def assertGradeHistoryItemsCount( # noqa
self, page_ordinal, expected_count,
course_identifier=None,
flow_session_id=None,
if course_identifier is None:
course_identifier = self.get_default_course_identifier()
switch_to = self.get_default_instructor_user(course_identifier)
else:
switch_to = self.get_logged_in_user()
with self.temporarily_switch_to_user(switch_to):
resp = self.get_page_grade_history_by_ordinal(
page_ordinal, course_identifier=course_identifier,
flow_session_id=flow_session_id)
import json
result = json.loads(resp.content.decode())["result"]
self.assertEqual(len(result), expected_count)
@classmethod
def get_update_course_url(cls, course_identifier=None):
if course_identifier is None:
course_identifier = cls.get_default_course_identifier()
return reverse("relate-update_course", args=[course_identifier])
@classmethod
def get_course_commit_sha(cls, participation, course=None):
course = course or cls.get_default_course()
from course.content import get_course_commit_sha
return get_course_commit_sha(course, participation)
@classmethod_with_client
def post_update_course_content(cls, client, commit_sha, *, # noqa: N805
prevent_discarding_revisions=True,
force_login_instructor=True,
course=None,
):
# course instead of course_identifier because we need to do
# refresh_from_db
course = course or cls.get_default_course()
try:
commit_sha = commit_sha.decode()
except Exception:
pass
data = {"new_sha": [commit_sha]}
if not prevent_discarding_revisions:
data["prevent_discarding_revisions"] = ["on"]
# normally, command should be in
# ["fetch", "fetch_update", "update", "fetch_preview", "preview",
# "end_preview"]
data[command] = "on"
force_login_user = cls.get_logged_in_user(client)
force_login_user = cls.get_default_instructor_user(course.identifier)
with cls.temporarily_switch_to_user(client, force_login_user):
response = client.post(
cls.get_update_course_url(course.identifier), data)
def get_page_data_by_page_id(
cls, page_id, course_identifier=None, flow_session_id=None):
flow_params = cls.get_flow_params(course_identifier, flow_session_id)
return FlowPageData.objects.get(
flow_session_id=flow_params["flow_session_id"], page_id=page_id)
@classmethod
def get_page_visits(cls, course_identifier=None,
flow_session_id=None, page_ordinal=None, page_id=None,
**kwargs):
query_kwargs = {}
if kwargs.get("answer_visit", False):
query_kwargs.update({"answer__isnull": False})
flow_params = cls.get_flow_params(course_identifier, flow_session_id)
query_kwargs.update({"flow_session_id": flow_params["flow_session_id"]})
if page_ordinal is not None:
query_kwargs.update({"page_data__page_ordinal": page_ordinal})
elif page_id is not None:
query_kwargs.update({"page_data__page_id": page_id})
return FlowPageVisit.objects.filter(**query_kwargs)
@classmethod
def get_last_answer_visit(cls, course_identifier=None,
flow_session_id=None, page_ordinal=None,
page_id=None, assert_not_none=True):
result_qset = cls.get_page_visits(course_identifier,
flow_session_id, page_ordinal, page_id,
answer_visit=True).order_by("-pk")[:1]
if result_qset:
result = result_qset[0]
else:
result = None
if assert_not_none:
assert result is not None, "The query returns None"
return result
@classmethod
def download_all_submissions_url(cls, flow_id, course_identifier):
params = {"course_identifier": course_identifier,
"flow_id": flow_id}
return reverse("relate-download_all_submissions", kwargs=params)
@classmethod_with_client
def get_download_all_submissions(cls, client, flow_id, *, # noqa: N805
course_identifier=None):
course_identifier = cls.get_default_course_identifier()
cls.download_all_submissions_url(flow_id, course_identifier))
def post_download_all_submissions_by_group_page_id(
cls, client, # noqa: N805
group_page_id, flow_id, *, course_identifier=None, **kwargs):
"""
:param group_page_id: format: group_id/page_id
:param flow_id:
:param course_identifier:
:param kwargs: for updating the default post_data
:return: response
"""
if course_identifier is None:
course_identifier = cls.get_default_course_identifier()
data = {"restrict_to_rules_tag": "<<<ALL>>>",
"which_attempt": "last",
"extra_file": "", "download": "Download",
"page_id": group_page_id,
"non_in_progress_only": "on"}
non_in_progress_only = kwargs.pop("non_in_progress_only", True)
if not non_in_progress_only:
del data["non_in_progress_only"]
cls.download_all_submissions_url(flow_id, course_identifier),
def get_flow_page_analytics_url(cls, flow_id, group_id, page_id,
course_identifier=None,
restrict_to_first_attempt=False):
course_identifier = cls.get_default_course_identifier()
params = {"course_identifier": course_identifier,
"flow_id": flow_id,
"group_id": group_id,
"page_id": page_id}
url = reverse("relate-page_analytics", kwargs=params)
if restrict_to_first_attempt:
url += "?restrict_to_first_attempt=1"
return url
@classmethod_with_client
def get_flow_page_analytics(cls, client, # noqa: N805
flow_id, group_id, page_id, *,
course_identifier=None,
force_login_instructor=True,
restrict_to_first_attempt=False):
course_identifier = course_identifier or cls.get_default_course_identifier()
url = cls.get_flow_page_analytics_url(
flow_id, group_id, page_id, course_identifier, restrict_to_first_attempt)
if not force_login_instructor:
user = cls.get_logged_in_user(client)
else:
user = cls.instructor_participation.user
with cls.temporarily_switch_to_user(client, user):
return client.get(url)
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
# {{{ hack getting session rules
default_session_start_rule = {
"tag_session": None,
"may_start_new_session": True,
"may_list_existing_sessions": True,
"default_expiration_mode": None}
def get_hacked_session_start_rule(self, **kwargs):
"""
Used for mocking session_start_rule
:param kwargs: attributes in the mocked FlowSessionStartRule instance
:return: a :class:`FlowSessionStartRule` instance
Example:
with mock.patch(
"course.flow.get_session_start_rule") as mock_get_nrule:
mock_get_nrule.return_value = (
self.get_hacked_session_start_rule())
"""
from course.utils import FlowSessionStartRule
defaults = deepcopy(self.default_session_start_rule)
defaults.update(kwargs)
return FlowSessionStartRule(**defaults)
default_session_access_rule = {
"permissions": [fperm.view, fperm.end_session]}
def get_hacked_session_access_rule(self, **kwargs):
"""
Used for mocking session_access_rule
:param kwargs: attributes in the mocked FlowSessionAccessRule instance
:return: a :class:`FlowSessionAccessRule` instance
Example:
with mock.patch(
"course.flow.get_session_access_rule") as mock_get_arule:
mock_get_arule.return_value = (
self.get_hacked_session_access_rule(
permissions=[fperm.end_session]))
"""
from course.utils import FlowSessionAccessRule
defaults = deepcopy(self.default_session_access_rule)
defaults.update(kwargs)
return FlowSessionAccessRule(**defaults)
default_session_grading_rule = {
"grade_identifier": "la_quiz",
"grade_aggregation_strategy": g_strategy.use_latest,
"due": None,
"generates_grade": True,
"description": None,
"credit_percent": 100,
"use_last_activity_as_completion_time": False,
"bonus_points": 0,
"max_points": None,
"max_points_enforced_cap": None,
}
def get_hacked_session_grading_rule(self, **kwargs):
"""
Used for mocking session_grading_rule
:param kwargs: attributes in the mocked FlowSessionGradingRule instance
:return: a :class:`FlowSessionGradingRule` instance
Example:
with mock.patch(
"course.flow.get_session_grading_rule") as mock_get_grule:
mock_get_grule.return_value = \
self.get_hacked_session_grading_rule(bonus_points=2)
"""
from course.utils import FlowSessionGradingRule
defaults = deepcopy(self.default_session_grading_rule)
defaults.update(kwargs)
return FlowSessionGradingRule(**defaults)
# }}}
def get_form_submit_inputs(self, form):
from crispy_forms.layout import Submit
inputs = [
(input.name, input.value) for input in form.helper.inputs
if isinstance(input, Submit)
]
names = list(dict(inputs).keys())
values = list(dict(inputs).values())
return names, values
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
def get_flow_analytics_url(self, flow_id, course_identifier,
restrict_to_first_attempt=None):
course_identifier = course_identifier or self.get_default_course_identifier()
kwargs = {
"flow_id": flow_id,
"course_identifier": course_identifier}
result = reverse("relate-flow_analytics", kwargs=kwargs)
if restrict_to_first_attempt:
result += "?restrict_to_first_attempt=%s" % restrict_to_first_attempt
return result
def get_flow_analytics_view(self, flow_id, course_identifier=None,
restrict_to_first_attempt=None,
force_login_instructor=True):
course_identifier = course_identifier or self.get_default_course_identifier()
if not force_login_instructor:
user = self.get_logged_in_user()
else:
user = self.instructor_participation.user
with self.temporarily_switch_to_user(user):
return self.client.get(
self.get_flow_analytics_url(
flow_id, course_identifier=course_identifier,
restrict_to_first_attempt=restrict_to_first_attempt))
def get_manage_authentication_token_url(self, course_identifier=None):
course_identifier = course_identifier or self.get_default_course_identifier()
return reverse("relate-manage_authentication_tokens",
args=(course_identifier,))
# }}}
# {{{ SingleCourseTestMixin
class SingleCourseTestMixin(CoursesTestMixinBase):
courses_setup_list = SINGLE_COURSE_SETUP_LIST
@classmethod
def setUpTestData(cls): # noqa
assert len(cls.course_qset) == 1
cls.course = cls.course_qset.first()
if cls.initial_commit_sha is not None:
cls.course.active_git_commit_sha = cls.initial_commit_sha
cls.course.save()
cls.instructor_participation = Participation.objects.filter(
course=cls.course,
roles__identifier="instructor",
status=participation_status.active
).first()
assert cls.instructor_participation
cls.student_participation = Participation.objects.filter(
course=cls.course,
roles__identifier="student",
status=participation_status.active
).first()
assert cls.student_participation
cls.ta_participation = Participation.objects.filter(
course=cls.course,
roles__identifier="ta",
status=participation_status.active
).first()
assert cls.ta_participation
cls.course_page_url = cls.get_course_page_url()
def setUp(self): # noqa
# reload objects created during setUpTestData in case they were modified in
# tests. Ref: https://goo.gl/AuzJRC#django.test.TestCase.setUpTestData
self.course.refresh_from_db()
self.instructor_participation.refresh_from_db()
self.student_participation.refresh_from_db()
self.ta_participation.refresh_from_db()
self.client.force_login(self.student_participation.user)
@classmethod
def get_default_course(cls):
return cls.course
@classmethod
def get_default_course_identifier(cls):
return cls.get_default_course().identifier
def copy_course_dict_and_set_attrs_for_post(self, attrs_dict=None):
if attrs_dict is None:
attrs_dict = {}
from course.models import Course
kwargs = Course.objects.first().__dict__
kwargs.update(attrs_dict)
if v is None:
kwargs[k] = ""
return kwargs
@classmethod
def get_course_page_context(cls, user):
request = rf.get(cls.get_course_page_url())
request.user = user
from course.utils import CoursePageContext
pctx = CoursePageContext(request, cls.course.identifier)
cls, user=None, flow_id=None, commit_sha=None,
del_rules=False, as_dict=False, **kwargs):
"""
Get a hacked version of flow_desc
:param user: the flow_desc viewed by which user, default to a student
:param flow_id: the flow_desc of which flow_id, default to `quiz-test`
:param commit_sha: default to corrent running commit_sha
:param kwargs: the attributes of the hacked flow_dec
:return: the faked flow_desc
"""
# {{{ get the actual flow_desc by a real visit
rf = RequestFactory()
request = rf.get(cls.get_course_page_url())
request.user = user
if flow_id is None:
flow_id = QUIZ_FLOW_ID
if commit_sha is None:
commit_sha = cls.course.active_git_commit_sha
commit_sha = commit_sha.encode()
from course.content import get_flow_desc
with cls.get_course_page_context(user) as pctx:
flow_desc = get_flow_desc(
pctx.repo, pctx.course, flow_id, commit_sha)
flow_desc_dict = struct_to_dict(flow_desc)
if del_rules:
del flow_desc_dict["rules"]
flow_desc_dict.update(kwargs)
if as_dict:
return flow_desc_dict
return dict_to_struct(flow_desc_dict)
def get_hacked_flow_desc_with_access_rule_tags(self, rule_tags):
assert isinstance(rule_tags, list)
hacked_flow_desc_dict = self.get_hacked_flow_desc(as_dict=True)
rules = hacked_flow_desc_dict["rules"]
rules_dict = struct_to_dict(rules)
rules_dict["tags"] = rule_tags
rules = dict_to_struct(rules_dict)
hacked_flow_desc_dict["rules"] = rules
hacked_flow_desc = dict_to_struct(hacked_flow_desc_dict)
assert hacked_flow_desc.rules.tags == rule_tags
return hacked_flow_desc