From 5531f1f68d85f1b65125e5ebebf3a73cdb8586e1 Mon Sep 17 00:00:00 2001 From: Tim Daniel Metzler Date: Wed, 26 Jul 2023 14:45:55 +0200 Subject: [PATCH] Remove authoring component and replace it with e2xauthoring --- e2xgrader/converters/__init__.py | 4 - e2xgrader/converters/converter.py | 28 -- e2xgrader/converters/generateexercise.py | 40 -- e2xgrader/models/__init__.py | 17 - e2xgrader/models/assignmentmodel.py | 34 -- e2xgrader/models/basemodel.py | 21 - e2xgrader/models/exercisemodel.py | 44 -- e2xgrader/models/presetmodel.py | 71 --- .../presets/questions/Code (Autograded).ipynb | 92 ---- .../presets/questions/Code (Manual).ipynb | 68 --- .../models/presets/questions/Diagram.ipynb | 73 --- .../models/presets/questions/Freetext.ipynb | 63 --- .../presets/questions/Multiple Choice.ipynb | 54 --- .../presets/questions/Single Choice.ipynb | 52 --- .../presets/questions/Upload Files.ipynb | 64 --- .../models/presets/template/Footer.ipynb | 47 -- .../models/presets/template/Group Info.ipynb | 42 -- .../models/presets/template/Header.ipynb | 47 -- .../presets/template/Student Info.ipynb | 41 -- e2xgrader/models/taskmodel.py | 127 ------ e2xgrader/models/taskpoolmodel.py | 61 --- e2xgrader/models/templatemodel.py | 67 --- e2xgrader/preprocessors/authoring/__init__.py | 19 - .../preprocessors/authoring/addtaskheader.py | 98 ----- .../preprocessors/authoring/copyfiles.py | 91 ---- .../preprocessors/authoring/copynotebooks.py | 21 - .../preprocessors/authoring/filltemplate.py | 37 -- .../authoring/generatetaskids.py | 60 --- .../preprocessors/authoring/makeexercise.py | 73 --- .../preprocessors/authoring/preprocessor.py | 10 - .../preprocessors/authoring/removeexercise.py | 19 - .../apps/authoring/__init__.py | 3 - .../apps/authoring/apihandlers.py | 166 ------- .../apps/authoring/authoring.py | 31 -- .../apps/authoring/handlers.py | 138 ------ .../authoring/notebookvariableextractor.py | 16 - .../authoring/static/css/editexercise.css | 54 --- .../apps/authoring/static/css/sidebar.css | 46 -- .../apps/authoring/static/css/taskcreator.css | 149 ------- .../apps/authoring/static/js/assignments.js | 59 --- .../apps/authoring/static/js/base.js | 150 ------- .../apps/authoring/static/js/exercises.js | 82 ---- .../apps/authoring/static/js/makeexercise.js | 416 ------------------ .../apps/authoring/static/js/taskpools.js | 124 ------ .../apps/authoring/static/js/tasks.js | 148 ------- .../apps/authoring/static/js/templates.js | 144 ------ .../templates/authoring/assignments.tpl | 33 -- .../authoring/templates/authoring/base.tpl | 46 -- .../templates/authoring/editexercise.tpl | 95 ---- .../templates/authoring/exercises.tpl | 40 -- .../templates/authoring/tablebase.tpl | 35 -- .../templates/authoring/taskcreator.tpl | 43 -- .../templates/authoring/taskpools.tpl | 37 -- .../authoring/templates/authoring/tasks.tpl | 43 -- .../templates/authoring/templates.tpl | 41 -- .../server_extensions/teacher/teacher.py | 2 +- pyproject.toml | 2 +- 57 files changed, 2 insertions(+), 3726 deletions(-) delete mode 100644 e2xgrader/converters/__init__.py delete mode 100644 e2xgrader/converters/converter.py delete mode 100644 e2xgrader/converters/generateexercise.py delete mode 100644 e2xgrader/models/__init__.py delete mode 100644 e2xgrader/models/assignmentmodel.py delete mode 100644 e2xgrader/models/basemodel.py delete mode 100644 e2xgrader/models/exercisemodel.py delete mode 100644 e2xgrader/models/presetmodel.py delete mode 100644 e2xgrader/models/presets/questions/Code (Autograded).ipynb delete mode 100644 e2xgrader/models/presets/questions/Code (Manual).ipynb delete mode 100644 e2xgrader/models/presets/questions/Diagram.ipynb delete mode 100644 e2xgrader/models/presets/questions/Freetext.ipynb delete mode 100644 e2xgrader/models/presets/questions/Multiple Choice.ipynb delete mode 100644 e2xgrader/models/presets/questions/Single Choice.ipynb delete mode 100644 e2xgrader/models/presets/questions/Upload Files.ipynb delete mode 100644 e2xgrader/models/presets/template/Footer.ipynb delete mode 100644 e2xgrader/models/presets/template/Group Info.ipynb delete mode 100644 e2xgrader/models/presets/template/Header.ipynb delete mode 100644 e2xgrader/models/presets/template/Student Info.ipynb delete mode 100644 e2xgrader/models/taskmodel.py delete mode 100644 e2xgrader/models/taskpoolmodel.py delete mode 100644 e2xgrader/models/templatemodel.py delete mode 100644 e2xgrader/preprocessors/authoring/__init__.py delete mode 100644 e2xgrader/preprocessors/authoring/addtaskheader.py delete mode 100644 e2xgrader/preprocessors/authoring/copyfiles.py delete mode 100644 e2xgrader/preprocessors/authoring/copynotebooks.py delete mode 100644 e2xgrader/preprocessors/authoring/filltemplate.py delete mode 100644 e2xgrader/preprocessors/authoring/generatetaskids.py delete mode 100644 e2xgrader/preprocessors/authoring/makeexercise.py delete mode 100644 e2xgrader/preprocessors/authoring/preprocessor.py delete mode 100644 e2xgrader/preprocessors/authoring/removeexercise.py delete mode 100644 e2xgrader/server_extensions/apps/authoring/__init__.py delete mode 100644 e2xgrader/server_extensions/apps/authoring/apihandlers.py delete mode 100644 e2xgrader/server_extensions/apps/authoring/authoring.py delete mode 100644 e2xgrader/server_extensions/apps/authoring/handlers.py delete mode 100644 e2xgrader/server_extensions/apps/authoring/notebookvariableextractor.py delete mode 100644 e2xgrader/server_extensions/apps/authoring/static/css/editexercise.css delete mode 100644 e2xgrader/server_extensions/apps/authoring/static/css/sidebar.css delete mode 100644 e2xgrader/server_extensions/apps/authoring/static/css/taskcreator.css delete mode 100644 e2xgrader/server_extensions/apps/authoring/static/js/assignments.js delete mode 100644 e2xgrader/server_extensions/apps/authoring/static/js/base.js delete mode 100644 e2xgrader/server_extensions/apps/authoring/static/js/exercises.js delete mode 100644 e2xgrader/server_extensions/apps/authoring/static/js/makeexercise.js delete mode 100644 e2xgrader/server_extensions/apps/authoring/static/js/taskpools.js delete mode 100644 e2xgrader/server_extensions/apps/authoring/static/js/tasks.js delete mode 100644 e2xgrader/server_extensions/apps/authoring/static/js/templates.js delete mode 100644 e2xgrader/server_extensions/apps/authoring/templates/authoring/assignments.tpl delete mode 100644 e2xgrader/server_extensions/apps/authoring/templates/authoring/base.tpl delete mode 100644 e2xgrader/server_extensions/apps/authoring/templates/authoring/editexercise.tpl delete mode 100644 e2xgrader/server_extensions/apps/authoring/templates/authoring/exercises.tpl delete mode 100644 e2xgrader/server_extensions/apps/authoring/templates/authoring/tablebase.tpl delete mode 100644 e2xgrader/server_extensions/apps/authoring/templates/authoring/taskcreator.tpl delete mode 100644 e2xgrader/server_extensions/apps/authoring/templates/authoring/taskpools.tpl delete mode 100644 e2xgrader/server_extensions/apps/authoring/templates/authoring/tasks.tpl delete mode 100644 e2xgrader/server_extensions/apps/authoring/templates/authoring/templates.tpl diff --git a/e2xgrader/converters/__init__.py b/e2xgrader/converters/__init__.py deleted file mode 100644 index 51ac4676..00000000 --- a/e2xgrader/converters/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .converter import Converter -from .generateexercise import GenerateExercise - -__all__ = ["Converter", "GenerateExercise"] diff --git a/e2xgrader/converters/converter.py b/e2xgrader/converters/converter.py deleted file mode 100644 index c4c890ab..00000000 --- a/e2xgrader/converters/converter.py +++ /dev/null @@ -1,28 +0,0 @@ -from traitlets import List -from traitlets.config import Config, LoggingConfigurable -from traitlets.utils.importstring import import_item - - -class Converter(LoggingConfigurable): - preprocessors = List([], help="List of preprocessors for the converter") - - def __init__(self, config=None): - with_default_config = self.default_config() - if config: - with_default_config.merge(config) - self.init_preprocessors() - - def init_preprocessors(self): - self._preprocessors = [] - for preprocessor in self.preprocessors: - if isinstance(preprocessor, type): - self._preprocessors.append(preprocessor()) - else: - self._preprocessors.append(import_item(preprocessor)()) - - def default_config(self): - return Config() - - def convert(self, resources): - for preprocessor in self._preprocessors: - preprocessor.preprocess(resources) diff --git a/e2xgrader/converters/generateexercise.py b/e2xgrader/converters/generateexercise.py deleted file mode 100644 index 3b02618c..00000000 --- a/e2xgrader/converters/generateexercise.py +++ /dev/null @@ -1,40 +0,0 @@ -import tempfile - -from traitlets import List - -from ..preprocessors.authoring import ( - AddTaskHeader, - CopyFiles, - CopyNotebooks, - FillTemplate, - GenerateTaskIDs, - MakeExercise, - RemoveExercise, -) -from .converter import Converter - - -class GenerateExercise(Converter): - preprocessors = List( - [ - RemoveExercise, - CopyNotebooks, - FillTemplate, - CopyFiles, - GenerateTaskIDs, - AddTaskHeader, - MakeExercise, - ] - ) - - def __init__(self, coursedir, config=None): - super(GenerateExercise, self).__init__(config=config) - self.coursedir = coursedir - - def convert(self, resources): - with tempfile.TemporaryDirectory() as tmp: - resources["tmp_dir"] = tmp - resources["course_prefix"] = self.coursedir.root - resources["source_dir"] = self.coursedir.source_directory - for preprocessor in self._preprocessors: - preprocessor.preprocess(resources) diff --git a/e2xgrader/models/__init__.py b/e2xgrader/models/__init__.py deleted file mode 100644 index 61da332f..00000000 --- a/e2xgrader/models/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -from .assignmentmodel import AssignmentModel -from .basemodel import BaseModel -from .exercisemodel import ExerciseModel -from .presetmodel import PresetModel -from .taskmodel import TaskModel -from .taskpoolmodel import TaskPoolModel -from .templatemodel import TemplateModel - -__all__ = [ - "TaskModel", - "TemplateModel", - "TaskPoolModel", - "AssignmentModel", - "ExerciseModel", - "PresetModel", - "BaseModel", -] diff --git a/e2xgrader/models/assignmentmodel.py b/e2xgrader/models/assignmentmodel.py deleted file mode 100644 index b7baeb64..00000000 --- a/e2xgrader/models/assignmentmodel.py +++ /dev/null @@ -1,34 +0,0 @@ -import glob -import os - -from traitlets import Unicode - -from .basemodel import BaseModel - - -class AssignmentModel(BaseModel): - directory = Unicode("source", help="The directory where assignments go.") - - def __get_assignment_info(self, assignment): - return len(glob.glob(os.path.join(self.base_path(), assignment, "*.ipynb"))) - - def list(self, **kwargs): - if not os.path.isdir(self.base_path()): - os.makedirs(self.base_path(), exist_ok=True) - assignmentfolders = os.listdir(self.base_path()) - assignments = [] - for assignmentfolder in assignmentfolders: - if assignmentfolder.startswith("."): - continue - exercises = self.__get_assignment_info(assignmentfolder) - assignments.append( - { - "name": assignmentfolder, - "exercises": exercises, - "link": os.path.join( - "taskcreator", "assignments", assignmentfolder - ), - } - ) - - return assignments diff --git a/e2xgrader/models/basemodel.py b/e2xgrader/models/basemodel.py deleted file mode 100644 index 5e8205a6..00000000 --- a/e2xgrader/models/basemodel.py +++ /dev/null @@ -1,21 +0,0 @@ -import re - -from traitlets import Unicode -from traitlets.config import LoggingConfigurable - -from ..utils import get_nbgrader_config - - -class BaseModel(LoggingConfigurable): - directory = Unicode(".", help="The directory of the model") - - def __init__(self, coursedir): - self.coursedir = coursedir - self.__pattern = re.compile(r"^\w+[\w\s]*\w+$") - self.config = get_nbgrader_config() - - def base_path(self): - return self.coursedir.format_path(self.directory, ".", ".") - - def is_valid_name(self, name): - return self.__pattern.match(name) is not None diff --git a/e2xgrader/models/exercisemodel.py b/e2xgrader/models/exercisemodel.py deleted file mode 100644 index ec0fb8c0..00000000 --- a/e2xgrader/models/exercisemodel.py +++ /dev/null @@ -1,44 +0,0 @@ -import glob -import os -import shutil - -from traitlets import Unicode - -from .basemodel import BaseModel - - -class ExerciseModel(BaseModel): - directory = Unicode("source", help="The directory where assignments go.") - - def get(self, **kwargs): - return {"name": kwargs["name"], "assignment": kwargs["assignment"]} - - def remove(self, **kwargs): - assignment = kwargs["assignment"] - name = kwargs["name"] - base_path = os.path.join(self.base_path(), assignment) - exercise_files = os.path.join(base_path, "{}_files".format(name)) - if os.path.exists(exercise_files): - shutil.rmtree(exercise_files) - exercise = os.path.join(base_path, "{}.ipynb".format(name)) - if os.path.exists(exercise): - os.remove(exercise) - - def list(self, **kwargs): - assignment = kwargs["assignment"] - base_path = os.path.join(self.base_path(), assignment) - exercisenbs = glob.glob(os.path.join(base_path, "*.ipynb")) - exercises = [] - for exercisenb in exercisenbs: - name = os.path.split(exercisenb)[-1].replace(".ipynb", "") - exercises.append( - { - "name": name, - "assignment": assignment, - "link": os.path.join( - "taskcreator", "assignments", assignment, name - ), - } - ) - - return exercises diff --git a/e2xgrader/models/presetmodel.py b/e2xgrader/models/presetmodel.py deleted file mode 100644 index fc5eb528..00000000 --- a/e2xgrader/models/presetmodel.py +++ /dev/null @@ -1,71 +0,0 @@ -import os - -import nbformat -from traitlets import Unicode - -from .basemodel import BaseModel - - -class PresetModel(BaseModel): - task_preset_path = Unicode( - os.path.join(os.path.dirname(__file__), "presets", "questions") - ).tag(config=True) - - template_preset_path = Unicode( - os.path.join( - os.path.dirname(__file__), - "presets", - "template", - ) - ).tag(config=True) - - extra_task_preset_path = Unicode(default_value=None, allow_none=True).tag( - config=True - ) - - extra_template_preset_path = Unicode(default_value=None, allow_none=True).tag( - config=True - ) - - def list_presets(self, preset_path): - presets = [] - if not os.path.exists(preset_path): - return presets - for item in os.listdir(preset_path): - if ".ipynb_checkpoints" in item: - continue - if os.path.isfile(os.path.join(preset_path, item)) and item.endswith( - ".ipynb" - ): - presets.append(os.path.splitext(item)[0]) - return sorted(presets) - - def get_preset(self, preset_path, preset_name): - path = os.path.join(preset_path, "{}.ipynb".format(preset_name)) - if os.path.isfile(path): - nb = nbformat.read(path, as_version=4) - return nb.cells - - def list_question_presets(self): - presets = self.list_presets(self.task_preset_path) - if self.extra_task_preset_path is not None: - presets.extend(self.list_presets(self.extra_task_preset_path)) - return presets - - def get_question_preset(self, preset_name): - if preset_name in self.list_presets(self.task_preset_path): - return self.get_preset(self.task_preset_path, preset_name) - elif self.extra_task_preset_path is not None: - return self.get_preset(self.extra_task_preset_path, preset_name) - - def list_template_presets(self): - presets = self.list_presets(self.template_preset_path) - if self.extra_template_preset_path is not None: - presets.extend(self.list_presets(self.extra_template_preset_path)) - return presets - - def get_template_preset(self, preset_name): - if preset_name in self.list_presets(self.template_preset_path): - return self.get_preset(self.template_preset_path, preset_name) - elif self.extra_template_preset_path is not None: - return self.get_preset(self.extra_template_preset_path, preset_name) diff --git a/e2xgrader/models/presets/questions/Code (Autograded).ipynb b/e2xgrader/models/presets/questions/Code (Autograded).ipynb deleted file mode 100644 index 25a8d01b..00000000 --- a/e2xgrader/models/presets/questions/Code (Autograded).ipynb +++ /dev/null @@ -1,92 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "grade_id": "task_question", - "locked": true, - "schema_version": 3, - "solution": false, - "task": false - } - }, - "source": [ - "## Question\n", - "\n", - "Please write your question here!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "nbgrader": { - "grade": false, - "grade_id": "task", - "locked": false, - "schema_version": 3, - "solution": true, - "task": false - } - }, - "outputs": [], - "source": [ - "### BEGIN SOLUTION\n", - "# Answer\n", - "\n", - "# Please write your code answer here!\n", - "\n", - "### END SOLUTION" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "nbgrader": { - "grade": true, - "grade_id": "test_task", - "locked": true, - "points": 0, - "schema_version": 3, - "solution": false, - "task": false - } - }, - "outputs": [], - "source": [ - - "### BEGIN HIDDEN TESTS\n", - "# Test\n", - "\n", - "# Please write your code test here!\n", - "\n", - "### END HIDDEN TESTS" - ] - } - ], - "metadata": { - "celltoolbar": "Create Assignment", - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/e2xgrader/models/presets/questions/Code (Manual).ipynb b/e2xgrader/models/presets/questions/Code (Manual).ipynb deleted file mode 100644 index ea23430e..00000000 --- a/e2xgrader/models/presets/questions/Code (Manual).ipynb +++ /dev/null @@ -1,68 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "grade_id": "task_question", - "locked": true, - "schema_version": 3, - "solution": false, - "task": false - } - }, - "source": [ - "## Question\n", - "\n", - "Please write your question here!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "nbgrader": { - "grade": true, - "grade_id": "task", - "locked": false, - "points": 0, - "schema_version": 3, - "solution": true, - "task": false - } - }, - "outputs": [], - "source": [ - "### BEGIN SOLUTION\n", - "# Answer\n", - "\n", - "# Please write your code answer here!\n", - "\n", - "### END SOLUTION" - ] - } - ], - "metadata": { - "celltoolbar": "Create Assignment", - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/e2xgrader/models/presets/questions/Diagram.ipynb b/e2xgrader/models/presets/questions/Diagram.ipynb deleted file mode 100644 index 3cf51c61..00000000 --- a/e2xgrader/models/presets/questions/Diagram.ipynb +++ /dev/null @@ -1,73 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "grade_id": "task_question", - "locked": true, - "schema_version": 3, - "solution": false, - "task": false - } - }, - "source": [ - "## Question\n", - "\n", - "Please write your question here!" - ] - }, - { - "attachments": { - "diagram.png": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAUAAAADwCAYAAABxLb1rAAAABHNCSVQICAgIfAhkiAAAAylJREFUeJzt1DEBACAMwDDAv+chY0cTBb16Z2YOQNDbDgDYYoBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZBghkGSCQZYBAlgECWQYIZBkgkGWAQJYBAlkGCGQZIJBlgECWAQJZH97eBdx+cY1yAAAAAElFTkSuQmCC" - } - }, - "cell_type": "markdown", - "metadata": { - "extended_cell": { - "type": "diagram" - }, - "nbgrader": { - "grade": true, - "grade_id": "task", - "locked": false, - "points": 0, - "schema_version": 3, - "solution": true, - "task": false - } - }, - "source": [ - "# Answer\n", - "\n", - "\n", - "\n", - "![diagram](attachment:diagram.png)" - ] - } - ], - "metadata": { - "celltoolbar": "Create Assignment", - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.12" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/e2xgrader/models/presets/questions/Freetext.ipynb b/e2xgrader/models/presets/questions/Freetext.ipynb deleted file mode 100644 index 1b53425a..00000000 --- a/e2xgrader/models/presets/questions/Freetext.ipynb +++ /dev/null @@ -1,63 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "grade_id": "task_question", - "locked": true, - "schema_version": 3, - "solution": false, - "task": false - } - }, - "source": [ - "## Question\n", - "\n", - "Please write your question here!" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": true, - "grade_id": "task", - "locked": false, - "points": 0, - "schema_version": 3, - "solution": true, - "task": false - } - }, - "source": [ - "## Answer\n", - "\n", - "Please write your answer here!" - ] - } - ], - "metadata": { - "celltoolbar": "Create Assignment", - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/e2xgrader/models/presets/questions/Multiple Choice.ipynb b/e2xgrader/models/presets/questions/Multiple Choice.ipynb deleted file mode 100644 index df212192..00000000 --- a/e2xgrader/models/presets/questions/Multiple Choice.ipynb +++ /dev/null @@ -1,54 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "extended_cell": { - "choice": [], - "num_of_choices": 3, - "type": "multiplechoice" - }, - "nbgrader": { - "grade": true, - "grade_id": "task", - "locked": false, - "points": 0, - "schema_version": 3, - "solution": true, - "task": false - } - }, - "source": [ - "## Multiplechoice Question\n", - "\n", - "- Choice 1\n", - "- Choice 2\n", - "- Choice 3\n", - "\n", - "Hint: Add the choices as list items, then select the correct answer!" - ] - } - ], - "metadata": { - "celltoolbar": "Create Assignment", - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/e2xgrader/models/presets/questions/Single Choice.ipynb b/e2xgrader/models/presets/questions/Single Choice.ipynb deleted file mode 100644 index 5dbf876a..00000000 --- a/e2xgrader/models/presets/questions/Single Choice.ipynb +++ /dev/null @@ -1,52 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "extended_cell": { - "type": "singlechoice" - }, - "nbgrader": { - "grade": true, - "grade_id": "task", - "locked": false, - "points": 0, - "schema_version": 3, - "solution": true, - "task": false - } - }, - "source": [ - "## Singlechoice Question\n", - "\n", - "- Choice 1\n", - "- Choice 2\n", - "- Choice 3\n", - "\n", - "Hint: Add the choices as list items, then select the correct answer!" - ] - } - ], - "metadata": { - "celltoolbar": "Create Assignment", - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/e2xgrader/models/presets/questions/Upload Files.ipynb b/e2xgrader/models/presets/questions/Upload Files.ipynb deleted file mode 100644 index d9edd428..00000000 --- a/e2xgrader/models/presets/questions/Upload Files.ipynb +++ /dev/null @@ -1,64 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "grade_id": "task_question", - "locked": true, - "schema_version": 3, - "solution": false, - "task": false - } - }, - "source": [ - "## Question\n", - "\n", - "Please write your question here!" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "extended_cell": { - "type": "attachments" - }, - "nbgrader": { - "grade": true, - "grade_id": "task", - "locked": false, - "points": 0, - "schema_version": 3, - "solution": true, - "task": false - } - }, - "source": [ - "# Answer" - ] - } - ], - "metadata": { - "celltoolbar": "Create Assignment", - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.12" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/e2xgrader/models/presets/template/Footer.ipynb b/e2xgrader/models/presets/template/Footer.ipynb deleted file mode 100644 index 788b7146..00000000 --- a/e2xgrader/models/presets/template/Footer.ipynb +++ /dev/null @@ -1,47 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "nbassignment": { - "type": "footer" - }, - "nbgrader": { - "grade": false, - "grade_id": "footer", - "locked": true, - "schema_version": 3, - "solution": false, - "task": false - } - }, - "source": [ - "### This is a footer cell\n", - "\n", - "All footer cells will always appear at the bottom of the notebook" - ] - } - ], - "metadata": { - "celltoolbar": "Create Assignment", - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/e2xgrader/models/presets/template/Group Info.ipynb b/e2xgrader/models/presets/template/Group Info.ipynb deleted file mode 100644 index c0665b19..00000000 --- a/e2xgrader/models/presets/template/Group Info.ipynb +++ /dev/null @@ -1,42 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "nbassignment": { - "type": "group_info" - } - }, - "outputs": [], - "source": [ - "# Please fill in the usernames of all your team members\n", - "\n", - "member1 = ''\n", - "member2 = ''" - ] - } - ], - "metadata": { - "celltoolbar": "Edit Metadata", - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/e2xgrader/models/presets/template/Header.ipynb b/e2xgrader/models/presets/template/Header.ipynb deleted file mode 100644 index 66c4862f..00000000 --- a/e2xgrader/models/presets/template/Header.ipynb +++ /dev/null @@ -1,47 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "nbassignment": { - "type": "header" - }, - "nbgrader": { - "grade": false, - "grade_id": "header", - "locked": true, - "schema_version": 3, - "solution": false, - "task": false - } - }, - "source": [ - "### This is a header cell\n", - "\n", - "It will always appear at the top of the notebook" - ] - } - ], - "metadata": { - "celltoolbar": "Create Assignment", - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/e2xgrader/models/presets/template/Student Info.ipynb b/e2xgrader/models/presets/template/Student Info.ipynb deleted file mode 100644 index 9995b1ea..00000000 --- a/e2xgrader/models/presets/template/Student Info.ipynb +++ /dev/null @@ -1,41 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "nbassignment": { - "type": "student_info" - } - }, - "outputs": [], - "source": [ - "# Please fill in your matriculation number\n", - "\n", - "matriculation = ''" - ] - } - ], - "metadata": { - "celltoolbar": "Edit Metadata", - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/e2xgrader/models/taskmodel.py b/e2xgrader/models/taskmodel.py deleted file mode 100644 index 16faf6f9..00000000 --- a/e2xgrader/models/taskmodel.py +++ /dev/null @@ -1,127 +0,0 @@ -import os -import shutil -from textwrap import dedent - -import nbformat -from traitlets import Unicode - -from ..utils.nbgrader_cells import get_valid_name -from .basemodel import BaseModel - - -class TaskModel(BaseModel): - directory = Unicode("pools", help="The directory where the task pools go.") - - def new_taskbook(self, name): - nb = nbformat.v4.new_notebook() - - nb.metadata["nbassignment"] = {"type": "task"} - header = nbformat.v4.new_markdown_cell() - - header.source = dedent( - """ - # {} - - Here you should give the general information about the task. - - Then add questions via the menu above. - - A task should be self contained. - """.format( - name - ) - ) - - header.metadata["nbgrader"] = { - "grade_id": "{}_Header".format(get_valid_name(name)), - "locked": True, - "solution": False, - "grade": False, - "task": False, - "schema_version": 3, - } - - nb.cells = [header] - - return nb - - def new(self, **kwargs): - name = kwargs["name"] - pool = kwargs["pool"] - if self.is_valid_name(name): - path = os.path.join(self.base_path(), pool, name) - if os.path.exists(path): - return { - "success": False, - "error": f"A task with the name {name} already exists!", - } - else: - base_path = os.path.join(self.base_path(), pool) - os.makedirs(os.path.join(base_path, name, "img"), exist_ok=True) - os.makedirs(os.path.join(base_path, name, "data"), exist_ok=True) - filename = "{}.ipynb".format(name) - nb = self.new_taskbook(name) - path = os.path.join(base_path, name, filename) - nbformat.write(nb, path) - return {"success": True, "path": os.path.join("notebooks", path)} - else: - return {"success": False, "error": "Invalid name"} - - def remove(self, **kwargs): - name = kwargs["name"] - pool = kwargs["pool"] - base_path = os.path.join(self.base_path(), pool) - shutil.rmtree(os.path.join(base_path, name)) - - def get(self, **kwargs): - name = kwargs["name"] - pool = kwargs["pool"] - points, questions = self.__get_task_info(name, pool) - return { - "name": name, - "points": points, - "questions": questions, - "pool": pool, - } - - def list(self, **kwargs): - pool = kwargs["pool"] - base_path = os.path.join(self.base_path(), pool) - if not os.path.exists(base_path): - return [] - taskfolders = os.listdir(base_path) - tasks = [] - for taskfolder in taskfolders: - if taskfolder.startswith("."): - continue - points, questions = self.__get_task_info(taskfolder, pool) - tasks.append( - { - "name": taskfolder, - "points": points, - "questions": questions, - "pool": pool, - "link": os.path.join("tree", base_path, taskfolder), - } - ) - - return tasks - - def __get_task_info(self, task, pool): - base_path = os.path.join(self.base_path(), pool) - notebooks = [ - file - for file in os.listdir(os.path.join(base_path, task)) - if file.endswith(".ipynb") - ] - - points = 0 - questions = 0 - - for notebook in notebooks: - nb = nbformat.read(os.path.join(base_path, task, notebook), as_version=4) - for cell in nb.cells: - if "nbgrader" in cell.metadata and cell.metadata.nbgrader.grade: - points += cell.metadata.nbgrader.points - questions += 1 - return points, questions diff --git a/e2xgrader/models/taskpoolmodel.py b/e2xgrader/models/taskpoolmodel.py deleted file mode 100644 index 3f00221c..00000000 --- a/e2xgrader/models/taskpoolmodel.py +++ /dev/null @@ -1,61 +0,0 @@ -import os -import shutil - -from traitlets import Unicode - -from .basemodel import BaseModel - - -class TaskPoolModel(BaseModel): - directory = Unicode("pools", help="The directory where the task pools go.") - - def new(self, **kwargs): - name = kwargs["name"] - if self.is_valid_name(name): - path = os.path.join(self.base_path(), name) - if os.path.exists(path): - return { - "success": False, - "error": f"A pool with the name {name} already exists!", - } - else: - os.makedirs(path, exist_ok=True) - return {"success": True, "path": path} - else: - return {"success": False, "error": "Invalid name"} - - def remove(self, **kwargs): - name = kwargs["name"] - path = os.path.join(self.base_path(), name) - shutil.rmtree(path) - - def get(self, **kwargs): - name = kwargs["name"] - tasks = self.__get_pool_info(name) - return { - "name": name, - "tasks": tasks, - "link": os.path.join("taskcreator", "pools", name), - } - - def list(self, **kwargs): - if not os.path.isdir(self.base_path()): - os.makedirs(self.base_path(), exist_ok=True) - poolfolders = os.listdir(self.base_path()) - pools = [] - for poolfolder in poolfolders: - if poolfolder.startswith("."): - continue - tasks = self.__get_pool_info(poolfolder) - pools.append( - { - "name": poolfolder, - "tasks": tasks, - "link": os.path.join("taskcreator", "pools", poolfolder), - } - ) - - return pools - - def __get_pool_info(self, name): - return len(os.listdir(os.path.join(self.base_path(), name))) diff --git a/e2xgrader/models/templatemodel.py b/e2xgrader/models/templatemodel.py deleted file mode 100644 index 70c47fd9..00000000 --- a/e2xgrader/models/templatemodel.py +++ /dev/null @@ -1,67 +0,0 @@ -import os -import shutil - -import nbformat -from traitlets import Unicode - -from ..utils.nbgrader_cells import new_read_only_cell -from .basemodel import BaseModel - - -class TemplateModel(BaseModel): - directory = Unicode("templates", help="The directory where the templates go.") - - def __init__(self, course_prefix): - super().__init__(course_prefix) - os.makedirs(self.base_path(), exist_ok=True) - - def new(self, **kwargs): - name = kwargs["name"] - if self.is_valid_name(name): - path = os.path.join(self.base_path(), name) - if os.path.exists(path): - return { - "success": False, - "error": f"A template with the name {name} already exists!", - } - else: - self.log.info("Creating a new template") - self.log.info(name) - os.makedirs(os.path.join(self.base_path(), name, "img"), exist_ok=True) - os.makedirs(os.path.join(self.base_path(), name, "data"), exist_ok=True) - filename = "{}.ipynb".format(name) - nb = nbformat.v4.new_notebook() - nb.metadata["nbassignment"] = {"type": "template"} - cell = new_read_only_cell( - grade_id="HeaderA", - source=( - "### This is a header cell\n\n" - "It will always appear at the top of the notebook" - ), - ) - cell.metadata["nbassignment"] = {"type": "header"} - nb.cells = [cell] - path = os.path.join(self.base_path(), name, filename) - nbformat.write(nb, path) - return {"success": True, "path": os.path.join("notebooks", path)} - else: - return {"success": False, "error": "Invalid name"} - - def remove(self, **kwargs): - name = kwargs["name"] - shutil.rmtree(os.path.join(self.base_path(), name)) - - def list(self, **kwargs): - templatefolders = os.listdir(self.base_path()) - templates = [] - for templatefolder in templatefolders: - if templatefolder.startswith("."): - continue - templates.append( - { - "name": templatefolder, - "link": os.path.join("tree", self.base_path(), templatefolder), - } - ) - - return templates diff --git a/e2xgrader/preprocessors/authoring/__init__.py b/e2xgrader/preprocessors/authoring/__init__.py deleted file mode 100644 index 6e30c266..00000000 --- a/e2xgrader/preprocessors/authoring/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -from .addtaskheader import AddTaskHeader -from .copyfiles import CopyFiles -from .copynotebooks import CopyNotebooks -from .filltemplate import FillTemplate -from .generatetaskids import GenerateTaskIDs -from .makeexercise import MakeExercise -from .preprocessor import Preprocessor -from .removeexercise import RemoveExercise - -__all__ = [ - "Preprocessor", - "RemoveExercise", - "CopyNotebooks", - "CopyFiles", - "GenerateTaskIDs", - "MakeExercise", - "FillTemplate", - "AddTaskHeader", -] diff --git a/e2xgrader/preprocessors/authoring/addtaskheader.py b/e2xgrader/preprocessors/authoring/addtaskheader.py deleted file mode 100644 index f60762e8..00000000 --- a/e2xgrader/preprocessors/authoring/addtaskheader.py +++ /dev/null @@ -1,98 +0,0 @@ -import os -from textwrap import dedent - -import nbformat - -from ...utils.nbgrader_cells import get_points, get_task_info -from .preprocessor import Preprocessor - - -class AddTaskHeader(Preprocessor): - def get_header(self, idx, points): - header = nbformat.v4.new_markdown_cell() - header.metadata["nbgrader"] = { - "grade_id": "taskheader_{}".format(idx), - "locked": True, - "solution": False, - "grade": False, - "task": False, - "schema_version": 3, - } - header.source = dedent( - """ - # Task {} - - **[{} Point(s)]** - """.format( - idx, points - ) - ).strip() - return header - - def get_sub_header(self, idx, sub_idx, points): - header = nbformat.v4.new_markdown_cell() - header.metadata["nbgrader"] = { - "grade_id": "taskheader_{}_{}".format(idx, sub_idx), - "locked": True, - "solution": False, - "grade": False, - "task": False, - "schema_version": 3, - } - header.source = dedent( - """ - ## Task {}.{} - - **[{} Point(s)]** - """.format( - idx, sub_idx, points - ) - ).strip() - return header - - def add_headers(self, nb, idx): - total_points = sum([get_points(cell) for cell in nb.cells]) - task = get_task_info(nb) - - if len(task["subtasks"]) < 1: - return nb - - new_cells = [] - header = self.get_header(idx, total_points) - new_cells.append(header) - if "header" in task: - new_cells.append(nb.cells[task["header"]]) - - if len(task["subtasks"]) == 1: - new_cells.extend([nb.cells[i] for i in task["subtasks"][0]]) - if "other" in task: - new_cells.extend([nb.cells[i] for i in task["other"]]) - nb.cells = new_cells - return nb - - if len(task["subtasks"]) > 1: - for sub_idx, subtask in enumerate(task["subtasks"]): - points = sum([get_points(nb.cells[i]) for i in subtask]) - new_cells.append(self.get_sub_header(idx, sub_idx + 1, points)) - new_cells.extend([nb.cells[i] for i in subtask]) - - if "other" in task: - new_cells.extend([nb.cells[i] for i in task["other"]]) - nb.cells = new_cells - return nb - - def preprocess(self, resources): - if not resources["exercise_options"]["task-headers"]: - return - idx = 0 - for task_dict in resources["tasks"]: - task = os.path.join(task_dict["pool"], task_dict["task"]) - task_path = os.path.join(resources["tmp_dir"], "tasks", task) - notebooks = [ - file for file in os.listdir(task_path) if file.endswith(".ipynb") - ] - for nb_file in notebooks: - idx += 1 - task_nb = nbformat.read(os.path.join(task_path, nb_file), as_version=4) - task_nb = self.add_headers(task_nb, idx) - nbformat.write(task_nb, os.path.join(task_path, nb_file)) diff --git a/e2xgrader/preprocessors/authoring/copyfiles.py b/e2xgrader/preprocessors/authoring/copyfiles.py deleted file mode 100644 index a933f129..00000000 --- a/e2xgrader/preprocessors/authoring/copyfiles.py +++ /dev/null @@ -1,91 +0,0 @@ -import filecmp -import glob -import os -import shutil - -import nbformat - -from .preprocessor import Preprocessor - - -class CopyFiles(Preprocessor): - def rename(self, task, old_name, new_name): - old_file_name = os.path.split(old_name)[1] - new_file_name = os.path.split(new_name)[1] - for nb_file in glob.glob(os.path.join(task, "*.ipynb")): - nb = nbformat.read(nb_file, as_version=4) - for cell in nb.cells: - cell.source = cell.source.replace(old_name, new_name) - if old_file_name != new_file_name: - cell.source = cell.source.replace(old_file_name, new_file_name) - nbformat.write(nb, nb_file) - - def get_new_name(self, file, dst): - suffix = 1 - name, extension = os.path.splitext(file) - new_name = "{}_{}{}".format(name, suffix, extension) - while os.path.exists(os.path.join(dst, new_name)): - suffix += 1 - new_name = "{}_{}{}".format(name, suffix, extension) - return new_name - - def get_files(self, task): - finds = [] - for subdir in ["img", "data"]: - for root, dirs, files in os.walk(os.path.join(task, subdir)): - dirs[:] = [d for d in dirs if d not in [".ipynb_checkpoints"]] - for file in files: - finds.append(os.path.relpath(os.path.join(root, file), task)) - return finds - - def copyfile(self, src, dst): - """ - Copy file - - Arguments: - src -- source file - dst -- destination file - Returns: - status -- True if dst does not exists or is equal to src, - False if dst exists and differs from src. - In this case nothing is copied - """ - if os.path.exists(dst): - return filecmp.cmp(src, dst) - dirs = os.path.split(dst)[0] - os.makedirs(dirs, exist_ok=True) - shutil.copyfile(src, dst) - return True - - def copyfiles(self, src, dst, resources): - exercise_base = "{}_files".format(resources["exercise"]) - for file in self.get_files(src): - src_file = os.path.join(src, file) - dst_file = os.path.join(dst, file) - new_name = os.path.join(exercise_base, file) - if not self.copyfile(src_file, dst_file): - # File with that name already exists - renamed = self.get_new_name(file, dst) - self.copyfile(src_file, os.path.join(dst, renamed)) - new_name = os.path.join(exercise_base, renamed) - # Rename in notebook - self.rename(src, file, new_name) - - def preprocess(self, resources): - file_folder = os.path.join( - resources["course_prefix"], - resources["source_dir"], - resources["assignment"], - "{}_files".format(resources["exercise"]), - ) - os.makedirs(file_folder, exist_ok=True) - - for task_dict in resources["tasks"]: - task = os.path.join(task_dict["pool"], task_dict["task"]) - task_path = os.path.join(resources["tmp_dir"], "tasks", task) - self.copyfiles(task_path, file_folder, resources) - - template_path = os.path.join( - resources["tmp_dir"], "template", resources["template"] - ) - self.copyfiles(template_path, file_folder, resources) diff --git a/e2xgrader/preprocessors/authoring/copynotebooks.py b/e2xgrader/preprocessors/authoring/copynotebooks.py deleted file mode 100644 index 1895ef39..00000000 --- a/e2xgrader/preprocessors/authoring/copynotebooks.py +++ /dev/null @@ -1,21 +0,0 @@ -import os -import shutil - -from .preprocessor import Preprocessor - - -class CopyNotebooks(Preprocessor): - def preprocess(self, resources): - for task_dict in resources["tasks"]: - task = task_dict["task"] - pool = task_dict["pool"] - task = os.path.join(pool, task) - src = os.path.join(resources["course_prefix"], self.task_path, task) - dst = os.path.join(resources["tmp_dir"], "tasks", task) - shutil.copytree(src, dst) - src = os.path.join( - resources["course_prefix"], self.template_path, resources["template"] - ) - dst = os.path.join(resources["tmp_dir"], "template", resources["template"]) - shutil.copytree(src, dst) - return resources diff --git a/e2xgrader/preprocessors/authoring/filltemplate.py b/e2xgrader/preprocessors/authoring/filltemplate.py deleted file mode 100644 index 87c8b7e9..00000000 --- a/e2xgrader/preprocessors/authoring/filltemplate.py +++ /dev/null @@ -1,37 +0,0 @@ -import os -import re - -import nbformat - -from .preprocessor import Preprocessor - - -class FillTemplate(Preprocessor): - def __init__(self): - self.__pattern = re.compile(r"({{\s*(\w+)\s*}})") - - def replace(self, nb, replacements): - replaced = nbformat.v4.new_notebook() - variables = [] - for cell in nb.cells: - source = cell.source - variables = self.__pattern.findall(source) - new_cell = cell.copy() - for variable in variables: - new_cell.source = new_cell.source.replace( - variable[0], replacements[variable[1]] - ) - replaced.cells.append(new_cell) - return replaced - - def preprocess(self, resources): - template_path = os.path.join( - resources["tmp_dir"], - "template", - resources["template"], - "{}.ipynb".format(resources["template"]), - ) - - template_nb = nbformat.read(template_path, as_version=4) - template_nb = self.replace(template_nb, resources["template-options"]) - nbformat.write(template_nb, template_path) diff --git a/e2xgrader/preprocessors/authoring/generatetaskids.py b/e2xgrader/preprocessors/authoring/generatetaskids.py deleted file mode 100644 index 65f866b3..00000000 --- a/e2xgrader/preprocessors/authoring/generatetaskids.py +++ /dev/null @@ -1,60 +0,0 @@ -import glob -import os - -import nbformat - -from ...utils.nbgrader_cells import ( - get_task_info, - get_valid_name, - is_description, - is_grade, - is_solution, -) -from .preprocessor import Preprocessor - - -class GenerateTaskIDs(Preprocessor): - def generate_ids(self, nb, name): - task = get_task_info(nb) - - ids = [] - suffix = ord("A") - - for subtask in task["subtasks"]: - subtask_id = "{}_{}".format(name, chr(suffix)) - ids.append(subtask_id) - suffix += 1 - tests = 0 - headers = 0 - for idx in subtask: - cell = nb.cells[idx] - if is_description(cell): - cell.metadata.nbgrader.grade_id = "{}_Description{}".format( - subtask_id, headers - ) - headers += 1 - elif is_solution(cell): - cell.metadata.nbgrader.grade_id = subtask_id - elif is_grade(cell): - cell.metadata.nbgrader.grade_id = "test_{}{}".format( - subtask_id, tests - ) - tests += 1 - - if "header" in task: - header = nb.cells[task["header"]] - header.metadata.nbgrader.grade_id = "{}_Header".format("".join(ids)) - - return nb - - def preprocess(self, resources): - for task_dict in resources["tasks"]: - task = os.path.join(task_dict["pool"], task_dict["task"]) - task_path = os.path.join(resources["tmp_dir"], "tasks", task) - nb_files = glob.glob(os.path.join(task_path, "*.ipynb")) - for nb_file in nb_files: - nb = nbformat.read(nb_file, as_version=4) - name = os.path.splitext(os.path.basename(nb_file))[0] - name = get_valid_name(name) - self.generate_ids(nb, name) - nbformat.write(nb, nb_file) diff --git a/e2xgrader/preprocessors/authoring/makeexercise.py b/e2xgrader/preprocessors/authoring/makeexercise.py deleted file mode 100644 index 6e99ecd3..00000000 --- a/e2xgrader/preprocessors/authoring/makeexercise.py +++ /dev/null @@ -1,73 +0,0 @@ -import os - -import nbformat -from jupyter_client.kernelspec import KernelSpecManager - -from .preprocessor import Preprocessor - - -class MakeExercise(Preprocessor): - def new_notebook(self, resources): - if "kernel" in resources["exercise_options"]: - kernelspec = ( - KernelSpecManager() - .get_kernel_spec(resources["exercise_options"]["kernel"]) - .to_dict() - ) - return nbformat.v4.new_notebook( - metadata={ - "kernelspec": { - "name": resources["exercise_options"]["kernel"], - "display_name": kernelspec["display_name"], - } - } - ) - else: - return nbformat.v4.new_notebook() - - def get_cell_type(self, cell): - if ("nbassignment" in cell.metadata) and ("type" in cell.metadata.nbassignment): - return cell.metadata.nbassignment.type - - def preprocess(self, resources): - exercise = self.new_notebook(resources) - template_path = os.path.join( - resources["tmp_dir"], - "template", - resources["template"], - "{}.ipynb".format(resources["template"]), - ) - - template_nb = nbformat.read(template_path, as_version=4) - header = [ - cell - for cell in template_nb.cells - if self.get_cell_type(cell) in ["header", "student_info", "group_info"] - ] - footer = [ - cell for cell in template_nb.cells if self.get_cell_type(cell) == "footer" - ] - - exercise.cells.extend(header) - - for task_dict in resources["tasks"]: - task = os.path.join(task_dict["pool"], task_dict["task"]) - task_path = os.path.join(resources["tmp_dir"], "tasks", task) - notebooks = [ - file for file in os.listdir(task_path) if file.endswith(".ipynb") - ] - for notebook in notebooks: - task_nb = nbformat.read(os.path.join(task_path, notebook), as_version=4) - exercise.cells.extend(task_nb.cells) - - exercise.cells.extend(footer) - - nbformat.write( - exercise, - os.path.join( - resources["course_prefix"], - resources["source_dir"], - resources["assignment"], - "{}.ipynb".format(resources["exercise"]), - ), - ) diff --git a/e2xgrader/preprocessors/authoring/preprocessor.py b/e2xgrader/preprocessors/authoring/preprocessor.py deleted file mode 100644 index 04b511f7..00000000 --- a/e2xgrader/preprocessors/authoring/preprocessor.py +++ /dev/null @@ -1,10 +0,0 @@ -from traitlets import Unicode -from traitlets.config import LoggingConfigurable - - -class Preprocessor(LoggingConfigurable): - template_path = Unicode("templates") - task_path = Unicode("pools") - - def preprocess(self, resources): - raise NotImplementedError diff --git a/e2xgrader/preprocessors/authoring/removeexercise.py b/e2xgrader/preprocessors/authoring/removeexercise.py deleted file mode 100644 index 03c9ded1..00000000 --- a/e2xgrader/preprocessors/authoring/removeexercise.py +++ /dev/null @@ -1,19 +0,0 @@ -import os -import shutil - -from .preprocessor import Preprocessor - - -class RemoveExercise(Preprocessor): - def preprocess(self, resources): - base_path = os.path.join( - resources["course_prefix"], resources["source_dir"], resources["assignment"] - ) - exercise_files = os.path.join( - base_path, "{}_files".format(resources["exercise"]) - ) - if os.path.exists(exercise_files): - shutil.rmtree(exercise_files) - exercise_nb = os.path.join(base_path, "{}.ipynb".format(resources["exercise"])) - if os.path.exists(exercise_nb): - os.remove(exercise_nb) diff --git a/e2xgrader/server_extensions/apps/authoring/__init__.py b/e2xgrader/server_extensions/apps/authoring/__init__.py deleted file mode 100644 index 6ca25a4f..00000000 --- a/e2xgrader/server_extensions/apps/authoring/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .authoring import AuthoringApp - -__all__ = ["AuthoringApp"] diff --git a/e2xgrader/server_extensions/apps/authoring/apihandlers.py b/e2xgrader/server_extensions/apps/authoring/apihandlers.py deleted file mode 100644 index 95dbb5f9..00000000 --- a/e2xgrader/server_extensions/apps/authoring/apihandlers.py +++ /dev/null @@ -1,166 +0,0 @@ -import json -import os - -from e2xcore import urljoin -from jupyter_client.kernelspec import KernelSpecManager -from nbgrader.server_extensions.formgrader.base import check_xsrf -from tornado import web - -from e2xgrader.converters import GenerateExercise -from e2xgrader.models import ( - AssignmentModel, - ExerciseModel, - PresetModel, - TaskModel, - TaskPoolModel, - TemplateModel, -) - -from ..e2xgraderapi.base import E2xApiHandler -from .notebookvariableextractor import NotebookVariableExtractor - - -class BaseApiManageHandler(E2xApiHandler): - def initialize(self, model_cls): - self.__model = model_cls(self.coursedir) - - @web.authenticated - @check_xsrf - def post(self, **kwargs): - self.write(self.__model.new(**kwargs)) - - @web.authenticated - @check_xsrf - def delete(self, **kwargs): - self.__model.remove(**kwargs) - self.write({"status": True}) - - @web.authenticated - @check_xsrf - def get(self, **kwargs): - self.write(json.dumps(self.__model.get(**kwargs))) - - @web.authenticated - @check_xsrf - def put(self, **kwargs): - self.write(self.__model.new(**kwargs)) - - -class BaseApiListHandler(E2xApiHandler): - def initialize(self, model_cls): - self.__model = model_cls(self.coursedir) - - @web.authenticated - @check_xsrf - def get(self, **kwargs): - self.write(json.dumps(self.__model.list(**kwargs))) - - -class PresetHandler(E2xApiHandler): - def initialize(self): - self.__model = PresetModel(self.coursedir) - - def _list_template(self): - self.write(json.dumps(self.__model.list_template_presets())) - - def _get_template(self): - name = self.get_argument("name") - self.write(json.dumps(self.__model.get_template_preset(name))) - - def _list_question(self): - self.write(json.dumps(self.__model.list_question_presets())) - - def _get_question(self): - name = self.get_argument("name") - self.write(json.dumps(self.__model.get_question_preset(name))) - - @web.authenticated - @check_xsrf - def get(self): - action = self.get_argument("action") - preset_type = self.get_argument("type") - handler = getattr(self, "_{}_{}".format(action, preset_type)) - handler() - - -class TemplateVariableHandler(E2xApiHandler): - @web.authenticated - @check_xsrf - def get(self): - template = self.get_argument("template") - variables = NotebookVariableExtractor().extract( - os.path.join( - self.url_prefix, "templates", template, "{}.ipynb".format(template) - ) - ) - self.write(json.dumps(variables)) - - -class KernelSpecHandler(E2xApiHandler): - @web.authenticated - @check_xsrf - def get(self): - self.write(json.dumps(KernelSpecManager().get_all_specs())) - - -class GenerateExerciseHandler(E2xApiHandler): - @web.authenticated - @check_xsrf - def get(self): - resources = json.loads(self.get_argument("resources")) - GenerateExercise(coursedir=self.coursedir).convert(resources) - self.write({"status": True}) - - -pool_regex = r"(?P[^/]+)" -name_regex = r"(?P[^/]+)" -assignment_regex = r"(?P[^/]+)" - -api_url = urljoin("e2x", "authoring", "api") -default_handlers = [ - (urljoin(api_url, "presets"), PresetHandler), - ( - urljoin(api_url, "assignments", "?"), - BaseApiListHandler, - dict(model_cls=AssignmentModel), - ), - ( - urljoin(api_url, "template", name_regex, "?"), - BaseApiManageHandler, - dict(model_cls=TemplateModel), - ), - ( - urljoin(api_url, "templates", "?"), - BaseApiListHandler, - dict(model_cls=TemplateModel), - ), - ( - urljoin(api_url, "pool", name_regex, "?"), - BaseApiManageHandler, - dict(model_cls=TaskPoolModel), - ), - (urljoin(api_url, "pools", "?"), BaseApiListHandler, dict(model_cls=TaskPoolModel)), - ( - urljoin(api_url, "pools", pool_regex, "?"), - BaseApiListHandler, - dict(model_cls=TaskModel), - ), - ( - urljoin(api_url, "task", pool_regex, name_regex, "?"), - BaseApiManageHandler, - dict(model_cls=TaskModel), - ), - ( - urljoin(api_url, "exercise", assignment_regex, name_regex, "?"), - BaseApiManageHandler, - dict(model_cls=ExerciseModel), - ), - ( - urljoin(api_url, "assignments", assignment_regex, "?"), - BaseApiListHandler, - dict(model_cls=ExerciseModel), - ), - (urljoin(api_url, "templates", "variables"), TemplateVariableHandler), - (urljoin(api_url, "kernelspec"), KernelSpecHandler), - (urljoin(api_url, "generate_exercise"), GenerateExerciseHandler), -] diff --git a/e2xgrader/server_extensions/apps/authoring/authoring.py b/e2xgrader/server_extensions/apps/authoring/authoring.py deleted file mode 100644 index 948a76ab..00000000 --- a/e2xgrader/server_extensions/apps/authoring/authoring.py +++ /dev/null @@ -1,31 +0,0 @@ -import os - -from e2xcore import BaseApp -from nbgrader.apps.baseapp import NbGrader -from tornado import web - -from .apihandlers import default_handlers as default_api_handlers -from .handlers import default_handlers - - -class AuthoringApp(NbGrader, BaseApp): - template_path = os.path.join(os.path.dirname(__file__), "templates") - static_path = os.path.join(os.path.dirname(__file__), "static") - - def __init__(self, **kwargs): - NbGrader.__init__(self, **kwargs) - BaseApp.__init__(self, **kwargs) - - def load_app(self): - self.log.info("Loading the e2xgrader authoring app") - self.add_template_path(self.template_path) - self.add_handlers(default_api_handlers) - self.add_handlers(default_handlers) - static_handlers = [ - ( - r"/e2x/authoring/static/(.*)", - web.StaticFileHandler, - {"path": self.static_path}, - ), - ] - self.add_handlers(static_handlers) diff --git a/e2xgrader/server_extensions/apps/authoring/handlers.py b/e2xgrader/server_extensions/apps/authoring/handlers.py deleted file mode 100644 index 305f6bf2..00000000 --- a/e2xgrader/server_extensions/apps/authoring/handlers.py +++ /dev/null @@ -1,138 +0,0 @@ -import os -import sys - -from e2xcore import urljoin -from nbgrader.server_extensions.formgrader.base import ( - BaseHandler, - check_notebook_dir, - check_xsrf, -) -from tornado import web - -from e2xgrader.models import ExerciseModel, TaskPoolModel, TemplateModel - -app_url = urljoin("e2x", "authoring", "app") - - -class TaskcreatorHandler(BaseHandler): - @web.authenticated - @check_xsrf - @check_notebook_dir - def get(self): - self.redirect(urljoin(self.base_url, app_url, "assignments")) - - -class ManageAssignmentsHandler(BaseHandler): - @web.authenticated - @check_xsrf - @check_notebook_dir - def get(self): - html = self.render( - os.path.join("authoring", "assignments.tpl"), - url_prefix=self.url_prefix, - base_url=self.base_url, - windows=(sys.prefix == "win32"), - ) - self.write(html) - - -class ManageExercisesHandler(BaseHandler): - @web.authenticated - @check_xsrf - @check_notebook_dir - def get(self, assignment): - html = self.render( - os.path.join("authoring", "exercises.tpl"), - url_prefix=self.url_prefix, - base_url=self.base_url, - assignment=assignment, - windows=(sys.prefix == "win32"), - ) - self.write(html) - - -class ManagePoolsHandler(BaseHandler): - @web.authenticated - @check_xsrf - @check_notebook_dir - def get(self): - html = self.render( - os.path.join("authoring", "taskpools.tpl"), - url_prefix=self.url_prefix, - base_url=self.base_url, - windows=(sys.prefix == "win32"), - ) - self.write(html) - - -class ManageTasksHandler(BaseHandler): - @web.authenticated - @check_xsrf - @check_notebook_dir - def get(self, pool): - html = self.render( - os.path.join("authoring", "tasks.tpl"), - url_prefix=self.url_prefix, - base_url=self.base_url, - pool=pool, - windows=(sys.prefix == "win32"), - ) - self.write(html) - - -class ManageTemplatesHandler(BaseHandler): - @web.authenticated - @check_xsrf - @check_notebook_dir - def get(self): - html = self.render( - os.path.join("authoring", "templates.tpl"), - url_prefix=self.url_prefix, - base_url=self.base_url, - windows=(sys.prefix == "win32"), - ) - self.write(html) - - -class EditExercisesHandler(BaseHandler): - def initialize(self): - self._model = ExerciseModel(self.coursedir) - - @web.authenticated - @check_xsrf - @check_notebook_dir - def get(self, assignment, exercise): - html = self.render( - os.path.join("authoring", "editexercise.tpl"), - url_prefix=self.url_prefix, - base_url=self.base_url, - exercise=exercise, - assignment=assignment, - templates=TemplateModel(self.coursedir).list(), - pools=TaskPoolModel(self.coursedir).list(), - windows=(sys.prefix == "win32"), - ) - self.write(html) - - -default_handlers = [ - (urljoin(app_url, "?"), TaskcreatorHandler), - (urljoin(app_url, "assignments", "?"), ManageAssignmentsHandler), - ( - urljoin(app_url, "assignments", r"(?P[^/]+)", "?"), - ManageExercisesHandler, - ), - (urljoin(app_url, "pools", "?"), ManagePoolsHandler), - (urljoin(app_url, "pools", r"(?P[^/]+)", "?"), ManageTasksHandler), - (urljoin(app_url, "templates", "?"), ManageTemplatesHandler), - ( - urljoin( - app_url, - "assignments", - r"(?P[^/]+)", - r"(?P[^/]+)", - "?", - ), - EditExercisesHandler, - ), -] diff --git a/e2xgrader/server_extensions/apps/authoring/notebookvariableextractor.py b/e2xgrader/server_extensions/apps/authoring/notebookvariableextractor.py deleted file mode 100644 index b436c6a1..00000000 --- a/e2xgrader/server_extensions/apps/authoring/notebookvariableextractor.py +++ /dev/null @@ -1,16 +0,0 @@ -import re - -import nbformat - - -class NotebookVariableExtractor: - def __init__(self): - self.__pattern = re.compile(r"{{\s*(\w+)\s*}}") - - def extract(self, nb_path): - nb = nbformat.read(nb_path, as_version=4) - variables = [] - for cell in nb.cells: - source = cell.source - variables.extend(self.__pattern.findall(source)) - return variables diff --git a/e2xgrader/server_extensions/apps/authoring/static/css/editexercise.css b/e2xgrader/server_extensions/apps/authoring/static/css/editexercise.css deleted file mode 100644 index d1514e69..00000000 --- a/e2xgrader/server_extensions/apps/authoring/static/css/editexercise.css +++ /dev/null @@ -1,54 +0,0 @@ -#tasks td { - text-align: center; -} - -.mid-col { - width: 20%; -} - -.mid-col button { - display: block; - width: 6em; - margin: auto; - margin-top: 0.5em; -} - -.side-col { - width: 40%; -} - -#selected-tasks { - min-width: 100%; - min-height: 15em; -} - -#available-tasks { - min-width: 100%; - min-height: 15em; -} - -#template-options { - margin-top: 1em; -} - -select[name="pool"] { - margin-left: 1em; -} - -.e2xtable { - min-width: 40%; -} - -.e2xtable th { - text-align: center; -} - -.btn-controls { - display: block; - width: 6em; - margin: 0.1em; -} - -.btn-primary a { - text-decoration: none; -} diff --git a/e2xgrader/server_extensions/apps/authoring/static/css/sidebar.css b/e2xgrader/server_extensions/apps/authoring/static/css/sidebar.css deleted file mode 100644 index 9ca066b8..00000000 --- a/e2xgrader/server_extensions/apps/authoring/static/css/sidebar.css +++ /dev/null @@ -1,46 +0,0 @@ -.sidebar { - background-color: #f2f2f2; - height: 100%; - min-height: 100%; - line-height: 3em; -} - -.sidebar a { - display: block; - padding: 0.2em 0 0.2em 1em; - margin: 0; - text-decoration: none; - color: #555; - font-size: 1.5em; -} - -.sidebar h3 { - display: block; - padding: 1.5em; - margin: 0; - font-size: 2em; - background-color: #2980b9; - color: #fff; - margin-bottom: 1em; -} - -.sidebar a:hover { - background-color: #ddd; -} - -.sidebar .active { - background-color: #5f5f5f; - color: #f2f2f2; -} - -.sidebar .active:hover { - background-color: #5f5f5f; - color: #f2f2f2; -} - -.body { - padding-left: 2em; - padding-right: 2em; - width: 100%; - overflow: auto; -} diff --git a/e2xgrader/server_extensions/apps/authoring/static/css/taskcreator.css b/e2xgrader/server_extensions/apps/authoring/static/css/taskcreator.css deleted file mode 100644 index 563f47e1..00000000 --- a/e2xgrader/server_extensions/apps/authoring/static/css/taskcreator.css +++ /dev/null @@ -1,149 +0,0 @@ -body { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 13px; - line-height: 1.42857143; - color: #000; - display: flex; - position: absolute; - margin: 0; - height: 100%; - width: 100%; -} - -.e2xbtn { - color: #fff; - background-color: #2980b9; - border: none; - border-radius: 0.3em; - box-shadow: 0px 0.2em 0.2px #3896d3; - padding: 0.5em 1em 0.5em 1em; -} - -.e2xbtn:hover { - color: #fff; - background-color: #51aae6; - border: none; - border-radius: 0.3em; - box-shadow: 0px 0.2em 0px #76bceb; -} - -#create_question { - margin-left: 3em; -} - -#create_question a { - border: 1px solid #dae4e7; - padding: 0.5em; - background-color: #eaf4f7; - text-decoration: none; - margin-left: -9px; - color: #333; -} - -.e2xtable { - border-collapse: collapse; - border-spacing: 0; - margin-bottom: 1em; - border: 1px solid #ddd; - min-width: 100%; -} - -.e2xtable td { - text-align: center; - padding: 0.5em; - border: 1px solid #ddd; -} - -.e2xtable tr:nth-child(even) { - background-color: white; -} - -.e2xtable tr:nth-child(odd) { - background-color: #f2f2f2; -} - -.e2xtable .column2 { - float: right; -} - -.e2xtable select { - height: 2.5em; - width: 15em; - border: 1px solid #bbb; -} - -.e2xtable input[type="text"] { - height: 2.5em; - width: 15em; -} - -#taskdiv { - margin: auto; -} - -.breadcrumbs li { - display: inline-block; -} - -.breadcrumbs ul { - padding: 0em; -} - -.breadcrumbs { - padding-left: 0.5em; - background-color: #f2f2f2; - border-radius: 0.5em; - line-height: 2em; -} - -a { - color: #337ab7; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - -th:nth-child(1) { - text-align: left; - padding-left: 0.8em; -} - -td:nth-child(1) { - text-align: left; - padding-left: 0.8em; -} - -th { - line-height: 3em; -} - -svg { - color: #23527c; -} - -.e2xtable thead th { - background-color: #2980b9; - color: white; -} - -.help { - background-color: #eee; - border-radius: 0.5em; - padding: 0.5em; - margin-bottom: 2em; -} - -#generate-exercise { - margin-bottom: 2em; -} - -.btn a { - text-decoration: none; - color: #fff; -} - -.btn { - margin: 0.5em; -} diff --git a/e2xgrader/server_extensions/apps/authoring/static/js/assignments.js b/e2xgrader/server_extensions/apps/authoring/static/js/assignments.js deleted file mode 100644 index 24155f20..00000000 --- a/e2xgrader/server_extensions/apps/authoring/static/js/assignments.js +++ /dev/null @@ -1,59 +0,0 @@ -let AssignmentUI = Backbone.View.extend({ - events: {}, - - initialize: function () { - this.$assignment_name = this.$el.find(".assignment-name"); - this.$number_of_exercises = this.$el.find(".number-of-exercises"); - - this.listenTo(this.model, "sync", this.render); - this.render(); - }, - - render: function () { - let name = this.model.get("name"); - this.$assignment_name.append( - $("") - .attr("href", base_url + "/e2x/authoring/app/assignments/" + name) - .text(name) - ); - this.$number_of_exercises.text(this.model.get("exercises")); - }, -}); - -function insertRow(table) { - let row = $(""); - row.append($("").addClass("assignment-name")); - row.append($("").addClass("number-of-exercises")); - table.append(row); - return row; -} - -function loadAssignments() { - console.log("Loading the assignments"); - let tbl = $("#main_table"); - models = new Assignments(); - views = []; - models.loaded = false; - models.fetch({ - success: function () { - tbl.empty(); - models.each(function (model) { - let view = new AssignmentUI({ - model: model, - el: insertRow(tbl), - }); - views.push(view); - }); - tbl.parent().DataTable(); - - models.loaded = true; - }, - }); -} - -let models = undefined; -let views = []; - -$(window).on("load", function () { - loadAssignments(); -}); diff --git a/e2xgrader/server_extensions/apps/authoring/static/js/base.js b/e2xgrader/server_extensions/apps/authoring/static/js/base.js deleted file mode 100644 index bec8dec9..00000000 --- a/e2xgrader/server_extensions/apps/authoring/static/js/base.js +++ /dev/null @@ -1,150 +0,0 @@ -let Assignment = Backbone.Model.extend({ - idAttribute: "name", - urlRoot: base_url + "/e2x/authoring/api/assignment", -}); - -let Assignments = Backbone.Collection.extend({ - model: Assignment, - url: base_url + "/e2x/authoring/api/assignments", -}); - -let Exercise = Backbone.Model.extend({ - idAttribute: "name", - initialize: function (options) { - this.urlRoot = - base_url + "/e2x/authoring/api/exercise/" + options.assignment; - }, -}); - -let Exercises = Backbone.Collection.extend({ - model: Exercise, - initialize: function (options) { - this.url = - base_url + "/e2x/authoring/api/assignments/" + options.assignment; - }, -}); - -let Pool = Backbone.Model.extend({ - idAttribute: "name", - urlRoot: base_url + "/e2x/authoring/api/pool", -}); - -let Pools = Backbone.Collection.extend({ - model: Pool, - url: base_url + "/e2x/authoring/api/pools/", - comparator: "name", -}); - -let Task = Backbone.Model.extend({ - idAttribute: "name", - initialize: function (options) { - this.urlRoot = base_url + "/e2x/authoring/api/task/" + options.pool; - }, -}); - -let Tasks = Backbone.Collection.extend({ - model: Task, - initialize: function (options) { - this.url = base_url + "/e2x/authoring/api/pools/" + options.pool; - }, - comparator: "name", -}); - -let Template = Backbone.Model.extend({ - idAttribute: "name", - urlRoot: base_url + "/e2x/authoring/api/template", -}); - -let Templates = Backbone.Collection.extend({ - model: Template, - url: base_url + "/e2x/authoring/api/templates/", -}); - -let BaseUI = Backbone.View.extend({ - events: {}, - - initialize: function () { - this.fields = []; - }, - - clear: function () { - this.fields.forEach((field) => field.empty()); - }, - - openRemoveModal: function (body, title) { - let footer = $("
"); - footer.append( - $("
- - -{% endblock body %} \ No newline at end of file diff --git a/e2xgrader/server_extensions/apps/authoring/templates/authoring/exercises.tpl b/e2xgrader/server_extensions/apps/authoring/templates/authoring/exercises.tpl deleted file mode 100644 index f286b9dd..00000000 --- a/e2xgrader/server_extensions/apps/authoring/templates/authoring/exercises.tpl +++ /dev/null @@ -1,40 +0,0 @@ -{%- extends 'authoring/tablebase.tpl' -%} - -{% block head %} - -{{ super() }} - -{% endblock head %} - -{% block sidebar %} -{{ super() }} - -{% endblock sidebar %} - -{% block headline %} -

Assignments

-{% endblock headline %} -{% block breadcrumbs %} -
  • Assignments
  • -
  • > {{ assignment }}
  • -{% endblock breadcrumbs %} - -{% block help %} -

    Choose your exercise

    -

    Here you can choose or create an exercise. An exercise is a single Jupyter Notebook consisting of tasks..

    -{% endblock help %} - -{% block table_head %} -Name -Remove -{% endblock table_head %} -{% block table_body %} -Loading... -{% endblock table_body %} -{% block add_new %} - -{% endblock add_new %} diff --git a/e2xgrader/server_extensions/apps/authoring/templates/authoring/tablebase.tpl b/e2xgrader/server_extensions/apps/authoring/templates/authoring/tablebase.tpl deleted file mode 100644 index d5ebfa93..00000000 --- a/e2xgrader/server_extensions/apps/authoring/templates/authoring/tablebase.tpl +++ /dev/null @@ -1,35 +0,0 @@ -{%- extends 'authoring/base.tpl' -%} - -{% block body %} - -{% block headline %} -{% endblock %} - - -
    - {% block help %} - {% endblock %} -
    - - -
    - - - {% block table_head %} - {% endblock %} - - - {% block table_body %} - {% endblock %} - -
    - {% block add_new %} - {% endblock %} -
    - -{% endblock body %} \ No newline at end of file diff --git a/e2xgrader/server_extensions/apps/authoring/templates/authoring/taskcreator.tpl b/e2xgrader/server_extensions/apps/authoring/templates/authoring/taskcreator.tpl deleted file mode 100644 index 06b6bb49..00000000 --- a/e2xgrader/server_extensions/apps/authoring/templates/authoring/taskcreator.tpl +++ /dev/null @@ -1,43 +0,0 @@ -{%- extends 'base.tpl' -%} - -{% block head %} - -{% endblock head %} - -{% block body %} - -

    Hello

    - -
    -
    -{% endblock body %} \ No newline at end of file diff --git a/e2xgrader/server_extensions/apps/authoring/templates/authoring/taskpools.tpl b/e2xgrader/server_extensions/apps/authoring/templates/authoring/taskpools.tpl deleted file mode 100644 index 7ebb125c..00000000 --- a/e2xgrader/server_extensions/apps/authoring/templates/authoring/taskpools.tpl +++ /dev/null @@ -1,37 +0,0 @@ -{%- extends 'authoring/tablebase.tpl' -%} - -{% block head %} -{{ super() }} - -{% endblock head %} - -{% block sidebar %} -{{ super() }} - -{% endblock sidebar %} - -{% block headline %} -

    Task Pools

    -{% endblock headline %} -{% block breadcrumbs %} -
  • Task Pools
  • -{% endblock breadcrumbs %} - -{% block help %} -

    Manage task pools

    -

    Task pools are collections of tasks about the same topic. A task consists of a collection of related questions.

    -{% endblock help %} - -{% block table_head %} -Name -Number of Tasks -Remove -{% endblock table_head %} -{% block table_body %} -Loading... -{% endblock table_body %} -{% block add_new %} - -{% endblock add_new %} diff --git a/e2xgrader/server_extensions/apps/authoring/templates/authoring/tasks.tpl b/e2xgrader/server_extensions/apps/authoring/templates/authoring/tasks.tpl deleted file mode 100644 index 3b1e6116..00000000 --- a/e2xgrader/server_extensions/apps/authoring/templates/authoring/tasks.tpl +++ /dev/null @@ -1,43 +0,0 @@ -{%- extends 'authoring/tablebase.tpl' -%} - -{% block head %} - -{{ super() }} - -{% endblock head %} - -{% block sidebar %} -{{ super() }} - -{% endblock sidebar %} - -{% block headline %} -

    Tasks

    -{% endblock headline %} -{% block breadcrumbs %} -
  • Task Pools
  • -
  • > {{ pool }}
  • -{% endblock breadcrumbs %} - -{% block help %} -

    Tasks

    -

    A task is a single Jupyter notebook consisting of a task with questions (i.e. Task 1.1, Task 1.2, Task1.3).

    -{% endblock help %} - -{% block table_head %} -Name -# of Questions -Points -Edit -Remove -{% endblock table_head %} -{% block table_body %} -Loading... -{% endblock table_body %} -{% block add_new %} - -{% endblock add_new %} diff --git a/e2xgrader/server_extensions/apps/authoring/templates/authoring/templates.tpl b/e2xgrader/server_extensions/apps/authoring/templates/authoring/templates.tpl deleted file mode 100644 index 12ce897b..00000000 --- a/e2xgrader/server_extensions/apps/authoring/templates/authoring/templates.tpl +++ /dev/null @@ -1,41 +0,0 @@ -{%- extends 'authoring/tablebase.tpl' -%} - -{% block head %} -{{ super() }} - -{% endblock head %} - -{% block sidebar %} -{{ super() }} - -{% endblock sidebar %} - - -{% block headline %} -

    Templates

    -{% endblock headline %} -{% block breadcrumbs %} -
  • Templates
  • -{% endblock breadcrumbs %} - -{% block help %} -

    Create and edit templates

    -

    Templates are used for creating exercises. A template consists of header and footer cells and special cells like student info. -You can use variables in templates by enclosing them in double curly braces (e.g. {{ my_var }}. -When creating an exercise you can set the values for those variables.

    -{% endblock help %} - - -{% block table_head %} -Name -Edit -Remove -{% endblock table_head %} -{% block table_body %} -Loading... -{% endblock table_body %} -{% block add_new %} - -{% endblock add_new %} diff --git a/e2xgrader/server_extensions/teacher/teacher.py b/e2xgrader/server_extensions/teacher/teacher.py index 8a02ccd1..50dceae0 100644 --- a/e2xgrader/server_extensions/teacher/teacher.py +++ b/e2xgrader/server_extensions/teacher/teacher.py @@ -1,7 +1,7 @@ +from e2xauthoring.app import AuthoringApp from traitlets import Any, List from ..apps.assignment_list import AssignmentList -from ..apps.authoring import AuthoringApp from ..apps.e2xgraderapi import E2xGraderApi from ..apps.formgrader import FormgradeApp from ..apps.help import Help diff --git a/pyproject.toml b/pyproject.toml index 7b8ee892..0c7ab71b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ classifiers=[ ] dependencies = [ "e2xcore", - "nbgrader>=0.7,<0.9", + "e2xauthoring", "pandas" ] dynamic = ["version"]