canvaslms 5.5__tar.gz → 5.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {canvaslms-5.5 → canvaslms-5.6}/PKG-INFO +1 -1
- {canvaslms-5.5 → canvaslms-5.6}/pyproject.toml +1 -1
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/cli/modules.nw +22 -7
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/cli/quizzes.nw +68 -0
- {canvaslms-5.5 → canvaslms-5.6}/LICENSE +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/README.md +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/.circleci/config.yml +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/.git +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/.gitignore +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/CONTRIBUTING.md +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/Dockerfile +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/Dockerfile.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/Dockerfile.tex +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/LICENSE +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/Makefile +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/Makefile.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/Makefile.tex +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/README.md +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/doc.mk +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/doc.mk.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/doc.tex +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/exam.bib +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/exam.mk +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/exam.mk.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/exam.tex +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/gitattributes +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/haskell.mk +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/haskell.mk.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/haskell.tex +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/intro.tex +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/latexmkrc +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/ltxobj/_minted/AAA0D43723DCC5BE9DB71A96B52C1142.highlight.minted +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/ltxobj/_minted/E5724293DA12A769F97F0E91498CAEEF.highlight.minted +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/ltxobj/_minted/FFC039B25D180E99FC9FEBDB2D42EBAF.highlight.minted +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/ltxobj/_minted/_7945F0071C510291A619CE1658F673CB.index.minted +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/ltxobj/_minted/default.style.minted +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/ltxobj/makefiles.aux +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/ltxobj/makefiles.bbl +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/ltxobj/makefiles.bcf +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/ltxobj/makefiles.blg +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/ltxobj/makefiles.fdb_latexmk +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/ltxobj/makefiles.fls +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/ltxobj/makefiles.log +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/ltxobj/makefiles.out +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/ltxobj/makefiles.pdf +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/ltxobj/makefiles.run.xml +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/ltxobj/makefiles.toc +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/ltxobj/makefiles.xdv +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/makefiles.bib +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/makefiles.tex +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/miun.course.mk +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/miun.depend.mk +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/miun.docs.mk +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/miun.port.mk +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/miun.pub.mk +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/noweb.mk +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/noweb.mk.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/noweb.tex +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/pkg.mk +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/pkg.mk.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/pkg.tex +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/portability.mk +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/portability.mk.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/portability.tex +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/preamble.tex +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/pub.mk +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/pub.mk.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/pub.tex +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/results.mk +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/results.mk.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/results.tex +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/subdir.mk +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/subdir.mk.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/subdir.tex +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/tex.bib +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/tex.mk +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/tex.mk.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/tex.tex +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/transform.bib +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/transform.mk +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/transform.mk.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/makefiles/transform.tex +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/Makefile +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/__init__.py +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/cli/Makefile +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/cli/assignments.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/cli/cache.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/cli/calendar.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/cli/cli.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/cli/content.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/cli/courses.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/cli/discussions.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/cli/grade.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/cli/login.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/cli/pages.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/cli/results.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/cli/results.py.broken +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/cli/submissions.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/cli/users.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/cli/utils.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/grades/Makefile +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/grades/conjunctavg.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/grades/conjunctavgsurvey.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/grades/disjunctmax.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/grades/grades.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/grades/grades.py +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/grades/maxgradesurvey.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/grades/tilkryLAB1.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/hacks/Makefile +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/hacks/__init__.py +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/hacks/attachment_cache.nw +0 -0
- {canvaslms-5.5 → canvaslms-5.6}/src/canvaslms/hacks/canvasapi.nw +0 -0
|
@@ -486,6 +486,14 @@ def get_item_modules(course, item_type, item_id):
|
|
|
486
486
|
Returns:
|
|
487
487
|
List of module names containing this item
|
|
488
488
|
"""
|
|
489
|
+
target_url = None
|
|
490
|
+
if item_type == 'Page':
|
|
491
|
+
try:
|
|
492
|
+
target_url = course.get_page(item_id).url
|
|
493
|
+
except Exception:
|
|
494
|
+
# If we can't resolve the target page, fall back to raw comparisons.
|
|
495
|
+
target_url = item_id
|
|
496
|
+
|
|
489
497
|
modules = []
|
|
490
498
|
for module in course.get_modules():
|
|
491
499
|
try:
|
|
@@ -514,10 +522,10 @@ elif item_type == 'Page':
|
|
|
514
522
|
if item.page_url == item_id:
|
|
515
523
|
modules.append(module.name)
|
|
516
524
|
break
|
|
517
|
-
#
|
|
525
|
+
# Compare canonical URLs to avoid duplicates when Canvas redirects old slugs.
|
|
518
526
|
try:
|
|
519
527
|
resolved_page = course.get_page(item.page_url)
|
|
520
|
-
if resolved_page.url ==
|
|
528
|
+
if resolved_page.url == target_url:
|
|
521
529
|
modules.append(module.name)
|
|
522
530
|
break
|
|
523
531
|
except Exception:
|
|
@@ -598,11 +606,18 @@ with its new canonical URL.
|
|
|
598
606
|
Without handling this, the direct comparison [[item.page_url == item_id]] would
|
|
599
607
|
fail, causing the page to be added to the module again (creating duplicates).
|
|
600
608
|
|
|
601
|
-
To detect this, we fetch
|
|
602
|
-
|
|
603
|
-
|
|
609
|
+
To detect this, we fetch both the target page ([[item_id]]) and the module
|
|
610
|
+
item's page ([[item.page_url]]) and compare canonical [[url]] values. This adds
|
|
611
|
+
API calls, but only when the direct comparison fails.
|
|
604
612
|
<<find current module item if present>>=
|
|
605
613
|
current_item = None
|
|
614
|
+
canonical_page_url = None
|
|
615
|
+
if item_type == 'Page':
|
|
616
|
+
try:
|
|
617
|
+
canonical_page_url = course.get_page(item_id).url
|
|
618
|
+
except Exception:
|
|
619
|
+
canonical_page_url = item_id
|
|
620
|
+
|
|
606
621
|
try:
|
|
607
622
|
for item in module.get_module_items():
|
|
608
623
|
if not hasattr(item, 'type') or item.type != item_type:
|
|
@@ -625,10 +640,10 @@ Canvas has created a redirect from an old URL to a new one.
|
|
|
625
640
|
if item.page_url == item_id:
|
|
626
641
|
current_item = item
|
|
627
642
|
break
|
|
628
|
-
# URLs don't match directly;
|
|
643
|
+
# URLs don't match directly; compare canonical URLs to avoid duplicates.
|
|
629
644
|
try:
|
|
630
645
|
resolved_page = course.get_page(item.page_url)
|
|
631
|
-
if resolved_page.url ==
|
|
646
|
+
if resolved_page.url == canonical_page_url:
|
|
632
647
|
current_item = item
|
|
633
648
|
break
|
|
634
649
|
except Exception:
|
|
@@ -343,6 +343,7 @@ import canvaslms.cli
|
|
|
343
343
|
import canvaslms.cli.courses as courses
|
|
344
344
|
import canvaslms.cli.assignments as assignments
|
|
345
345
|
import canvaslms.cli.content as content
|
|
346
|
+
import canvaslms.cli.modules as modules
|
|
346
347
|
import canvaslms.cli.utils
|
|
347
348
|
from rich.console import Console
|
|
348
349
|
from rich.markdown import Markdown
|
|
@@ -2982,6 +2983,24 @@ NEW_QUIZ_RESULT_VIEW_SCHEMA = {
|
|
|
2982
2983
|
\subsection{File formats for quiz editing}
|
|
2983
2984
|
\label{sec:quiz-file-formats}
|
|
2984
2985
|
|
|
2986
|
+
\subsection{Updating module membership}
|
|
2987
|
+
|
|
2988
|
+
When a quiz is edited from a file, the front matter may include a [[modules]]
|
|
2989
|
+
field. We interpret this the same way as [[assignments edit]]:
|
|
2990
|
+
\begin{description}
|
|
2991
|
+
\item[Absent] Leave module membership unchanged.
|
|
2992
|
+
\item[Empty list] Remove the quiz from all modules.
|
|
2993
|
+
\item[List of regexes] Ensure the quiz appears in every matching module and is
|
|
2994
|
+
removed from non-matching modules.
|
|
2995
|
+
\end{description}
|
|
2996
|
+
|
|
2997
|
+
New Quizzes are implemented as assignments, and the module item type Canvas uses
|
|
2998
|
+
is [[Assignment]]. We therefore update membership using the quiz's assignment ID.
|
|
2999
|
+
Classic quizzes also appear as module items and can be targeted the same way.
|
|
3000
|
+
|
|
3001
|
+
We centralize this logic in a helper function so both file-based and interactive
|
|
3002
|
+
edit paths behave identically.
|
|
3003
|
+
|
|
2985
3004
|
The [[quizzes edit]] command supports three file formats, auto-detected from
|
|
2986
3005
|
the file extension and verified against the content:
|
|
2987
3006
|
\begin{description}
|
|
@@ -3003,6 +3022,18 @@ characters of the file:
|
|
|
3003
3022
|
\item Front matter format starts with [[---]]
|
|
3004
3023
|
\end{itemize}
|
|
3005
3024
|
|
|
3025
|
+
<<functions>>=
|
|
3026
|
+
def update_quiz_module_membership(quiz, module_regexes):
|
|
3027
|
+
"""Update module membership for a quiz based on module regex list"""
|
|
3028
|
+
item_id = int(quiz.id) if is_new_quiz(quiz) else quiz.id
|
|
3029
|
+
added, removed = modules.update_item_modules(
|
|
3030
|
+
quiz.course, 'Assignment', item_id, module_regexes)
|
|
3031
|
+
if added:
|
|
3032
|
+
print(f" Added to modules: {', '.join(added)}", file=sys.stderr)
|
|
3033
|
+
if removed:
|
|
3034
|
+
print(f" Removed from modules: {', '.join(removed)}", file=sys.stderr)
|
|
3035
|
+
|
|
3036
|
+
|
|
3006
3037
|
<<functions>>=
|
|
3007
3038
|
def detect_quiz_file_format(filepath):
|
|
3008
3039
|
"""Detect quiz file format from extension and content
|
|
@@ -3270,6 +3301,15 @@ If [[--replace-items]] is specified and the file contains items, we replace
|
|
|
3270
3301
|
the quiz questions. But first we check for student submissions and ask for
|
|
3271
3302
|
confirmation if any exist.
|
|
3272
3303
|
|
|
3304
|
+
If the file contains a [[modules]] key (front matter, YAML, or JSON), we also
|
|
3305
|
+
update the quiz's module membership after a successful edit. We interpret this
|
|
3306
|
+
field the same way as in [[assignments edit]]:
|
|
3307
|
+
\begin{description}
|
|
3308
|
+
\item[Absent] Module membership is not modified
|
|
3309
|
+
\item[Empty list] Quiz is removed from all modules
|
|
3310
|
+
\item[List of regexes] Quiz is placed in all modules matching the patterns
|
|
3311
|
+
\end{description}
|
|
3312
|
+
|
|
3273
3313
|
<<handle item replacement if requested>>=
|
|
3274
3314
|
items = quiz_data.get('items')
|
|
3275
3315
|
if args.replace_items and items:
|
|
@@ -3294,6 +3334,7 @@ for quiz in quiz_list:
|
|
|
3294
3334
|
success = apply_quiz_edit(quiz, settings, body, requester, args.html)
|
|
3295
3335
|
if success:
|
|
3296
3336
|
print(f"Updated quiz: {quiz.title}")
|
|
3337
|
+
<<update quiz module membership from file>>
|
|
3297
3338
|
else:
|
|
3298
3339
|
canvaslms.cli.warn(f"Failed to update quiz: {quiz.title}")
|
|
3299
3340
|
@
|
|
@@ -3396,6 +3437,8 @@ def edit_quiz_interactive(quiz, requester, html_mode=False):
|
|
|
3396
3437
|
|
|
3397
3438
|
# Apply the changes
|
|
3398
3439
|
success = apply_quiz_edit(quiz, final_attrs, final_body, requester, html_mode)
|
|
3440
|
+
if success:
|
|
3441
|
+
<<update quiz module membership interactively>>
|
|
3399
3442
|
return 'updated' if success else 'error'
|
|
3400
3443
|
@
|
|
3401
3444
|
|
|
@@ -3415,6 +3458,11 @@ The workflow is:
|
|
|
3415
3458
|
\item Apply the changes (settings only, unless [[--replace-items]])
|
|
3416
3459
|
\end{enumerate}
|
|
3417
3460
|
|
|
3461
|
+
<<update quiz module membership interactively>>=
|
|
3462
|
+
if 'modules' in final_attrs:
|
|
3463
|
+
update_quiz_module_membership(quiz, final_attrs['modules'])
|
|
3464
|
+
@
|
|
3465
|
+
|
|
3418
3466
|
<<functions>>=
|
|
3419
3467
|
def edit_quiz_interactive_json(quiz, requester, html_mode=False,
|
|
3420
3468
|
replace_items=False):
|
|
@@ -3680,6 +3728,11 @@ The [[replace_quiz_items]] function handles the complete process of replacing
|
|
|
3680
3728
|
quiz items. It first checks for submissions, then deletes existing items,
|
|
3681
3729
|
and finally creates the new items.
|
|
3682
3730
|
|
|
3731
|
+
<<update quiz module membership from file>>=
|
|
3732
|
+
if 'modules' in settings:
|
|
3733
|
+
update_quiz_module_membership(quiz, settings['modules'])
|
|
3734
|
+
@
|
|
3735
|
+
|
|
3683
3736
|
<<functions>>=
|
|
3684
3737
|
def replace_quiz_items(quiz, items, requester):
|
|
3685
3738
|
"""Replace all items in a quiz with new ones
|
|
@@ -4256,6 +4309,11 @@ The export command finds the quiz, extracts its settings, and exports all
|
|
|
4256
4309
|
questions. We reuse the existing [[export_new_quiz_items]] and
|
|
4257
4310
|
[[export_classic_questions]] functions for question export.
|
|
4258
4311
|
|
|
4312
|
+
If the quiz appears in modules, we also export a [[modules]] list. The
|
|
4313
|
+
[[quizzes edit]] command interprets this list as regex patterns, so we export
|
|
4314
|
+
module names as anchored, regex-escaped patterns (e.g., [[^FBF$]]) to mean
|
|
4315
|
+
\enquote{match this module name exactly}.
|
|
4316
|
+
|
|
4259
4317
|
<<functions>>=
|
|
4260
4318
|
def export_command(config, canvas, args):
|
|
4261
4319
|
"""Exports a complete quiz (settings + questions) to JSON"""
|
|
@@ -4305,6 +4363,11 @@ def export_full_new_quiz(quiz, requester, include_banks=True, importable=False):
|
|
|
4305
4363
|
"""
|
|
4306
4364
|
# Extract basic settings
|
|
4307
4365
|
settings = {
|
|
4366
|
+
'modules': [
|
|
4367
|
+
"^" + re.escape(name) + "$"
|
|
4368
|
+
for name in modules.get_item_modules(
|
|
4369
|
+
quiz.course, 'Assignment', int(quiz.id))
|
|
4370
|
+
],
|
|
4308
4371
|
'title': getattr(quiz, 'title', ''),
|
|
4309
4372
|
'instructions': getattr(quiz, 'instructions', '') or '',
|
|
4310
4373
|
'time_limit': getattr(quiz, 'time_limit', None),
|
|
@@ -4354,6 +4417,11 @@ def export_full_classic_quiz(quiz, importable=False):
|
|
|
4354
4417
|
"""
|
|
4355
4418
|
# Extract settings
|
|
4356
4419
|
settings = {
|
|
4420
|
+
'modules': [
|
|
4421
|
+
"^" + re.escape(name) + "$"
|
|
4422
|
+
for name in modules.get_item_modules(
|
|
4423
|
+
quiz.course, 'Assignment', quiz.id)
|
|
4424
|
+
],
|
|
4357
4425
|
'title': getattr(quiz, 'title', ''),
|
|
4358
4426
|
'description': getattr(quiz, 'description', '') or '',
|
|
4359
4427
|
'quiz_type': getattr(quiz, 'quiz_type', 'assignment'),
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|